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 mckusick@monet.Berkeley.EDU - 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: }