blob: 157a41b307c4dd6b160befa8d9d63c33d6235adb [file] [log] [blame]
Simon Kelley824af852008-02-12 20:43:05 +00001/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Simon Kelley849a8352006-06-09 21:02:31 +010019static struct frec *frec_list = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000020
Simon Kelley832af0b2007-01-21 20:01:28 +000021static struct frec *lookup_frec(unsigned short id, unsigned int crc);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000022static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +010023 union mysockaddr *addr,
24 unsigned int crc);
Simon Kelley832af0b2007-01-21 20:01:28 +000025static unsigned short get_id(int force, unsigned short force_id, unsigned int crc);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000026
Simon Kelley9e4abcb2004-01-22 19:47:41 +000027
Simon Kelley824af852008-02-12 20:43:05 +000028/* Send a UDP packet with its source address set as "source"
Simon Kelley44a2a312004-03-10 20:04:35 +000029 unless nowild is true, when we just send it with the kernel default */
Simon Kelleycdeda282006-03-16 20:16:06 +000030static void send_from(int fd, int nowild, char *packet, size_t len,
Simon Kelleydfa666f2004-08-02 18:27:27 +010031 union mysockaddr *to, struct all_addr *source,
32 unsigned int iface)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000033{
Simon Kelley44a2a312004-03-10 20:04:35 +000034 struct msghdr msg;
35 struct iovec iov[1];
Simon Kelley44a2a312004-03-10 20:04:35 +000036 union {
37 struct cmsghdr align; /* this ensures alignment */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010038#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +000039 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
40#elif defined(IP_SENDSRCADDR)
41 char control[CMSG_SPACE(sizeof(struct in_addr))];
42#endif
43#ifdef HAVE_IPV6
44 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
45#endif
46 } control_u;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010047
Simon Kelley44a2a312004-03-10 20:04:35 +000048 iov[0].iov_base = packet;
49 iov[0].iov_len = len;
50
Simon Kelleyfeba5c12004-07-27 20:28:58 +010051 msg.msg_control = NULL;
52 msg.msg_controllen = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +000053 msg.msg_flags = 0;
54 msg.msg_name = to;
55 msg.msg_namelen = sa_len(to);
56 msg.msg_iov = iov;
57 msg.msg_iovlen = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010058
Simon Kelley26128d22004-11-14 16:43:54 +000059 if (!nowild)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010060 {
Simon Kelley26128d22004-11-14 16:43:54 +000061 struct cmsghdr *cmptr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010062 msg.msg_control = &control_u;
63 msg.msg_controllen = sizeof(control_u);
Simon Kelley26128d22004-11-14 16:43:54 +000064 cmptr = CMSG_FIRSTHDR(&msg);
Simon Kelley44a2a312004-03-10 20:04:35 +000065
Simon Kelley26128d22004-11-14 16:43:54 +000066 if (to->sa.sa_family == AF_INET)
67 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010068#if defined(HAVE_LINUX_NETWORK)
Simon Kelley26128d22004-11-14 16:43:54 +000069 struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
70 pkt->ipi_ifindex = 0;
71 pkt->ipi_spec_dst = source->addr.addr4;
72 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
73 cmptr->cmsg_level = SOL_IP;
74 cmptr->cmsg_type = IP_PKTINFO;
75#elif defined(IP_SENDSRCADDR)
76 struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
77 *a = source->addr.addr4;
78 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
79 cmptr->cmsg_level = IPPROTO_IP;
80 cmptr->cmsg_type = IP_SENDSRCADDR;
Simon Kelley44a2a312004-03-10 20:04:35 +000081#endif
Simon Kelley26128d22004-11-14 16:43:54 +000082 }
Simon Kelley26128d22004-11-14 16:43:54 +000083 else
Simon Kelleyb8187c82005-11-26 21:46:27 +000084#ifdef HAVE_IPV6
Simon Kelley26128d22004-11-14 16:43:54 +000085 {
86 struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
87 pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
88 pkt->ipi6_addr = source->addr.addr6;
89 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
90 cmptr->cmsg_type = IPV6_PKTINFO;
91 cmptr->cmsg_level = IPV6_LEVEL;
92 }
Simon Kelley3d8df262005-08-29 12:19:27 +010093#else
94 iface = 0; /* eliminate warning */
Simon Kelley26128d22004-11-14 16:43:54 +000095#endif
96 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +010097
Simon Kelleyfd9fa482004-10-21 20:24:00 +010098 retry:
99 if (sendmsg(fd, &msg, 0) == -1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100100 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100101 /* certain Linux kernels seem to object to setting the source address in the IPv6 stack
102 by returning EINVAL from sendmsg. In that case, try again without setting the
103 source address, since it will nearly alway be correct anyway. IPv6 stinks. */
104 if (errno == EINVAL && msg.msg_controllen)
105 {
106 msg.msg_controllen = 0;
107 goto retry;
108 }
109 if (retry_send())
110 goto retry;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100111 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000112}
113
Simon Kelley5aabfc72007-08-29 11:24:47 +0100114static unsigned short search_servers(time_t now, struct all_addr **addrpp,
Simon Kelley36717ee2004-09-20 19:20:58 +0100115 unsigned short qtype, char *qdomain, int *type, char **domain)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100116
117{
118 /* If the query ends in the domain in one of our servers, set
119 domain to point to that name. We find the largest match to allow both
120 domain.org and sub.domain.org to exist. */
121
122 unsigned int namelen = strlen(qdomain);
123 unsigned int matchlen = 0;
124 struct server *serv;
125 unsigned short flags = 0;
126
Simon Kelley3be34542004-09-11 19:12:13 +0100127 for (serv = daemon->servers; serv; serv=serv->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100128 /* domain matches take priority over NODOTS matches */
Simon Kelley3d8df262005-08-29 12:19:27 +0100129 if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100130 {
131 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
132 *type = SERV_FOR_NODOTS;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100133 if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100134 flags = F_NXDOMAIN;
135 else if (serv->flags & SERV_LITERAL_ADDRESS)
136 {
137 if (sflag & qtype)
138 {
139 flags = sflag;
140 if (serv->addr.sa.sa_family == AF_INET)
141 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100142#ifdef HAVE_IPV6
Simon Kelley36717ee2004-09-20 19:20:58 +0100143 else
144 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100145#endif
Simon Kelley36717ee2004-09-20 19:20:58 +0100146 }
Simon Kelley824af852008-02-12 20:43:05 +0000147 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100148 flags = F_NOERR;
149 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100150 }
151 else if (serv->flags & SERV_HAS_DOMAIN)
152 {
153 unsigned int domainlen = strlen(serv->domain);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000154 char *matchstart = qdomain + namelen - domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100155 if (namelen >= domainlen &&
Simon Kelleyb8187c82005-11-26 21:46:27 +0000156 hostname_isequal(matchstart, serv->domain) &&
157 domainlen >= matchlen &&
Simon Kelleycdeda282006-03-16 20:16:06 +0000158 (domainlen == 0 || namelen == domainlen || *(serv->domain) == '.' || *(matchstart-1) == '.' ))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100159 {
160 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
161 *type = SERV_HAS_DOMAIN;
162 *domain = serv->domain;
163 matchlen = domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100164 if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100165 flags = F_NXDOMAIN;
166 else if (serv->flags & SERV_LITERAL_ADDRESS)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100167 {
Simon Kelley824af852008-02-12 20:43:05 +0000168 if (sflag & qtype)
Simon Kelley36717ee2004-09-20 19:20:58 +0100169 {
Simon Kelley824af852008-02-12 20:43:05 +0000170 flags = sflag;
Simon Kelley36717ee2004-09-20 19:20:58 +0100171 if (serv->addr.sa.sa_family == AF_INET)
172 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100173#ifdef HAVE_IPV6
Simon Kelley36717ee2004-09-20 19:20:58 +0100174 else
175 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100176#endif
Simon Kelley36717ee2004-09-20 19:20:58 +0100177 }
Simon Kelley824af852008-02-12 20:43:05 +0000178 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100179 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100180 }
181 }
182 }
183
Simon Kelley824af852008-02-12 20:43:05 +0000184 if (flags == 0 && !(qtype & F_BIGNAME) &&
185 (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
186 /* don't forward simple names, make exception for NS queries and empty name. */
Simon Kelley36717ee2004-09-20 19:20:58 +0100187 flags = F_NXDOMAIN;
188
Simon Kelley5aabfc72007-08-29 11:24:47 +0100189 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100190 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100191
Simon Kelley824af852008-02-12 20:43:05 +0000192 if (flags)
193 {
194 int logflags = 0;
195
196 if (flags == F_NXDOMAIN || flags == F_NOERR)
197 logflags = F_NEG | qtype;
198
199 log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, 0, NULL, 0);
200 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100201
202 return flags;
203}
Simon Kelley44a2a312004-03-10 20:04:35 +0000204
Simon Kelley824af852008-02-12 20:43:05 +0000205static int forward_query(int udpfd, union mysockaddr *udpaddr,
206 struct all_addr *dst_addr, unsigned int dst_iface,
207 HEADER *header, size_t plen, time_t now, struct frec *forward)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000208{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000209 char *domain = NULL;
Simon Kelley0a852542005-03-23 20:28:59 +0000210 int type = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000211 struct all_addr *addrp = NULL;
Simon Kelleycdeda282006-03-16 20:16:06 +0000212 unsigned int crc = questions_crc(header, plen, daemon->namebuff);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000213 unsigned short flags = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +0000214 unsigned short gotname = extract_request(header, plen, daemon->namebuff, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100215 struct server *start = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100216
217 /* may be no servers available. */
218 if (!daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000219 forward = NULL;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000220 else if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000221 {
Simon Kelleyde379512004-06-22 20:23:33 +0100222 /* retry on existing query, send to all available servers */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000223 domain = forward->sentto->domain;
Simon Kelley824af852008-02-12 20:43:05 +0000224 forward->sentto->failed_queries++;
Simon Kelley3be34542004-09-11 19:12:13 +0100225 if (!(daemon->options & OPT_ORDER))
Simon Kelleyde379512004-06-22 20:23:33 +0100226 {
Simon Kelley0a852542005-03-23 20:28:59 +0000227 forward->forwardall = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100228 daemon->last_server = NULL;
Simon Kelleyde379512004-06-22 20:23:33 +0100229 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000230 type = forward->sentto->flags & SERV_TYPE;
Simon Kelleyde379512004-06-22 20:23:33 +0100231 if (!(start = forward->sentto->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100232 start = daemon->servers; /* at end of list, recycle */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000233 header->id = htons(forward->new_id);
234 }
235 else
236 {
237 if (gotname)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100238 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000239
Simon Kelley5aabfc72007-08-29 11:24:47 +0100240 if (!flags && !(forward = get_new_frec(now, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100241 /* table full - server failure. */
242 flags = F_NEG;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000243
244 if (forward)
245 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000246 /* force unchanging id for signed packets */
247 int is_sign;
248 find_pseudoheader(header, plen, NULL, NULL, &is_sign);
249
Simon Kelley0a852542005-03-23 20:28:59 +0000250 forward->source = *udpaddr;
251 forward->dest = *dst_addr;
252 forward->iface = dst_iface;
Simon Kelley0a852542005-03-23 20:28:59 +0000253 forward->orig_id = ntohs(header->id);
Simon Kelley832af0b2007-01-21 20:01:28 +0000254 forward->new_id = get_id(is_sign, forward->orig_id, crc);
255 forward->fd = udpfd;
Simon Kelley0a852542005-03-23 20:28:59 +0000256 forward->crc = crc;
257 forward->forwardall = 0;
258 header->id = htons(forward->new_id);
259
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000260 /* In strict_order mode, or when using domain specific servers
261 always try servers in the order specified in resolv.conf,
262 otherwise, use the one last known to work. */
263
Simon Kelley3be34542004-09-11 19:12:13 +0100264 if (type != 0 || (daemon->options & OPT_ORDER))
265 start = daemon->servers;
266 else if (!(start = daemon->last_server))
Simon Kelleyde379512004-06-22 20:23:33 +0100267 {
Simon Kelley3be34542004-09-11 19:12:13 +0100268 start = daemon->servers;
Simon Kelley0a852542005-03-23 20:28:59 +0000269 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100270 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000271 }
272 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100273
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000274 /* check for send errors here (no route to host)
275 if we fail to send to all nameservers, send back an error
276 packet straight away (helps modem users when offline) */
277
278 if (!flags && forward)
279 {
Simon Kelleyde379512004-06-22 20:23:33 +0100280 struct server *firstsentto = start;
281 int forwarded = 0;
282
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000283 while (1)
284 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000285 /* only send to servers dealing with our domain.
286 domain may be NULL, in which case server->domain
287 must be NULL also. */
288
Simon Kelleyde379512004-06-22 20:23:33 +0100289 if (type == (start->flags & SERV_TYPE) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100290 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
291 !(start->flags & SERV_LITERAL_ADDRESS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000292 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100293 if (sendto(start->sfd->fd, (char *)header, plen, 0,
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100294 &start->addr.sa,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100295 sa_len(&start->addr)) == -1)
296 {
297 if (retry_send())
298 continue;
299 }
300 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000301 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000302 /* Keep info in case we want to re-send this packet */
303 daemon->srv_save = start;
304 daemon->packet_len = plen;
305
Simon Kelleyde379512004-06-22 20:23:33 +0100306 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100307 strcpy(daemon->namebuff, "query");
Simon Kelleyde379512004-06-22 20:23:33 +0100308 if (start->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100309 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100310 (struct all_addr *)&start->addr.in.sin_addr, 0,
311 NULL, 0);
Simon Kelleyde379512004-06-22 20:23:33 +0100312#ifdef HAVE_IPV6
313 else
Simon Kelley3be34542004-09-11 19:12:13 +0100314 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100315 (struct all_addr *)&start->addr.in6.sin6_addr, 0,
316 NULL, 0);
Simon Kelleyde379512004-06-22 20:23:33 +0100317#endif
Simon Kelley824af852008-02-12 20:43:05 +0000318 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100319 forwarded = 1;
320 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000321 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100322 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000323 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000324 }
325 }
326
Simon Kelleyde379512004-06-22 20:23:33 +0100327 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100328 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000329
Simon Kelleyde379512004-06-22 20:23:33 +0100330 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000331 break;
332 }
333
Simon Kelleyde379512004-06-22 20:23:33 +0100334 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000335 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100336
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000337 /* could not send on, prepare to return */
338 header->id = htons(forward->orig_id);
Simon Kelley832af0b2007-01-21 20:01:28 +0000339 forward->sentto = NULL; /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000340 }
341
342 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000343 if (udpfd != -1)
344 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000345 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000346 send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
347 }
348
Simon Kelley824af852008-02-12 20:43:05 +0000349 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000350}
351
Simon Kelley5aabfc72007-08-29 11:24:47 +0100352static size_t process_reply(HEADER *header, time_t now,
Simon Kelley832af0b2007-01-21 20:01:28 +0000353 struct server *server, size_t n)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100354{
Simon Kelley36717ee2004-09-20 19:20:58 +0100355 unsigned char *pheader, *sizep;
Simon Kelley832af0b2007-01-21 20:01:28 +0000356 int munged = 0, is_sign;
Simon Kelleycdeda282006-03-16 20:16:06 +0000357 size_t plen;
358
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100359 /* If upstream is advertising a larger UDP packet size
360 than we allow, trim it so that we don't get overlarge
Simon Kelley832af0b2007-01-21 20:01:28 +0000361 requests for the client. We can't do this for signed packets. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100362
Simon Kelley832af0b2007-01-21 20:01:28 +0000363 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100364 {
365 unsigned short udpsz;
Simon Kelley36717ee2004-09-20 19:20:58 +0100366 unsigned char *psave = sizep;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100367
Simon Kelley36717ee2004-09-20 19:20:58 +0100368 GETSHORT(udpsz, sizep);
Simon Kelley3be34542004-09-11 19:12:13 +0100369 if (udpsz > daemon->edns_pktsz)
370 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100371 }
372
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000373 if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100374 return n;
375
Simon Kelley0a852542005-03-23 20:28:59 +0000376 /* Complain loudly if the upstream server is non-recursive. */
377 if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
378 server && !(server->flags & SERV_WARNED_RECURSIVE))
379 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100380 prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100381 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley0a852542005-03-23 20:28:59 +0000382 if (!(daemon->options & OPT_LOG))
383 server->flags |= SERV_WARNED_RECURSIVE;
384 }
385
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100386 if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
387 check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100388 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100389 munged = 1;
390 header->rcode = NXDOMAIN;
391 header->aa = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100392 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100393 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100394 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100395 if (header->rcode == NXDOMAIN &&
396 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100397 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100398 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100399 /* if we forwarded a query for a locally known name (because it was for
400 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
401 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100402 munged = 1;
403 header->aa = 1;
404 header->rcode = NOERROR;
Simon Kelley36717ee2004-09-20 19:20:58 +0100405 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000406
Simon Kelley824af852008-02-12 20:43:05 +0000407 if (extract_addresses(header, n, daemon->namebuff, now))
408 {
409 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected"));
410 munged = 1;
411 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100412 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100413
414 /* do this after extract_addresses. Ensure NODATA reply and remove
415 nameserver info. */
416
417 if (munged)
418 {
419 header->ancount = htons(0);
420 header->nscount = htons(0);
421 header->arcount = htons(0);
422 }
423
Simon Kelley36717ee2004-09-20 19:20:58 +0100424 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
425 sections of the packet. Find the new length here and put back pseudoheader
426 if it was removed. */
427 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100428}
429
Simon Kelley3be34542004-09-11 19:12:13 +0100430/* sets new last_server */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100431void reply_query(struct serverfd *sfd, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000432{
433 /* packet from peer server, extract data for cache, and send to
434 original requester */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000435 HEADER *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100436 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000437 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100438 socklen_t addrlen = sizeof(serveraddr);
Simon Kelleycdeda282006-03-16 20:16:06 +0000439 ssize_t n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
440 size_t nn;
441
442 /* packet buffer overwritten */
443 daemon->srv_save = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000444
Simon Kelleyde379512004-06-22 20:23:33 +0100445 /* Determine the address of the server replying so that we can mark that as good */
446 serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
447#ifdef HAVE_IPV6
448 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100449 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100450#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000451
Simon Kelley3be34542004-09-11 19:12:13 +0100452 header = (HEADER *)daemon->packet;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100453
Simon Kelley832af0b2007-01-21 20:01:28 +0000454 if (n >= (int)sizeof(HEADER) && header->qr &&
455 (forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000456 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000457 struct server *server = forward->sentto;
458
Simon Kelley6b010842007-02-12 20:32:07 +0000459 if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
460 !(daemon->options & OPT_ORDER) &&
461 forward->forwardall == 0)
Simon Kelley832af0b2007-01-21 20:01:28 +0000462 /* for broken servers, attempt to send to another one. */
463 {
464 unsigned char *pheader;
465 size_t plen;
466 int is_sign;
467
468 /* recreate query from reply */
469 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
470 if (!is_sign)
471 {
472 header->ancount = htons(0);
473 header->nscount = htons(0);
474 header->arcount = htons(0);
475 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
476 {
477 header->qr = 0;
478 header->tc = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100479 forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
Simon Kelley832af0b2007-01-21 20:01:28 +0000480 return;
481 }
482 }
483 }
484
485 if ((forward->sentto->flags & SERV_TYPE) == 0)
486 {
487 if (header->rcode == SERVFAIL || header->rcode == REFUSED)
488 server = NULL;
489 else
490 {
491 struct server *last_server;
492 /* find good server by address if possible, otherwise assume the last one we sent to */
493 for (last_server = daemon->servers; last_server; last_server = last_server->next)
494 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
495 sockaddr_isequal(&last_server->addr, &serveraddr))
496 {
497 server = last_server;
498 break;
499 }
500 }
Simon Kelley824af852008-02-12 20:43:05 +0000501 if (!(daemon->options & OPT_ALL_SERVERS))
502 daemon->last_server = server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000503 }
504
Simon Kelley0a852542005-03-23 20:28:59 +0000505 /* If the answer is an error, keep the forward record in place in case
506 we get a good reply from another server. Kill it when we've
507 had replies from all to avoid filling the forwarding table when
508 everything is broken */
509 if (forward->forwardall == 0 || --forward->forwardall == 1 ||
510 (header->rcode != REFUSED && header->rcode != SERVFAIL))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000511 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100512 if ((nn = process_reply(header, now, server, (size_t)n)))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000513 {
514 header->id = htons(forward->orig_id);
515 header->ra = 1; /* recursion if available */
Simon Kelleycdeda282006-03-16 20:16:06 +0000516 send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
Simon Kelleyb8187c82005-11-26 21:46:27 +0000517 &forward->source, &forward->dest, forward->iface);
518 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000519 forward->sentto = NULL; /* cancel */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000520 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000521 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000522}
Simon Kelley44a2a312004-03-10 20:04:35 +0000523
Simon Kelley5aabfc72007-08-29 11:24:47 +0100524void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +0000525{
Simon Kelley3be34542004-09-11 19:12:13 +0100526 HEADER *header = (HEADER *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +0000527 union mysockaddr source_addr;
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100528 unsigned short type;
Simon Kelley44a2a312004-03-10 20:04:35 +0000529 struct all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000530 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +0000531 size_t m;
532 ssize_t n;
533 int if_index = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000534 struct iovec iov[1];
535 struct msghdr msg;
536 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +0000537 union {
538 struct cmsghdr align; /* this ensures alignment */
539#ifdef HAVE_IPV6
540 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
541#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100542#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +0000543 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +0000544#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
545 char control[CMSG_SPACE(sizeof(struct in_addr)) +
546 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +0000547#elif defined(IP_RECVDSTADDR)
548 char control[CMSG_SPACE(sizeof(struct in_addr)) +
549 CMSG_SPACE(sizeof(struct sockaddr_dl))];
550#endif
551 } control_u;
552
Simon Kelleycdeda282006-03-16 20:16:06 +0000553 /* packet buffer overwritten */
554 daemon->srv_save = NULL;
555
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000556 if (listen->family == AF_INET && (daemon->options & OPT_NOWILD))
557 {
558 dst_addr_4 = listen->iface->addr.in.sin_addr;
559 netmask = listen->iface->netmask;
560 }
561 else
Simon Kelley3d8df262005-08-29 12:19:27 +0100562 {
563 dst_addr_4.s_addr = 0;
564 netmask.s_addr = 0;
565 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000566
Simon Kelley3be34542004-09-11 19:12:13 +0100567 iov[0].iov_base = daemon->packet;
568 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +0000569
570 msg.msg_control = control_u.control;
571 msg.msg_controllen = sizeof(control_u);
572 msg.msg_flags = 0;
573 msg.msg_name = &source_addr;
574 msg.msg_namelen = sizeof(source_addr);
575 msg.msg_iov = iov;
576 msg.msg_iovlen = 1;
577
Simon Kelleyde379512004-06-22 20:23:33 +0100578 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +0100579 return;
Simon Kelley44a2a312004-03-10 20:04:35 +0000580
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100581 if (n < (int)sizeof(HEADER) ||
582 (msg.msg_flags & MSG_TRUNC) ||
583 header->qr)
Simon Kelley3be34542004-09-11 19:12:13 +0100584 return;
Simon Kelley44a2a312004-03-10 20:04:35 +0000585
Simon Kelley26128d22004-11-14 16:43:54 +0000586 source_addr.sa.sa_family = listen->family;
587#ifdef HAVE_IPV6
588 if (listen->family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100589 source_addr.in6.sin6_flowinfo = 0;
Simon Kelley26128d22004-11-14 16:43:54 +0000590#endif
591
592 if (!(daemon->options & OPT_NOWILD))
Simon Kelley44a2a312004-03-10 20:04:35 +0000593 {
Simon Kelley8a911cc2004-03-16 18:35:52 +0000594 struct ifreq ifr;
595
Simon Kelley26128d22004-11-14 16:43:54 +0000596 if (msg.msg_controllen < sizeof(struct cmsghdr))
597 return;
598
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100599#if defined(HAVE_LINUX_NETWORK)
Simon Kelley26128d22004-11-14 16:43:54 +0000600 if (listen->family == AF_INET)
601 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
602 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
603 {
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000604 dst_addr_4 = dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
Simon Kelley26128d22004-11-14 16:43:54 +0000605 if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
606 }
607#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
608 if (listen->family == AF_INET)
609 {
610 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
611 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000612 dst_addr_4 = dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
Simon Kelley26128d22004-11-14 16:43:54 +0000613 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
Simon Kelley824af852008-02-12 20:43:05 +0000614#ifdef HAVE_SOLARIS_NETWORK
615 if_index = *((unsigned int *)CMSG_DATA(cmptr));
616#else
Simon Kelley26128d22004-11-14 16:43:54 +0000617 if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
Simon Kelley824af852008-02-12 20:43:05 +0000618#endif
Simon Kelley26128d22004-11-14 16:43:54 +0000619 }
620#endif
621
622#ifdef HAVE_IPV6
623 if (listen->family == AF_INET6)
624 {
625 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
626 if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
627 {
628 dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
629 if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
630 }
631 }
632#endif
633
634 /* enforce available interface configuration */
635
Simon Kelley8a911cc2004-03-16 18:35:52 +0000636 if (if_index == 0)
Simon Kelley3be34542004-09-11 19:12:13 +0100637 return;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000638
Simon Kelley8a911cc2004-03-16 18:35:52 +0000639#ifdef SIOCGIFNAME
Simon Kelley832af0b2007-01-21 20:01:28 +0000640 ifr.ifr_ifindex = if_index;
641 if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100642 return;
Simon Kelley832af0b2007-01-21 20:01:28 +0000643#else
644 if (!if_indextoname(if_index, ifr.ifr_name))
645 return;
646#endif
647
Simon Kelley5aabfc72007-08-29 11:24:47 +0100648 if (!iface_check(listen->family, &dst_addr, &ifr, &if_index))
Simon Kelley832af0b2007-01-21 20:01:28 +0000649 return;
650
651 if (listen->family == AF_INET &&
652 (daemon->options & OPT_LOCALISE) &&
653 ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
654 return;
655
656 netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
Simon Kelley44a2a312004-03-10 20:04:35 +0000657 }
658
Simon Kelleycdeda282006-03-16 20:16:06 +0000659 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +0000660 {
661 if (listen->family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100662 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100663 (struct all_addr *)&source_addr.in.sin_addr, type, NULL, 0);
Simon Kelley44a2a312004-03-10 20:04:35 +0000664#ifdef HAVE_IPV6
665 else
Simon Kelley3be34542004-09-11 19:12:13 +0100666 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100667 (struct all_addr *)&source_addr.in6.sin6_addr, type, NULL, 0);
Simon Kelley44a2a312004-03-10 20:04:35 +0000668#endif
669 }
670
Simon Kelley5aabfc72007-08-29 11:24:47 +0100671 m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n,
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000672 dst_addr_4, netmask, now);
Simon Kelley44a2a312004-03-10 20:04:35 +0000673 if (m >= 1)
Simon Kelley824af852008-02-12 20:43:05 +0000674 {
675 send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header,
676 m, &source_addr, &dst_addr, if_index);
677 daemon->local_answer++;
678 }
679 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
680 header, (size_t)n, now, NULL))
681 daemon->queries_forwarded++;
Simon Kelley44a2a312004-03-10 20:04:35 +0000682 else
Simon Kelley824af852008-02-12 20:43:05 +0000683 daemon->local_answer++;
Simon Kelley44a2a312004-03-10 20:04:35 +0000684}
685
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100686/* The daemon forks before calling this: it should deal with one connection,
687 blocking as neccessary, and then return. Note, need to be a bit careful
688 about resources for debug mode, when the fork is suppressed: that's
689 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100690unsigned char *tcp_request(int confd, time_t now,
Simon Kelley3d8df262005-08-29 12:19:27 +0100691 struct in_addr local_addr, struct in_addr netmask)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100692{
Simon Kelleycdeda282006-03-16 20:16:06 +0000693 int size = 0;
694 size_t m;
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100695 unsigned short qtype, gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100696 unsigned char c1, c2;
697 /* Max TCP packet + slop */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100698 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100699 HEADER *header;
Simon Kelley3be34542004-09-11 19:12:13 +0100700 struct server *last_server;
701
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100702 while (1)
703 {
704 if (!packet ||
705 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
706 !(size = c1 << 8 | c2) ||
707 !read_write(confd, packet, size, 1))
708 return packet;
709
710 if (size < (int)sizeof(HEADER))
711 continue;
712
713 header = (HEADER *)packet;
714
Simon Kelley3be34542004-09-11 19:12:13 +0100715 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100716 {
717 union mysockaddr peer_addr;
718 socklen_t peer_len = sizeof(union mysockaddr);
719
720 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
721 {
722 if (peer_addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100723 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100724 (struct all_addr *)&peer_addr.in.sin_addr, qtype, NULL, 0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100725#ifdef HAVE_IPV6
726 else
Simon Kelley3be34542004-09-11 19:12:13 +0100727 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100728 (struct all_addr *)&peer_addr.in6.sin6_addr, qtype, NULL, 0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100729#endif
730 }
731 }
732
733 /* m > 0 if answered from cache */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100734 m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000735 local_addr, netmask, now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100736
737 /* Do this by steam now we're not in the select() loop */
738 check_log_writer(NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100739
740 if (m == 0)
741 {
742 unsigned short flags = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100743 struct all_addr *addrp = NULL;
744 int type = 0;
745 char *domain = NULL;
746
747 if (gotname)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100748 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100749
Simon Kelley3be34542004-09-11 19:12:13 +0100750 if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
751 last_server = daemon->servers;
752 else
753 last_server = daemon->last_server;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100754
755 if (!flags && last_server)
756 {
757 struct server *firstsendto = NULL;
Simon Kelley0a852542005-03-23 20:28:59 +0000758 unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
759
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100760 /* Loop round available servers until we succeed in connecting to one.
761 Note that this code subtley ensures that consecutive queries on this connection
762 which can go to the same server, do so. */
763 while (1)
764 {
765 if (!firstsendto)
766 firstsendto = last_server;
767 else
768 {
769 if (!(last_server = last_server->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100770 last_server = daemon->servers;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100771
772 if (last_server == firstsendto)
773 break;
774 }
775
776 /* server for wrong domain */
777 if (type != (last_server->flags & SERV_TYPE) ||
778 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
779 continue;
780
781 if ((last_server->tcpfd == -1) &&
782 (last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
Simon Kelley824af852008-02-12 20:43:05 +0000783 (!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
784 connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100785 {
786 close(last_server->tcpfd);
787 last_server->tcpfd = -1;
788 }
789
790 if (last_server->tcpfd == -1)
791 continue;
Simon Kelley824af852008-02-12 20:43:05 +0000792
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100793 c1 = size >> 8;
794 c2 = size;
795
796 if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
797 !read_write(last_server->tcpfd, &c2, 1, 0) ||
798 !read_write(last_server->tcpfd, packet, size, 0) ||
799 !read_write(last_server->tcpfd, &c1, 1, 1) ||
800 !read_write(last_server->tcpfd, &c2, 1, 1))
801 {
802 close(last_server->tcpfd);
803 last_server->tcpfd = -1;
804 continue;
805 }
Simon Kelley824af852008-02-12 20:43:05 +0000806
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100807 m = (c1 << 8) | c2;
808 if (!read_write(last_server->tcpfd, packet, m, 1))
809 return packet;
810
811 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100812 strcpy(daemon->namebuff, "query");
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100813 if (last_server->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100814 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100815 (struct all_addr *)&last_server->addr.in.sin_addr, 0, NULL, 0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100816#ifdef HAVE_IPV6
817 else
Simon Kelley3be34542004-09-11 19:12:13 +0100818 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100819 (struct all_addr *)&last_server->addr.in6.sin6_addr, 0, NULL, 0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100820#endif
821
822 /* There's no point in updating the cache, since this process will exit and
Simon Kelley832af0b2007-01-21 20:01:28 +0000823 lose the information after a few queries. We make this call for the alias and
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100824 bogus-nxdomain side-effects. */
Simon Kelley832af0b2007-01-21 20:01:28 +0000825 /* If the crc of the question section doesn't match the crc we sent, then
826 someone might be attempting to insert bogus values into the cache by
827 sending replies containing questions and bogus answers. */
828 if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100829 m = process_reply(header, now, last_server, (unsigned int)m);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100830
831 break;
832 }
833 }
834
835 /* In case of local answer or no connections made. */
836 if (m == 0)
Simon Kelley3be34542004-09-11 19:12:13 +0100837 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100838 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100839
840 check_log_writer(NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100841
842 c1 = m>>8;
843 c2 = m;
844 if (!read_write(confd, &c1, 1, 0) ||
845 !read_write(confd, &c2, 1, 0) ||
846 !read_write(confd, packet, m, 0))
847 return packet;
848 }
849}
850
Simon Kelley16972692006-10-16 20:04:18 +0100851static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000852{
Simon Kelley16972692006-10-16 20:04:18 +0100853 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000854
Simon Kelley5aabfc72007-08-29 11:24:47 +0100855 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000856 {
857 f->next = frec_list;
858 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +0000859 f->sentto = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000860 frec_list = f;
861 }
Simon Kelley16972692006-10-16 20:04:18 +0100862
863 return f;
864}
865
866/* if wait==NULL return a free or older than TIMEOUT record.
867 else return *wait zero if one available, or *wait is delay to
868 when the oldest in-use record will expire. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100869struct frec *get_new_frec(time_t now, int *wait)
Simon Kelley16972692006-10-16 20:04:18 +0100870{
871 struct frec *f, *oldest;
872 int count;
873
874 if (wait)
875 *wait = 0;
876
877 for (f = frec_list, oldest = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +0000878 if (!f->sentto)
Simon Kelley16972692006-10-16 20:04:18 +0100879 {
880 f->time = now;
881 return f;
882 }
883 else if (!oldest || difftime(f->time, oldest->time) <= 0)
884 oldest = f;
885
886 /* can't find empty one, use oldest if there is one
887 and it's older than timeout */
888 if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
889 {
890 /* keep stuff for twice timeout if we can by allocating a new
891 record instead */
892 if (difftime(now, oldest->time) < 2*TIMEOUT &&
893 count <= daemon->ftabsize &&
894 (f = allocate_frec(now)))
895 return f;
896
897 if (!wait)
898 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000899 oldest->sentto = 0;
Simon Kelley16972692006-10-16 20:04:18 +0100900 oldest->time = now;
901 }
902 return oldest;
903 }
904
905 /* none available, calculate time 'till oldest record expires */
906 if (count > daemon->ftabsize)
907 {
908 if (oldest && wait)
909 *wait = oldest->time + (time_t)TIMEOUT - now;
910 return NULL;
911 }
912
913 if (!(f = allocate_frec(now)) && wait)
914 /* wait one second on malloc failure */
915 *wait = 1;
916
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000917 return f; /* OK if malloc fails and this is NULL */
918}
919
Simon Kelley832af0b2007-01-21 20:01:28 +0000920/* crc is all-ones if not known. */
921static struct frec *lookup_frec(unsigned short id, unsigned int crc)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000922{
923 struct frec *f;
924
925 for(f = frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +0000926 if (f->sentto && f->new_id == id &&
927 (f->crc == crc || crc == 0xffffffff))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000928 return f;
929
930 return NULL;
931}
932
933static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100934 union mysockaddr *addr,
935 unsigned int crc)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936{
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100937 struct frec *f;
938
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000939 for(f = frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +0000940 if (f->sentto &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000941 f->orig_id == id &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100942 f->crc == crc &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000943 sockaddr_isequal(&f->source, addr))
944 return f;
945
946 return NULL;
947}
948
Simon Kelley849a8352006-06-09 21:02:31 +0100949/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100950void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +0100951{
952 struct frec *f;
953
954 for (f = frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +0000955 if (f->sentto && f->sentto == server)
956 f->sentto = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +0100957
958 if (daemon->last_server == server)
959 daemon->last_server = NULL;
960
961 if (daemon->srv_save == server)
962 daemon->srv_save = NULL;
963}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000964
Simon Kelley832af0b2007-01-21 20:01:28 +0000965/* return unique random ids.
966 For signed packets we can't change the ID without breaking the
967 signing, so we keep the same one. In this case force is set, and this
968 routine degenerates into killing any conflicting forward record. */
969static unsigned short get_id(int force, unsigned short force_id, unsigned int crc)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000970{
971 unsigned short ret = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000972
973 if (force)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000974 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000975 struct frec *f = lookup_frec(force_id, crc);
976 if (f)
977 f->sentto = NULL; /* free */
978 ret = force_id;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000979 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000980 else do
981 ret = rand16();
982 while (lookup_frec(ret, crc));
983
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000984 return ret;
985}
986
987
988
989
990