This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.sbin / named / ns_main.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1986, 1989, 1990 Regents of the University of California.
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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35char copyright[] =
36"@(#) Copyright (c) 1986, 1989, 1990 Regents of the University of California.\n\
37 All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91";
42#endif /* not lint */
43
44/*
45* Internet Name server (see rfc883 & others).
46*/
47
48#include <sys/param.h>
49#if defined(SYSV)
50#include <fcntl.h>
51#endif SYSV
52#include <sys/file.h>
53#include <sys/time.h>
54#if !defined(SYSV)
55#include <sys/wait.h>
56#endif !SYSV
57#include <sys/resource.h>
58#include <sys/ioctl.h>
59#include <sys/socket.h>
60#include <netinet/in.h>
61#include <net/if.h>
62#include <stdio.h>
63#include <syslog.h>
64#include <errno.h>
65#include <signal.h>
66#include <netdb.h>
67#include <arpa/nameser.h>
68#include <arpa/inet.h>
69#include <resolv.h>
70#undef nsaddr /* XXX */
71#include "ns.h"
72#include "db.h"
73#include "pathnames.h"
74
75#ifdef BOOTFILE /* default boot file */
76char *bootfile = BOOTFILE;
77#else
78char *bootfile = _PATH_BOOT;
79#endif
80
81#ifdef DEBUGFILE /* default debug output file */
82char *debugfile = DEBUGFILE;
83#else
84char *debugfile = _PATH_DEBUG;
85#endif
86
87#ifdef PIDFILE /* file to store current named PID */
88char *PidFile = PIDFILE;
89#else
90char *PidFile = _PATH_PIDFILE;
91#endif
92
93#ifndef FD_SET
94#define NFDBITS 32
95#define FD_SETSIZE 32
96#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
97#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
98#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
99#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
100#endif
101
102FILE *fp; /* file descriptor for pid file */
103
104#ifdef DEBUG
105FILE *ddt;
106#endif
107
108int debug = 0; /* debugging flag */
109int ds; /* datagram socket */
110int needreload = 0; /* received SIGHUP, need to reload db */
111int needmaint = 0; /* need to call ns_maint()*/
112int needzoneload = 0; /* need to reload secondary zone(s) */
113int needToDoadump = 0; /* need to dump database */
114int needToChkpt = 0; /* need to checkpoint cache */
115int needStatsDump = 0; /* need to dump statistics */
116#ifdef ALLOW_UPDATES
117int needToExit = 0; /* need to exit (may need to doadump
118 * first, if database has changed since
119 * it was last dumped/booted). Gets
120 * set by shutdown signal handler
121 * (onintr)
122 */
123#endif ALLOW_UPDATES
124
125int priming = 0; /* is cache being primed */
126
127#ifdef SO_RCVBUF
128int rbufsize = 8 * 1024; /* UDP recive buffer size */
129#endif
130
131struct qstream *streamq = QSTREAM_NULL; /* list of open streams */
132struct qdatagram *datagramq = QDATAGRAM_NULL; /* list of datagram interfaces */
133struct sockaddr_in nsaddr;
134struct timeval tt;
135/*
136 * We keep a list of favored networks headed by nettab.
137 * There are three (possibly empty) parts to this list, in this order:
138 * 1. directly attached (sub)nets.
139 * 2. logical networks for directly attached subnetted networks.
140 * 3. networks from the sort list.
141 * The value (*elocal) points at the first entry in the second part of the list,
142 * if any, while (*enettab) points at the first entry in the sort list.
143 */
144struct netinfo *nettab = NULL;
145struct netinfo **elocal = &nettab;
146struct netinfo **enettab = &nettab;
147struct netinfo netloop;
148struct netinfo *findnetinfo();
149u_long net_mask();
150u_short ns_port;
151struct sockaddr_in from_addr; /* Source addr of last packet */
152int from_len; /* Source addr size of last packet */
153time_t boottime, resettime; /* Used by ns_stats */
154static fd_set mask; /* select mask of open descriptors */
155static int vs; /* listening TCP socket */
156
157char **Argv = NULL; /* pointer to argument vector */
158char *LastArg = NULL; /* end of argv */
159
160extern int errno;
161
162#if defined(SYSV)
163getdtablesize()
164{
165 return(FD_SETSIZE);
166}
167#endif SYSV
168
169main(argc, argv, envp)
170 int argc;
171 char *argv[], *envp[];
172{
173 register int n, udpcnt;
174 register char *arg;
175 register struct qstream *sp;
176 register struct qdatagram *dqp;
177 struct qstream *nextsp;
178 int nfds;
179 int on = 1;
180 int rfd, size;
181 u_long lasttime, maxctime;
182 char buf[BUFSIZ];
183#ifndef SYSV
184 struct sigvec vec;
185#endif
186
187 fd_set tmpmask;
188
189 struct timeval t, *tp;
190 struct qstream *candidate = QSTREAM_NULL;
191 extern SIG_FN onintr(), maint_alarm(), endxfer();
192 extern SIG_FN setdumpflg(), onhup();
193 extern SIG_FN setIncrDbgFlg(), setNoDbgFlg(), sigprof();
194 extern SIG_FN setchkptflg(), setstatsflg();
195 extern int loadxfer();
196 extern struct qstream *sqadd();
197 extern struct qinfo *qhead;
198 extern char Version[];
199
200 ns_port = htons(NAMESERVER_PORT);
201
202 /*
203 ** Save start and extent of argv for setproctitle.
204 */
205
206 Argv = argv;
207 if (envp == 0 || *envp == 0)
208 envp = argv;
209 while (*envp)
210 envp++;
211 LastArg = envp[-1] + strlen(envp[-1]);
212
213 (void) umask(022);
214 while (--argc > 0) {
215 arg = *++argv;
216 if (*arg == '-') {
217 while (*++arg)
218 switch (*arg) {
219 case 'b':
220 if (--argc <= 0)
221 usage();
222 bootfile = *++argv;
223 break;
224
225 case 'd':
226 ++argv;
227
228 if (*argv != 0) {
229 if (**argv == '-') {
230 argv--;
231 break;
232 }
233 debug = atoi(*argv);
234 --argc;
235 }
236 if (debug <= 0)
237 debug = 1;
238 setdebug(1);
239 break;
240
241 case 'p':
242 if (--argc <= 0)
243 usage();
244 ns_port = htons((u_short)atoi(*++argv));
245 break;
246
247 default:
248 usage();
249 }
250 } else
251 bootfile = *argv;
252 }
253
254 if (!debug)
255 for (n = getdtablesize() - 1; n > 2; n--)
256 (void) close(n);
257#ifdef DEBUG
258 else {
259 fprintf(ddt,"Debug turned ON, Level %d\n",debug);
260 fprintf(ddt,"Version = %s\t",Version);
261 fprintf(ddt,"bootfile = %s\n",bootfile);
262 }
263#endif
264
265#ifdef LOG_DAEMON
266 openlog("named", LOG_PID|LOG_CONS|LOG_NDELAY, LOG_DAEMON);
267#else
268 openlog("named", LOG_PID);
269#endif
270
271 /* tuck my process id away */
272 fp = fopen(PidFile, "w");
273 if (fp != NULL) {
274 fprintf(fp, "%d\n", getpid());
275 (void) fclose(fp);
276 }
277 syslog(LOG_NOTICE, "restarted\n");
278
279 _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
280
281 nsaddr.sin_family = AF_INET;
282 nsaddr.sin_addr.s_addr = INADDR_ANY;
283 nsaddr.sin_port = ns_port;
284
285 /*
286 ** Open stream port.
287 */
288 if ((vs = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
289 syslog(LOG_ERR, "socket(SOCK_STREAM): %m");
290 exit(1);
291 }
292 (void)setsockopt(vs, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
293 if (bind(vs, (struct sockaddr *)&nsaddr, sizeof(nsaddr))) {
294 syslog(LOG_ERR, "bind(vs, %s[%d]): %m",
295 inet_ntoa(nsaddr.sin_addr), ntohs(nsaddr.sin_port));
296 exit(1);
297 }
298 (void) listen(vs, 5);
299
300 /*
301 * Get list of local addresses and set up datagram sockets.
302 */
303 getnetconf();
304
305 /*
306 ** Initialize and load database.
307 */
308 gettime(&tt);
309 buildservicelist();
310 buildprotolist();
311 ns_init(bootfile);
312#ifdef DEBUG
313 if (debug) {
314 fprintf(ddt, "Network and sort list:\n");
315 printnetinfo(nettab);
316 }
317#endif DEBUG
318
319 time(&boottime);
320 resettime = boottime;
321
322 (void) signal(SIGHUP, onhup);
323#if defined(SYSV)
324 (void) signal(SIGCLD, endxfer);
325 (void) signal(SIGALRM, maint_alarm);
326#else
327 bzero((char *)&vec, sizeof(vec));
328 vec.sv_handler = maint_alarm;
329 vec.sv_mask = sigmask(SIGCHLD);
330 (void) sigvec(SIGALRM, &vec, (struct sigvec *)NULL);
331
332 vec.sv_handler = endxfer;
333 vec.sv_mask = sigmask(SIGALRM);
334 (void) sigvec(SIGCHLD, &vec, (struct sigvec *)NULL);
335#endif SYSV
336 (void) signal(SIGPIPE, SIG_IGN);
337 (void) signal(SIGSYS, sigprof);
338 (void) signal(SIGINT, setdumpflg);
339 (void) signal(SIGQUIT, setchkptflg);
340 (void) signal(SIGIOT, setstatsflg);
341
342#ifdef ALLOW_UPDATES
343 /* Catch SIGTERM so we can dump the database upon shutdown if it
344 has changed since it was last dumped/booted */
345 (void) signal(SIGTERM, onintr);
346#endif ALLOW_UPDATES
347
348#if defined(SIGUSR1) && defined(SIGUSR2)
349 (void) signal(SIGUSR1, setIncrDbgFlg);
350 (void) signal(SIGUSR2, setNoDbgFlg);
351#else SIGUSR1&&SIGUSR2
352 (void) signal(SIGEMT, setIncrDbgFlg);
353 (void) signal(SIGFPE, setNoDbgFlg);
354#endif SIGUSR1&&SIGUSR2
355
356#ifdef DEBUG
357 if (debug) {
358 fprintf(ddt,"database initialized\n");
359 }
360#endif
361
362 t.tv_usec = 0;
363
364 /*
365 * Fork and go into background now that
366 * we've done any slow initialization
367 * and are ready to answer queries.
368 */
369 if (!debug) {
370#if defined(BSD) && BSD >= 199006
371 daemon(1, 0);
372#else
373 if (fork() > 0)
374 exit(0);
375 n = open(_PATH_DEVNULL, O_RDONLY);
376 (void) dup2(n, 0);
377 (void) dup2(n, 1);
378 (void) dup2(n, 2);
379 if (n > 2)
380 (void) close(n);
381#ifdef SYSV
382 setpgrp();
383#else
384 {
385 struct itimerval ival;
386
387 /*
388 * The open below may hang on pseudo ttys if the person
389 * who starts named logs out before this point.
390 *
391 * needmaint may get set inapropriately if the open
392 * hangs, but all that will happen is we will see that
393 * no maintenance is required.
394 */
395 bzero((char *)&ival, sizeof(ival));
396 ival.it_value.tv_sec = 120;
397 (void) setitimer(ITIMER_REAL, &ival,
398 (struct itimerval *)NULL);
399 n = open(_PATH_TTY, O_RDWR);
400 ival.it_value.tv_sec = 0;
401 (void) setitimer(ITIMER_REAL, &ival,
402 (struct itimerval *)NULL);
403 if (n > 0) {
404 (void) ioctl(n, TIOCNOTTY, (char *)NULL);
405 (void) close(n);
406 }
407 }
408#endif /* SYSV */
409#endif /* BSD > 199006 */
410 }
411 /* tuck my process id away again */
412 fp = fopen(PidFile, "w");
413 if (fp != NULL) {
414 fprintf(fp, "%d\n", getpid());
415 (void) fclose(fp);
416 }
417
418#ifdef DEBUG
419 if (debug)
420 fprintf(ddt,"Ready to answer queries.\n");
421#endif
422 prime_cache();
423 nfds = getdtablesize(); /* get the number of file descriptors */
424 if (nfds > FD_SETSIZE) {
425 nfds = FD_SETSIZE; /* Bulletproofing */
426 syslog(LOG_ERR, "Return from getdtablesize() > FD_SETSIZE");
427#ifdef DEBUG
428 if (debug)
429 fprintf(ddt,"Return from getdtablesize() > FD_SETSIZE\n");
430#endif
431 }
432 FD_ZERO(&mask);
433 FD_SET(vs, &mask);
434 for (dqp = datagramq; dqp != QDATAGRAM_NULL; dqp = dqp->dq_next)
435 FD_SET(dqp->dq_dfd, &mask);
436 for (;;) {
437#ifdef DEBUG
438 if (ddt && debug == 0) {
439 fprintf(ddt,"Debug turned OFF\n");
440 (void) fclose(ddt);
441 ddt = 0;
442 }
443#endif
444#ifdef ALLOW_UPDATES
445 if (needToExit) {
446 struct zoneinfo *zp;
447 sigblock(~0); /*
448 * Block all blockable signals
449 * to ensure a consistant
450 * state during final dump
451 */
452#ifdef DEBUG
453 if (debug)
454 fprintf(ddt, "Received shutdown signal\n");
455#endif DEBUG
456 for (zp = zones; zp < &zones[nzones]; zp++) {
457 if (zp->hasChanged)
458 zonedump(zp);
459 }
460 exit(0);
461 }
462#endif ALLOW_UPDATES
463 if (needreload) {
464 needreload = 0;
465 db_reload();
466 }
467#ifdef STATS
468 if (needStatsDump) {
469 needStatsDump = 0;
470 ns_stats();
471 }
472#endif STATS
473 if (needzoneload) {
474 needzoneload = 0;
475 loadxfer();
476 }
477 if (needmaint) {
478 needmaint = 0;
479 ns_maint();
480 }
481 if(needToChkpt) {
482 needToChkpt = 0;
483 doachkpt();
484 }
485 if(needToDoadump) {
486 needToDoadump = 0;
487 doadump();
488 }
489 /*
490 ** Wait until a query arrives
491 */
492 if (retryqp != NULL) {
493 gettime(&tt);
494 t.tv_sec = (long) retryqp->q_time - tt.tv_sec;
495 if (t.tv_sec <= 0) {
496 retry(retryqp);
497 continue;
498 }
499 tp = &t;
500 } else
501 tp = NULL;
502 tmpmask = mask;
503 n = select(nfds, &tmpmask, (fd_set *)NULL, (fd_set *)NULL, tp);
504 if (n < 0) {
505 if (errno == EINTR)
506 continue;
507 syslog(LOG_ERR, "select: %m");
508#ifdef DEBUG
509 if (debug)
510 fprintf(ddt,"select error\n");
511#endif
512 ;
513 }
514 if (n == 0)
515 continue;
516
517 for (dqp = datagramq; dqp != QDATAGRAM_NULL;
518 dqp = dqp->dq_next) {
519 if (FD_ISSET(dqp->dq_dfd, &tmpmask))
520 for(udpcnt = 0; udpcnt < 25; udpcnt++) {
521 from_len = sizeof(from_addr);
522 if ((n = recvfrom(dqp->dq_dfd, buf, sizeof(buf), 0,
523 (struct sockaddr *)&from_addr, &from_len)) < 0)
524 {
525 if ((n == -1) && (errno == EWOULDBLOCK))
526 break;
527 syslog(LOG_WARNING, "recvfrom: %m");
528 break;
529 }
530#ifdef STATS
531 stats[S_INPKTS].cnt++;
532#endif
533#ifdef DEBUG
534 if (debug)
535 fprintf(ddt,
536 "\ndatagram from %s port %d, fd %d, len %d\n",
537 inet_ntoa(from_addr.sin_addr),
538 ntohs(from_addr.sin_port), dqp->dq_dfd, n);
539 if (debug >= 10)
540 fp_query(buf, ddt);
541#endif
542 /*
543 * Consult database to get the answer.
544 */
545 gettime(&tt);
546 ns_req(buf, n, PACKETSZ, QSTREAM_NULL, &from_addr,
547 dqp->dq_dfd);
548 }
549 }
550 /*
551 ** Process stream connection
552 */
553 if (FD_ISSET(vs, &tmpmask)) {
554 from_len = sizeof(from_addr);
555 rfd = accept(vs, (struct sockaddr *)&from_addr, &from_len);
556 gettime(&tt);
557 if (rfd < 0 && errno == EMFILE && streamq != NULL) {
558 maxctime = 0;
559 candidate = QSTREAM_NULL;
560 for (sp = streamq; sp != QSTREAM_NULL;
561 sp = nextsp) {
562 nextsp = sp->s_next;
563 if (sp->s_refcnt != 0)
564 continue;
565 lasttime = tt.tv_sec - sp->s_time;
566 if (lasttime >= 900)
567 sqrm(sp);
568 else if (lasttime > maxctime) {
569 candidate = sp;
570 maxctime = lasttime;
571 }
572 }
573 rfd = accept(vs, (struct sockaddr *)&from_addr, &from_len);
574 if ((rfd < 0) && (errno == EMFILE) &&
575 candidate != QSTREAM_NULL) {
576 sqrm(candidate);
577 rfd = accept(vs, (struct sockaddr *)&from_addr, &from_len);
578 }
579 }
580 if (rfd < 0) {
581 syslog(LOG_WARNING, "accept: %m");
582 continue;
583 }
584 (void) fcntl(rfd, F_SETFL, O_NONBLOCK);
585 (void) setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE,
586 (char *)&on, sizeof(on));
587 if ((sp = sqadd()) == QSTREAM_NULL) {
588 (void) close(rfd);
589 continue;
590 }
591 sp->s_rfd = rfd; /* stream file descriptor */
592 sp->s_size = -1; /* amount of data to receive */
593 gettime(&tt);
594 sp->s_time = tt.tv_sec; /* last transaction time */
595 sp->s_from = from_addr; /* address to respond to */
596 sp->s_bufp = (char *)&sp->s_tempsize;
597 FD_SET(rfd, &mask);
598 FD_SET(rfd, &tmpmask);
599#ifdef DEBUG
600 if (debug) {
601 fprintf(ddt,
602 "\nTCP connection from %s port %d (fd %d)\n",
603 inet_ntoa(sp->s_from.sin_addr),
604 ntohs(sp->s_from.sin_port), rfd);
605 }
606#endif
607 }
608#ifdef DEBUG
609 if (debug > 2 && streamq)
610 fprintf(ddt,"streamq = x%x\n",streamq);
611#endif
612 if (streamq != NULL) {
613 for (sp = streamq; sp != QSTREAM_NULL; sp = nextsp) {
614 nextsp = sp->s_next;
615 if (FD_ISSET(sp->s_rfd, &tmpmask)) {
616#ifdef DEBUG
617 if (debug > 5) {
618 fprintf(ddt,
619 "sp x%x rfd %d size %d time %d ",
620 sp, sp->s_rfd, sp->s_size,
621 sp->s_time );
622 fprintf(ddt," next x%x \n", sp->s_next );
623 fprintf(ddt,"\tbufsize %d",sp->s_bufsize);
624 fprintf(ddt," buf x%x ",sp->s_buf);
625 fprintf(ddt," bufp x%x\n",sp->s_bufp);
626 }
627#endif DEBUG
628 if (sp->s_size < 0) {
629 size = sizeof(u_short) -
630 (sp->s_bufp - (char *)&sp->s_tempsize);
631 while (size > 0 &&
632 (n = read(sp->s_rfd, sp->s_bufp, size)) > 0){
633 sp->s_bufp += n;
634 size -= n;
635 }
636 if ((n == -1) && (errno == EWOULDBLOCK))
637 continue;
638 if (n <= 0) {
639 sqrm(sp);
640 continue;
641 }
642 if ((sp->s_bufp - (char *)&sp->s_tempsize) ==
643 sizeof(u_short)) {
644 sp->s_size = htons(sp->s_tempsize);
645 if (sp->s_bufsize == 0) {
646 if ( (sp->s_buf = malloc(BUFSIZ))
647 == NULL) {
648 sp->s_buf = buf;
649 sp->s_size = sizeof(buf);
650 } else {
651 sp->s_bufsize = BUFSIZ;
652 }
653 }
654 if (sp->s_size > sp->s_bufsize &&
655 sp->s_bufsize != 0) {
656 if ((sp->s_buf = realloc(
657 (char *)sp->s_buf,
658 (unsigned)sp->s_size)) == NULL){
659 sp->s_buf = buf;
660 sp->s_bufsize = 0;
661 sp->s_size = sizeof(buf);
662 } else {
663 sp->s_bufsize = sp->s_size;
664 }
665 }
666 sp->s_bufp = sp->s_buf;
667 }
668 }
669 gettime(&tt);
670 sp->s_time = tt.tv_sec;
671 while (sp->s_size > 0 &&
672 (n = read(sp->s_rfd, sp->s_bufp, sp->s_size)) > 0)
673 {
674 sp->s_bufp += n;
675 sp->s_size -= n;
676 }
677 /*
678 * we don't have enough memory for the query.
679 * if we have a query id, then we will send an
680 * error back to the user.
681 */
682 if (sp->s_bufsize == 0 &&
683 (sp->s_bufp - sp->s_buf > sizeof(u_short))) {
684 HEADER *hp;
685
686 hp = (HEADER *)sp->s_buf;
687 hp->qr = 1;
688 hp->ra = 1;
689 hp->ancount = 0;
690 hp->qdcount = 0;
691 hp->nscount = 0;
692 hp->arcount = 0;
693 hp->rcode = SERVFAIL;
694 (void) writemsg(sp->s_rfd, sp->s_buf,
695 sizeof(HEADER));
696 continue;
697 }
698 if ((n == -1) && (errno == EWOULDBLOCK))
699 continue;
700 if (n <= 0) {
701 sqrm(sp);
702 continue;
703 }
704 /*
705 * Consult database to get the answer.
706 */
707 if (sp->s_size == 0) {
708 sq_query(sp);
709 ns_req(sp->s_buf,
710 sp->s_bufp - sp->s_buf,
711 sp->s_bufsize, sp,
712 &sp->s_from, -1);
713 sp->s_bufp = (char *)&sp->s_tempsize;
714 sp->s_size = -1;
715 continue;
716 }
717 }
718 }
719 }
720 }
721 /* NOTREACHED */
722}
723
724usage()
725{
726 fprintf(stderr, "Usage: named [-d #] [-p port] [{-b} bootfile]\n");
727 exit(1);
728}
729
730getnetconf()
731{
732 register struct netinfo *ntp;
733 struct netinfo *ontp;
734 struct ifconf ifc;
735 struct ifreq ifreq, *ifr;
736 struct qdatagram *dqp;
737 static int first = 1;
738 char buf[BUFSIZ], *cp, *cplim;
739 u_long nm;
740
741 ifc.ifc_len = sizeof(buf);
742 ifc.ifc_buf = buf;
743 if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) {
744 syslog(LOG_ERR, "get interface configuration: %m");
745 exit(1);
746 }
747 ntp = NULL;
748#ifdef AF_LINK
749#define max(a, b) (a > b ? a : b)
750#define size(p) max((p).sa_len, sizeof(p))
751#else
752#define size(p) (sizeof (p))
753#endif
754 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
755 for (cp = buf; cp < cplim;
756 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
757#undef size
758 ifr = (struct ifreq *)cp;
759 if (ifr->ifr_addr.sa_family != AF_INET ||
760 ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr == 0)
761 continue;
762 ifreq = *ifr;
763 /*
764 * Don't test IFF_UP, packets may still be received at this
765 * address if any other interface is up.
766 */
767 if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) {
768 syslog(LOG_ERR, "get interface addr: %m");
769 continue;
770 }
771 /* build datagram queue */
772 /*
773 * look for an already existing source interface address.
774 * This happens mostly when reinitializing. Also, if
775 * the machine has multiple point to point interfaces, then
776 * the local address may appear more than once.
777 */
778 for (dqp=datagramq; dqp != NULL; dqp = dqp->dq_next)
779 if (((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr
780 == dqp->dq_addr.s_addr) {
781#ifdef DEBUG
782 if (debug)
783 fprintf(ddt, "dup interface address %s on %s\n",
784 inet_ntoa(dqp->dq_addr), ifreq.ifr_name);
785#endif
786 break;
787 }
788 if (dqp != NULL)
789 continue;
790
791 if ((dqp = (struct qdatagram *)calloc(1,
792 sizeof(struct qdatagram))) == NULL) {
793#ifdef DEBUG
794 if (debug >= 5)
795 fprintf(ddt,"getnetconf: malloc error\n");
796#endif
797 syslog(LOG_ERR, "getnetconf: Out Of Memory");
798 exit(12);
799 }
800 dqp->dq_next = datagramq;
801 datagramq = dqp;
802 dqp->dq_addr = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
803 opensocket(dqp);
804
805 /*
806 * Add interface to list of directly-attached (sub)nets
807 * for use in sorting addresses.
808 */
809 if (ntp == NULL)
810 ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
811 ntp->my_addr =
812 ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
813#ifdef SIOCGIFNETMASK
814 if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
815 syslog(LOG_ERR, "get netmask: %m");
816 ntp->mask = net_mask(ntp->my_addr);
817 } else
818 ntp->mask = ((struct sockaddr_in *)
819 &ifreq.ifr_addr)->sin_addr.s_addr;
820#else
821 /* 4.2 does not support subnets */
822 ntp->mask = net_mask(ntp->my_addr);
823#endif
824 if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
825 syslog(LOG_ERR, "get interface flags: %m");
826 continue;
827 }
828#ifdef IFF_LOOPBACK
829 if (ifreq.ifr_flags & IFF_LOOPBACK)
830#else
831 /* test against 127.0.0.1 (yuck!!) */
832 if (ntp->my_addr.s_addr == htonl(0x7F000001))
833#endif
834 {
835 if (netloop.my_addr.s_addr == 0) {
836 netloop.my_addr = ntp->my_addr;
837 netloop.mask = 0xffffffff;
838 netloop.net = ntp->my_addr.s_addr;
839#ifdef DEBUG
840 if (debug)
841 fprintf(ddt,"loopback address: x%lx\n",
842 netloop.my_addr.s_addr);
843#endif DEBUG
844 }
845 continue;
846 } else if ((ifreq.ifr_flags & IFF_POINTOPOINT)) {
847 if (ioctl(vs, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
848 syslog(LOG_ERR, "get dst addr: %m");
849 continue;
850 }
851 ntp->mask = 0xffffffff;
852 ntp->net = ((struct sockaddr_in *)
853 &ifreq.ifr_addr)->sin_addr.s_addr;
854 } else {
855 ntp->net = ntp->mask & ntp->my_addr.s_addr;
856 }
857 /*
858 * Place on end of list of locally-attached (sub)nets,
859 * but before logical nets for subnetted nets.
860 */
861 ntp->next = *elocal;
862 *elocal = ntp;
863 if (elocal == enettab)
864 enettab = &ntp->next;
865 elocal = &ntp->next;
866 ntp = NULL;
867 }
868 if (ntp)
869 (void) free((char *)ntp);
870
871 /*
872 * Create separate qdatagram structure for socket
873 * wildcard address.
874 */
875 if (first) {
876 if ((dqp = (struct qdatagram *)calloc(1, sizeof(*dqp))) == NULL) {
877#ifdef DEBUG
878 if (debug >= 5)
879 fprintf(ddt,"getnetconf: malloc error\n");
880#endif
881 syslog(LOG_ERR, "getnetconf: Out Of Memory");
882 exit(12);
883 }
884 dqp->dq_next = datagramq;
885 datagramq = dqp;
886 dqp->dq_addr.s_addr = INADDR_ANY;
887 opensocket(dqp);
888 ds = dqp->dq_dfd; /* used externally */
889 }
890
891 /*
892 * Compute logical networks to which we're connected
893 * based on attached subnets;
894 * used for sorting based on network configuration.
895 */
896 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
897 nm = net_mask(ntp->my_addr);
898 if (nm != ntp->mask) {
899 if (findnetinfo(ntp->my_addr))
900 continue;
901 ontp = (struct netinfo *)malloc(sizeof(struct netinfo));
902 if (ontp == NULL) {
903#ifdef DEBUG
904 if (debug >= 5)
905 fprintf(ddt,"getnetconf: malloc error\n");
906#endif
907 syslog(LOG_ERR, "getnetconf: Out Of Memory");
908 exit(12);
909 }
910 ontp->my_addr = ntp->my_addr;
911 ontp->mask = nm;
912 ontp->net = ontp->my_addr.s_addr & nm;
913 ontp->next = *enettab;
914 *enettab = ontp;
915 enettab = &ontp->next;
916 }
917 }
918 first = 0;
919}
920
921/*
922 * Find netinfo structure for logical network implied by address "addr",
923 * if it's on list of local/favored networks.
924 */
925struct netinfo *
926findnetinfo(addr)
927 struct in_addr addr;
928{
929 register struct netinfo *ntp;
930 u_long net, mask;
931
932 mask = net_mask(addr);
933 net = addr.s_addr & mask;
934 for (ntp = nettab; ntp != NULL; ntp = ntp->next)
935 if (ntp->net == net && ntp->mask == mask)
936 return (ntp);
937 return ((struct netinfo *) NULL);
938}
939
940#ifdef DEBUG
941printnetinfo(ntp)
942 register struct netinfo *ntp;
943{
944 for ( ; ntp != NULL; ntp = ntp->next) {
945 fprintf(ddt,"net x%lx mask x%lx", ntp->net, ntp->mask);
946 fprintf(ddt," my_addr x%lx", ntp->my_addr.s_addr);
947 fprintf(ddt," %s\n", inet_ntoa(ntp->my_addr));
948 }
949}
950#endif
951
952opensocket(dqp)
953 register struct qdatagram *dqp;
954{
955 int on = 1;
956
957 /*
958 * Open datagram sockets bound to interface address.
959 */
960 if ((dqp->dq_dfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
961 syslog(LOG_ERR, "socket(SOCK_DGRAM): %m");
962 exit(1);
963 }
964#ifdef DEBUG
965 if (debug)
966 fprintf(ddt,"dqp->dq_addr %s d_dfd %d\n",
967 inet_ntoa(dqp->dq_addr), dqp->dq_dfd);
968#endif DEBUG
969 (void)setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_REUSEADDR,
970 (char *)&on, sizeof(on));
971#ifdef SO_RCVBUF
972 (void)setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF,
973 (char *)&rbufsize, sizeof(rbufsize));
974#endif SO_RCVBUF
975 (void) fcntl(dqp->dq_dfd, F_SETFL, O_NONBLOCK);
976 /*
977 * NOTE: Some versions of SunOS have problems with the following
978 * call to bind. Bind still seems to function on these systems
979 * if you comment out the exit inside the if. This may cause
980 * Suns with multiple interfaces to reply strangely.
981 */
982 nsaddr.sin_addr = dqp->dq_addr;
983 if (bind(dqp->dq_dfd, (struct sockaddr *)&nsaddr, sizeof(nsaddr))) {
984 syslog(LOG_ERR, "bind(dfd %d, %s[%d]): %m",
985 dqp->dq_dfd, inet_ntoa(nsaddr.sin_addr),
986 ntohs(nsaddr.sin_port));
987#if !defined(sun)
988 exit(1);
989#endif
990 }
991}
992
993/*
994** Set flag saying to reload database upon receiving SIGHUP.
995** Must make sure that someone isn't walking through a data
996** structure at the time.
997*/
998
999SIG_FN
1000onhup()
1001{
1002#if defined(SYSV)
1003 (void)signal(SIGHUP, onhup);
1004#endif SYSV
1005 needreload = 1;
1006}
1007
1008/*
1009** Set flag saying to call ns_maint()
1010** Must make sure that someone isn't walking through a data
1011** structure at the time.
1012*/
1013
1014SIG_FN
1015maint_alarm()
1016{
1017#if defined(SYSV)
1018 (void)signal(SIGALRM, maint_alarm);
1019#endif SYSV
1020 needmaint = 1;
1021 }
1022
1023
1024#ifdef ALLOW_UPDATES
1025/*
1026 * Signal handler to schedule shutdown. Just set flag, to ensure a consistent
1027 * state during dump.
1028 */
1029SIG_FN
1030onintr()
1031{
1032 needToExit = 1;
1033}
1034#endif ALLOW_UPDATES
1035
1036/*
1037 * Signal handler to schedule a data base dump. Do this instead of dumping the
1038 * data base immediately, to avoid seeing it in a possibly inconsistent state
1039 * (due to updates), and to avoid long disk I/O delays at signal-handler
1040 * level
1041 */
1042SIG_FN
1043setdumpflg()
1044{
1045#if defined(SYSV)
1046 (void)signal(SIGINT, setdumpflg);
1047#endif SYSV
1048 needToDoadump = 1;
1049}
1050
1051/*
1052** Turn on or off debuging by open or closeing the debug file
1053*/
1054
1055setdebug(code)
1056int code;
1057{
1058#if defined(lint) && !defined(DEBUG)
1059 code = code;
1060#endif
1061#ifdef DEBUG
1062
1063 if (code) {
1064 ddt = freopen(debugfile, "w+", stderr);
1065 if ( ddt == NULL) {
1066 syslog(LOG_WARNING, "can't open debug file %s: %m",
1067 debugfile);
1068 debug = 0;
1069 } else {
1070#if defined(SYSV)
1071 setvbuf(ddt, NULL, _IOLBF, BUFSIZ);
1072#else
1073 setlinebuf(ddt);
1074#endif
1075 (void) fcntl(fileno(ddt), F_SETFL, FAPPEND);
1076 }
1077 } else
1078 debug = 0;
1079 /* delay closing ddt, we might interrupt someone */
1080#endif
1081}
1082
1083/*
1084** Catch a special signal and set debug level.
1085**
1086** If debuging is off then turn on debuging else increment the level.
1087**
1088** Handy for looking in on long running name servers.
1089*/
1090
1091SIG_FN
1092setIncrDbgFlg()
1093{
1094#if defined(SYSV)
1095 (void)signal(SIGUSR1, setIncrDbgFlg);
1096#endif SYSV
1097#ifdef DEBUG
1098 if (debug == 0) {
1099 debug++;
1100 setdebug(1);
1101 }
1102 else {
1103 debug++;
1104 }
1105 fprintf(ddt,"Debug turned ON, Level %d\n",debug);
1106#endif
1107}
1108
1109/*
1110** Catch a special signal to turn off debugging
1111*/
1112
1113SIG_FN
1114setNoDbgFlg()
1115{
1116#if defined(SYSV)
1117 (void)signal(SIGUSR2, setNoDbgFlg);
1118#endif SYSV
1119 setdebug(0);
1120}
1121
1122/*
1123** Set flag for statistics dump
1124*/
1125SIG_FN
1126setstatsflg()
1127{
1128#if defined(SYSV)
1129 (void)signal(SIGIOT, setstatsflg);
1130#endif SYSV
1131 needStatsDump = 1;
1132}
1133
1134SIG_FN
1135setchkptflg()
1136{
1137#if defined(SYSV)
1138 (void)signal(SIGQUIT, setchkptflg);
1139#endif SYSV
1140 needToChkpt = 1;
1141}
1142
1143/*
1144** Catch a special signal SIGSYS
1145**
1146** this is setup to fork and exit to drop to /usr/tmp/gmon.out
1147** and keep the server running
1148*/
1149
1150SIG_FN
1151sigprof()
1152{
1153#if defined(SYSV)
1154 (void)signal(SIGSYS, sigprof);
1155#endif SYSV
1156#ifdef DEBUG
1157 if (debug)
1158 fprintf(ddt,"sigprof()\n");
1159#endif
1160 if ( fork() == 0)
1161 {
1162 (void) chdir(_PATH_TMPDIR);
1163 exit(1);
1164 }
1165}
1166
1167/*
1168** Routines for managing stream queue
1169*/
1170
1171struct qstream *
1172sqadd()
1173{
1174 register struct qstream *sqp;
1175
1176 if ((sqp = (struct qstream *)calloc(1, sizeof(struct qstream)))
1177 == NULL ) {
1178#ifdef DEBUG
1179 if (debug >= 5)
1180 fprintf(ddt,"sqadd: malloc error\n");
1181#endif
1182 syslog(LOG_ERR, "sqadd: Out Of Memory");
1183 return(QSTREAM_NULL);
1184 }
1185#ifdef DEBUG
1186 if (debug > 3)
1187 fprintf(ddt,"sqadd(x%x)\n", sqp);
1188#endif
1189
1190 sqp->s_next = streamq;
1191 streamq = sqp;
1192 return(sqp);
1193}
1194
1195/*
1196 * Remove stream queue structure.
1197 * No current queries may refer to this stream when it is removed.
1198 */
1199sqrm(qp)
1200 register struct qstream *qp;
1201{
1202 register struct qstream *qsp;
1203
1204#ifdef DEBUG
1205 if (debug > 1) {
1206 fprintf(ddt,"sqrm(%#x, %d ) rfcnt=%d\n",
1207 qp, qp->s_rfd, qp->s_refcnt);
1208 }
1209#endif
1210
1211 if (qp->s_bufsize != 0)
1212 (void) free(qp->s_buf);
1213 FD_CLR(qp->s_rfd, &mask);
1214 (void) close(qp->s_rfd);
1215 if (qp == streamq) {
1216 streamq = qp->s_next;
1217 } else {
1218 for (qsp = streamq; qsp->s_next != qp; qsp = qsp->s_next)
1219 ;
1220 qsp->s_next = qp->s_next;
1221 }
1222 (void)free((char *)qp);
1223}
1224
1225sqflush()
1226{
1227 register struct qstream *sp, *spnext;
1228
1229 for (sp = streamq; sp != QSTREAM_NULL; sp = spnext) {
1230 spnext = sp->s_next;
1231 sqrm(sp);
1232 }
1233}
1234
1235/*
1236 * Initiate query on stream;
1237 * mark as referenced and stop selecting for input.
1238 */
1239sq_query(sp)
1240 register struct qstream *sp;
1241{
1242 sp->s_refcnt++;
1243 FD_CLR(sp->s_rfd, &mask);
1244}
1245
1246/*
1247 * Note that the current request on a stream has completed,
1248 * and that we should continue looking for requests on the stream.
1249 */
1250sq_done(sp)
1251 register struct qstream *sp;
1252{
1253
1254 sp->s_refcnt = 0;
1255 sp->s_time = tt.tv_sec;
1256 FD_SET(sp->s_rfd, &mask);
1257}
1258
1259setproctitle(a, s)
1260 char *a;
1261 int s;
1262{
1263 int size;
1264 register char *cp;
1265 struct sockaddr_in sin;
1266 char buf[80];
1267
1268 cp = Argv[0];
1269 size = sizeof(sin);
1270 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1271 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
1272 else {
1273 syslog(LOG_DEBUG, "getpeername: %m");
1274 (void) sprintf(buf, "-%s", a);
1275 }
1276 (void) strncpy(cp, buf, LastArg - cp);
1277 cp += strlen(cp);
1278 while (cp < LastArg)
1279 *cp++ = ' ';
1280}
1281
1282u_long
1283net_mask(in)
1284struct in_addr in;
1285{
1286 register u_long i = ntohl(in.s_addr);
1287
1288 if (IN_CLASSA(i))
1289 return (htonl(IN_CLASSA_NET));
1290 else if (IN_CLASSB(i))
1291 return (htonl(IN_CLASSB_NET));
1292 else
1293 return (htonl(IN_CLASSC_NET));
1294}
1295
1296gettime(ttp)
1297struct timeval *ttp;
1298{
1299 if (gettimeofday(ttp, (struct timezone *)0) < 0)
1300 syslog(LOG_ERR, "gettimeofday failed: %m");
1301 return;
1302}