]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/forward.c
import of dnsmasq-2.8.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,
22 union mysockaddr *addr);
23static unsigned short get_id(void);
24
25/* May be called more than once. */
26void forward_init(int first)
27{
28 struct frec *f;
29
30 if (first)
31 frec_list = NULL;
32 for (f = frec_list; f; f = f->next)
33 f->new_id = 0;
34}
35
44a2a316
SK
36/* Send a UDP packet with it's source address set as "source"
37 unless nowild is true, when we just send it with the kernel default */
38static void send_from(int fd, int nowild, char *packet, int len,
39 union mysockaddr *to, struct all_addr *source)
9e4abcb5 40{
44a2a316
SK
41 struct msghdr msg;
42 struct iovec iov[1];
43 struct cmsghdr *cmptr;
44 union {
45 struct cmsghdr align; /* this ensures alignment */
46#if defined(IP_PKTINFO)
47 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
48#elif defined(IP_SENDSRCADDR)
49 char control[CMSG_SPACE(sizeof(struct in_addr))];
50#endif
51#ifdef HAVE_IPV6
52 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
53#endif
54 } control_u;
55
56 iov[0].iov_base = packet;
57 iov[0].iov_len = len;
58
59 if (nowild)
60 {
61 msg.msg_control = NULL;
62 msg.msg_controllen = 0;
63 }
64 else
65 {
66 msg.msg_control = &control_u;
67 msg.msg_controllen = sizeof(control_u);
68 }
69 msg.msg_flags = 0;
70 msg.msg_name = to;
71 msg.msg_namelen = sa_len(to);
72 msg.msg_iov = iov;
73 msg.msg_iovlen = 1;
74
75 cmptr = CMSG_FIRSTHDR(&msg);
9e4abcb5 76
44a2a316
SK
77#if defined(IP_PKTINFO)
78 if (!nowild && to->sa.sa_family == AF_INET)
79 {
80 struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
81 pkt->ipi_ifindex = 0;
82 pkt->ipi_spec_dst = source->addr.addr4;
83 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
84 cmptr->cmsg_level = SOL_IP;
85 cmptr->cmsg_type = IP_PKTINFO;
86 }
87#elif defined(IP_SENDSRCADDR)
88 if (!nowild && to->sa.sa_family == AF_INET)
89 {
90 struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
91 *a = source->addr.addr4;
92 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
93 cmptr->cmsg_level = IPPROTO_IP;
94 cmptr->cmsg_type = IP_SENDSRCADDR;
95 }
96#endif
97
98#ifdef HAVE_IPV6
99 if (!nowild && to->sa.sa_family == AF_INET6)
100 {
101 struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
102 pkt->ipi6_ifindex = 0;
103 pkt->ipi6_addr = source->addr.addr6;
104 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
105 cmptr->cmsg_type = IPV6_PKTINFO;
106 cmptr->cmsg_level = IPV6_LEVEL;
44a2a316
SK
107 }
108#endif
109
110 sendmsg(fd, &msg, 0);
9e4abcb5 111}
44a2a316
SK
112
113
9e4abcb5 114/* returns new last_server */
44a2a316
SK
115static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
116 struct all_addr *dst_addr, HEADER *header,
117 int plen, unsigned int options, char *dnamebuff,
118 struct server *servers, struct server *last_server,
119 time_t now, unsigned long local_ttl)
9e4abcb5
SK
120{
121 struct frec *forward;
122 char *domain = NULL;
123 int type = 0;
124 struct server *serv;
125 struct all_addr *addrp = NULL;
126 unsigned short flags = 0;
127 unsigned short gotname = extract_request(header, (unsigned int)plen, dnamebuff);
128
129 /* may be recursion not speced or no servers available. */
130 if (!header->rd || !servers)
131 forward = NULL;
132 else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr)))
133 {
134 /* retry on existing query, send to next server */
135 domain = forward->sentto->domain;
136 type = forward->sentto->flags & SERV_TYPE;
137 if (!(forward->sentto = forward->sentto->next))
138 forward->sentto = servers; /* at end of list, recycle */
139 header->id = htons(forward->new_id);
140 }
141 else
142 {
143 if (gotname)
144 {
145 /* If the query ends in the domain in one of our servers, set
146 domain to point to that name. We find the largest match to allow both
147 domain.org and sub.domain.org to exist. */
148
149 unsigned int namelen = strlen(dnamebuff);
150 unsigned int matchlen = 0;
151
152 for (serv=servers; serv; serv=serv->next)
153 /* domain matches take priority over NODOTS matches */
154 if ((serv->flags & SERV_FOR_NODOTS) && type != SERV_HAS_DOMAIN && !strchr(dnamebuff, '.'))
155 {
156 if (serv->flags & SERV_LITERAL_ADDRESS)
157 {
158 /* flags gets set if server is in fact an answer */
159 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
160 if (sflag & gotname) /* only OK if addrfamily == query */
161 {
162 type = SERV_FOR_NODOTS;
163 flags = sflag;
164 if (serv->addr.sa.sa_family == AF_INET)
165 addrp = (struct all_addr *)&serv->addr.in.sin_addr;
166#ifdef HAVE_IPV6
167 else
168 addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
169#endif
170 }
171 }
172 else
173 flags = 0;
174 }
175 else if (serv->flags & SERV_HAS_DOMAIN)
176 {
177 unsigned int domainlen = strlen(serv->domain);
178 if (namelen >= domainlen &&
179 hostname_isequal(dnamebuff + namelen - domainlen, serv->domain) &&
a222641c 180 domainlen >= matchlen)
9e4abcb5
SK
181 {
182 if (serv->flags & SERV_LITERAL_ADDRESS)
183 { /* flags gets set if server is in fact an answer */
184 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
44a2a316 185 if ((sflag | F_QUERY ) & gotname) /* only OK if addrfamily == query */
9e4abcb5
SK
186 {
187 type = SERV_HAS_DOMAIN;
44a2a316 188 flags = gotname;
9e4abcb5
SK
189 domain = serv->domain;
190 matchlen = domainlen;
191 if (serv->addr.sa.sa_family == AF_INET)
192 addrp = (struct all_addr *)&serv->addr.in.sin_addr;
193#ifdef HAVE_IPV6
194 else
195 addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
196#endif
197 }
198 }
199 else
200 {
201 flags = 0; /* may be better match from previous literal */
202 domain = serv->domain;
203 matchlen = domainlen;
1ab84e2f 204 type = SERV_HAS_DOMAIN;
9e4abcb5
SK
205 }
206 }
207 }
208 }
209
210 if (flags) /* flags set here means a literal found */
44a2a316
SK
211 {
212 if (flags & F_QUERY)
213 log_query(F_CONFIG | F_FORWARD | F_NEG, dnamebuff, NULL);
214 else
215 log_query(F_CONFIG | F_FORWARD | flags, dnamebuff, addrp);
216 }
9e4abcb5
SK
217 else
218 {
219 /* we may by policy not forward names without a domain part */
220 if (gotname && (options & OPT_NODOTS_LOCAL) && !strchr(dnamebuff, '.'))
221 flags = F_NXDOMAIN;
222 else if (!(forward = get_new_frec(now)))
223 /* table full - server failure. */
224 flags = F_NEG;
225 }
226
227 if (forward)
228 {
229 /* In strict_order mode, or when using domain specific servers
230 always try servers in the order specified in resolv.conf,
231 otherwise, use the one last known to work. */
232
233 if (type != 0 || (options & OPT_ORDER))
234 forward->sentto = servers;
235 else
236 forward->sentto = last_server;
237
238 forward->source = *udpaddr;
44a2a316 239 forward->dest = *dst_addr;
9e4abcb5
SK
240 forward->new_id = get_id();
241 forward->fd = udpfd;
242 forward->orig_id = ntohs(header->id);
243 header->id = htons(forward->new_id);
244 }
245 }
246
247 /* check for send errors here (no route to host)
248 if we fail to send to all nameservers, send back an error
249 packet straight away (helps modem users when offline) */
250
251 if (!flags && forward)
252 {
253 struct server *firstsentto = forward->sentto;
254
255 while (1)
256 {
257 int logflags = 0;
258
259 if (forward->sentto->addr.sa.sa_family == AF_INET)
260 {
261 logflags = F_SERVER | F_IPV4 | F_FORWARD;
262 addrp = (struct all_addr *)&forward->sentto->addr.in.sin_addr;
263 }
264#ifdef HAVE_IPV6
265 else
266 {
267 logflags = F_SERVER | F_IPV6 | F_FORWARD;
268 addrp = (struct all_addr *)&forward->sentto->addr.in6.sin6_addr;
269 }
270#endif
271 /* only send to servers dealing with our domain.
272 domain may be NULL, in which case server->domain
273 must be NULL also. */
274
275 if (type == (forward->sentto->flags & SERV_TYPE) &&
276 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, forward->sentto->domain)))
277 {
278 if (forward->sentto->flags & SERV_NO_ADDR)
279 flags = F_NOERR; /* NULL servers are OK. */
280 else if (!(forward->sentto->flags & SERV_LITERAL_ADDRESS) &&
281 sendto(forward->sentto->sfd->fd, (char *)header, plen, 0,
282 &forward->sentto->addr.sa,
283 sa_len(&forward->sentto->addr)) != -1)
284 {
285 log_query(logflags, gotname ? dnamebuff : "query", addrp);
286 /* for no-domain, don't update last_server */
287 return domain ? last_server : (forward->sentto->next ? forward->sentto->next : servers);
288 }
289 }
290
291 if (!(forward->sentto = forward->sentto->next))
292 forward->sentto = servers;
293
294 /* check if we tried all without success */
295 if (forward->sentto == firstsentto)
296 break;
297 }
298
299 /* could not send on, prepare to return */
300 header->id = htons(forward->orig_id);
301 forward->new_id = 0; /* cancel */
302 }
303
304 /* could not send on, return empty answer or address if known for whole domain */
305 plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
44a2a316
SK
306 send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr);
307
9e4abcb5
SK
308 if (flags & (F_NOERR | F_NXDOMAIN))
309 log_query(F_CONFIG | F_FORWARD | F_NEG | gotname | (flags & F_NXDOMAIN), dnamebuff, NULL);
310
311 return last_server;
312}
313
314/* returns new last_server */
315struct server *reply_query(int fd, int options, char *packet, time_t now,
1cff166d
SK
316 char *dnamebuff, struct server *last_server,
317 struct bogus_addr *bogus_nxdomain, struct doctor *doctors)
9e4abcb5
SK
318{
319 /* packet from peer server, extract data for cache, and send to
320 original requester */
321 struct frec *forward;
322 HEADER *header;
323 int n = recv(fd, packet, PACKETSZ, 0);
324
325 header = (HEADER *)packet;
326 if (n >= (int)sizeof(HEADER) && header->qr)
327 {
328 if ((forward = lookup_frec(ntohs(header->id))))
329 {
330 if (header->rcode == NOERROR || header->rcode == NXDOMAIN)
331 {
332 if (!forward->sentto->domain)
333 last_server = forward->sentto; /* known good */
334 if (header->opcode == QUERY)
335 {
336 if (!(bogus_nxdomain &&
337 header->rcode == NOERROR &&
338 check_for_bogus_wildcard(header, (unsigned int)n, dnamebuff, bogus_nxdomain, now)))
339 {
340 if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
1cff166d 341 extract_addresses(header, (unsigned int)n, dnamebuff, now, doctors);
9e4abcb5
SK
342 else if (!(options & OPT_NO_NEG))
343 extract_neg_addrs(header, (unsigned int)n, dnamebuff, now);
344 }
345 }
346 }
347 header->id = htons(forward->orig_id);
348 /* There's no point returning an upstream reply marked as truncated,
349 since that will prod the resolver into moving to TCP - which we
350 don't support. */
351 header->tc = 0; /* goodbye truncate */
44a2a316 352 send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest);
9e4abcb5
SK
353 forward->new_id = 0; /* cancel */
354 }
355 }
356
357 return last_server;
358}
44a2a316
SK
359
360struct server *receive_query(struct listener *listen, char *packet, char *mxname,
361 char *mxtarget, unsigned int options, time_t now,
362 unsigned long local_ttl, char *namebuff,
363 struct iname *names, struct iname *addrs, struct iname *except,
364 struct server *last_server, struct server *servers)
365{
366 HEADER *header = (HEADER *)packet;
367 union mysockaddr source_addr;
368 struct iname *tmp;
369 struct all_addr dst_addr;
8a911ccc 370 int m, n, if_index = 0;
44a2a316
SK
371 struct iovec iov[1];
372 struct msghdr msg;
373 struct cmsghdr *cmptr;
44a2a316
SK
374 union {
375 struct cmsghdr align; /* this ensures alignment */
376#ifdef HAVE_IPV6
377 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
378#endif
379#if defined(IP_PKTINFO)
380 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
381#elif defined(IP_RECVDSTADDR)
382 char control[CMSG_SPACE(sizeof(struct in_addr)) +
383 CMSG_SPACE(sizeof(struct sockaddr_dl))];
384#endif
385 } control_u;
386
387 iov[0].iov_base = packet;
388 iov[0].iov_len = PACKETSZ;
389
390 msg.msg_control = control_u.control;
391 msg.msg_controllen = sizeof(control_u);
392 msg.msg_flags = 0;
393 msg.msg_name = &source_addr;
394 msg.msg_namelen = sizeof(source_addr);
395 msg.msg_iov = iov;
396 msg.msg_iovlen = 1;
397
398 n = recvmsg(listen->fd, &msg, 0);
399
400 source_addr.sa.sa_family = listen->family;
401#ifdef HAVE_IPV6
402 if (listen->family == AF_INET6)
403 source_addr.in6.sin6_flowinfo = htonl(0);
404#endif
405
406 if (!(options & OPT_NOWILD) && msg.msg_controllen < sizeof(struct cmsghdr))
407 return last_server;
408
409#if defined(IP_PKTINFO)
410 if (!(options & OPT_NOWILD) && listen->family == AF_INET)
411 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
412 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
413 {
414 dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
8a911ccc 415 if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
44a2a316
SK
416 }
417#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
418 if (!(options & OPT_NOWILD) && listen->family == AF_INET)
419 {
420 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
421 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
8a911ccc 422 dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
44a2a316 423 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
8a911ccc 424 if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
44a2a316
SK
425 }
426#endif
427
428#ifdef HAVE_IPV6
429 if (!(options & OPT_NOWILD) && listen->family == AF_INET6)
430 {
431 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
432 if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
433 {
434 dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
8a911ccc 435 if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
44a2a316
SK
436 }
437 }
438#endif
439
440 if (n < (int)sizeof(HEADER) || header->qr)
441 return last_server;
442
443 /* enforce available interface configuration */
444 if (!(options & OPT_NOWILD))
445 {
8a911ccc
SK
446 struct ifreq ifr;
447
448 if (if_index == 0)
44a2a316
SK
449 return last_server;
450
8a911ccc
SK
451 if (except || names)
452 {
453#ifdef SIOCGIFNAME
454 ifr.ifr_ifindex = if_index;
455 if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
456 return last_server;
457#else
458 if (!if_indextoname(if_index, ifr.ifr_name))
459 return last_server;
460#endif
461 }
462
44a2a316 463 for (tmp = except; tmp; tmp = tmp->next)
8a911ccc 464 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
44a2a316 465 return last_server;
9e4abcb5 466
44a2a316
SK
467 if (names || addrs)
468 {
469 for (tmp = names; tmp; tmp = tmp->next)
8a911ccc 470 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
44a2a316
SK
471 break;
472 if (!tmp)
473 for (tmp = addrs; tmp; tmp = tmp->next)
474 if (tmp->addr.sa.sa_family == listen->family)
475 {
476 if (tmp->addr.sa.sa_family == AF_INET &&
477 tmp->addr.in.sin_addr.s_addr == dst_addr.addr.addr4.s_addr)
478 break;
479#ifdef HAVE_IPV6
480 else if (tmp->addr.sa.sa_family == AF_INET6 &&
481 memcmp(&tmp->addr.in6.sin6_addr,
482 &dst_addr.addr.addr6,
483 sizeof(struct in6_addr)) == 0)
484 break;
485#endif
486 }
487 if (!tmp)
488 return last_server;
489 }
490 }
491
492 if (extract_request(header, (unsigned int)n, namebuff))
493 {
494 if (listen->family == AF_INET)
495 log_query(F_QUERY | F_IPV4 | F_FORWARD, namebuff,
496 (struct all_addr *)&source_addr.in.sin_addr);
497#ifdef HAVE_IPV6
498 else
499 log_query(F_QUERY | F_IPV6 | F_FORWARD, namebuff,
500 (struct all_addr *)&source_addr.in6.sin6_addr);
501#endif
502 }
503
504 m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
505 mxname, mxtarget, options, now, local_ttl, namebuff);
506 if (m >= 1)
507 send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
508 else
509 last_server = forward_query(listen->fd, &source_addr, &dst_addr,
510 header, n, options, namebuff, servers,
511 last_server, now, local_ttl);
512 return last_server;
513}
514
9e4abcb5
SK
515static struct frec *get_new_frec(time_t now)
516{
517 struct frec *f = frec_list, *oldest = NULL;
518 time_t oldtime = now;
519 int count = 0;
520 static time_t warntime = 0;
521
522 while (f)
523 {
524 if (f->new_id == 0)
525 {
526 f->time = now;
527 return f;
528 }
529
530 if (difftime(f->time, oldtime) <= 0)
531 {
532 oldtime = f->time;
533 oldest = f;
534 }
535
536 count++;
537 f = f->next;
538 }
539
540 /* can't find empty one, use oldest if there is one
541 and it's older than timeout */
542 if (oldest && difftime(now, oldtime) > TIMEOUT)
543 {
544 oldest->time = now;
545 return oldest;
546 }
547
548 if (count > FTABSIZ)
549 { /* limit logging rate so syslog isn't DOSed either */
550 if (!warntime || difftime(now, warntime) > LOGRATE)
551 {
552 warntime = now;
553 syslog(LOG_WARNING, "forwarding table overflow: check for server loops.");
554 }
555 return NULL;
556 }
557
558 if ((f = (struct frec *)malloc(sizeof(struct frec))))
559 {
560 f->next = frec_list;
561 f->time = now;
562 frec_list = f;
563 }
564 return f; /* OK if malloc fails and this is NULL */
565}
566
567static struct frec *lookup_frec(unsigned short id)
568{
569 struct frec *f;
570
571 for(f = frec_list; f; f = f->next)
572 if (f->new_id == id)
573 return f;
574
575 return NULL;
576}
577
578static struct frec *lookup_frec_by_sender(unsigned short id,
579 union mysockaddr *addr)
580{
581 struct frec *f;
582
583 for(f = frec_list; f; f = f->next)
584 if (f->new_id &&
585 f->orig_id == id &&
586 sockaddr_isequal(&f->source, addr))
587 return f;
588
589 return NULL;
590}
591
592
593/* return unique random ids between 1 and 65535 */
594static unsigned short get_id(void)
595{
596 unsigned short ret = 0;
597
598 while (ret == 0)
599 {
600 ret = rand16();
601
602 /* scrap ids already in use */
603 if ((ret != 0) && lookup_frec(ret))
604 ret = 0;
605 }
606
607 return ret;
608}
609
610
611
612
613