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