|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)ns_main.c 4.3 (Berkeley) 5/30/86";
3: #endif
4:
5: /*
6: * Copyright (c) 1986 Regents of the University of California
7: * All Rights Reserved
8: */
9:
10: /*
11: * Internet Name server (see rfc883 & others).
12: */
13:
14: #include <sys/param.h>
15: #include <sys/file.h>
16: #include <sys/time.h>
17: #include <sys/wait.h>
18: #include <sys/resource.h>
19: #include <sys/ioctl.h>
20: #include <sys/socket.h>
21: #include <netinet/in.h>
22: #include <stdio.h>
23: #include <syslog.h>
24: #include <errno.h>
25: #include <signal.h>
26: #include <arpa/nameser.h>
27: #include <arpa/inet.h>
28: #include "ns.h"
29: #include "db.h"
30:
31: #ifdef BOOTFILE /* default boot file */
32: char *bootfile = BOOTFILE;
33: #else
34: char *bootfile = "/etc/named.boot";
35: #endif
36:
37: #ifdef DEBUGFILE /* default debug output file */
38: char *debugfile = DEBUGFILE;
39: #else
40: char *debugfile = "/usr/tmp/named.run";
41: #endif
42:
43: #ifdef PIDFILE /* file to store current named PID */
44: char *PidFile = PIDFILE;
45: #else
46: char *PidFile = "/etc/named.pid";
47: #endif
48:
49: #ifndef FD_SET
50: #define NFDBITS 32
51: #define FD_SETSIZE 32
52: #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
53: #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
54: #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
55: #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
56: #endif
57:
58: FILE *fp; /* file descriptor for pid file */
59:
60: #ifdef DEBUG
61: FILE *ddt;
62: #endif
63:
64: int debug = 0; /* debugging flag */
65: int ds; /* datagram socket */
66: int read_interrupted = 0; /* flag for read timer */
67: int needreload = 0; /* received SIGHUP, need to reload db */
68: int needmaint = 0; /* need to call ns_maint()*/
69: int rbufsize = 8 * 1024; /* UDP recive buffer size */
70:
71: struct qstream *streamq = QSTREAM_NULL; /* list of open streams */
72: struct sockaddr_in nsaddr;
73: struct timeval tt;
74: short ns_port;
75:
76: char **Argv = NULL; /* pointer to argument vector */
77: char *LastArg = NULL; /* end of argv */
78:
79: extern char *malloc(), *realloc(), *calloc();
80:
81: extern int errno;
82:
83:
84:
85: main(argc, argv, envp)
86: int argc;
87: char *argv[], *envp[];
88: {
89: register int n, udpcnt;
90: register char *arg;
91: register struct qstream *sp;
92: int vs, len;
93: int nfds;
94: int on = 1;
95: int rfd, size;
96: u_long lasttime, maxctime;
97: char buf[BUFSIZ];
98:
99: fd_set mask, tmpmask;
100:
101: struct timeval t, *tp;
102: struct sockaddr_in from;
103: struct qstream *candidate = QSTREAM_NULL;
104: extern int onintr(), maint_alarm(), reapchild(), doadump(), onhup();
105: extern int sigsetdebug(), signodebug(), sigprof();
106: extern struct qstream *sqadd();
107: extern char Version[];
108: struct sigvec sv;
109:
110: ns_port = htons(NAMESERVER_PORT);
111:
112: /*
113: ** Save start and extent of argv for setproctitle.
114: */
115:
116: Argv = argv;
117: if (envp == 0 || *envp == 0)
118: envp = argv;
119: while (*envp)
120: envp++;
121: LastArg = envp[-1] + strlen(envp[-1]);
122:
123: while (--argc > 0) {
124: arg = *++argv;
125: if (*arg == '-') {
126: while (*++arg)
127: switch (*arg) {
128: case 'b':
129: if (--argc <= 0)
130: usage();
131: bootfile = *++argv;
132: break;
133:
134: case 'd':
135: ++argv;
136:
137: if (*argv != 0) {
138: if (**argv == '-') {
139: argv--;
140: break;
141: }
142: debug = atoi(*argv);
143: --argc;
144: }
145: if (debug <= 0)
146: debug = 1;
147: setdebug(1);
148: break;
149:
150: case 'p':
151: if (--argc <= 0)
152: usage();
153: ns_port = htons((u_short)atoi(*++argv));
154: break;
155:
156: default:
157: usage();
158: }
159: } else
160: bootfile = *argv;
161: }
162:
163: if (!debug) {
164: if (fork())
165: exit(0);
166: for (n = getdtablesize() - 1; n >= 0; n--)
167: (void) close(n);
168: (void) open("/dev/null", O_RDONLY);
169: (void) dup2(0, 1);
170: (void) dup2(0, 2);
171: n = open("/dev/tty", O_RDWR);
172: if (n > 0) {
173: (void) ioctl(n, TIOCNOTTY, (char *)NULL);
174: (void) close(n);
175: }
176: }
177: #ifdef DEBUG
178: else {
179: fprintf(ddt,"Debug turned ON, Level %d\n",debug);
180: fprintf(ddt,"Version = %s\t",Version);
181: fprintf(ddt,"bootfile = %s\n",bootfile);
182: }
183: #endif
184:
185: #ifdef BSD4_3
186: openlog("named", LOG_PID|LOG_CONS|LOG_NDELAY, LOG_DAEMON);
187: #else
188: openlog("named", LOG_PID);
189: #endif
190:
191: nsaddr.sin_family = AF_INET;
192: nsaddr.sin_addr.s_addr = INADDR_ANY;
193: nsaddr.sin_port = ns_port;
194: /*
195: ** Initialize and load database.
196: */
197: ns_init(bootfile);
198:
199: /* Block signals during maintenance */
200: sv.sv_handler = maint_alarm;
201: sv.sv_onstack = 0;
202: sv.sv_mask = ~0;
203:
204: (void) sigvec(SIGALRM, &sv, (struct sigvec *)0);
205:
206: (void) signal(SIGHUP, onhup);
207: (void) signal(SIGCHLD, reapchild);
208: (void) signal(SIGPIPE, SIG_IGN);
209: (void) signal(SIGSYS, sigprof);
210:
211: #if BSD >= 43
212: /* flames to [email protected] - I lost the battle -KJD */
213: (void) signal(SIGINT, doadump);
214: (void) signal(SIGUSR1, sigsetdebug);
215: (void) signal(SIGUSR2, signodebug);
216: #else BSD
217: (void) signal(SIGQUIT, doadump);
218: (void) signal(SIGEMT, sigsetdebug);
219: (void) signal(SIGFPE, signodebug);
220: #endif BSD
221:
222: #ifdef DEBUG
223: if (debug) {
224: fprintf(ddt,"database initialized\n");
225: }
226: #endif
227: /*
228: ** Open stream port.
229: */
230: if ((vs = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
231: syslog(LOG_ERR, "socket(SOCK_STREAM): %m");
232: exit(1);
233: }
234: (void)setsockopt(vs, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
235: if (bind(vs, &nsaddr, sizeof(nsaddr))) {
236: syslog(LOG_ERR, "bind(vs): %m");
237: exit(1);
238: }
239: (void) listen(vs, 5);
240: /*
241: ** Open datagram port.
242: */
243: if ((ds = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
244: syslog(LOG_ERR, "socket(SOCK_DGRAM): %m");
245: exit(1);
246: }
247: (void)setsockopt(ds, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
248: #ifdef BSD4_3
249: (void)setsockopt(ds, SOL_SOCKET, SO_RCVBUF, (char *)&rbufsize,
250: sizeof(rbufsize));
251: #endif
252: (void) fcntl(ds, F_SETFL, FNDELAY);
253: if (bind(ds, &nsaddr, sizeof(nsaddr))) {
254: syslog(LOG_ERR, "bind(ds): %m");
255: exit(1);
256: }
257: /* tuck my process id away */
258: fp = fopen(PidFile, "w");
259: if (fp != NULL) {
260: fprintf(fp, "%d\n", getpid());
261: (void) fclose(fp);
262: }
263:
264: t.tv_usec = 0;
265:
266: #ifdef DEBUG
267: if (debug)
268: fprintf(ddt,"Ready to answer queries.\n");
269: #endif
270: nfds = getdtablesize(); /* get the number of file descriptors */
271: if (nfds > FD_SETSIZE) {
272: syslog(LOG_ERR, "Return from getdtablesize() > FD_SETSIZE");
273: #ifdef DEBUG
274: if (debug)
275: fprintf(ddt,"Return from getdtablesize() > FD_SETSIZE\n");
276: #endif
277: }
278: FD_ZERO(&mask);
279: FD_SET(vs, &mask);
280: FD_SET(ds, &mask);
281: for (;;) {
282: /*
283: ** Wait until a query arrives; can be interrupted by maintenance
284: */
285: if (retryqp != NULL) {
286: if (gettimeofday(&tt, (struct timezone *)0) < 0)
287: syslog(LOG_ERR, "gettimeofday failed: %m");
288: t.tv_sec = (long) retryqp->q_time - tt.tv_sec;
289: if (t.tv_sec <= 0) {
290: retry(retryqp);
291: continue;
292: }
293: tp = &t;
294: } else
295: tp = NULL;
296: if(needreload) {
297: needreload = 0;
298: db_reload();
299: }
300: if(needmaint) {
301: needmaint = 0;
302: ns_maint();
303: }
304: tmpmask = mask;
305: n = select(nfds, &tmpmask, (fd_set *)NULL, (fd_set *)NULL, tp);
306: if (n < 0) {
307: if (errno == EINTR)
308: continue;
309: syslog(LOG_ERR, "select: %m");
310: break;
311: }
312: if (n == 0) {
313: retry(retryqp);
314: continue;
315: }
316: if (gettimeofday(&tt, (struct timezone *)0) < 0) {
317: syslog(LOG_ERR, "gettimeofday failed: %m");
318: break;
319: }
320: /*
321: ** Process datagram
322: */
323: if (FD_ISSET(ds, &tmpmask))
324: for(udpcnt = 0; udpcnt < 25; udpcnt++) {
325: len = sizeof(from);
326: if ((n = recvfrom(ds, buf, sizeof(buf), 0,
327: &from, &len)) < 0)
328: {
329: if ((n == -1) && (errno == EWOULDBLOCK))
330: break;
331: syslog(LOG_WARNING, "recvfrom: %m");
332: break;
333: }
334: #ifdef DEBUG
335: if (debug)
336: fprintf(ddt,"datagram from %s, %d (%d)\n",
337: inet_ntoa(from.sin_addr),
338: ntohs(from.sin_port), n);
339: if (debug >= 10)
340: fp_query(buf, ddt);
341: #endif
342: /*
343: * Consult database to get the answer.
344: */
345: if (gettimeofday(&tt, (struct timezone *)0) < 0) {
346: syslog(LOG_ERR, "gettimeofday failed: %m");
347: break;
348: }
349: ns_req(buf, n, PACKETSZ, QSTREAM_NULL, &from);
350: }
351: /*
352: ** Process stream connection
353: */
354: if (FD_ISSET(vs, &tmpmask)) {
355: len = sizeof(from);
356: rfd = accept(vs, &from, &len);
357: if (gettimeofday(&tt, (struct timezone *)0) < 0) {
358: syslog(LOG_ERR, "gettimeofday failed: %m");
359: break;
360: }
361: if (rfd < 0) {
362: if (errno == EMFILE) {
363: if (streamq != NULL) {
364: maxctime = 0;
365: candidate = QSTREAM_NULL;
366: for (sp = streamq; sp != QSTREAM_NULL;
367: sp = sp->s_next)
368: {
369: if (sp->s_refcnt != 0)
370: continue;
371: lasttime = tt.tv_sec - sp->s_time;
372: if (lasttime >= 900)
373: sqrm(sp, &tmpmask);
374: else if (lasttime > maxctime) {
375: candidate = sp;
376: maxctime = lasttime;
377: }
378: }
379: rfd = accept(vs, &from, &len);
380: if ((rfd < 0) && (errno == EMFILE))
381: if (candidate != QSTREAM_NULL) {
382: sqrm(candidate, &tmpmask);
383: rfd = accept(vs, &from, &len);
384: if (rfd < 0)
385: syslog(LOG_WARNING,
386: "accept: %m");
387: continue;
388: }
389: } else {
390: syslog(LOG_WARNING, "accept: %m");
391: continue;
392: }
393: } else {
394: syslog(LOG_WARNING, "accept: %m");
395: continue;
396: }
397: }
398: (void) fcntl(rfd, F_SETFL, FNDELAY);
399: (void) setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE,
400: (char *)&on, sizeof(on));
401: if ((sp = sqadd()) == QSTREAM_NULL)
402: (void) close(rfd);
403: sp->s_rfd = rfd; /* stream file descriptor */
404: sp->s_size = -1; /* amount of data to recive */
405: if (gettimeofday(&tt, (struct timezone *)0) < 0) {
406: syslog(LOG_ERR, "gettimeofday failed: %m");
407: break;
408: }
409: sp->s_time = tt.tv_sec; /* last transaction time */
410: sp->s_from = from; /* address to respond to */
411: sp->s_bufsize = 0;
412: sp->s_bufp = (char *)&sp->s_tempsize;
413: sp->s_refcnt = 0;
414: FD_SET(rfd, &mask);
415: FD_SET(rfd, &tmpmask);
416: #ifdef DEBUG
417: if (debug)
418: {
419: fprintf(ddt,"stream from %s, %d (%d)\n",
420: inet_ntoa(sp->s_from.sin_addr),
421: ntohs(sp->s_from.sin_port), n);
422: }
423: #endif
424: }
425: #ifdef DEBUG
426: if (debug > 2)
427: fprintf(ddt,"streamq = x%x\n",streamq);
428: #endif
429: if (streamq != NULL) {
430: for (sp = streamq; sp != QSTREAM_NULL; sp = sp->s_next)
431: if (FD_ISSET(sp->s_rfd, &tmpmask)) {
432: #ifdef DEBUG
433: if (debug > 5) {
434: fprintf(ddt,
435: "sp x%x rfd %d size %d time %d ",
436: sp, sp->s_rfd, sp->s_size,
437: sp->s_time );
438: fprintf(ddt," next x%x \n", sp->s_next );
439: fprintf(ddt,"\tbufsize %d",sp->s_bufsize);
440: fprintf(ddt," buf x%x%d ",sp->s_buf);
441: fprintf(ddt," bufp x%x%d\n",sp->s_bufp);
442: }
443: #endif DEBUG
444: if (sp->s_size < 0) {
445: size = sizeof(u_short) -
446: (sp->s_bufp - (char *)&sp->s_tempsize);
447: while (size > 0 &&
448: (n = read(sp->s_rfd, sp->s_bufp, size)) > 0){
449: sp->s_bufp += n;
450: size -= n;
451: }
452: if ((n == -1) && (errno == EWOULDBLOCK))
453: continue;
454: if (n <= 0) {
455: sp->s_refcnt = 0;
456: sqrm(sp, &mask);
457: continue;
458: }
459: if ((sp->s_bufp - (char *)&sp->s_tempsize) ==
460: sizeof(u_short)) {
461: sp->s_size = htons(sp->s_tempsize);
462: if (sp->s_bufsize == 0) {
463: if ( (sp->s_buf = malloc(BUFSIZ))
464: == NULL) {
465: sp->s_buf = buf;
466: sp->s_size = sizeof(buf);
467: } else {
468: sp->s_bufsize = BUFSIZ;
469: }
470: }
471: if (sp->s_size > sp->s_bufsize &&
472: sp->s_bufsize != 0) {
473: if ((sp->s_buf = realloc(
474: (char *)sp->s_buf,
475: (unsigned)sp->s_size)) == NULL){
476: sp->s_buf = buf;
477: sp->s_bufsize = 0;
478: sp->s_size = sizeof(buf);
479: } else {
480: sp->s_bufsize = sp->s_size;
481: }
482: }
483: sp->s_bufp = sp->s_buf;
484: }
485: }
486: if (gettimeofday(&tt, (struct timezone *)0) < 0) {
487: syslog(LOG_ERR, "gettimeofday failed: %m");
488: break;
489: }
490: sp->s_time = tt.tv_sec;
491: while (sp->s_size > 0 &&
492: (n = read(sp->s_rfd, sp->s_buf, sp->s_size)) > 0)
493: {
494: sp->s_bufp += n;
495: sp->s_size -= n;
496: }
497: /*
498: * we don't have enough memory for the query.
499: * if we have a query id, then we will send an
500: * error back to the user.
501: */
502: if (sp->s_bufsize == 0 &&
503: (sp->s_bufp - sp->s_buf > sizeof(u_short))) {
504: HEADER *hp;
505:
506: hp = (HEADER *)sp->s_buf;
507: hp->qr = 1;
508: hp->ra = 1;
509: hp->ancount = 0;
510: hp->qdcount = 0;
511: hp->nscount = 0;
512: hp->arcount = 0;
513: hp->rcode = SERVFAIL;
514: (void) writemsg(sp->s_rfd, sp->s_buf,
515: sizeof(HEADER));
516: continue;
517: }
518: if ((n == -1) && (errno == EWOULDBLOCK))
519: continue;
520: if (n <= 0) {
521: sp->s_refcnt = 0;
522: sqrm(sp, &mask);
523: continue;
524: }
525: /*
526: * Consult database to get the answer.
527: */
528: if (sp->s_size == 0) {
529: sp->s_refcnt++;
530: ns_req(sp->s_buf,
531: sp->s_bufp - sp->s_buf,
532: sp->s_bufsize, sp,
533: &sp->s_from);
534: sp->s_bufp = (char *)&sp->s_tempsize;
535: sp->s_size = -1;
536: continue;
537: }
538: }
539: }
540: }
541: (void) close(vs);
542: (void) close(ds);
543: return (0);
544: }
545:
546: usage()
547: {
548: fprintf(stderr, "Usage: named [-d #] [-p port] [{-b} bootfile]\n");
549: exit(1);
550: }
551:
552: /*
553: ** Set flag saying to reload database upon receiving SIGHUP.
554: ** Must make sure that someone isn't walking through a data
555: ** structure at the time.
556: */
557:
558: onhup()
559: {
560: needreload = 1;
561: }
562:
563: /*
564: ** Set flag saying to call ns_maint()
565: ** Must make sure that someone isn't walking through a data
566: ** structure at the time.
567: */
568:
569: maint_alarm()
570: {
571: needmaint = 1;
572: }
573:
574: /*
575: ** Set flag saying to read was interrupted
576: ** used for a read timer
577: */
578:
579: read_alarm()
580: {
581: extern int read_interrupted;
582: read_interrupted = 1;
583: }
584:
585: reapchild()
586: {
587: union wait status;
588:
589: while (wait3(&status, WNOHANG, (struct rusage *)NULL) > 0)
590: ;
591: }
592:
593: /*
594: ** Turn on or off debuging by open or closeing the debug file
595: */
596:
597: setdebug(code)
598: int code;
599: {
600: #if defined(lint) && !defined(DEBUG)
601: code = code;
602: #endif
603: #ifdef DEBUG
604:
605: if (code) {
606: ddt = freopen(debugfile, "w+", stderr);
607: if ( ddt == NULL)
608: syslog(LOG_WARNING, "can't open debug file: %m");
609: else
610: setlinebuf(ddt);
611: }
612: else {
613: fprintf(ddt,"Debug turned OFF, Level %d\n",debug);
614: (void) fclose(ddt);
615: debug = 0;
616: }
617: #endif
618: }
619:
620: /*
621: ** Catch a special signal SIGEMT and set debug level
622: **
623: ** SIGEMT - if debuging is off then turn on debuging else incremnt the level
624: **
625: ** Handy for looking in on long running name servers.
626: */
627:
628: sigsetdebug()
629: {
630:
631: #ifdef DEBUG
632: if (debug == 0) {
633: debug++;
634: setdebug(1);
635: }
636: else {
637: debug++;
638: }
639: fprintf(ddt,"Debug turned ON, Level %d\n",debug);
640: #endif
641: }
642:
643: /*
644: ** Catch a special signal's SIGFPE and turn off debugging
645: **
646: ** SIGFPE - turn off debugging
647: */
648:
649: signodebug()
650: {
651: setdebug(0);
652: }
653:
654:
655: /*
656: ** Catch a special signal SIGSYS
657: **
658: ** this is setup to fork and exit to drop to /usr/tmp/gmon.out
659: ** and keep the server running
660: */
661:
662: sigprof()
663: {
664: #ifdef DEBUG
665: if (debug)
666: fprintf(ddt,"sigprof()\n");
667: #endif
668: if ( fork() == 0)
669: {
670: (void) chdir("/usr/tmp");
671: exit(1);
672: }
673: }
674:
675: /*
676: ** Routines for managing stream queue
677: */
678:
679: struct qstream *
680: sqadd()
681: {
682: register struct qstream *sqp;
683:
684: if ((sqp = (struct qstream *)calloc(1, sizeof(struct qstream)))
685: == NULL ) {
686: #ifdef DEBUG
687: if (debug >= 5)
688: fprintf(ddt,"sqadd: malloc error\n");
689: #endif
690: syslog(LOG_ERR, "sqadd: Out Of Memory");
691: return(QSTREAM_NULL);
692: }
693: #ifdef DEBUG
694: if (debug > 3)
695: fprintf(ddt,"sqadd(x%x)\n", sqp);
696: #endif
697:
698: sqp->s_next = streamq;
699: streamq = sqp;
700: return(sqp);
701: }
702:
703: sqrm(qp, mask)
704: register struct qstream *qp;
705: fd_set *mask;
706: {
707: register struct qstream *qsp;
708:
709: #ifdef DEBUG
710: if (debug > 1) {
711: fprintf(ddt,"sqrm(%#x, %d ) rfcnt=%d\n",
712: qp, qp->s_rfd, qp->s_refcnt);
713: }
714: #endif
715: if (qp->s_refcnt != 0)
716: return;
717:
718: if (qp->s_bufsize != 0)
719: (void) free(qp->s_buf);
720: FD_CLR(qp->s_rfd, mask);
721: (void) close(qp->s_rfd);
722: if (qp == streamq) {
723: streamq = qp->s_next;
724: } else {
725: for (qsp = streamq; qsp->s_next != qp; qsp = qsp->s_next)
726: ;
727: qsp->s_next = qp->s_next;
728: }
729: (void)free((char *)qp);
730: }
731:
732: setproctitle(a, s)
733: char *a;
734: int s;
735: {
736: int size;
737: register char *cp;
738: struct sockaddr_in sin;
739: char buf[80];
740:
741: cp = Argv[0];
742: size = sizeof(sin);
743: if (getpeername(s, &sin, &size) == 0)
744: (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
745: else
746: (void) sprintf(buf, "-%s", a);
747: (void) strncpy(cp, buf, LastArg - cp);
748: cp += strlen(cp);
749: while (cp < LastArg)
750: *cp++ = ' ';
751: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.