Blob


1 /*
2 * Copyright (c) 2002-2014 Peter J. Philipp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28 #include "include.h"
29 #include "dns.h"
30 #include "db.h"
31 #include "config.h"
33 /* prototypes */
35 extern void add_rrlimit(int, u_int16_t *, int, char *);
36 extern void axfrloop(int *, int, char **, DB *);
37 extern int check_rrlimit(int, u_int16_t *, int, char *);
38 extern void collects_init(void);
39 extern void dolog(int, char *, ...);
40 extern int find_filter(struct sockaddr_storage *, int);
41 extern int find_recurse(struct sockaddr_storage *, int);
42 extern u_int8_t find_region(struct sockaddr_storage *, int);
43 extern int find_whitelist(struct sockaddr_storage *, int);
44 extern int find_wildcard(struct sockaddr_storage *, int);
45 extern void init_wildcard(void);
46 extern void init_recurse(void);
47 extern void init_region(void);
48 extern void init_filter(void);
49 extern void init_notifyslave(void);
50 extern void init_whitelist(void);
51 extern void recurseloop(int sp, int *, DB *);
52 extern void receivelog(char *, int);
53 extern int reply_a(struct sreply *, DB *);
54 extern int reply_aaaa(struct sreply *, DB *);
55 extern int reply_any(struct sreply *);
56 extern int reply_cname(struct sreply *);
57 extern int reply_fmterror(struct sreply *);
58 extern int reply_notimpl(struct sreply *);
59 extern int reply_nxdomain(struct sreply *);
60 extern int reply_noerror(struct sreply *);
61 extern int reply_soa(struct sreply *);
62 extern int reply_mx(struct sreply *, DB *);
63 extern int reply_naptr(struct sreply *, DB *);
64 extern int reply_ns(struct sreply *, DB *);
65 extern int reply_ptr(struct sreply *);
66 extern int reply_refused(struct sreply *);
67 extern int reply_spf(struct sreply *);
68 extern int reply_srv(struct sreply *, DB *);
69 extern int reply_sshfp(struct sreply *);
70 extern int reply_txt(struct sreply *);
71 extern int remotelog(int, char *, ...);
72 extern char *rrlimit_setup(int);
74 struct question *build_fake_question(char *, int, u_int16_t);
75 struct question *build_question(char *, int, int);
76 void build_reply(struct sreply *, int, char *, int, struct question *, struct sockaddr *, socklen_t, struct domain *, struct domain *, u_int8_t, int, int, struct recurses *, char *);
77 int compress_label(u_char *, u_int16_t, int);
78 u_int16_t check_qtype(struct domain *, u_int16_t, int, int *);
79 char *dns_label(char *, int *);
80 int free_question(struct question *);
81 char *get_dns_type(int dnstype);
82 int get_soa(DB *, struct question *, struct domain *, int);
83 int lookup_zone(DB *, struct question *, struct domain *, int *, char *, int);
84 void mainloop(struct cfg *);
85 void master_reload(int);
86 void master_shutdown(int);
87 int memcasecmp(u_char *, u_char *, int);
88 void recurseheader(struct srecurseheader *, int, struct sockaddr_storage *, struct sockaddr_storage *, int);
89 void setup_master(DB *, DB_ENV *, char **);
90 void slave_signal(int);
91 void slave_shutdown(void);
93 /* aliases */
95 #ifndef DEFAULT_PRIVILEGE
96 #define DEFAULT_PRIVILEGE "wdnsd"
97 #endif
99 #define PIDFILE "/var/run/wildcarddnsd.pid"
100 #define MYDB_PATH "/var/db/wdns"
103 struct typetable {
104 char *type;
105 int number;
106 } TT[] = {
107 { "A", DNS_TYPE_A},
108 { "NS", DNS_TYPE_NS},
109 { "CNAME", DNS_TYPE_CNAME},
110 { "SOA", DNS_TYPE_SOA},
111 { "PTR", DNS_TYPE_PTR},
112 { "MX", DNS_TYPE_MX},
113 { "TXT", DNS_TYPE_TXT},
114 { "AAAA", DNS_TYPE_AAAA},
115 { "ANY", DNS_TYPE_ANY },
116 { "SRV", DNS_TYPE_SRV },
117 { "SPF", DNS_TYPE_SPF },
118 { "SSHFP", DNS_TYPE_SSHFP },
119 { "NAPTR", DNS_TYPE_NAPTR },
120 { NULL, 0}
121 };
124 /* global variables */
126 extern char *__progname;
127 extern struct logging logging;
128 extern int axfrport;
129 extern int ratelimit;
130 extern int ratelimit_packets_per_second;
131 extern int whitelist;
133 static int *ptr = NULL;
134 static int reload = 0;
135 static int mshutdown = 0;
136 static int msig;
137 static char *database;
138 static char mydatabase[512];
139 static char *rptr;
140 static int ratelimit_backlog;
142 int debug = 0;
143 int verbose = 0;
144 int bflag = 0;
145 int iflag = 0;
146 int lflag = 0;
147 int nflag = 0;
148 int rflag = 0;
149 int bcount = 0;
150 int icount = 0;
151 u_int16_t port = 53;
152 u_int32_t cachesize = 0;
153 char *bind_list[255];
154 char *interface_list[255];
156 /* singly linked list for tcp operations */
157 SLIST_HEAD(listhead, tcps) tcpshead;
159 static struct tcps {
160 char *input;
161 char *ident;
162 char *address;
163 int offset;
164 int length;
165 int maxlen;
166 int so;
167 int isv6;
168 u_int8_t region;
169 int wildcard;
170 time_t time;
171 SLIST_ENTRY(tcps) tcps_entry;
172 } *tn1, *tnp, *tntmp;
175 static const char rcsid[] = "$Id: main.c,v 1.103 2014/11/07 10:33:12 pjp Exp $";
177 /*
178 * MAIN - set up arguments, set up database, set up sockets, call mainloop
180 */
182 int
183 main(int argc, char *argv[])
185 static int udp[DEFAULT_SOCKET];
186 static int tcp[DEFAULT_SOCKET];
187 static int afd[DEFAULT_SOCKET];
188 static int uafd[DEFAULT_SOCKET];
189 int raw[2];
190 int lfd = -1;
191 int fd, n;
193 int ch, i, j;
194 int gai_error;
195 int salen, ret;
196 int found = 0;
197 int on = 1;
198 int sp[2];
200 pid_t pid;
202 static char *ident[DEFAULT_SOCKET];
203 char *conffile = CONFFILE;
204 char buf[512];
205 char **av = NULL;
207 struct passwd *pw;
208 struct addrinfo hints, *res0, *res;
209 struct ifaddrs *ifap, *pifap;
210 struct sockaddr_in *sin;
211 struct sockaddr_in6 *sin6;
212 struct cfg *cfg;
214 static DB_ENV *dbenv;
215 static DB *db;
217 key_t key;
219 if (geteuid() != 0) {
220 fprintf(stderr, "must be started as root\n"); /* .. dolt */
221 exit(1);
224 av = argv;
226 while ((ch = getopt(argc, argv, "b:c:df:i:ln:p:rv")) != -1) {
227 switch (ch) {
228 case 'b':
229 bflag = 1;
230 if (bcount > 253) {
231 fprintf(stderr, "too many -b flags\n");
232 exit(1);
234 bind_list[bcount++] = optarg;
235 break;
236 case 'c':
237 #if !defined __OpenBSD__
238 cachesize = atoi(optarg);
239 #else
240 cachesize = strtonum(optarg, 1, 0xffffffff, NULL);
241 #endif
242 break;
243 case 'd':
244 debug = 1;
245 break;
246 case 'f':
247 conffile = optarg;
248 break;
249 case 'i':
250 iflag = 1;
251 if (icount > 254) {
252 fprintf(stderr, "too many -i flags\n");
253 exit(1);
255 interface_list[icount++] = optarg;
256 break;
257 case 'l':
258 lflag = 1;
259 break;
260 case 'n':
261 nflag = atoi(optarg);
262 break;
263 case 'p':
264 port = atoi(optarg) & 0xffff;
265 break;
266 case 'r':
267 rflag = 1;
268 break;
269 case 'v':
270 verbose++;
271 break;
272 default:
273 fprintf(stderr, "usage: wildcarddnsd [-i interface] [-b bindaddress] [-f configfile] [-p portnumber] [-drv]\n");
274 exit (1);
278 if (bflag && iflag) {
279 fprintf(stderr, "you may specify -i or -b but not both\n");
280 exit(1);
283 /*
284 * calling daemon before a sleuth of configurations ala rwhod.c
285 */
287 if (! debug)
288 daemon(0,0);
291 openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
292 dolog(LOG_INFO, "starting up\n");
294 /* cfg struct */
295 cfg = calloc(1, sizeof(struct cfg));
296 if (cfg == NULL) {
297 dolog(LOG_ERR, "calloc: %s\n", strerror(errno));
298 exit(1);
301 /*
302 * make a shared memory segment for signaling kills between
303 * processes...
304 */
307 ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED |\
308 MAP_ANON, -1, 0);
310 if (ptr == MAP_FAILED) {
311 dolog(LOG_ERR, "failed to setup mmap segment, exit\n");
312 exit(1);
315 *ptr = 0;
317 if ((ret = db_env_create(&dbenv, 0)) != 0) {
318 dolog(LOG_INFO, "db_env_create: %s\n", db_strerror(ret));
319 slave_shutdown();
320 exit(1);
323 key = ftok("/usr/local/sbin/wildcarddnsd", 1);
324 if (key == (key_t)-1) {
325 dolog(LOG_INFO, "ftok failed, does /usr/local/sbin/wildcarddnsd exist?\n");
326 slave_shutdown();
327 exit(1);
331 if ((ret = dbenv->set_shm_key(dbenv, key)) != 0) {
332 dolog(LOG_INFO, "dbenv->set_shm_key failed\n");
333 slave_shutdown();
334 exit(1);
337 /* set cache size , if requested */
339 if (cachesize) {
340 if ((ret = dbenv->set_cachesize(dbenv, 0, cachesize, 0)) != 0) {
341 dolog(LOG_INFO, "dbenv->set_cachesize: %s\n",
342 db_strerror(ret));
343 slave_shutdown();
344 exit(1);
348 (void)mkdir(MYDB_PATH, 0700);
349 snprintf(mydatabase, sizeof(mydatabase), "%s/%ld",
350 MYDB_PATH, (long)getpid());
352 if (mkdir(mydatabase, 0750) < 0) {
353 if (errno != EEXIST) {
354 dolog(LOG_ERR, "mkdir: %s\n", strerror(errno));
355 exit(1);
359 if ((ret = dbenv->open(dbenv, mydatabase, DB_CREATE | \
360 DB_INIT_LOCK | DB_INIT_MPOOL | DB_SYSTEM_MEM, \
361 S_IRUSR | S_IWUSR)) != 0) {
362 dolog(LOG_INFO, "dbenv->open failed: %s\n", db_strerror(ret));
363 slave_shutdown();
364 exit(1);
367 if (db_create((DB **)&db, (DB_ENV *)dbenv, 0) != 0) {
368 dolog(LOG_INFO, "db_create: %s\n", strerror(errno));
369 slave_shutdown();
370 exit(1);
373 /*
374 * we want to run multiple instances of different versions so we'll
375 * make a temporary database...
376 */
379 snprintf(mydatabase, sizeof(mydatabase), "%s/%ld/wdns.db",
380 MYDB_PATH, (long)getpid());
382 (void)unlink(mydatabase);
384 database = mydatabase;
387 fd = open(database, O_WRONLY | O_CREAT, 0600);
388 if (fd < 0) {
389 dolog(LOG_INFO, "open: %s\n", strerror(errno));
391 close(fd);
393 if (db->open(db, NULL, database, NULL, DB_BTREE, DB_CREATE, 0600) != 0) {
394 dolog(LOG_INFO, "db->open: %s\n", strerror(errno));
395 db->close(db, DB_NOSYNC);
396 slave_shutdown();
397 exit(1);
400 /* make a master program that holds the pidfile, boss of ... eek */
402 pid = fork();
403 switch (pid) {
404 case -1:
405 dolog(LOG_ERR, "fork(): %s\n", strerror(errno));
406 exit(1);
407 case 0:
408 break;
409 default:
410 setup_master(db, dbenv, av);
411 /* NOTREACHED */
412 exit(1);
415 /* end of setup_master code */
417 init_wildcard();
418 init_recurse();
419 init_region();
420 init_filter();
421 init_whitelist();
422 init_notifyslave();
424 if (parse_file(db, conffile) < 0) {
425 dolog(LOG_INFO, "parsing config file failed\n");
426 slave_shutdown();
427 exit(1);
430 /* ratelimiting setup */
431 if (ratelimit) {
432 ratelimit_backlog = ratelimit_packets_per_second * 2;
433 rptr = rrlimit_setup(ratelimit_backlog);
434 if (rptr == NULL) {
435 dolog(LOG_INFO, "ratelimiting error\n");
436 slave_shutdown();
437 exit(1);
442 pw = getpwnam(DEFAULT_PRIVILEGE);
443 if (pw == NULL) {
444 dolog(LOG_INFO, "getpwnam: %s\n", strerror(errno));
445 slave_shutdown();
446 exit(1);
449 if (bcount > DEFAULT_SOCKET) {
450 dolog(LOG_INFO, "not enough sockets available\n");
451 slave_shutdown();
452 exit(1);
455 if (bflag) {
456 for (i = 0; i < bcount; i++) {
457 memset(&hints, 0, sizeof(hints));
459 if (strchr(bind_list[i], ':') != NULL) {
460 hints.ai_family = AF_INET6;
461 } else {
462 hints.ai_family = AF_INET;
465 hints.ai_socktype = SOCK_DGRAM;
466 hints.ai_protocol = IPPROTO_UDP;
467 hints.ai_flags = AI_NUMERICHOST;
469 snprintf(buf, sizeof(buf) - 1, "%u", port);
471 if ((gai_error = getaddrinfo(bind_list[i], buf, &hints, &res0)) != 0) {
472 dolog(LOG_INFO, "getaddrinfo: %s\n", gai_strerror(gai_error));
473 slave_shutdown();
474 exit (1);
477 res = res0;
479 if ((udp[i] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
480 dolog(LOG_INFO, "socket: %s\n", strerror(errno));
481 slave_shutdown();
482 exit(1);
485 if (bind(udp[i], res->ai_addr, res->ai_addrlen) < 0) {
486 dolog(LOG_INFO, "bind: %s\n", strerror(errno));
487 slave_shutdown();
488 exit(1);
491 if (res->ai_family == AF_INET) {
492 #ifdef __NetBSD__
493 if (setsockopt(udp[i], IPPROTO_IP, IP_TTL,
494 &on, sizeof(on)) < 0) {
495 #else
496 if (setsockopt(udp[i], IPPROTO_IP, IP_RECVTTL,
497 &on, sizeof(on)) < 0) {
498 #endif
499 dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
501 } else if (res->ai_family == AF_INET6) {
502 /* RFC 3542 page 30 */
503 on = 1;
504 if (setsockopt(udp[i], IPPROTO_IPV6,
505 IPV6_RECVHOPLIMIT, &on, sizeof(on)) < 0) {
506 dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
510 ident[i] = bind_list[i];
512 /* tcp below */
513 hints.ai_socktype = SOCK_STREAM;
514 hints.ai_protocol = IPPROTO_TCP;
515 hints.ai_flags = AI_NUMERICHOST;
517 snprintf(buf, sizeof(buf) - 1, "%u", port);
519 if ((gai_error = getaddrinfo(bind_list[i], buf, &hints, &res0)) != 0) {
520 dolog(LOG_INFO, "getaddrinfo: %s\n", gai_strerror(gai_error));
521 slave_shutdown();
522 exit (1);
525 res = res0;
527 if ((tcp[i] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
528 dolog(LOG_INFO, "tcp socket: %s\n", strerror(errno));
529 slave_shutdown();
530 exit(1);
532 if (setsockopt(tcp[i], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
533 dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
534 slave_shutdown();
535 exit(1);
537 if (bind(tcp[i], res->ai_addr, res->ai_addrlen) < 0) {
538 dolog(LOG_INFO, "tcp bind: %s\n", strerror(errno));
539 slave_shutdown();
540 exit(1);
543 if (axfrport) {
544 /* axfr port below */
545 hints.ai_socktype = SOCK_STREAM;
546 hints.ai_protocol = IPPROTO_TCP;
547 hints.ai_flags = AI_NUMERICHOST;
549 snprintf(buf, sizeof(buf) - 1, "%u", axfrport);
551 if ((gai_error = getaddrinfo(bind_list[i], buf, &hints, &res0)) != 0) {
552 dolog(LOG_INFO, "getaddrinfo: %s\n", gai_strerror(gai_error));
553 slave_shutdown();
554 exit (1);
557 res = res0;
559 if ((afd[i] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
560 dolog(LOG_INFO, "tcp socket: %s\n", strerror(errno));
561 slave_shutdown();
562 exit(1);
564 if (setsockopt(afd[i], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
565 dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
566 slave_shutdown();
567 exit(1);
569 if (bind(afd[i], res->ai_addr, res->ai_addrlen) < 0) {
570 dolog(LOG_INFO, "tcp bind: %s\n", strerror(errno));
571 slave_shutdown();
572 exit(1);
575 if ((uafd[i] = socket(res->ai_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
576 dolog(LOG_INFO, "axfr udp socket: %s\n", strerror(errno));
577 slave_shutdown();
578 exit(1);
580 if (bind(uafd[i], res->ai_addr, res->ai_addrlen) < 0) {
581 dolog(LOG_INFO, "axfr udp socket bind: %s\n", strerror(errno));
582 slave_shutdown();
583 exit(1);
585 } /* axfrport */
587 } /* for .. bcount */
589 } else {
590 if (getifaddrs(&ifap) < 0) {
591 dolog(LOG_INFO, "getifaddrs\n");
592 slave_shutdown();
593 exit(1);
596 for (pifap = ifap, i = 0; i < DEFAULT_SOCKET && pifap; pifap = pifap->ifa_next, i++) {
598 found = 0;
600 /* we want only one interface not the rest */
601 if (icount > 0) {
602 for (j = 0; j < icount; j++) {
603 if (strcmp(pifap->ifa_name, interface_list[j]) == 0) {
604 found = 1;
608 if (! found) {
609 i--;
610 continue;
614 if ((pifap->ifa_flags & IFF_UP) != IFF_UP) {
615 dolog(LOG_INFO, "skipping interface %s\n", pifap->ifa_name);
616 i--;
617 continue;
620 if (pifap->ifa_addr->sa_family == AF_INET) {
621 sin = (struct sockaddr_in *)pifap->ifa_addr;
622 sin->sin_port = htons(port);
623 salen = sizeof(struct sockaddr_in);
624 /* no address bound to this interface */
625 if (sin->sin_addr.s_addr == INADDR_ANY) {
626 i--;
627 continue;
629 } else if (pifap->ifa_addr->sa_family == AF_INET6) {
630 sin6 = (struct sockaddr_in6 *)pifap->ifa_addr;
631 sin6->sin6_port = htons(port);
632 /* no address bound to this interface */
633 salen = sizeof(struct sockaddr_in6);
635 } else {
636 dolog(LOG_DEBUG, "unknown address family %d\n", pifap->ifa_addr->sa_family);
637 i--;
638 continue;
642 if ((udp[i] = socket(pifap->ifa_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
643 dolog(LOG_INFO, "socket: %s\n", strerror(errno));
644 slave_shutdown();
645 exit(1);
648 if (bind(udp[i], (struct sockaddr *)pifap->ifa_addr, salen) < 0) {
649 dolog(LOG_INFO, "bind: %s\n", strerror(errno));
650 slave_shutdown();
651 exit(1);
654 if (pifap->ifa_addr->sa_family == AF_INET) {
655 #ifdef __NetBSD__
656 if (setsockopt(udp[i], IPPROTO_IP, IP_TTL,
657 &on, sizeof(on)) < 0) {
658 #else
659 if (setsockopt(udp[i], IPPROTO_IP, IP_RECVTTL,
660 &on, sizeof(on)) < 0) {
661 #endif
662 dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
664 } else if (pifap->ifa_addr->sa_family == AF_INET6) {
665 /* RFC 3542 page 30 */
666 on = 1;
667 if (setsockopt(udp[i], IPPROTO_IPV6,
668 IPV6_RECVHOPLIMIT, &on, sizeof(on)) < 0) {
669 dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
674 ident[i] = pifap->ifa_name;
676 if ((tcp[i] = socket(pifap->ifa_addr->sa_family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
677 dolog(LOG_INFO, "tcp socket: %s\n", strerror(errno));
678 slave_shutdown();
679 exit(1);
681 if (setsockopt(tcp[i], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
682 dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
683 slave_shutdown();
684 exit(1);
687 if (bind(tcp[i], (struct sockaddr *)pifap->ifa_addr, salen) < 0) {
688 dolog(LOG_INFO, "tcp bind: %s\n", strerror(errno));
689 slave_shutdown();
690 exit(1);
694 /* axfr socket */
695 if (axfrport) {
696 if ((afd[i] = socket(pifap->ifa_addr->sa_family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
697 dolog(LOG_INFO, "tcp socket: %s\n", strerror(errno));
698 slave_shutdown();
699 exit(1);
701 if (setsockopt(afd[i], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
702 dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
703 slave_shutdown();
704 exit(1);
707 ((struct sockaddr_in *)pifap->ifa_addr)->sin_port = htons(axfrport);
709 if (bind(afd[i], (struct sockaddr *)pifap->ifa_addr, salen) < 0) {
710 dolog(LOG_INFO, "tcp bind: %s\n", strerror(errno));
711 slave_shutdown();
712 exit(1);
714 if ((uafd[i] = socket(pifap->ifa_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
715 dolog(LOG_INFO, "axfr udp socket: %s\n", strerror(errno));
716 slave_shutdown();
717 exit(1);
719 if (bind(uafd[i], (struct sockaddr *)pifap->ifa_addr, salen) < 0) {
720 dolog(LOG_INFO, "udp axfr bind: %s\n", strerror(errno));
721 slave_shutdown();
722 exit(1);
724 } /* axfrport */
726 } /* AF_INET */
728 if (i >= DEFAULT_SOCKET) {
729 dolog(LOG_INFO, "not enough sockets available\n");
730 slave_shutdown();
731 exit(1);
733 } /* if bflag? */
735 if (rflag == 1) {
736 if ((raw[0] = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
737 dolog(LOG_INFO, "raw socket: %s\n", strerror(errno));
738 slave_shutdown();
739 exit(1);
742 if (setsockopt(raw[0], IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {
743 dolog(LOG_INFO, "raw setsockopt: %s\n", strerror(errno));
744 slave_shutdown();
745 exit(1);
748 if ((raw[1] = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP)) < 0) {
749 dolog(LOG_INFO, "raw socket[1]: %s\n", strerror(errno));
750 slave_shutdown();
751 exit(1);
754 } /* rflag */
757 /* if we are binding a log socket do it now */
758 if (logging.bind == 1 || logging.active == 1) {
759 switch (logging.loghost2.ss_family) {
760 case AF_INET:
761 lfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
762 if (lfd < 0) {
763 dolog(LOG_INFO, "logging socket: %s\n", strerror(errno));
764 slave_shutdown();
765 exit(1);
767 sin = (struct sockaddr_in *)&logging.loghost2;
768 sin->sin_port = htons(logging.logport2);
769 break;
770 case AF_INET6:
771 lfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
772 if (lfd < 0) {
773 dolog(LOG_INFO, "logging socket: %s\n", strerror(errno));
774 slave_shutdown();
775 exit(1);
777 sin6 = (struct sockaddr_in6 *)&logging.loghost2;
778 sin6->sin6_port = htons(logging.logport2);
779 break;
782 if (logging.bind == 1) {
783 if (bind(lfd, (struct sockaddr *)&logging.loghost2,
784 ((logging.loghost2.ss_family == AF_INET6) ?
785 sizeof(struct sockaddr_in6) :
786 sizeof(struct sockaddr_in))
787 ) < 0) {
788 dolog(LOG_INFO, "binding log socket: %s\n", strerror(errno));
789 slave_shutdown();
790 exit(1);
793 #ifndef __linux__
794 if (shutdown(lfd, SHUT_WR) < 0) {
795 dolog(LOG_INFO, "shutdown log socket: %s\n", strerror(errno));
796 slave_shutdown();
797 exit(1);
799 #endif
801 } else {
802 if (connect(lfd, (struct sockaddr *)&logging.loghost2,
803 ((logging.loghost2.ss_family == AF_INET6) ?
804 sizeof(struct sockaddr_in6) :
805 sizeof(struct sockaddr_in))) < 0) {
806 dolog(LOG_INFO, "connecting log socket: %s\n", strerror(errno));
807 slave_shutdown();
808 exit(1);
811 if (shutdown(lfd, SHUT_RD) < 0) {
812 dolog(LOG_INFO, "shutdown log socket: %s\n", strerror(errno));
813 slave_shutdown();
814 exit(1);
817 } /* if logging.bind */
819 } /* if logging.bind */
821 /* chroot to the drop priv user home directory */
822 if (chroot(pw->pw_dir) < 0) {
823 dolog(LOG_INFO, "chroot: %s\n", strerror(errno));
824 slave_shutdown();
825 exit(1);
828 if (chdir("/") < 0) {
829 dolog(LOG_INFO, "chdir: %s\n", strerror(errno));
830 slave_shutdown();
831 exit(1);
834 /*
835 * add signals
836 */
838 signal(SIGPIPE, SIG_IGN);
840 signal(SIGTERM, slave_signal);
841 signal(SIGINT, slave_signal);
842 signal(SIGQUIT, slave_signal);
844 /*
845 * I open the log again after the chroot just in case I can't
846 * reach the old /dev/log anymore.
847 */
849 closelog();
850 openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
852 /* set groups */
854 if (setgroups(1, &pw->pw_gid) < 0) {
855 dolog(LOG_INFO, "setgroups: %s\n", strerror(errno));
856 slave_shutdown();
857 exit(1);
860 #if defined __OpenBSD__ || defined __FreeBSD__
861 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0) {
862 dolog(LOG_INFO, "setresgid: %s\n", strerror(errno));
863 slave_shutdown();
864 exit(1);
867 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) {
868 dolog(LOG_INFO, "setresuid: %s\n", strerror(errno));
869 slave_shutdown();
870 exit(1);
873 #else
874 if (setgid(pw->pw_gid) < 0) {
875 dolog(LOG_INFO, "setgid: %s\n", strerror(errno));
876 slave_shutdown();
877 exit(1);
879 if (setuid(pw->pw_uid) < 0) {
880 dolog(LOG_INFO, "setuid: %s\n", strerror(errno));
881 slave_shutdown();
882 exit(1);
884 #endif
886 /*
887 * start our axfr process
888 */
890 if (axfrport) {
891 switch (pid = fork()) {
892 case 0:
893 /* close descriptors that we don't need */
894 for (j = 0; j < i; j++) {
895 close(tcp[j]);
896 close(udp[j]);
897 close(uafd[j]);
900 if (rflag) {
901 close(raw[0]);
902 close(raw[1]);
905 #if !defined __linux__ && !defined __APPLE__
906 setproctitle("AXFR engine on port %d", axfrport);
907 #endif
909 axfrloop(afd, i, ident, db);
910 /* NOTREACHED */
911 exit(1);
912 default:
913 /* close afd descriptors, they aren't needed here */
914 for (j = 0; j < i; j++) {
915 close(afd[j]);
918 break;
921 } /* axfrport */
923 /* what follows is a bit mangled code, we set up nflag + 1 amount of
924 * server instances (1 per cpu?) and if we're recursive we also set up
925 * the same amount of recursive instances all connected through a
926 * socketpair() so that it looks somewhat like this (with 4 instances):
928 * replies <--- [] ---- [] recursive end
929 * |
930 * replies <--- [] ---- []
931 * request * ---> |
932 * replies <--- [] ---- []
933 * |
934 * replies <--- [] ---- []
936 */
938 for (n = 0; n < nflag; n++) {
939 switch (pid = fork()) {
940 case 0:
941 if (rflag) {
942 /*
943 * set up socket pair
944 */
946 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, (int *)&sp) < 0) {
947 dolog(LOG_INFO, "socketpair: %s\n", strerror(errno));
948 slave_shutdown();
949 exit(1);
952 switch (pid = fork()) {
953 case -1:
954 dolog(LOG_INFO, "fork: %s\n", strerror(errno));
955 slave_shutdown();
956 exit(1);
958 case 0:
959 for (j = 0; j < i; j++) {
960 close(tcp[j]);
961 close(udp[j]);
963 close (sp[1]);
965 recurseloop(sp[0], (int *)&raw, db);
966 /* NOTREACHED */
967 break;
969 default:
970 close(raw[0]);
971 close(raw[1]);
972 close (sp[0]);
973 break;
974 } /* switch */
975 } /* rflag */
978 cfg->sockcount = i;
979 cfg->db = db;
980 for (i = 0; i < cfg->sockcount; i++) {
981 cfg->udp[i] = udp[i];
982 cfg->tcp[i] = tcp[i];
984 if (axfrport)
985 cfg->axfr[i] = uafd[i];
987 cfg->ident[i] = strdup(ident[i]);
989 cfg->recurse = (rflag ? sp[1] : -1);
990 cfg->log = lfd;
993 (void)mainloop(cfg);
995 /* NOTREACHED */
996 default:
997 break;
998 } /* switch pid= fork */
999 } /* for (.. nflag */
1001 if (rflag) {
1003 * set up socket pair
1006 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, (int *)&sp) < 0) {
1007 dolog(LOG_INFO, "socketpair: %s\n", strerror(errno));
1008 slave_shutdown();
1009 exit(1);
1012 switch (pid = fork()) {
1013 case -1:
1014 dolog(LOG_INFO, "fork: %s\n", strerror(errno));
1015 slave_shutdown();
1016 exit(1);
1018 case 0:
1019 for (j = 0; j < i; j++) {
1020 close(tcp[j]);
1021 close(udp[j]);
1022 close(uafd[j]);
1024 close (sp[1]);
1026 recurseloop(sp[0], (int *)&raw, db);
1027 /* NOTREACHED */
1028 break;
1030 default:
1031 close(raw[0]);
1032 close(raw[1]);
1033 close (sp[0]);
1034 break;
1035 } /* switch */
1037 } /* rflag */
1040 cfg->sockcount = i;
1041 cfg->db = db;
1042 for (i = 0; i < cfg->sockcount; i++) {
1043 cfg->udp[i] = udp[i];
1044 cfg->tcp[i] = tcp[i];
1046 if (axfrport)
1047 cfg->axfr[i] = uafd[i];
1049 cfg->ident[i] = strdup(ident[i]);
1051 cfg->recurse = (rflag ? sp[1] : -1);
1052 cfg->log = lfd;
1055 (void)mainloop(cfg);
1057 /* NOTREACHED */
1058 return (0);
1063 * BUILD_QUESTION - fill the question structure with the DNS query.
1066 struct question *
1067 build_question(char *buf, int len, int additional)
1069 u_int i;
1070 u_int namelen = 0;
1071 u_int16_t *qtype, *qclass;
1072 int num_label;
1074 char *p, *end_name = NULL;
1076 struct dns_optrr *opt = NULL;
1077 struct question *q = NULL;
1079 /* find the end of name */
1080 for (i = sizeof(struct dns_header); i < len; i++) {
1081 /* XXX */
1082 if (buf[i] == 0) {
1083 end_name = &buf[i];
1084 break;
1089 * implies i >= len , because end_name still points to NULL and not
1090 * &buf[i]
1093 if (end_name == NULL) {
1094 dolog(LOG_INFO, "query name is not null terminated\n");
1095 return NULL;
1098 /* parse the size of the name */
1099 for (i = sizeof(struct dns_header), num_label = 0; i < len && &buf[i] < end_name;) {
1100 u_int labellen;
1102 ++num_label;
1104 labellen = (u_int)buf[i];
1107 * do some checks on the label, if it's 0 or over 63 it's
1108 * illegal, also if it reaches beyond the entire name it's
1109 * also illegal.
1111 if (labellen == 0) {
1112 dolog(LOG_INFO, "illegal label len (0)\n");
1113 return NULL;
1115 if (labellen > DNS_MAXLABEL) {
1116 dolog(LOG_INFO, "illegal label len (> 63)\n");
1117 return NULL;
1119 if (labellen > (end_name - &buf[i])) {
1120 dolog(LOG_INFO, "label len extends beyond name\n");
1121 return NULL;
1124 i += (labellen + 1);
1125 namelen += labellen;
1128 if (&buf[i] != end_name || i >= len) {
1129 dolog(LOG_INFO, "query name is maliciously malformed\n");
1130 return NULL;
1133 if (i > DNS_MAXNAME) {
1134 dolog(LOG_INFO, "query name is too long (%u)\n", i);
1135 return NULL;
1139 /* check if there is space for qtype and qclass */
1140 if (len < ((end_name - &buf[0]) + (2 * sizeof(u_int16_t)))) {
1141 dolog(LOG_INFO, "question rr is truncated\n");
1142 return NULL;
1146 q = (void *)calloc(1, sizeof(struct question));
1147 if (q == NULL) {
1148 dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
1149 return NULL;
1151 q->hdr = (void *)calloc(1, sizeof(struct dns_question_hdr));
1152 if (q->hdr == NULL) {
1153 dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
1154 free(q);
1155 return NULL;
1157 q->hdr->namelen = (end_name - &buf[sizeof(struct dns_header)]) + 1; /* XXX */
1158 q->hdr->name = (void *) calloc(1, q->hdr->namelen);
1159 if (q->hdr->name == NULL) {
1160 dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
1161 free(q->hdr);
1162 free(q);
1163 return NULL;
1165 q->converted_name = (void *)calloc(1, namelen + num_label + 2);
1166 if (q->converted_name == NULL) {
1167 dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
1168 free(q->hdr->name);
1169 free(q->hdr);
1170 free(q);
1171 return NULL;
1174 p = q->converted_name;
1177 * parse the name again this time filling the labels
1178 * XXX this is expensive going over the buffer twice
1180 for (i = sizeof(struct dns_header); i < len && &buf[i] < end_name;) {
1181 u_int labelend;
1184 /* check for compression */
1185 if ((buf[i] & 0xc0) == 0xc0) {
1186 dolog(LOG_INFO, "question has compressed name, drop\n");
1187 free_question(q);
1188 return NULL; /* XXX should say error */
1191 labelend = (u_int)buf[i] + 1 + i; /* i = offset, plus contents of buf[i], + 1 */
1194 * i is reused here to count every character, this is not
1195 * a bug!
1198 for (i++; i < labelend; i++) {
1199 int c0;
1201 c0 = buf[i];
1202 *p++ = tolower(c0);
1205 *p++ = '.';
1208 /* XXX */
1209 if (&buf[sizeof(struct dns_header)] == end_name)
1210 *p++ = '.';
1212 *p = '\0';
1214 /* check for edns0 opt rr */
1215 do {
1216 /* if we don't have an additional section, break */
1217 if (additional != 1)
1218 break;
1220 i += (2 * sizeof(u_int16_t)) + 1;
1222 /* check that the minimum optrr fits */
1223 /* 10 */
1224 if (i + sizeof(struct dns_optrr) > len)
1225 break;
1227 opt = (struct dns_optrr *)&buf[i];
1228 if (opt->name[0] != 0)
1229 break;
1231 if (ntohs(opt->type) != DNS_TYPE_OPT)
1232 break;
1234 /* if we got options here I don't want to know about them */
1235 if (ntohs(opt->rdlen) > 0)
1236 break;
1238 /* RFC 3225 */
1239 if (ntohl(opt->ttl) & DNSSEC_OK)
1240 q->dnssecok = 1;
1241 else if (ntohl(opt->ttl) != 0)
1242 break;
1244 q->edns0len = ntohs(opt->class);
1245 if (q->edns0len < 512)
1246 q->edns0len = 512; /* RFC 6891 - page 10 */
1248 } while (0);
1250 /* fill our name into the dns header struct */
1252 memcpy(q->hdr->name, &buf[sizeof(struct dns_header)], q->hdr->namelen);
1254 /* make it lower case */
1256 for (i = 0; i < q->hdr->namelen; i++) {
1257 int c0;
1259 c0 = q->hdr->name[i];
1260 if (isalpha(c0)) {
1261 q->hdr->name[i] = tolower(c0);
1265 /* parse type and class from the question */
1267 qtype = (u_int16_t *)(end_name + 1);
1268 qclass = (u_int16_t *)(end_name + sizeof(u_int16_t) + 1);
1270 memcpy((char *)&q->hdr->qtype, (char *)qtype, sizeof(u_int16_t));
1271 memcpy((char *)&q->hdr->qclass, (char *)qclass, sizeof(u_int16_t));
1274 return (q);
1278 * FREE_QUESTION - free a question struct
1282 int
1283 free_question(struct question *q)
1285 free(q->hdr->name);
1286 free(q->hdr);
1287 free(q->converted_name);
1288 free(q);
1290 return 0;
1294 * DNS_LABEL - build a DNS NAME (with labels) from a canonical name
1298 char *
1299 dns_label(char *name, int *returnlen)
1301 int len, newlen = 0;
1302 int i, lc = 0; /* lc = label count */
1304 char *dnslabel, *p;
1305 char *labels[255];
1306 char **pl;
1307 char tname[DNS_MAXNAME + 1]; /* 255 bytes + 1*/
1308 char *pt = &tname[0];
1311 if (name == NULL)
1312 return NULL;
1314 #if __linux__
1315 strncpy(tname, name, sizeof(tname));
1316 tname[sizeof(tname) - 1] = 0;
1317 #else
1318 strlcpy(tname, name, sizeof(tname));
1319 #endif
1321 len = strlen(tname);
1322 if (tname[len - 1] == '.')
1323 tname[len - 1] = '\0';
1325 for (pl=labels;pl<&labels[254]&&(*pl=strsep(&pt,"."))!= NULL;pl++,lc++)
1326 newlen += strlen(*pl);
1328 newlen += lc; /* add label count to length */
1331 /* make the buffer space, add 1 for trailing NULL */
1332 if ((dnslabel = malloc(newlen + 1)) == NULL) {
1333 return NULL;
1336 *returnlen = newlen + 1;
1337 dnslabel[newlen] = '\0'; /* trailing NULL */
1339 for (i = 0, p = dnslabel; i < lc; i++) {
1340 len = strlen(labels[i]);
1341 *p++ = len;
1342 #if __linux__
1343 /* XXX */
1344 strncpy(p, labels[i], newlen - (p - dnslabel) + 1);
1345 p[newlen - (p - dnslabel)] = 0;
1346 #else
1347 strlcpy(p, labels[i], newlen - (p - dnslabel) + 1);
1348 #endif
1349 p += len;
1353 * XXX hack to make all DNS names lower case, we only preserve
1354 * case on compressed answers..
1357 for (i = 0, p = dnslabel; i < *returnlen; i++) {
1358 int c;
1360 c = *p;
1361 if (isalpha(c))
1362 *p = tolower(c);
1363 p++;
1366 dolog(LOG_DEBUG, "converting name= %s\n", name);
1368 return dnslabel;
1372 * COMPRESS_LABEL - compress a DNS name, must be passed an entire reply
1373 * with the to be compressed name before the offset of
1374 * that reply.
1377 int
1378 compress_label(u_char *buf, u_int16_t offset, int labellen)
1380 u_char *label[256]; /* should be enough */
1381 u_char *end = &buf[offset];
1382 struct question {
1383 u_int16_t type;
1384 u_int16_t class;
1385 } __attribute__((packed));
1386 struct answer {
1387 u_int16_t type;
1388 u_int16_t class;
1389 u_int32_t ttl;
1390 u_int16_t rdlength;
1391 } __attribute__((packed));
1392 struct soa {
1393 u_int32_t serial;
1394 u_int32_t refresh;
1395 u_int32_t retry;
1396 u_int32_t expire;
1397 u_int32_t minttl;
1398 } __attribute__((packed));
1400 struct answer *a;
1402 u_int i, j;
1403 u_int checklen;
1404 u_int16_t *compressor;
1406 u_char *p, *e;
1407 u_char *compressmark;
1410 p = &buf[sizeof(struct dns_header)];
1411 label[0] = p;
1413 while (p <= end && *p) {
1414 p += *p;
1415 p++;
1419 * the question label was bogus, we'll just get out of there, return 0
1422 if (p >= end)
1423 return (0);
1425 p += sizeof(struct question);
1426 p++; /* one more */
1427 /* start of answer/additional/authoritative */
1429 for (i = 1; i < 100; i++) {
1430 label[i] = p;
1432 while (p <= end && *p) {
1433 if ((*p & 0xc0) == 0xc0) {
1434 p++;
1435 break;
1437 p += *p;
1438 p++;
1440 if (p >= end)
1441 goto end;
1444 p++; /* one more */
1447 a = (struct answer *)p;
1448 p += sizeof(struct answer);
1450 /* Thanks FreeLogic! */
1451 if (p >= end)
1452 goto end;
1454 switch (ntohs(a->type)) {
1455 case DNS_TYPE_A:
1456 p += sizeof(in_addr_t);
1457 break;
1458 case DNS_TYPE_AAAA:
1459 p += 16; /* sizeof 4 * 32 bit */
1460 break;
1461 case DNS_TYPE_TXT:
1462 case DNS_TYPE_SPF:
1463 p += *p;
1464 p++;
1465 break;
1466 case DNS_TYPE_SSHFP:
1467 p++;
1468 switch (*p) {
1469 case 1:
1470 p += DNS_SSHFP_SIZE_SHA1 + 1;
1471 break;
1472 case 2:
1473 p += DNS_SSHFP_SIZE_SHA256 + 1;
1474 break;
1475 default:
1476 /* XXX */
1477 goto end;
1480 break;
1481 case DNS_TYPE_SRV:
1482 p += (2 * sizeof(u_int16_t)); /* priority, weight */
1483 /* the port will be assumed in the fall through for
1484 mx_priority..
1486 /* FALLTHROUGH */
1487 case DNS_TYPE_MX:
1488 p += sizeof(u_int16_t); /* mx_priority */
1489 /* FALLTHROUGH */
1490 case DNS_TYPE_NS:
1491 case DNS_TYPE_PTR:
1492 case DNS_TYPE_CNAME:
1493 label[++i] = p;
1494 while (p <= end && *p) {
1495 if ((*p & 0xc0) == 0xc0) {
1496 p++;
1497 break;
1499 p += *p;
1500 p++;
1502 if (p >= end)
1503 goto end;
1506 p++; /* one more */
1507 break;
1508 case DNS_TYPE_SOA:
1509 /* nsserver */
1510 label[++i] = p;
1511 while (p <= end && *p) {
1512 if ((*p & 0xc0) == 0xc0) {
1513 p++;
1514 break;
1516 p += *p;
1517 p++;
1518 if (p >= end)
1519 goto end;
1522 p++; /* one more */
1524 if (p >= end)
1525 break;
1527 /* responsible person */
1528 label[++i] = p;
1529 while (p <= end && *p) {
1530 if ((*p & 0xc0) == 0xc0) {
1531 p++;
1532 break;
1534 p += *p;
1535 p++;
1538 p++; /* one more */
1540 if (p >= end)
1541 break;
1543 p += sizeof(struct soa); /* advance struct soa */
1545 break;
1546 case DNS_TYPE_NAPTR:
1547 p += (2 * sizeof(u_int16_t)); /* order and preference */
1548 p += *p; /* flags */
1549 p++;
1550 p += *p; /* services */
1551 p++;
1552 p += *p; /* regexp */
1553 p++;
1555 label[++i] = p;
1556 while (p <= end && *p) {
1557 if ((*p & 0xc0) == 0xc0) {
1558 p++;
1559 break;
1561 p += *p;
1562 p++;
1564 if (p >= end)
1565 goto end;
1568 p++; /* one more */
1569 break;
1571 default:
1572 break;
1573 /* XXX */
1574 } /* switch */
1576 if (p >= end)
1577 break;
1578 } /* for (i *) */
1580 end:
1582 p = &buf[offset - labellen];
1583 checklen = labellen;
1585 for (;*p != 0;) {
1586 for (j = 0; j < i; j++) {
1587 for (e = label[j]; *e; e += *e, e++) {
1588 if ((*e & 0xc0) == 0xc0)
1589 break;
1591 if (memcasecmp(e, p, checklen) == 0) {
1592 /* e is now our compress offset */
1593 compressmark = e;
1594 goto out; /* found one */
1596 } /* for (e .. */
1598 } /* for (j .. */
1600 if (*p > DNS_MAXLABEL)
1601 return 0; /* totally bogus label */
1603 checklen -= *p;
1604 p += *p;
1605 checklen--;
1606 p++;
1609 return (0); /* no compression possible */
1611 out:
1612 /* take off our compress length */
1613 offset -= checklen;
1614 /* write compressed label */
1615 compressor = (u_int16_t *)&buf[offset];
1617 *compressor = (compressmark - &buf[0]);
1618 *compressor |= 0xc000;
1620 /* network byte order */
1621 HTONS(*compressor);
1623 offset += sizeof(u_int16_t);
1625 return (offset);
1629 * MEMCASECMP - check if buffer is identical to another buffer with
1630 * one exception if a character is alphabetic it's
1631 * compared to it's lower case value so that heLLo is
1632 * the same as hello
1635 int
1636 memcasecmp(u_char *b1, u_char *b2, int len)
1638 int i;
1639 int identical = 1;
1641 for (i = 0; i < len; i++) {
1642 int c0, c1;
1644 c0 = b1[i];
1645 c1 = b2[i];
1647 if ((isalpha(c0) ? tolower(c0) : c0) !=
1648 (isalpha(c1) ? tolower(c1) : c1)) {
1649 identical = 0;
1650 break;
1654 if (identical)
1655 return 0;
1657 return 1; /* XXX */
1662 * LOOKUP_ZONE - look up a zone filling sd and returning RR TYPE, if error
1663 * occurs returns -1, and sets errno on what type of error.
1667 int
1668 lookup_zone(DB *db, struct question *question, struct domain *sd, int *lzerrno, char *replystring, int wildcard)
1671 int plen, onemore = 0;
1672 int ret = 0;
1673 int returnval, error;
1674 int w = 0;
1676 char *wildlookup = "*";
1677 char *p;
1679 DBT key, data;
1682 * if the asked domain name is foo.bar.baz.org then
1683 * lookup foo.bar.baz.org, bar.baz.org, baz.org,
1684 * org and if there is a match return that.
1687 p = question->hdr->name;
1688 plen = question->hdr->namelen;
1689 onemore = 0;
1691 returnval = 0;
1693 do {
1695 memset(&key, 0, sizeof(key));
1696 memset(&data, 0, sizeof(data));
1698 key.data = (char *)p;
1699 key.size = plen;
1701 data.data = NULL;
1702 data.size = 0;
1704 ret = db->get(db, NULL, &key, &data, 0);
1706 if (ret != 0) {
1707 if (! wildcard)
1708 w = 1;
1709 /* next label */
1710 if (*p != 0) {
1711 plen -= (*p + 1);
1712 p = (p + (*p + 1));
1713 } else if (*p == 0 && ! onemore) {
1714 plen = 1;
1715 onemore = 1;
1716 continue;
1718 } else {
1719 /* we have a match check if the type has an answer, if not we leave */
1720 if (data.size != sizeof(struct domain)) {
1721 dolog(LOG_INFO, "btree db is damaged, drop\n");
1722 *lzerrno = ERR_DROP;
1723 return -1;
1726 memcpy((char *)sd, (char *)data.data, data.size);
1727 snprintf(replystring, DNS_MAXNAME, "%s", sd->zonename);
1730 * If we're not wildcarding and ns_type is 0, NXDOMAIN
1732 if (! wildcard)
1733 if (w && sd->ns_type == 0) {
1734 *lzerrno = ERR_NXDOMAIN;
1735 return -1;
1739 * we're of ns_type > 0, return an NS record
1742 if (sd->ns_type > 0) {
1743 returnval = DNS_TYPE_NS;
1744 *lzerrno = ERR_NOERROR;
1745 goto out;
1749 * check if our record is dynamic (non-static)
1750 * if so, we'll hand it down to the recurse
1751 * process later on...
1754 if (! (sd->flags & DOMAIN_STATIC_ZONE)) {
1755 dolog(LOG_INFO, "non-static zone %s passed to recurse process\n", sd->zonename);
1756 *lzerrno = ERR_NOERROR;
1757 return (-1);
1761 returnval = check_qtype(sd, ntohs(question->hdr->qtype), 0, &error);
1762 if (returnval == 0) {
1763 *lzerrno = ERR_NOERROR;
1764 return (-1);
1767 break;
1771 } while (*p != 0 && ret != 0);
1773 if (ret != 0) {
1775 * somehow we managed to get here and wildcardding is off
1776 * return with NXDOMAIN
1778 if (! wildcard) {
1779 *lzerrno = ERR_NXDOMAIN;
1780 return -1;
1783 memset(&key, 0, sizeof(key));
1784 memset(&data, 0, sizeof(data));
1786 key.data = wildlookup;
1787 key.size = 1;
1789 if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) {
1790 db->err(db, ret, "db->get");
1791 dolog(LOG_INFO, "don't have wildcard answer\n");
1792 *lzerrno = ERR_NXDOMAIN;
1793 return -1;
1796 if (data.size != sizeof(struct domain)) {
1797 dolog(LOG_INFO, "btree db is damaged, drop\n");
1798 *lzerrno = ERR_DROP;
1799 return -1;
1802 memcpy((char *)sd, (char *)data.data, data.size);
1804 if (sd->ns_type > 0) {
1805 returnval = DNS_TYPE_NS;
1806 goto out;
1809 returnval = check_qtype(sd, ntohs(question->hdr->qtype), 1, &error);
1810 if (returnval == 0) {
1811 switch (error) {
1812 case -2:
1813 *lzerrno = ERR_NXDOMAIN;
1814 break;
1815 case -1:
1816 *lzerrno = ERR_NOERROR;
1817 break;
1820 return (-1);
1823 snprintf(replystring, DNS_MAXNAME, "*");
1826 out:
1827 return returnval;
1831 * BUILD_FAKE_QUESTION - fill the fake question structure with the DNS query.
1834 struct question *
1835 build_fake_question(char *name, int namelen, u_int16_t type)
1837 struct question *q;
1839 q = (void *)calloc(1, sizeof(struct question));
1840 if (q == NULL) {
1841 dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
1842 return NULL;
1845 q->hdr = (void *)calloc(1, sizeof(struct dns_question_hdr));
1846 if (q->hdr == NULL) {
1847 dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
1848 free(q);
1849 return NULL;
1851 q->hdr->namelen = namelen;
1852 q->hdr->name = (void *) calloc(1, q->hdr->namelen);
1853 if (q->hdr->name == NULL) {
1854 dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
1855 free(q->hdr);
1856 free(q);
1857 return NULL;
1859 q->converted_name = NULL;
1861 /* fill our name into the dns header struct */
1863 memcpy(q->hdr->name, name, q->hdr->namelen);
1865 q->hdr->qtype = type;
1866 q->hdr->qclass = htons(DNS_CLASS_IN);
1868 return (q);
1872 * GET_SOA - get authoritative soa for a particular domain
1875 int
1876 get_soa(DB *db, struct question *question, struct domain *sd, int wildcard)
1878 int plen;
1879 int ret = 0;
1881 DBT key, data;
1883 char *p;
1885 p = question->hdr->name;
1886 plen = question->hdr->namelen;
1888 do {
1890 memset(&key, 0, sizeof(key));
1891 memset(&data, 0, sizeof(data));
1893 key.data = (char *)p;
1894 key.size = plen;
1896 data.data = NULL;
1897 data.size = 0;
1899 ret = db->get(db, NULL, &key, &data, 0);
1900 if (ret != 0) {
1902 * If we're not wildcarding end the search here and
1903 * return with -1
1905 if (! wildcard)
1906 return -1;
1908 plen -= (*p + 1);
1909 p = (p + (*p + 1));
1910 continue;
1913 if (data.size != sizeof(struct domain)) {
1914 dolog(LOG_INFO, "btree db is damaged, drop\n");
1915 return -1;
1918 memcpy((char *)sd, (char *)data.data, data.size);
1920 if ((sd->flags & DOMAIN_HAVE_SOA) == DOMAIN_HAVE_SOA) {
1921 /* we'll take this one */
1922 return 0;
1923 } else {
1924 plen -= (*p + 1);
1925 p = (p + (*p + 1));
1928 } while (*p);
1930 return -1;
1934 * GET_DNS_TYPE - take integer and compare to table, then spit back a static
1935 * string with the result. This function can't fail.
1938 char *
1939 get_dns_type(int dnstype)
1941 static char type[128];
1942 struct typetable *t;
1944 t = TT;
1946 while (t->type != NULL) {
1947 if (dnstype == t->number)
1948 break;
1950 t = (t + 1);
1953 if (t->type == NULL) {
1954 snprintf(type, sizeof(type) - 1, "%u", dnstype);
1955 } else
1956 snprintf(type, sizeof(type) - 1, "%s(%u)", t->type, dnstype);
1958 return (type);
1962 * MAINLOOP - does the polling of tcp & udp descriptors and if ready receives the
1963 * requests, builds the question and calls for replies, loops
1967 void
1968 mainloop(struct cfg *cfg)
1970 fd_set rset;
1971 int sel;
1972 int len, slen;
1973 int is_ipv6;
1974 int i;
1975 int istcp = 1;
1976 int maxso;
1977 int so;
1978 int type0, type1;
1979 int lzerrno;
1980 int wildcard = 0;
1981 int filter = 0;
1982 int rcheck = 0;
1983 int blacklist = 1;
1984 int sp;
1985 int lfd;
1987 u_int32_t received_ttl;
1988 #if defined __FreeBSD__ || defined __OpenBSD__
1989 u_char *ttlptr;
1990 #else
1991 int *ttlptr;
1992 #endif
1994 u_int8_t aregion; /* region where the address comes from */
1996 char *pbuf;
1997 char buf[4096];
1998 char *replybuf = NULL;
1999 char address[INET6_ADDRSTRLEN];
2000 char replystring[DNS_MAXNAME + 1];
2001 char fakereplystring[DNS_MAXNAME + 1];
2002 char controlbuf[64];
2004 union {
2005 struct sockaddr sa;
2006 struct sockaddr_in sin;
2007 struct sockaddr_in6 sin6;
2008 } sockaddr_large;
2010 socklen_t fromlen = sizeof(sockaddr_large);
2011 socklen_t namelen = sizeof(struct sockaddr_storage);
2012 socklen_t logfromlen = sizeof(struct sockaddr_storage);
2014 struct sockaddr *from = (void *)&sockaddr_large;
2015 struct sockaddr_in *sin;
2016 struct sockaddr_in6 *sin6;
2017 struct sockaddr_storage sto;
2018 struct sockaddr_storage logfrom;
2020 struct dns_header *dh;
2021 struct question *question, *fakequestion;
2022 struct domain sd0, sd1;
2024 struct sreply sreply;
2025 struct srecurseheader rh;
2026 struct timeval tv = { 10, 0};
2028 struct msghdr msgh;
2029 struct cmsghdr *cmsg;
2030 struct iovec iov;
2032 int flag;
2033 int recursion = 0;
2036 SLIST_INIT(&tcpshead);
2037 collects_init();
2039 replybuf = calloc(1, 65536);
2040 if (replybuf == NULL) {
2041 dolog(LOG_ERR, "calloc: %s\n", strerror(errno));
2042 slave_shutdown();
2043 exit(1);
2047 sp = cfg->recurse;
2048 lfd = cfg->log;
2051 * set descriptors nonblocking, and listen on them
2054 for (i = 0; i < cfg->sockcount; i++) {
2055 listen(cfg->tcp[i], 5);
2058 for (;;) {
2059 is_ipv6 = 0;
2060 maxso = 0;
2062 * check for timeouts
2065 #ifdef __linux__
2066 SLIST_FOREACH(tnp, &tcpshead, tcps_entry) {
2067 #else
2068 SLIST_FOREACH_SAFE(tnp, &tcpshead, tcps_entry, tntmp) {
2069 #endif
2070 if ((tnp->time + 10) < time(NULL)) {
2071 free(tnp->input);
2072 free(tnp->ident);
2073 free(tnp->address);
2074 close(tnp->so);
2075 SLIST_REMOVE(&tcpshead, tnp, tcps, tcps_entry);
2076 free(tnp);
2080 FD_ZERO(&rset);
2081 for (i = 0; i < cfg->sockcount; i++) {
2082 if (maxso < cfg->tcp[i])
2083 maxso = cfg->tcp[i];
2085 if (maxso < cfg->udp[i])
2086 maxso = cfg->udp[i];
2088 if (axfrport && maxso < cfg->axfr[i])
2089 maxso = cfg->axfr[i];
2091 FD_SET(cfg->tcp[i], &rset);
2092 FD_SET(cfg->udp[i], &rset);
2094 if (axfrport)
2095 FD_SET(cfg->axfr[i], &rset);
2098 SLIST_FOREACH(tnp, &tcpshead, tcps_entry) {
2099 if (maxso < tnp->so)
2100 maxso = tnp->so;
2102 FD_SET(tnp->so, &rset);
2105 if (logging.bind == 1) {
2106 if (maxso < lfd)
2107 maxso = lfd;
2108 FD_SET(lfd, &rset);
2111 tv.tv_sec = 10;
2112 tv.tv_usec = 0;
2114 sel = select(maxso + 1, &rset, NULL, NULL, &tv);
2116 if (sel < 0) {
2117 dolog(LOG_INFO, "select: %s\n", strerror(errno));
2118 continue;
2121 if (sel == 0) {
2122 #ifdef __linux__
2123 SLIST_FOREACH(tnp, &tcpshead, tcps_entry) {
2124 #else
2125 SLIST_FOREACH_SAFE(tnp, &tcpshead, tcps_entry, tntmp) {
2126 #endif
2127 if ((tnp->time + 10) < time(NULL)) {
2128 free(tnp->input);
2129 free(tnp->ident);
2130 free(tnp->address);
2131 close(tnp->so);
2132 SLIST_REMOVE(&tcpshead, tnp, tcps, tcps_entry);
2133 free(tnp);
2136 continue;
2139 for (i = 0; i < cfg->sockcount; i++) {
2140 if (FD_ISSET(cfg->tcp[i], &rset)) {
2141 fromlen = sizeof(sockaddr_large);
2143 so = accept(cfg->tcp[i], (struct sockaddr*)from, &fromlen);
2145 if (so < 0) {
2146 dolog(LOG_INFO, "tcp accept: %s\n", strerror(errno));
2147 continue;
2150 if (from->sa_family == AF_INET6) {
2151 is_ipv6 = 1;
2153 fromlen = sizeof(struct sockaddr_in6);
2154 sin6 = (struct sockaddr_in6 *)from;
2155 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, (char *)&address, sizeof(address));
2156 aregion = find_region((struct sockaddr_storage *)sin6, AF_INET6);
2157 wildcard = find_wildcard((struct sockaddr_storage *)sin6, AF_INET6);
2158 filter = find_filter((struct sockaddr_storage *)sin6, AF_INET6);
2159 if (whitelist) {
2160 blacklist = find_whitelist((struct sockaddr_storage *)sin6, AF_INET6);
2162 } else if (from->sa_family == AF_INET) {
2163 is_ipv6 = 0;
2165 fromlen = sizeof(struct sockaddr_in);
2166 sin = (struct sockaddr_in *)from;
2167 inet_ntop(AF_INET, (void *)&sin->sin_addr, (char *)&address, sizeof(address));
2168 wildcard = find_wildcard((struct sockaddr_storage *)sin, AF_INET);
2169 aregion = find_region((struct sockaddr_storage *)sin, AF_INET);
2170 filter = find_filter((struct sockaddr_storage *)sin, AF_INET);
2171 if (whitelist) {
2172 blacklist = find_whitelist((struct sockaddr_storage *)sin, AF_INET);
2174 } else {
2175 dolog(LOG_INFO, "TCP packet received on descriptor %u interface \"%s\" had weird address family (%u), drop\n", so, cfg->ident[i], from->sa_family);
2176 close(so);
2177 continue;
2181 if (filter) {
2182 dolog(LOG_INFO, "TCP connection refused on descriptor %u interface \"%s\" from %s, filter policy\n", so, cfg->ident[i], address);
2183 close(so);
2184 continue;
2187 if (whitelist && blacklist == 0) {
2188 dolog(LOG_INFO, "TCP connection refused on descriptor %u interface \"%s\" from %s, whitelist policy\n", so, cfg->ident[i], address);
2189 close(so);
2190 continue;
2197 * make this socket nonblocking
2200 if ((flag = fcntl(so, F_GETFL)) < 0) {
2201 dolog(LOG_INFO, "fcntl: %s\n", strerror(errno));
2203 flag |= O_NONBLOCK;
2204 if (fcntl(so, F_SETFL, flag) < 0) {
2205 dolog(LOG_INFO, "fcntl 2: %s\n", strerror(errno));
2209 /* fill the tcps struct */
2211 tn1 = malloc(sizeof(struct tcps));
2212 if (tn1 == NULL) {
2213 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
2214 close(so);
2215 continue;
2218 tn1->input = (char *)malloc(0xffff + 2);
2219 if (tn1->input == NULL) {
2220 dolog(LOG_INFO, "tcp malloc 2: %s\n", strerror(errno));
2221 close(so);
2222 continue;
2225 tn1->offset = 0;
2226 tn1->length = 0;
2227 tn1->maxlen = 0xffff + 2;
2228 tn1->so = so;
2229 tn1->isv6 = is_ipv6;
2230 tn1->ident = strdup(cfg->ident[i]);
2231 tn1->address = strdup(address);
2232 tn1->region = aregion;
2233 tn1->wildcard = wildcard;
2234 tn1->time = time(NULL);
2236 SLIST_INSERT_HEAD(&tcpshead, tn1, tcps_entry);
2238 } /* FD_ISSET(); */
2239 } /* if sockcount */
2241 #ifdef __linux__
2242 SLIST_FOREACH(tnp, &tcpshead, tcps_entry) {
2243 #else
2244 SLIST_FOREACH_SAFE(tnp, &tcpshead, tcps_entry, tntmp) {
2245 #endif
2246 if (FD_ISSET(tnp->so, &rset)) {
2248 istcp = 1;
2249 len = recv(tnp->so, tnp->input + tnp->offset, tnp->maxlen - tnp->offset, 0);
2250 if (len < 0) {
2251 if (errno == EWOULDBLOCK)
2252 continue;
2253 else {
2254 free(tnp->input);
2255 free(tnp->ident);
2256 free(tnp->address);
2257 close(tnp->so);
2258 SLIST_REMOVE(&tcpshead, tnp, tcps, tcps_entry);
2259 free(tnp);
2260 continue;
2262 } /* if len */
2264 if (len == 0) {
2265 free(tnp->input);
2266 free(tnp->ident);
2267 free(tnp->address);
2268 close(tnp->so);
2269 SLIST_REMOVE(&tcpshead, tnp, tcps, tcps_entry);
2270 free(tnp);
2271 continue;
2274 tnp->offset += len;
2275 tnp->time = time(NULL);
2277 if (tnp->offset >= 2) {
2278 tnp->length = ntohs(*((u_int16_t *) tnp->input));
2282 * only go on if the full packet was written
2285 if (tnp->length + 2 != tnp->offset)
2286 continue;
2288 len = tnp->length;
2289 pbuf = tnp->input + 2;
2291 /* if UDP packet check length for minimum / maximum */
2292 if (len > DNS_MAXUDP || len < sizeof(struct dns_header)){
2293 dolog(LOG_INFO, "TCP packet on descriptor %u interface \"%s\" illegal dns packet length from %s, drop\n", tnp->so, tnp->ident, tnp->address);
2294 goto drop;
2297 dh = (struct dns_header *)&pbuf[0];
2299 /* check if we're a question or reply, drop replies */
2300 if ((ntohs(dh->query) & DNS_REPLY)) {
2301 dolog(LOG_INFO, "TCP packet on descriptor %u interface \"%s\" dns header from %s is not a question, drop\n", tnp->so, tnp->ident, tnp->address);
2302 goto drop;
2306 * if questions aren't exactly 1 then drop
2309 if (ntohs(dh->question) != 1) {
2310 dolog(LOG_INFO, "TCP packet on descriptor %u interface \"%s\" header from %s has no question, drop\n", tnp->so, tnp->ident, tnp->address);
2312 /* format error */
2313 build_reply( &sreply, tnp->so, pbuf, len, NULL,
2314 from, fromlen, NULL, NULL, tnp->region,
2315 istcp, tnp->wildcard, NULL, replybuf);
2317 slen = reply_fmterror(&sreply);
2318 dolog(LOG_INFO, "TCP question on descriptor %d interface \"%s\" from %s, did not have question of 1 replying format error\n", tnp->so, tnp->ident, tnp->address);
2319 goto drop;
2323 if ((question = build_question(pbuf, len, 0)) == NULL) {
2324 dolog(LOG_INFO, "TCP packet on descriptor %u interface \"%s\" malformed question from %s, drop\n", tnp->so, tnp->ident, tnp->address);
2325 goto drop;
2328 /* goto drop beyond this point should goto out instead */
2329 fakequestion = NULL;
2331 if ((type0 = lookup_zone(cfg->db, question, &sd0, &lzerrno, (char *)&replystring, wildcard)) < 0) {
2333 switch (lzerrno) {
2334 default:
2335 dolog(LOG_INFO, "invalid lzerrno! dropping\n");
2336 /* FALLTHROUGH */
2337 case ERR_DROP:
2338 snprintf(replystring, DNS_MAXNAME, "DROP");
2339 goto tcpout;
2341 case ERR_NXDOMAIN:
2342 goto tcpnxdomain;
2343 case ERR_NOERROR:
2345 * this is hackish not sure if this should be here
2348 snprintf(replystring, DNS_MAXNAME, "NOERROR");
2351 * lookup an authoritative soa
2354 memset(&sd0, 0, sizeof(sd0));
2355 (void)get_soa(cfg->db, question, &sd0, wildcard);
2357 build_reply( &sreply, tnp->so, pbuf, len,
2358 question, from, fromlen,
2359 &sd0, NULL, tnp->region, istcp,
2360 tnp->wildcard, NULL, replybuf);
2362 slen = reply_noerror(&sreply);
2363 goto tcpout;
2368 switch (type0) {
2369 case 0:
2371 * lookup_zone could not find an RR for the
2372 * question at all -> nxdomain
2374 tcpnxdomain:
2375 snprintf(replystring, DNS_MAXNAME, "NXDOMAIN");
2378 * lookup an authoritative soa
2381 memset(&sd0, 0, sizeof(sd0));
2382 (void)get_soa(cfg->db, question, &sd0, wildcard);
2384 build_reply( &sreply, tnp->so, pbuf, len, question,
2385 from, fromlen, &sd0, NULL,
2386 tnp->region, istcp, tnp->wildcard, NULL,
2387 replybuf);
2389 slen = reply_nxdomain(&sreply);
2390 goto tcpout;
2391 case DNS_TYPE_CNAME:
2392 fakequestion = build_fake_question(sd0.cname, sd0.cnamelen, question->hdr->qtype);
2393 if (fakequestion == NULL) {
2394 dolog(LOG_INFO, "fakequestion failed\n");
2395 break;
2398 type1 = lookup_zone(cfg->db, fakequestion, &sd1, &lzerrno, (char *)&fakereplystring, wildcard);
2399 /* break CNAMES pointing to CNAMES */
2400 if (type1 == DNS_TYPE_CNAME)
2401 type1 = 0;
2403 break;
2404 default:
2406 break;
2410 * Allow CLASS IN, CHAOS and others are
2411 * not implemented and so we build a reply for
2412 * that and go out.
2415 switch (ntohs(question->hdr->qclass)) {
2416 case DNS_CLASS_IN:
2417 break;
2418 default:
2419 build_reply( &sreply, tnp->so, pbuf, len, question,
2420 from, fromlen, NULL, NULL, tnp->region,
2421 istcp, tnp->wildcard, NULL, replybuf);
2423 slen = reply_notimpl(&sreply);
2424 snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
2425 goto tcpout;
2428 switch (ntohs(question->hdr->qtype)) {
2429 case DNS_TYPE_A:
2430 if (type0 == DNS_TYPE_CNAME) {
2431 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2432 fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
2433 tnp->region, istcp, tnp->wildcard, NULL, replybuf);
2434 slen = reply_cname(&sreply);
2435 } else if (type0 == DNS_TYPE_NS) {
2437 build_reply(&sreply, tnp->so, pbuf, len, question,
2438 from, fromlen, &sd0, NULL,
2439 tnp->region, istcp, tnp->wildcard, NULL,
2440 replybuf);
2442 slen = reply_ns(&sreply, cfg->db);
2443 break;
2444 } else if (type0 == DNS_TYPE_A) {
2445 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2446 fromlen, &sd0, NULL, tnp->region, istcp, tnp->wildcard,
2447 NULL, replybuf);
2448 slen = reply_a(&sreply, cfg->db);
2449 break; /* must break here */
2452 break;
2454 case DNS_TYPE_ANY:
2455 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2456 fromlen, &sd0, NULL, tnp->region, istcp, tnp->wildcard,
2457 NULL, replybuf);
2459 slen = reply_any(&sreply);
2460 break; /* must break here */
2462 case DNS_TYPE_AAAA:
2464 if (type0 == DNS_TYPE_CNAME) {
2465 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2466 fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
2467 tnp->region, istcp, tnp->wildcard, NULL, replybuf);
2468 slen = reply_cname(&sreply);
2469 } else if (type0 == DNS_TYPE_NS) {
2470 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2471 fromlen, &sd0, NULL, tnp->region, istcp,
2472 tnp->wildcard, NULL, replybuf);
2474 slen = reply_ns(&sreply, cfg->db);
2475 break;
2476 } else if (type0 == DNS_TYPE_AAAA) {
2477 build_reply(&sreply, tnp->so, pbuf, len, question, from,
2478 fromlen, &sd0, NULL, tnp->region, istcp,
2479 tnp->wildcard, NULL, replybuf);
2481 slen = reply_aaaa(&sreply, cfg->db);
2482 break; /* must break here */
2485 break;
2486 case DNS_TYPE_MX:
2488 if (type0 == DNS_TYPE_CNAME) {
2489 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2490 fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
2491 tnp->region, istcp, tnp->wildcard, NULL, replybuf);
2493 slen = reply_cname(&sreply);
2495 } else if (type0 == DNS_TYPE_NS) {
2496 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2497 fromlen, &sd0, NULL, tnp->region, istcp,
2498 tnp->wildcard, NULL, replybuf);
2500 slen = reply_ns(&sreply, cfg->db);
2502 break;
2503 } else if (type0 == DNS_TYPE_MX) {
2504 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2505 fromlen, &sd0, NULL, tnp->region, istcp,
2506 tnp->wildcard, NULL, replybuf);
2508 slen = reply_mx(&sreply, cfg->db);
2509 break; /* must break here */
2512 break;
2513 case DNS_TYPE_SOA:
2514 if (type0 == DNS_TYPE_SOA) {
2515 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2516 fromlen, &sd0, NULL, tnp->region, istcp,
2517 tnp->wildcard, NULL, replybuf);
2519 slen = reply_soa(&sreply);
2520 } else if (type0 == DNS_TYPE_NS) {
2521 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2522 fromlen, &sd0, NULL, tnp->region, istcp,
2523 tnp->wildcard, NULL, replybuf);
2525 slen = reply_ns(&sreply, cfg->db);
2526 break;
2528 break;
2529 case DNS_TYPE_NS:
2530 if (type0 == DNS_TYPE_NS) {
2531 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2532 fromlen, &sd0, NULL, tnp->region, istcp,
2533 tnp->wildcard, NULL, replybuf);
2535 slen = reply_ns(&sreply, cfg->db);
2537 break;
2539 case DNS_TYPE_SSHFP:
2540 if (type0 == DNS_TYPE_SSHFP) {
2541 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2542 fromlen, &sd0, NULL, tnp->region, istcp,
2543 tnp->wildcard, NULL, replybuf);
2545 slen = reply_sshfp(&sreply);
2547 break;
2550 case DNS_TYPE_SRV:
2551 if (type0 == DNS_TYPE_SRV) {
2552 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2553 fromlen, &sd0, NULL, tnp->region, istcp,
2554 tnp->wildcard, NULL, replybuf);
2556 slen = reply_srv(&sreply, cfg->db);
2558 break;
2560 case DNS_TYPE_NAPTR:
2561 if (type0 == DNS_TYPE_NAPTR) {
2562 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2563 fromlen, &sd0, NULL, tnp->region, istcp,
2564 tnp->wildcard, NULL, replybuf);
2566 slen = reply_naptr(&sreply, cfg->db);
2568 break;
2570 case DNS_TYPE_CNAME:
2571 if (type0 == DNS_TYPE_CNAME) {
2572 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2573 fromlen, &sd0, NULL, tnp->region, istcp,
2574 tnp->wildcard, NULL, replybuf);
2576 slen = reply_cname(&sreply);
2577 } else if (type0 == DNS_TYPE_NS) {
2578 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2579 fromlen, &sd0, NULL, tnp->region, istcp,
2580 tnp->wildcard, NULL, replybuf);
2582 slen = reply_ns(&sreply, cfg->db);
2583 break;
2585 break;
2587 case DNS_TYPE_PTR:
2588 if (type0 == DNS_TYPE_CNAME) {
2589 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2590 fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL) \
2591 , tnp->region, istcp, tnp->wildcard, NULL,
2592 replybuf);
2594 slen = reply_cname(&sreply);
2596 } else if (type0 == DNS_TYPE_NS) {
2598 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2599 fromlen, &sd0, NULL, tnp->region, istcp,
2600 tnp->wildcard, NULL, replybuf);
2602 slen = reply_ns(&sreply, cfg->db);
2604 break;
2605 } else if (type0 == DNS_TYPE_PTR) {
2607 build_reply(&sreply, tnp->so, pbuf, len, question, from,
2608 fromlen, &sd0, NULL, tnp->region, istcp,
2609 tnp->wildcard, NULL, replybuf);
2611 slen = reply_ptr(&sreply);
2612 break; /* must break here */
2614 break;
2616 case DNS_TYPE_TXT:
2617 if (type0 == DNS_TYPE_TXT) {
2619 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2620 fromlen, &sd0, NULL, tnp->region, istcp,
2621 tnp->wildcard, NULL, replybuf);
2623 slen = reply_txt(&sreply);
2625 break;
2627 case DNS_TYPE_SPF:
2628 if (type0 == DNS_TYPE_SPF) {
2630 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2631 fromlen, &sd0, NULL, tnp->region, istcp,
2632 tnp->wildcard, NULL, replybuf);
2634 slen = reply_spf(&sreply);
2636 break;
2639 default:
2642 * ANY unknown RR TYPE gets a NOTIMPL
2646 * except for delegations
2649 if (type0 == DNS_TYPE_NS) {
2650 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2651 fromlen, &sd0, NULL, aregion, istcp,
2652 tnp->wildcard, NULL, replybuf);
2654 slen = reply_ns(&sreply, cfg->db);
2656 } else {
2658 build_reply(&sreply, tnp->so, pbuf, len, question, from, \
2659 fromlen, NULL, NULL, tnp->region, istcp,
2660 tnp->wildcard, NULL, replybuf);
2662 slen = reply_notimpl(&sreply);
2663 snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
2665 break;
2668 tcpout:
2669 if (lflag)
2670 dolog(LOG_INFO, "request on descriptor %u interface \"%s\" from %s (ttl=TCP, region=%d) for \"%s\" type=%s class=%u, answering \"%s\" (%d/%d)\n", tnp->so, tnp->ident, tnp->address, tnp->region, question->converted_name, get_dns_type(ntohs(question->hdr->qtype)), ntohs(question->hdr->qclass), replystring, len, slen);
2673 if (fakequestion != NULL) {
2674 free_question(fakequestion);
2677 free_question(question);
2679 } /* END ISSET */
2681 memset(tnp->input, 0, tnp->maxlen);
2682 tnp->offset = 0;
2684 } /* SLIST_FOREACH */
2686 /* UDP marriage */
2687 for (i = 0; i < cfg->sockcount; i++) {
2688 if (axfrport && FD_ISSET(cfg->axfr[i], &rset)) {
2689 istcp = 0;
2690 so = cfg->axfr[i];
2692 goto axfrentry;
2695 if (FD_ISSET(cfg->udp[i], &rset)) {
2696 istcp = 0;
2697 so = cfg->udp[i];
2698 axfrentry:
2699 fromlen = sizeof(sockaddr_large);
2701 memset(&msgh, 0, sizeof(msgh));
2702 iov.iov_base = buf;
2703 iov.iov_len = sizeof(buf);
2704 msgh.msg_name = from;
2705 msgh.msg_namelen = fromlen;
2706 msgh.msg_iov = &iov;
2707 msgh.msg_iovlen = 1;
2708 msgh.msg_control = (struct cmsghdr*)&controlbuf;
2709 msgh.msg_controllen = sizeof(controlbuf);
2711 len = recvmsg(so, &msgh, 0);
2712 if (len < 0) {
2713 dolog(LOG_INFO, "recvmsg: on descriptor %u interface \"%s\" %s\n", so, cfg->ident[i], strerror(errno));
2714 continue;
2717 received_ttl = 0;
2719 for (cmsg = CMSG_FIRSTHDR(&msgh);
2720 cmsg != NULL;
2721 cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
2722 if (cmsg->cmsg_level == IPPROTO_IP
2723 #ifdef __linux__
2724 && cmsg->cmsg_type == IP_TTL) {
2725 #elif defined __NetBSD__
2726 && cmsg->cmsg_type == IP_TTL) {
2728 #else
2730 && cmsg->cmsg_type == IP_RECVTTL) {
2731 #endif
2733 #if defined __FreeBSD__ || defined __OpenBSD__
2735 ttlptr = (u_char *) CMSG_DATA(cmsg);
2736 received_ttl = (u_int)*ttlptr;
2737 #else
2739 ttlptr = (int *) CMSG_DATA(cmsg);
2740 received_ttl = (u_int)*ttlptr;
2741 #endif
2744 if (cmsg->cmsg_level == IPPROTO_IPV6 &&
2745 cmsg->cmsg_type == IPV6_HOPLIMIT) {
2747 if (cmsg->cmsg_len !=
2748 CMSG_LEN(sizeof(int))) {
2749 dolog(LOG_INFO, "cmsg->cmsg_len == %d\n", cmsg->cmsg_len);
2750 continue;
2753 #ifdef __NetBSD__
2754 ttlptr = (int *) CMSG_DATA(cmsg);
2755 #else
2756 ttlptr = (u_char *) CMSG_DATA(cmsg);
2757 #endif
2760 received_ttl = (u_int)*ttlptr;
2764 if (rflag) {
2765 if (getsockname(so, (struct sockaddr*)&sto, &namelen) < 0) {
2766 dolog(LOG_INFO, "getsockname failed: %s\n", strerror(errno));
2769 memset(&rh, 0, sizeof(rh));
2772 if (from->sa_family == AF_INET6) {
2773 is_ipv6 = 1;
2775 fromlen = sizeof(struct sockaddr_in6);
2776 sin6 = (struct sockaddr_in6 *)from;
2777 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, (char *)&address, sizeof(address));
2778 if (ratelimit) {
2779 add_rrlimit(ratelimit_backlog, (u_int16_t *)&sin6->sin6_addr, sizeof(sin6->sin6_addr), rptr);
2781 rcheck = check_rrlimit(ratelimit_backlog, (u_int16_t *)&sin6->sin6_addr, sizeof(sin6->sin6_addr), rptr);
2784 aregion = find_region((struct sockaddr_storage *)sin6, AF_INET6);
2785 wildcard = find_wildcard((struct sockaddr_storage *)sin6, AF_INET6);
2786 filter = find_filter((struct sockaddr_storage *)sin6, AF_INET6);
2787 if (whitelist) {
2788 blacklist = find_whitelist((struct sockaddr_storage *)sin6, AF_INET6);
2790 if (rflag) {
2791 recursion = find_recurse((struct sockaddr_storage *)sin6, AF_INET6);
2792 recurseheader(&rh, IPPROTO_UDP, (struct sockaddr_storage*)sin6, &sto, AF_INET6);
2794 } else if (from->sa_family == AF_INET) {
2795 is_ipv6 = 0;
2797 fromlen = sizeof(struct sockaddr_in);
2798 sin = (struct sockaddr_in *)from;
2799 inet_ntop(AF_INET, (void *)&sin->sin_addr, (char *)&address, sizeof(address));
2800 if (ratelimit) {
2801 add_rrlimit(ratelimit_backlog, (u_int16_t *)&sin->sin_addr.s_addr, sizeof(sin->sin_addr.s_addr), rptr);
2803 rcheck = check_rrlimit(ratelimit_backlog, (u_int16_t *)&sin->sin_addr.s_addr, sizeof(sin->sin_addr.s_addr), rptr);
2806 aregion = find_region((struct sockaddr_storage *)sin, AF_INET);
2807 wildcard = find_wildcard((struct sockaddr_storage *)sin, AF_INET);
2808 filter = find_filter((struct sockaddr_storage *)sin, AF_INET);
2809 if (whitelist) {
2810 blacklist = find_whitelist((struct sockaddr_storage *)sin, AF_INET);
2813 if (rflag) {
2814 recursion = find_recurse((struct sockaddr_storage *)sin, AF_INET);
2815 recurseheader(&rh, IPPROTO_UDP, (struct sockaddr_storage*)sin, &sto, AF_INET);
2817 } else {
2818 dolog(LOG_INFO, "packet received on descriptor %u interface \"%s\" had weird address family (%u), drop\n", so, cfg->ident[i], from->sa_family);
2819 goto drop;
2822 /* if UDP packet check length for minimum / maximum */
2823 if (len > DNS_MAXUDP || len < sizeof(struct dns_header)){
2824 dolog(LOG_INFO, "on descriptor %u interface \"%s\" illegal dns packet length from %s, drop\n", so, cfg->ident[i], address);
2825 goto drop;
2828 dh = (struct dns_header *)&buf[0];
2830 /* check if we're a question or reply, drop replies */
2831 if ((ntohs(dh->query) & DNS_REPLY)) {
2832 dolog(LOG_INFO, "on descriptor %u interface \"%s\" dns header from %s is not a question, drop\n", so, cfg->ident[i], address);
2833 goto drop;
2837 * if questions aren't exactly 1 then drop
2840 if (ntohs(dh->question) != 1) {
2841 dolog(LOG_INFO, "on descriptor %u interface \"%s\" header from %s has no question, drop\n", so, cfg->ident[i], address);
2843 /* format error */
2844 build_reply(&sreply, so, buf, len, NULL, from, fromlen, NULL, NULL, aregion, istcp, wildcard, NULL, replybuf);
2846 slen = reply_fmterror(&sreply);
2847 dolog(LOG_INFO, "question on descriptor %d interface \"%s\" from %s, did not have question of 1 replying format error\n", so, cfg->ident[i], address);
2848 goto drop;
2851 if (filter) {
2853 build_reply(&sreply, so, buf, len, NULL, from, fromlen, NULL, NULL, aregion, istcp, wildcard, NULL, replybuf);
2854 slen = reply_refused(&sreply);
2856 dolog(LOG_INFO, "UDP connection refused on descriptor %u interface \"%s\" from %s (ttl=%d, region=%d) replying REFUSED, filter policy\n", so, cfg->ident[i], address, received_ttl, aregion);
2857 goto drop;
2860 if (whitelist && blacklist == 0) {
2862 build_reply(&sreply, so, buf, len, NULL, from, fromlen, NULL, NULL, aregion, istcp, wildcard, NULL, replybuf);
2863 slen = reply_refused(&sreply);
2865 dolog(LOG_INFO, "UDP connection refused on descriptor %u interface \"%s\" from %s (ttl=%d, region=%d) replying REFUSED, whitelist policy\n", so, cfg->ident[i], address, received_ttl, aregion);
2866 goto drop;
2869 if (ratelimit && rcheck) {
2870 dolog(LOG_INFO, "UDP connection refused on descriptor %u interface \"%s\" from %s (ttl=%d, region=%d) ratelimit policy dropping packet\n", so, cfg->ident[i], address, received_ttl, aregion);
2871 goto drop;
2874 if (rflag && recursion) {
2875 memcpy(&rh.buf, buf, len);
2876 rh.len = len;
2879 if ((question = build_question(buf, len, ntohs(dh->additional))) == NULL) {
2880 dolog(LOG_INFO, "on descriptor %u interface \"%s\" malformed question from %s, drop\n", so, cfg->ident[i], address);
2881 goto drop;
2884 /* goto drop beyond this point should goto out instead */
2885 fakequestion = NULL;
2887 if ((type0 = lookup_zone(cfg->db, question, &sd0, &lzerrno, (char *)&replystring, wildcard)) < 0) {
2888 switch (lzerrno) {
2889 default:
2890 dolog(LOG_INFO, "invalid lzerrno! dropping\n");
2891 /* FALLTHROUGH */
2892 case ERR_DROP:
2893 snprintf(replystring, DNS_MAXNAME, "DROP");
2894 goto udpout;
2896 case ERR_NXDOMAIN:
2897 goto udpnxdomain;
2898 case ERR_NOERROR:
2899 if (rflag && recursion) {
2900 snprintf(replystring, DNS_MAXNAME, "RECURSE");
2901 if (send(sp, (char *)&rh, sizeof(rh), 0) < 0) {
2902 dolog(LOG_INFO, "send sp: %s\n", strerror(errno));
2905 goto udpout;
2906 } else {
2908 * this is hackish not sure if this should be here
2911 snprintf(replystring, DNS_MAXNAME, "NOERROR");
2914 * lookup an authoritative soa
2917 memset(&sd0, 0, sizeof(sd0));
2918 (void)get_soa(cfg->db, question, &sd0, wildcard);
2920 build_reply(&sreply, so, buf, len, question, from, \
2921 fromlen, &sd0, NULL, aregion, istcp, wildcard,
2922 NULL, replybuf);
2924 slen = reply_noerror(&sreply);
2925 goto udpout;
2926 } /* else rflag */
2930 switch (type0) {
2931 case 0:
2932 udpnxdomain:
2933 if (rflag && recursion) {
2934 snprintf(replystring, DNS_MAXNAME, "RECURSE");
2935 if (send(sp, (char *)&rh, sizeof(rh), 0) < 0) {
2936 dolog(LOG_INFO, "send sp: %s\n", strerror(errno));
2939 goto udpout;
2940 } else {
2943 * lookup_zone could not find an RR for the
2944 * question at all -> nxdomain
2946 snprintf(replystring, DNS_MAXNAME, "NXDOMAIN");
2949 * lookup an authoritative soa
2952 memset(&sd0, 0, sizeof(sd0));
2953 (void)get_soa(cfg->db, question, &sd0, wildcard);
2955 build_reply(&sreply, so, buf, len, question, from, \
2956 fromlen, &sd0, NULL, aregion, istcp, \
2957 wildcard, NULL, replybuf);
2959 slen = reply_nxdomain(&sreply);
2960 goto udpout;
2961 } /* else rflag */
2962 case DNS_TYPE_CNAME:
2963 fakequestion = build_fake_question(sd0.cname, sd0.cnamelen, question->hdr->qtype);
2964 if (fakequestion == NULL) {
2965 dolog(LOG_INFO, "fakequestion failed\n");
2966 break;
2969 type1 = lookup_zone(cfg->db, fakequestion, &sd1, &lzerrno, (char *)&fakereplystring, wildcard);
2970 /* break CNAMES pointing to CNAMES */
2971 if (type1 == DNS_TYPE_CNAME)
2972 type1 = 0;
2974 break;
2975 default:
2977 break;
2981 * Allow CLASS IN, CHAOS and others are
2982 * not implemented and so we build a reply for
2983 * that and go out.
2986 switch (ntohs(question->hdr->qclass)) {
2987 case DNS_CLASS_IN:
2988 break;
2989 default:
2990 build_reply(&sreply, so, buf, len, question, from, \
2991 fromlen, NULL, NULL, aregion, istcp, wildcard, \
2992 NULL, replybuf);
2994 slen = reply_notimpl(&sreply);
2995 snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
2996 goto udpout;
2999 switch (ntohs(question->hdr->qtype)) {
3000 case DNS_TYPE_A:
3001 if (type0 == DNS_TYPE_CNAME) {
3003 build_reply(&sreply, so, buf, len, question, from, \
3004 fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
3005 aregion, istcp, wildcard, NULL, replybuf);
3007 slen = reply_cname(&sreply);
3008 } else if (type0 == DNS_TYPE_NS) {
3010 build_reply(&sreply, so, buf, len, question, from, \
3011 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3012 NULL, replybuf);
3014 slen = reply_ns(&sreply, cfg->db);
3015 break;
3016 } else if (type0 == DNS_TYPE_A) {
3018 build_reply(&sreply, so, buf, len, question, from, \
3019 fromlen, &sd0, NULL, aregion, istcp, wildcard,
3020 NULL, replybuf);
3022 slen = reply_a(&sreply, cfg->db);
3023 break; /* must break here */
3026 break;
3028 case DNS_TYPE_ANY:
3030 build_reply(&sreply, so, buf, len, question, from, \
3031 fromlen, &sd0, NULL, aregion, istcp, wildcard, NULL,
3032 replybuf);
3034 slen = reply_any(&sreply);
3035 break; /* must break here */
3037 case DNS_TYPE_AAAA:
3039 if (type0 == DNS_TYPE_CNAME) {
3041 build_reply(&sreply, so, buf, len, question, from, \
3042 fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
3043 aregion, istcp, wildcard, NULL, replybuf);
3045 slen = reply_cname(&sreply);
3046 } else if (type0 == DNS_TYPE_NS) {
3048 build_reply(&sreply, so, buf, len, question, from, \
3049 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3050 NULL, replybuf);
3052 slen = reply_ns(&sreply, cfg->db);
3053 break;
3054 } else if (type0 == DNS_TYPE_AAAA) {
3056 build_reply(&sreply, so, buf, len, question, from,
3057 fromlen, &sd0, NULL, aregion, istcp, wildcard,
3058 NULL, replybuf);
3060 slen = reply_aaaa(&sreply, cfg->db);
3061 break; /* must break here */
3064 break;
3065 case DNS_TYPE_MX:
3067 if (type0 == DNS_TYPE_CNAME) {
3069 build_reply(&sreply, so, buf, len, question, from, \
3070 fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
3071 aregion, istcp, wildcard, NULL, replybuf);
3073 slen = reply_cname(&sreply);
3074 } else if (type0 == DNS_TYPE_NS) {
3076 build_reply(&sreply, so, buf, len, question, from, \
3077 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3078 NULL, replybuf);
3080 slen = reply_ns(&sreply, cfg->db);
3081 break;
3082 } else if (type0 == DNS_TYPE_MX) {
3083 build_reply(&sreply, so, buf, len, question, from, \
3084 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3085 NULL, replybuf);
3086 slen = reply_mx(&sreply, cfg->db);
3087 break; /* must break here */
3090 break;
3091 case DNS_TYPE_SOA:
3092 if (type0 == DNS_TYPE_SOA) {
3094 build_reply(&sreply, so, buf, len, question, from, \
3095 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3096 NULL, replybuf);
3098 slen = reply_soa(&sreply);
3099 } else if (type0 == DNS_TYPE_NS) {
3101 build_reply(&sreply, so, buf, len, question, from, \
3102 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3103 NULL, replybuf);
3105 slen = reply_ns(&sreply, cfg->db);
3106 break;
3108 break;
3109 case DNS_TYPE_NS:
3110 if (type0 == DNS_TYPE_NS) {
3112 build_reply(&sreply, so, buf, len, question, from, \
3113 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3114 NULL, replybuf);
3116 slen = reply_ns(&sreply, cfg->db);
3118 break;
3120 case DNS_TYPE_SSHFP:
3121 if (type0 == DNS_TYPE_SSHFP) {
3122 build_reply(&sreply, so, buf, len, question, from, \
3123 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3124 NULL, replybuf);
3126 slen = reply_sshfp(&sreply);
3128 break;
3131 case DNS_TYPE_SRV:
3132 if (type0 == DNS_TYPE_SRV) {
3134 build_reply(&sreply, so, buf, len, question, from, \
3135 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3136 NULL, replybuf);
3138 slen = reply_srv(&sreply, cfg->db);
3140 break;
3142 case DNS_TYPE_NAPTR:
3143 if (type0 == DNS_TYPE_NAPTR) {
3145 build_reply(&sreply, so, buf, len, question, from, \
3146 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3147 NULL, replybuf);
3149 slen = reply_naptr(&sreply, cfg->db);
3151 break;
3153 case DNS_TYPE_CNAME:
3154 if (type0 == DNS_TYPE_CNAME) {
3156 build_reply(&sreply, so, buf, len, question, from, \
3157 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3158 NULL, replybuf);
3160 slen = reply_cname(&sreply);
3161 } else if (type0 == DNS_TYPE_NS) {
3163 build_reply(&sreply, so, buf, len, question, from, \
3164 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3165 NULL, replybuf);
3167 slen = reply_ns(&sreply, cfg->db);
3168 break;
3170 break;
3172 case DNS_TYPE_PTR:
3173 if (type0 == DNS_TYPE_CNAME) {
3175 build_reply(&sreply, so, buf, len, question, from, \
3176 fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL) \
3177 , aregion, istcp, wildcard, NULL, replybuf);
3179 slen = reply_cname(&sreply);
3180 } else if (type0 == DNS_TYPE_NS) {
3182 build_reply(&sreply, so, buf, len, question, from, \
3183 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3184 NULL, replybuf);
3186 slen = reply_ns(&sreply, cfg->db);
3187 break;
3188 } else if (type0 == DNS_TYPE_PTR) {
3190 build_reply(&sreply, so, buf, len, question, from,
3191 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3192 NULL, replybuf);
3194 slen = reply_ptr(&sreply);
3195 break; /* must break here */
3197 break;
3198 case DNS_TYPE_TXT:
3199 if (type0 == DNS_TYPE_TXT) {
3201 build_reply(&sreply, so, buf, len, question, from, \
3202 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3203 NULL, replybuf);
3205 slen = reply_txt(&sreply);
3207 break;
3208 case DNS_TYPE_SPF:
3209 if (type0 == DNS_TYPE_SPF) {
3211 build_reply(&sreply, so, buf, len, question, from, \
3212 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3213 NULL, replybuf);
3215 slen = reply_spf(&sreply);
3217 break;
3218 default:
3221 * ANY unkown RR TYPE gets a NOTIMPL
3224 * except for delegations
3227 if (type0 == DNS_TYPE_NS) {
3229 build_reply(&sreply, so, buf, len, question, from, \
3230 fromlen, &sd0, NULL, aregion, istcp, wildcard, \
3231 NULL, replybuf);
3233 slen = reply_ns(&sreply, cfg->db);
3234 } else {
3237 build_reply(&sreply, so, buf, len, question, from, \
3238 fromlen, NULL, NULL, aregion, istcp, wildcard, \
3239 NULL, replybuf);
3241 slen = reply_notimpl(&sreply);
3242 snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
3244 break;
3247 udpout:
3248 if (lflag) {
3249 dolog(LOG_INFO, "request on descriptor %u interface \"%s\" from %s (ttl=%u, region=%d) for \"%s\" type=%s class=%u, %s%sanswering \"%s\" (%d/%d)\n", so, cfg->ident[i], address, received_ttl, aregion, question->converted_name, get_dns_type(ntohs(question->hdr->qtype)), ntohs(question->hdr->qclass), (question->edns0len ? "edns0, " : ""), (question->dnssecok ? "dnssecok, " : "") , replystring, len, slen);
3253 if (logging.active == 1 && logging.bind == 0) {
3254 remotelog(lfd, "request on descriptor %u interface \"%s\" from %s (ttl=%u, region=%d) for \"%s\" type=%s class=%u, %s%sanswering \"%s\" (%d/%d)", so, cfg->ident[i], address, received_ttl, aregion, question->converted_name, get_dns_type(ntohs(question->hdr->qtype)), ntohs(question->hdr->qclass), (question->edns0len ? "edns0, ": ""), (question->dnssecok ? "dnssecok" : ""), replystring, len, slen);
3257 if (fakequestion != NULL) {
3258 free_question(fakequestion);
3261 free_question(question);
3263 } /* END ISSET */
3265 } /* for */
3267 if (logging.bind == 1 && FD_ISSET(lfd, &rset)) {
3268 logfromlen = sizeof(struct sockaddr_storage);
3269 len = recvfrom(lfd, buf, sizeof(buf), 0, (struct sockaddr *)&logfrom, &logfromlen);
3270 if (len < 0) {
3271 dolog(LOG_INFO, "recvfrom: logging %s\n", strerror(errno));
3272 } else
3273 receivelog(buf, len);
3276 drop:
3278 continue;
3279 } /* for (;;) */
3281 /* NOTREACHED */
3285 * BUILD_REPLY - a function that populates struct reply from arguments, doesn't
3286 * return anything. This replaces the alias BUILD_REPLY.
3290 void
3291 build_reply(struct sreply *reply, int so, char *buf, int len, struct question *q, struct sockaddr *sa, socklen_t slen, struct domain *sd1, struct domain *sd2, u_int8_t region, int istcp, int wildcard, struct recurses *sr, char *replybuf)
3293 reply->so = so;
3294 reply->buf = buf;
3295 reply->len = len;
3296 reply->q = q;
3297 reply->sa = sa;
3298 reply->salen = slen;
3299 reply->sd1 = sd1;
3300 reply->sd2 = sd2;
3301 reply->region = region;
3302 reply->istcp = istcp;
3303 reply->wildcard = wildcard;
3304 reply->sr = sr;
3305 reply->replybuf = replybuf;
3307 return;
3311 void
3312 recurseheader(struct srecurseheader *rh, int proto, struct sockaddr_storage *src, struct sockaddr_storage *dst, int family)
3314 struct sockaddr_in *sin, *sin0;
3315 struct sockaddr_in6 *sin6, *sin60;
3317 rh->af = family;
3318 rh->proto = proto;
3320 if (family == AF_INET) {
3321 sin = (struct sockaddr_in *)&rh->dest;
3322 sin0 = (struct sockaddr_in *)dst;
3323 sin->sin_family = sin0->sin_family;
3324 sin->sin_port = sin0->sin_port;
3325 memcpy((char *)&sin->sin_addr.s_addr,
3326 (char *)&sin0->sin_addr.s_addr,
3327 sizeof(sin->sin_addr.s_addr));
3328 sin = (struct sockaddr_in *)&rh->source;
3329 sin0 = (struct sockaddr_in *)src;
3330 sin->sin_family = sin0->sin_family;
3331 sin->sin_port = sin0->sin_port;
3332 memcpy((char *)&sin->sin_addr.s_addr,
3333 (char *)&sin0->sin_addr.s_addr,
3334 sizeof(sin->sin_addr.s_addr));
3335 } else if (family == AF_INET6) {
3336 sin6 = (struct sockaddr_in6 *)&rh->dest;
3337 sin60 = (struct sockaddr_in6 *)dst;
3339 sin6->sin6_family = sin60->sin6_family;
3340 sin6->sin6_port = sin60->sin6_port;
3342 memcpy((char *)&sin6->sin6_addr,
3343 (char *)&sin60->sin6_addr,
3344 sizeof(sin6->sin6_addr));
3346 sin6 = (struct sockaddr_in6 *)&rh->source;
3347 sin60 = (struct sockaddr_in6 *)src;
3349 sin6->sin6_family = sin60->sin6_family;
3350 sin6->sin6_port = sin60->sin6_port;
3352 memcpy((char *)&sin6->sin6_addr,
3353 (char *)&sin60->sin6_addr,
3354 sizeof(sin6->sin6_addr));
3358 return;
3362 * The master process, waits to be killed, if any other processes are killed
3363 * and they indicate shutdown through the shared memory segment it will kill
3364 * the rest of processes in the parent group.
3367 void
3368 setup_master(DB *db, DB_ENV *dbenv, char **av)
3370 DB *destroy;
3371 char buf[512];
3372 pid_t pid;
3373 int fd, ret;
3375 #if !defined __linux__ && !defined __APPLE__
3376 setproctitle("wildcarddnsd master");
3377 #endif
3379 fd = open(PIDFILE, O_WRONLY | O_APPEND | O_CREAT, 0644);
3380 if (fd < 0) {
3381 dolog(LOG_ERR, "couldn't install pid file, exiting...\n");
3382 pid = getpgrp();
3383 killpg(pid, SIGTERM);
3384 exit(1);
3387 pid = getpid();
3388 snprintf(buf, sizeof(buf), "%u\n", pid);
3390 write(fd, buf, strlen(buf));
3391 close(fd);
3393 signal(SIGTERM, master_shutdown);
3394 signal(SIGINT, master_shutdown);
3395 signal(SIGQUIT, master_shutdown);
3396 signal(SIGHUP, master_reload);
3398 for (;;) {
3399 sleep(1);
3401 if (*ptr) {
3402 dolog(LOG_INFO, "pid %u died, killing wildcarddnsd\n", *ptr);
3403 master_shutdown(SIGTERM);
3406 if (mshutdown) {
3407 dolog(LOG_INFO, "shutting down on signal %d\n", msig);
3408 unlink(PIDFILE);
3409 db->close(db, 0);
3412 if (db_create((DB **)&destroy, (DB_ENV *)dbenv, 0) != 0) {
3413 dolog(LOG_INFO, "db_create: %s\n", strerror(errno));
3416 ret = destroy->remove(destroy, database, NULL, 0);
3417 if (ret != 0) {
3418 dolog(LOG_INFO, "db->remove: %s\n", db_strerror(ret));
3421 dbenv->close(dbenv, 0);
3423 /* clean up our database */
3424 pid = getpid();
3425 snprintf(buf, sizeof(buf), "%s/%lu/__db.001", MYDB_PATH,
3426 (long)getpid());
3427 unlink(buf);
3428 snprintf(buf, sizeof(buf), "%s/%lu", MYDB_PATH,
3429 (long)getpid());
3431 rmdir(buf);
3433 pid = getpgrp();
3434 killpg(pid, msig);
3436 exit(0);
3439 if (reload) {
3441 signal(SIGTERM, SIG_IGN);
3443 pid = getpgrp();
3444 killpg(pid, SIGTERM);
3445 if (munmap(ptr, sizeof(int)) < 0) {
3446 dolog(LOG_ERR, "munmap: %s\n", strerror(errno));
3449 unlink(PIDFILE);
3450 db->close(db, 0);
3452 if (db_create((DB **)&destroy, (DB_ENV *)dbenv, 0) != 0) {
3453 dolog(LOG_INFO, "db_create: %s\n", strerror(errno));
3456 ret = destroy->remove(destroy, database, NULL, 0);
3457 if (ret != 0) {
3458 dolog(LOG_INFO, "db->remove: %s\n", db_strerror(ret));
3461 dbenv->close(dbenv, 0);
3463 /* clean up our database */
3464 pid = getpid();
3465 snprintf(buf, sizeof(buf), "%s/%lu/__db.001", MYDB_PATH,
3466 (long)getpid());
3467 unlink(buf);
3468 snprintf(buf, sizeof(buf), "%s/%lu", MYDB_PATH,
3469 (long)getpid());
3471 rmdir(buf);
3473 dolog(LOG_INFO, "restarting on SIGHUP\n");
3475 closelog();
3476 if (execvp("/usr/local/sbin/wildcarddnsd", av) < 0) {
3477 dolog(LOG_ERR, "execvp: %s\n", strerror(errno));
3479 /* NOTREACHED */
3480 exit(1);
3484 /* NOTREACHED */
3488 * master_shutdown - unlink pid file and kill parent group
3491 void
3492 master_shutdown(int sig)
3494 msig = sig;
3495 mshutdown = 1;
3499 * slave_shutdown - a slave wishes to shutdown, enter its pid into the
3500 * shutdown shared memory and return.
3503 void
3504 slave_shutdown(void)
3506 pid_t pid;
3508 pid = getpid();
3510 *ptr = pid;
3514 * slave_signal - a slave got a signal, call slave_shutdown and exit..
3517 void
3518 slave_signal(int sig)
3520 slave_shutdown();
3521 dolog(LOG_INFO, "shutting down on signal\n");
3522 exit(1);
3526 * master_reload - reload the wildcarddnsd system
3529 void
3530 master_reload(int sig)
3532 reload = 1;
3536 * CHECK_QTYPE - check the query type and return appropriately if we have
3537 * such a record in our DB..
3538 * returns 0 on error, or the DNS TYPE from 1 through 65535
3539 * when the return is 0 the error variable is set with the error
3540 * code (-1 or -2)
3543 u_int16_t
3544 check_qtype(struct domain *sd, u_int16_t type, int nxdomain, int *error)
3546 u_int16_t returnval;
3548 switch (type) {
3550 case DNS_TYPE_ANY:
3551 returnval = DNS_TYPE_ANY;
3552 break;
3554 case DNS_TYPE_A:
3555 if ((sd->flags & DOMAIN_HAVE_A) == DOMAIN_HAVE_A) {
3556 returnval = DNS_TYPE_A;
3557 break;
3558 } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
3559 returnval = DNS_TYPE_CNAME;
3560 break;
3563 *error = -1;
3564 return 0;
3565 case DNS_TYPE_AAAA:
3566 if ((sd->flags & DOMAIN_HAVE_AAAA) == DOMAIN_HAVE_AAAA) {
3567 returnval = DNS_TYPE_AAAA;
3568 break;
3569 } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
3570 returnval = DNS_TYPE_CNAME;
3571 break;
3574 *error = -1;
3575 return 0;
3576 case DNS_TYPE_MX:
3577 if ((sd->flags & DOMAIN_HAVE_MX) ==
3578 DOMAIN_HAVE_MX) {
3579 returnval = DNS_TYPE_MX;
3580 break;
3581 } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
3582 returnval = DNS_TYPE_CNAME;
3583 break;
3586 *error = -1;
3587 return 0;
3588 case DNS_TYPE_PTR:
3589 if ((sd->flags & DOMAIN_HAVE_PTR) == DOMAIN_HAVE_PTR) {
3590 returnval = DNS_TYPE_PTR;
3591 break;
3592 } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
3593 returnval = DNS_TYPE_CNAME;
3594 break;
3597 *error = -1;
3598 return 0;
3600 case DNS_TYPE_SOA:
3601 if ((sd->flags & DOMAIN_HAVE_SOA) == DOMAIN_HAVE_SOA) {
3603 returnval = DNS_TYPE_SOA;
3604 break;
3607 if (nxdomain)
3608 *error = -2;
3609 else
3610 *error = -1;
3612 return 0;
3614 case DNS_TYPE_SSHFP:
3615 if ((sd->flags & DOMAIN_HAVE_SSHFP) == DOMAIN_HAVE_SSHFP) {
3616 returnval = DNS_TYPE_SSHFP;
3617 break;
3620 *error = -1;
3621 return 0;
3623 case DNS_TYPE_SRV:
3624 if ((sd->flags & DOMAIN_HAVE_SRV) == DOMAIN_HAVE_SRV) {
3625 returnval = DNS_TYPE_SRV;
3626 break;
3629 *error = -1;
3630 return 0;
3632 case DNS_TYPE_NAPTR:
3633 if ((sd->flags & DOMAIN_HAVE_NAPTR) == DOMAIN_HAVE_NAPTR) {
3634 returnval = DNS_TYPE_NAPTR;
3635 break;
3638 *error = -1;
3639 return 0;
3640 case DNS_TYPE_CNAME:
3641 if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
3642 returnval = DNS_TYPE_CNAME;
3643 break;
3646 *error = -1;
3647 return 0;
3649 case DNS_TYPE_NS:
3650 if ((sd->flags & DOMAIN_HAVE_NS) == DOMAIN_HAVE_NS) {
3651 returnval = DNS_TYPE_NS;
3652 break;
3655 *error = -1;
3656 return 0;
3657 case DNS_TYPE_TXT:
3658 if ((sd->flags & DOMAIN_HAVE_TXT) == DOMAIN_HAVE_TXT) {
3659 returnval = DNS_TYPE_TXT;
3660 break;
3663 *error = -1;
3664 return 0;
3665 case DNS_TYPE_SPF:
3666 if ((sd->flags & DOMAIN_HAVE_SPF) == DOMAIN_HAVE_SPF) {
3667 returnval = DNS_TYPE_SPF;
3668 break;
3671 *error = -1;
3672 return 0;
3674 default: /* RR's that we don't support, but have a zone for */
3676 *error = -1;
3677 return 0;
3678 break;
3681 return (returnval);