]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/forward.c
import of dnsmasq-2.16.tar.gz
[people/ms/dnsmasq.git] / src / forward.c
CommitLineData
9e4abcb5
SK
1/* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
2
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
5 the Free Software Foundation; version 2 dated June, 1991.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
13/* Author's email: simon@thekelleys.org.uk */
14
15#include "dnsmasq.h"
16
17static struct frec *frec_list;
18
19static struct frec *get_new_frec(time_t now);
20static struct frec *lookup_frec(unsigned short id);
21static struct frec *lookup_frec_by_sender(unsigned short id,
fd9fa481
SK
22 union mysockaddr *addr,
23 unsigned int crc);
9e4abcb5
SK
24static unsigned short get_id(void);
25
26/* May be called more than once. */
27void forward_init(int first)
28{
29 struct frec *f;
feba5c1d 30
9e4abcb5
SK
31 if (first)
32 frec_list = NULL;
33 for (f = frec_list; f; f = f->next)
34 f->new_id = 0;
35}
36
44a2a316
SK
37/* Send a UDP packet with it's source address set as "source"
38 unless nowild is true, when we just send it with the kernel default */
39static void send_from(int fd, int nowild, char *packet, int len,
dfa666f2
SK
40 union mysockaddr *to, struct all_addr *source,
41 unsigned int iface)
9e4abcb5 42{
44a2a316
SK
43 struct msghdr msg;
44 struct iovec iov[1];
44a2a316
SK
45 union {
46 struct cmsghdr align; /* this ensures alignment */
47#if defined(IP_PKTINFO)
48 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
49#elif defined(IP_SENDSRCADDR)
50 char control[CMSG_SPACE(sizeof(struct in_addr))];
51#endif
52#ifdef HAVE_IPV6
53 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
54#endif
55 } control_u;
feba5c1d 56
44a2a316
SK
57 iov[0].iov_base = packet;
58 iov[0].iov_len = len;
59
feba5c1d
SK
60 msg.msg_control = NULL;
61 msg.msg_controllen = 0;
44a2a316
SK
62 msg.msg_flags = 0;
63 msg.msg_name = to;
64 msg.msg_namelen = sa_len(to);
65 msg.msg_iov = iov;
66 msg.msg_iovlen = 1;
feba5c1d 67
44a2a316
SK
68 if (!nowild && to->sa.sa_family == AF_INET)
69 {
feba5c1d
SK
70 msg.msg_control = &control_u;
71 msg.msg_controllen = sizeof(control_u);
72 {
73 struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
74#if defined(IP_PKTINFO)
75 struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
76 pkt->ipi_ifindex = 0;
77 pkt->ipi_spec_dst = source->addr.addr4;
78 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
79 cmptr->cmsg_level = SOL_IP;
80 cmptr->cmsg_type = IP_PKTINFO;
44a2a316 81#elif defined(IP_SENDSRCADDR)
feba5c1d
SK
82 struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
83 *a = source->addr.addr4;
84 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
85 cmptr->cmsg_level = IPPROTO_IP;
86 cmptr->cmsg_type = IP_SENDSRCADDR;
44a2a316 87#endif
feba5c1d
SK
88 }
89 }
44a2a316
SK
90
91#ifdef HAVE_IPV6
feba5c1d 92 if (to->sa.sa_family == AF_INET6)
44a2a316 93 {
feba5c1d
SK
94 msg.msg_control = &control_u;
95 msg.msg_controllen = sizeof(control_u);
96 {
97 struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
98 struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
dfa666f2 99 pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
feba5c1d
SK
100 pkt->ipi6_addr = source->addr.addr6;
101 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
102 cmptr->cmsg_type = IPV6_PKTINFO;
103 cmptr->cmsg_level = IPV6_LEVEL;
104 }
44a2a316
SK
105 }
106#endif
feba5c1d 107
fd9fa481
SK
108 retry:
109 if (sendmsg(fd, &msg, 0) == -1)
feba5c1d 110 {
fd9fa481
SK
111 /* certain Linux kernels seem to object to setting the source address in the IPv6 stack
112 by returning EINVAL from sendmsg. In that case, try again without setting the
113 source address, since it will nearly alway be correct anyway. IPv6 stinks. */
114 if (errno == EINVAL && msg.msg_controllen)
115 {
116 msg.msg_controllen = 0;
117 goto retry;
118 }
119 if (retry_send())
120 goto retry;
feba5c1d 121 }
9e4abcb5 122}
44a2a316 123
36717eee
SK
124static unsigned short search_servers(struct daemon *daemon, time_t now, struct all_addr **addrpp,
125 unsigned short qtype, char *qdomain, int *type, char **domain)
feba5c1d
SK
126
127{
128 /* If the query ends in the domain in one of our servers, set
129 domain to point to that name. We find the largest match to allow both
130 domain.org and sub.domain.org to exist. */
131
132 unsigned int namelen = strlen(qdomain);
133 unsigned int matchlen = 0;
134 struct server *serv;
135 unsigned short flags = 0;
136
3be34541 137 for (serv = daemon->servers; serv; serv=serv->next)
feba5c1d
SK
138 /* domain matches take priority over NODOTS matches */
139 if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.'))
140 {
141 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
142 *type = SERV_FOR_NODOTS;
feba5c1d 143 if (serv->flags & SERV_NO_ADDR)
36717eee
SK
144 flags = F_NXDOMAIN;
145 else if (serv->flags & SERV_LITERAL_ADDRESS)
146 {
147 if (sflag & qtype)
148 {
149 flags = sflag;
150 if (serv->addr.sa.sa_family == AF_INET)
151 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
feba5c1d 152#ifdef HAVE_IPV6
36717eee
SK
153 else
154 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
feba5c1d 155#endif
36717eee
SK
156 }
157 else if (!flags)
158 flags = F_NOERR;
159 }
feba5c1d
SK
160 }
161 else if (serv->flags & SERV_HAS_DOMAIN)
162 {
163 unsigned int domainlen = strlen(serv->domain);
164 if (namelen >= domainlen &&
165 hostname_isequal(qdomain + namelen - domainlen, serv->domain) &&
166 domainlen >= matchlen)
167 {
168 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
169 *type = SERV_HAS_DOMAIN;
170 *domain = serv->domain;
171 matchlen = domainlen;
feba5c1d 172 if (serv->flags & SERV_NO_ADDR)
36717eee
SK
173 flags = F_NXDOMAIN;
174 else if (serv->flags & SERV_LITERAL_ADDRESS)
feba5c1d 175 {
36717eee
SK
176 if ((sflag | F_QUERY ) & qtype)
177 {
178 flags = qtype;
179 if (serv->addr.sa.sa_family == AF_INET)
180 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
feba5c1d 181#ifdef HAVE_IPV6
36717eee
SK
182 else
183 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
feba5c1d 184#endif
36717eee
SK
185 }
186 else if (!flags)
187 flags = F_NOERR;
feba5c1d
SK
188 }
189 }
190 }
191
36717eee 192 if (flags & ~(F_NOERR | F_NXDOMAIN)) /* flags set here means a literal found */
feba5c1d
SK
193 {
194 if (flags & F_QUERY)
fd9fa481 195 log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL, 0, NULL, 0);
feba5c1d 196 else
fd9fa481 197 log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0, NULL, 0);
feba5c1d 198 }
3be34541 199 else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
36717eee
SK
200 flags = F_NXDOMAIN;
201
202 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now, daemon->mxnames))
c1bb8504 203 flags = F_NOERR;
feba5c1d 204
36717eee 205 if (flags == F_NXDOMAIN || flags == F_NOERR)
fd9fa481 206 log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL, 0, NULL, 0);
feba5c1d
SK
207
208 return flags;
209}
44a2a316 210
9e4abcb5 211/* returns new last_server */
3be34541
SK
212static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *udpaddr,
213 struct all_addr *dst_addr, unsigned int dst_iface,
214 HEADER *header, int plen, time_t now)
9e4abcb5
SK
215{
216 struct frec *forward;
217 char *domain = NULL;
de37951c 218 int forwardall = 0, type = 0;
9e4abcb5
SK
219 struct all_addr *addrp = NULL;
220 unsigned short flags = 0;
3be34541 221 unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL);
de37951c 222 struct server *start = NULL;
fd9fa481 223 unsigned int crc = questions_crc(header,(unsigned int)plen);
de37951c 224
9e4abcb5 225 /* may be recursion not speced or no servers available. */
3be34541 226 if (!header->rd || !daemon->servers)
9e4abcb5 227 forward = NULL;
fd9fa481 228 else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
9e4abcb5 229 {
de37951c 230 /* retry on existing query, send to all available servers */
9e4abcb5 231 domain = forward->sentto->domain;
3be34541 232 if (!(daemon->options & OPT_ORDER))
de37951c
SK
233 {
234 forwardall = 1;
3be34541 235 daemon->last_server = NULL;
de37951c 236 }
9e4abcb5 237 type = forward->sentto->flags & SERV_TYPE;
de37951c 238 if (!(start = forward->sentto->next))
3be34541 239 start = daemon->servers; /* at end of list, recycle */
9e4abcb5
SK
240 header->id = htons(forward->new_id);
241 }
242 else
243 {
244 if (gotname)
36717eee 245 flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
9e4abcb5 246
feba5c1d
SK
247 if (!flags && !(forward = get_new_frec(now)))
248 /* table full - server failure. */
249 flags = F_NEG;
9e4abcb5
SK
250
251 if (forward)
252 {
253 /* In strict_order mode, or when using domain specific servers
254 always try servers in the order specified in resolv.conf,
255 otherwise, use the one last known to work. */
256
3be34541
SK
257 if (type != 0 || (daemon->options & OPT_ORDER))
258 start = daemon->servers;
259 else if (!(start = daemon->last_server))
de37951c 260 {
3be34541 261 start = daemon->servers;
de37951c
SK
262 forwardall = 1;
263 }
feba5c1d 264
9e4abcb5 265 forward->source = *udpaddr;
44a2a316 266 forward->dest = *dst_addr;
dfa666f2 267 forward->iface = dst_iface;
9e4abcb5
SK
268 forward->new_id = get_id();
269 forward->fd = udpfd;
270 forward->orig_id = ntohs(header->id);
fd9fa481 271 forward->crc = crc;
9e4abcb5
SK
272 header->id = htons(forward->new_id);
273 }
274 }
feba5c1d 275
9e4abcb5
SK
276 /* check for send errors here (no route to host)
277 if we fail to send to all nameservers, send back an error
278 packet straight away (helps modem users when offline) */
279
280 if (!flags && forward)
281 {
de37951c
SK
282 struct server *firstsentto = start;
283 int forwarded = 0;
284
9e4abcb5
SK
285 while (1)
286 {
9e4abcb5
SK
287 /* only send to servers dealing with our domain.
288 domain may be NULL, in which case server->domain
289 must be NULL also. */
290
de37951c 291 if (type == (start->flags & SERV_TYPE) &&
fd9fa481
SK
292 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
293 !(start->flags & SERV_LITERAL_ADDRESS))
9e4abcb5 294 {
fd9fa481 295 if (sendto(start->sfd->fd, (char *)header, plen, 0,
feba5c1d 296 &start->addr.sa,
fd9fa481
SK
297 sa_len(&start->addr)) == -1)
298 {
299 if (retry_send())
300 continue;
301 }
302 else
9e4abcb5 303 {
de37951c 304 if (!gotname)
3be34541 305 strcpy(daemon->namebuff, "query");
de37951c 306 if (start->addr.sa.sa_family == AF_INET)
3be34541 307 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
fd9fa481
SK
308 (struct all_addr *)&start->addr.in.sin_addr, 0,
309 NULL, 0);
de37951c
SK
310#ifdef HAVE_IPV6
311 else
3be34541 312 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
fd9fa481
SK
313 (struct all_addr *)&start->addr.in6.sin6_addr, 0,
314 NULL, 0);
de37951c
SK
315#endif
316 forwarded = 1;
317 forward->sentto = start;
318 if (!forwardall)
319 break;
9e4abcb5
SK
320 }
321 }
322
de37951c 323 if (!(start = start->next))
3be34541 324 start = daemon->servers;
9e4abcb5 325
de37951c 326 if (start == firstsentto)
9e4abcb5
SK
327 break;
328 }
329
de37951c 330 if (forwarded)
3be34541 331 return;
de37951c 332
9e4abcb5
SK
333 /* could not send on, prepare to return */
334 header->id = htons(forward->orig_id);
335 forward->new_id = 0; /* cancel */
336 }
337
338 /* could not send on, return empty answer or address if known for whole domain */
3be34541
SK
339 plen = setup_reply(header, (unsigned int)plen, addrp, flags, daemon->local_ttl);
340 send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
44a2a316 341
3be34541 342 return;
9e4abcb5
SK
343}
344
3be34541 345static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
36717eee 346 union mysockaddr *serveraddr, unsigned int n)
feba5c1d 347{
36717eee 348 unsigned char *pheader, *sizep;
fd9fa481 349 unsigned int plen, munged = 0;
feba5c1d
SK
350
351 /* If upstream is advertising a larger UDP packet size
352 than we allow, trim it so that we don't get overlarge
353 requests for the client. */
354
36717eee 355 if ((pheader = find_pseudoheader(header, n, &plen, &sizep)))
feba5c1d
SK
356 {
357 unsigned short udpsz;
36717eee 358 unsigned char *psave = sizep;
feba5c1d 359
36717eee 360 GETSHORT(udpsz, sizep);
3be34541
SK
361 if (udpsz > daemon->edns_pktsz)
362 PUTSHORT(daemon->edns_pktsz, psave);
feba5c1d
SK
363 }
364
365 /* Complain loudly if the upstream server is non-recursive. */
366 if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0)
367 {
368 char addrbuff[ADDRSTRLEN];
369#ifdef HAVE_IPV6
370 if (serveraddr->sa.sa_family == AF_INET)
371 inet_ntop(AF_INET, &serveraddr->in.sin_addr, addrbuff, ADDRSTRLEN);
372 else if (serveraddr->sa.sa_family == AF_INET6)
373 inet_ntop(AF_INET6, &serveraddr->in6.sin6_addr, addrbuff, ADDRSTRLEN);
374#else
375 strcpy(addrbuff, inet_ntoa(serveraddr->in.sin_addr));
376#endif
377 syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff);
378 return 0;
379 }
380
36717eee
SK
381 if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
382 return n;
383
fd9fa481
SK
384 if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
385 check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
feba5c1d 386 {
fd9fa481
SK
387 munged = 1;
388 header->rcode = NXDOMAIN;
389 header->aa = 0;
36717eee 390 }
fd9fa481 391 else
36717eee 392 {
fd9fa481
SK
393 if (header->rcode == NXDOMAIN &&
394 extract_request(header, n, daemon->namebuff, NULL) &&
395 check_for_local_domain(daemon->namebuff, now, daemon->mxnames))
36717eee
SK
396 {
397 /* if we forwarded a query for a locally known name (because it was for
398 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
399 since we know that the domain exists, even if upstream doesn't */
fd9fa481
SK
400 munged = 1;
401 header->aa = 1;
402 header->rcode = NOERROR;
feba5c1d 403 }
fd9fa481
SK
404
405 extract_addresses(header, n, daemon->namebuff, now, daemon);
feba5c1d 406 }
fd9fa481
SK
407
408 /* do this after extract_addresses. Ensure NODATA reply and remove
409 nameserver info. */
410
411 if (munged)
412 {
413 header->ancount = htons(0);
414 header->nscount = htons(0);
415 header->arcount = htons(0);
416 }
417
36717eee
SK
418 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
419 sections of the packet. Find the new length here and put back pseudoheader
420 if it was removed. */
421 return resize_packet(header, n, pheader, plen);
feba5c1d
SK
422}
423
3be34541
SK
424/* sets new last_server */
425void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
9e4abcb5
SK
426{
427 /* packet from peer server, extract data for cache, and send to
428 original requester */
429 struct frec *forward;
430 HEADER *header;
de37951c
SK
431 union mysockaddr serveraddr;
432 socklen_t addrlen = sizeof(serveraddr);
3be34541 433 int n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
de37951c
SK
434
435 /* Determine the address of the server replying so that we can mark that as good */
436 serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
437#ifdef HAVE_IPV6
438 if (serveraddr.sa.sa_family == AF_INET6)
439 serveraddr.in6.sin6_flowinfo = htonl(0);
440#endif
9e4abcb5 441
3be34541 442 header = (HEADER *)daemon->packet;
fd9fa481
SK
443 forward = lookup_frec(ntohs(header->id));
444
445 if (n >= (int)sizeof(HEADER) && header->qr && forward)
9e4abcb5 446 {
de37951c
SK
447 /* find good server by address if possible, otherwise assume the last one we sent to */
448 if ((forward->sentto->flags & SERV_TYPE) == 0)
449 {
3be34541
SK
450 struct server *last_server;
451 daemon->last_server = forward->sentto;
452 for (last_server = daemon->servers; last_server; last_server = last_server->next)
de37951c
SK
453 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
454 sockaddr_isequal(&last_server->addr, &serveraddr))
3be34541
SK
455 {
456 daemon->last_server = last_server;
457 break;
458 }
de37951c 459 }
de37951c 460
36717eee 461 if ((n = process_reply(daemon, header, now, &serveraddr, (unsigned int)n)))
3be34541
SK
462 {
463 header->id = htons(forward->orig_id);
fd9fa481
SK
464 header->ra = 1; /* recursion if available */
465send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
3be34541
SK
466 &forward->source, &forward->dest, forward->iface);
467 forward->new_id = 0; /* cancel */
468 }
9e4abcb5 469 }
9e4abcb5 470}
44a2a316 471
3be34541 472void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
44a2a316 473{
3be34541 474 HEADER *header = (HEADER *)daemon->packet;
44a2a316 475 union mysockaddr source_addr;
c1bb8504 476 unsigned short type;
44a2a316
SK
477 struct iname *tmp;
478 struct all_addr dst_addr;
3be34541 479 int check_dst = !(daemon->options & OPT_NOWILD);
8a911ccc 480 int m, n, if_index = 0;
44a2a316
SK
481 struct iovec iov[1];
482 struct msghdr msg;
483 struct cmsghdr *cmptr;
44a2a316
SK
484 union {
485 struct cmsghdr align; /* this ensures alignment */
486#ifdef HAVE_IPV6
487 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
488#endif
489#if defined(IP_PKTINFO)
490 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
491#elif defined(IP_RECVDSTADDR)
492 char control[CMSG_SPACE(sizeof(struct in_addr)) +
493 CMSG_SPACE(sizeof(struct sockaddr_dl))];
494#endif
495 } control_u;
496
3be34541
SK
497 iov[0].iov_base = daemon->packet;
498 iov[0].iov_len = daemon->edns_pktsz;
44a2a316
SK
499
500 msg.msg_control = control_u.control;
501 msg.msg_controllen = sizeof(control_u);
502 msg.msg_flags = 0;
503 msg.msg_name = &source_addr;
504 msg.msg_namelen = sizeof(source_addr);
505 msg.msg_iov = iov;
506 msg.msg_iovlen = 1;
507
de37951c 508 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
3be34541 509 return;
44a2a316
SK
510
511 source_addr.sa.sa_family = listen->family;
512#ifdef HAVE_IPV6
513 if (listen->family == AF_INET6)
feba5c1d
SK
514 {
515 check_dst = 1;
516 source_addr.in6.sin6_flowinfo = htonl(0);
517 }
44a2a316
SK
518#endif
519
feba5c1d 520 if (check_dst && msg.msg_controllen < sizeof(struct cmsghdr))
3be34541 521 return;
44a2a316
SK
522
523#if defined(IP_PKTINFO)
feba5c1d 524 if (check_dst && listen->family == AF_INET)
44a2a316
SK
525 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
526 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
527 {
528 dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
8a911ccc 529 if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
44a2a316
SK
530 }
531#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
feba5c1d 532 if (check_dst && listen->family == AF_INET)
44a2a316
SK
533 {
534 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
535 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
8a911ccc 536 dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
44a2a316 537 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
8a911ccc 538 if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
44a2a316
SK
539 }
540#endif
541
542#ifdef HAVE_IPV6
feba5c1d 543 if (listen->family == AF_INET6)
44a2a316
SK
544 {
545 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
546 if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
547 {
548 dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
8a911ccc 549 if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
44a2a316
SK
550 }
551 }
552#endif
553
554 if (n < (int)sizeof(HEADER) || header->qr)
3be34541 555 return;
44a2a316
SK
556
557 /* enforce available interface configuration */
feba5c1d 558 if (check_dst)
44a2a316 559 {
8a911ccc
SK
560 struct ifreq ifr;
561
562 if (if_index == 0)
3be34541 563 return;
44a2a316 564
3be34541 565 if (daemon->if_except || daemon->if_names)
8a911ccc
SK
566 {
567#ifdef SIOCGIFNAME
568 ifr.ifr_ifindex = if_index;
569 if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
3be34541 570 return;
8a911ccc
SK
571#else
572 if (!if_indextoname(if_index, ifr.ifr_name))
3be34541 573 return;
8a911ccc
SK
574#endif
575 }
576
3be34541 577 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
8a911ccc 578 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
3be34541 579 return;
9e4abcb5 580
3be34541 581 if (daemon->if_names || daemon->if_addrs)
44a2a316 582 {
3be34541 583 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
8a911ccc 584 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
44a2a316
SK
585 break;
586 if (!tmp)
3be34541 587 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
44a2a316
SK
588 if (tmp->addr.sa.sa_family == listen->family)
589 {
590 if (tmp->addr.sa.sa_family == AF_INET &&
591 tmp->addr.in.sin_addr.s_addr == dst_addr.addr.addr4.s_addr)
592 break;
593#ifdef HAVE_IPV6
594 else if (tmp->addr.sa.sa_family == AF_INET6 &&
595 memcmp(&tmp->addr.in6.sin6_addr,
596 &dst_addr.addr.addr6,
597 sizeof(struct in6_addr)) == 0)
598 break;
599#endif
600 }
601 if (!tmp)
3be34541 602 return;
44a2a316
SK
603 }
604 }
605
3be34541 606 if (extract_request(header, (unsigned int)n, daemon->namebuff, &type))
44a2a316
SK
607 {
608 if (listen->family == AF_INET)
3be34541 609 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
fd9fa481 610 (struct all_addr *)&source_addr.in.sin_addr, type, NULL, 0);
44a2a316
SK
611#ifdef HAVE_IPV6
612 else
3be34541 613 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
fd9fa481 614 (struct all_addr *)&source_addr.in6.sin6_addr, type, NULL, 0);
44a2a316
SK
615#endif
616 }
617
3be34541 618 m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n, daemon, now);
44a2a316 619 if (m >= 1)
3be34541 620 send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
44a2a316 621 else
3be34541
SK
622 forward_query(daemon, listen->fd, &source_addr, &dst_addr, if_index,
623 header, n, now);
44a2a316
SK
624}
625
feba5c1d
SK
626static int read_write(int fd, char *packet, int size, int rw)
627{
628 int n, done;
629
630 for (done = 0; done < size; done += n)
631 {
632 retry:
633 if (rw)
634 n = read(fd, &packet[done], (size_t)(size - done));
635 else
636 n = write(fd, &packet[done], (size_t)(size - done));
637
638 if (n == 0)
639 return 0;
640 else if (n == -1)
641 {
fd9fa481 642 if (retry_send())
feba5c1d 643 goto retry;
feba5c1d
SK
644 else
645 return 0;
646 }
647 }
648 return 1;
649}
650
651/* The daemon forks before calling this: it should deal with one connection,
652 blocking as neccessary, and then return. Note, need to be a bit careful
653 about resources for debug mode, when the fork is suppressed: that's
654 done by the caller. */
3be34541 655char *tcp_request(struct daemon *daemon, int confd, time_t now)
feba5c1d
SK
656{
657 int size = 0, m;
c1bb8504 658 unsigned short qtype, gotname;
feba5c1d
SK
659 unsigned char c1, c2;
660 /* Max TCP packet + slop */
661 char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ);
662 HEADER *header;
3be34541
SK
663 struct server *last_server;
664
feba5c1d
SK
665 while (1)
666 {
667 if (!packet ||
668 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
669 !(size = c1 << 8 | c2) ||
670 !read_write(confd, packet, size, 1))
671 return packet;
672
673 if (size < (int)sizeof(HEADER))
674 continue;
675
676 header = (HEADER *)packet;
677
3be34541 678 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
feba5c1d
SK
679 {
680 union mysockaddr peer_addr;
681 socklen_t peer_len = sizeof(union mysockaddr);
682
683 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
684 {
685 if (peer_addr.sa.sa_family == AF_INET)
3be34541 686 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
fd9fa481 687 (struct all_addr *)&peer_addr.in.sin_addr, qtype, NULL, 0);
feba5c1d
SK
688#ifdef HAVE_IPV6
689 else
3be34541 690 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
fd9fa481 691 (struct all_addr *)&peer_addr.in6.sin6_addr, qtype, NULL, 0);
feba5c1d
SK
692#endif
693 }
694 }
695
696 /* m > 0 if answered from cache */
3be34541 697 m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, daemon, now);
feba5c1d
SK
698
699 if (m == 0)
700 {
701 unsigned short flags = 0;
feba5c1d
SK
702 struct all_addr *addrp = NULL;
703 int type = 0;
704 char *domain = NULL;
705
706 if (gotname)
36717eee 707 flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
feba5c1d 708
3be34541
SK
709 if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
710 last_server = daemon->servers;
711 else
712 last_server = daemon->last_server;
feba5c1d
SK
713
714 if (!flags && last_server)
715 {
716 struct server *firstsendto = NULL;
717
718 /* Loop round available servers until we succeed in connecting to one.
719 Note that this code subtley ensures that consecutive queries on this connection
720 which can go to the same server, do so. */
721 while (1)
722 {
723 if (!firstsendto)
724 firstsendto = last_server;
725 else
726 {
727 if (!(last_server = last_server->next))
3be34541 728 last_server = daemon->servers;
feba5c1d
SK
729
730 if (last_server == firstsendto)
731 break;
732 }
733
734 /* server for wrong domain */
735 if (type != (last_server->flags & SERV_TYPE) ||
736 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
737 continue;
738
739 if ((last_server->tcpfd == -1) &&
740 (last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
741 connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
742 {
743 close(last_server->tcpfd);
744 last_server->tcpfd = -1;
745 }
746
747 if (last_server->tcpfd == -1)
748 continue;
749
750 c1 = size >> 8;
751 c2 = size;
752
753 if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
754 !read_write(last_server->tcpfd, &c2, 1, 0) ||
755 !read_write(last_server->tcpfd, packet, size, 0) ||
756 !read_write(last_server->tcpfd, &c1, 1, 1) ||
757 !read_write(last_server->tcpfd, &c2, 1, 1))
758 {
759 close(last_server->tcpfd);
760 last_server->tcpfd = -1;
761 continue;
762 }
763
764 m = (c1 << 8) | c2;
765 if (!read_write(last_server->tcpfd, packet, m, 1))
766 return packet;
767
768 if (!gotname)
3be34541 769 strcpy(daemon->namebuff, "query");
feba5c1d 770 if (last_server->addr.sa.sa_family == AF_INET)
3be34541 771 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
fd9fa481 772 (struct all_addr *)&last_server->addr.in.sin_addr, 0, NULL, 0);
feba5c1d
SK
773#ifdef HAVE_IPV6
774 else
3be34541 775 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
fd9fa481 776 (struct all_addr *)&last_server->addr.in6.sin6_addr, 0, NULL, 0);
feba5c1d
SK
777#endif
778
779 /* There's no point in updating the cache, since this process will exit and
780 lose the information after one query. We make this call for the alias and
781 bogus-nxdomain side-effects. */
36717eee 782 m = process_reply(daemon, header, now, &last_server->addr, (unsigned int)m);
feba5c1d
SK
783
784 break;
785 }
786 }
787
788 /* In case of local answer or no connections made. */
789 if (m == 0)
3be34541 790 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
feba5c1d
SK
791 }
792
793 c1 = m>>8;
794 c2 = m;
795 if (!read_write(confd, &c1, 1, 0) ||
796 !read_write(confd, &c2, 1, 0) ||
797 !read_write(confd, packet, m, 0))
798 return packet;
799 }
800}
801
9e4abcb5
SK
802static struct frec *get_new_frec(time_t now)
803{
804 struct frec *f = frec_list, *oldest = NULL;
805 time_t oldtime = now;
806 int count = 0;
807 static time_t warntime = 0;
808
809 while (f)
810 {
811 if (f->new_id == 0)
812 {
813 f->time = now;
814 return f;
815 }
816
817 if (difftime(f->time, oldtime) <= 0)
818 {
819 oldtime = f->time;
820 oldest = f;
821 }
822
823 count++;
824 f = f->next;
825 }
826
827 /* can't find empty one, use oldest if there is one
828 and it's older than timeout */
829 if (oldest && difftime(now, oldtime) > TIMEOUT)
830 {
831 oldest->time = now;
832 return oldest;
833 }
834
835 if (count > FTABSIZ)
836 { /* limit logging rate so syslog isn't DOSed either */
837 if (!warntime || difftime(now, warntime) > LOGRATE)
838 {
839 warntime = now;
840 syslog(LOG_WARNING, "forwarding table overflow: check for server loops.");
841 }
842 return NULL;
843 }
844
845 if ((f = (struct frec *)malloc(sizeof(struct frec))))
846 {
847 f->next = frec_list;
848 f->time = now;
849 frec_list = f;
850 }
851 return f; /* OK if malloc fails and this is NULL */
852}
853
854static struct frec *lookup_frec(unsigned short id)
855{
856 struct frec *f;
857
858 for(f = frec_list; f; f = f->next)
859 if (f->new_id == id)
860 return f;
861
862 return NULL;
863}
864
865static struct frec *lookup_frec_by_sender(unsigned short id,
fd9fa481
SK
866 union mysockaddr *addr,
867 unsigned int crc)
9e4abcb5 868{
feba5c1d
SK
869 struct frec *f;
870
9e4abcb5
SK
871 for(f = frec_list; f; f = f->next)
872 if (f->new_id &&
873 f->orig_id == id &&
fd9fa481 874 f->crc == crc &&
9e4abcb5
SK
875 sockaddr_isequal(&f->source, addr))
876 return f;
877
878 return NULL;
879}
880
881
882/* return unique random ids between 1 and 65535 */
883static unsigned short get_id(void)
884{
885 unsigned short ret = 0;
886
887 while (ret == 0)
888 {
889 ret = rand16();
890
891 /* scrap ids already in use */
892 if ((ret != 0) && lookup_frec(ret))
893 ret = 0;
894 }
895
896 return ret;
897}
898
899
900
901
902