summaryrefslogtreecommitdiffstats
path: root/contrib/bind/named/ns_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/named/ns_main.c')
-rw-r--r--contrib/bind/named/ns_main.c1669
1 files changed, 1669 insertions, 0 deletions
diff --git a/contrib/bind/named/ns_main.c b/contrib/bind/named/ns_main.c
new file mode 100644
index 0000000..bac7d5a
--- /dev/null
+++ b/contrib/bind/named/ns_main.c
@@ -0,0 +1,1669 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91";
+static char rcsid[] = "$Id: ns_main.c,v 8.17 1996/08/05 08:31:30 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1989, 1990
+ * -
+ * Copyright (c) 1986, 1989, 1990
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if !defined(lint) && !defined(SABER)
+char copyright[] =
+"@(#) Copyright (c) 1986, 1989, 1990 The Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ portions Copyright (c) 1995 Internet Software Consortium\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Internet Name server (see RCF1035 & others).
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#if !defined(SYSV) && defined(XXX)
+#include <sys/wait.h>
+#endif /* !SYSV */
+#if defined(__osf__)
+# define _SOCKADDR_LEN /* XXX - should be in portability.h but that
+ * would need to be included before socket.h
+ */
+#endif
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#if defined(__osf__)
+# include <sys/mbuf.h>
+# include <net/route.h>
+#endif
+#if defined(_AIX)
+# include <sys/time.h>
+# define TIME_H_INCLUDED
+#endif
+#include <net/if.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+#include <signal.h>
+#include <netdb.h>
+#include <resolv.h>
+#if defined(SVR4)
+# include <sys/sockio.h>
+#endif
+
+#define MAIN_PROGRAM
+#include "named.h"
+#undef MAIN_PROGRAM
+
+#undef nsaddr
+
+ /* UDP receive, TCP send buffer size */
+static const int rbufsize = 8 * 1024,
+ /* TCP send window size */
+ sbufsize = 16 * 1024;
+
+static struct sockaddr_in nsaddr;
+static u_int16_t local_ns_port, /* our service port */
+ nsid_state;
+static fd_set mask; /* open descriptors */
+static char **Argv = NULL;
+static char *LastArg = NULL; /* end of argv */
+
+static struct qstream *sqadd __P((void));
+static void sq_query __P((struct qstream *)),
+ opensocket __P((struct qdatagram *)),
+#ifdef DEBUG
+ printnetinfo __P((struct netinfo *)),
+#endif
+ setdebug __P((int));
+static int sq_here __P((struct qstream *));
+
+static SIG_FN onintr __P(()),
+ maint_alarm __P(()),
+ setdumpflg __P(()),
+ onhup __P(()),
+#if defined(QRYLOG) && defined(SIGWINCH)
+ setQrylogFlg __P(()),
+#endif
+ setIncrDbgFlg __P(()),
+ setNoDbgFlg __P(()),
+#ifdef SIGSYS
+ sigprof __P(()),
+#endif /* SIGSYS */
+ setchkptflg __P(()),
+ setstatsflg __P(());
+
+static void
+usage()
+{
+ fprintf(stderr,
+"Usage: named [-d #] [-q] [-r] [-p port[/localport]] [[-b] bootfile]\n");
+ exit(1);
+}
+
+/*ARGSUSED*/
+void
+main(argc, argv, envp)
+ int argc;
+ char *argv[], *envp[];
+{
+ register int n, udpcnt;
+ register char *arg;
+ register struct qstream *sp;
+ register struct qdatagram *dqp;
+ struct qstream *nextsp;
+ int nfds;
+ const int on = 1;
+ int rfd, size, len;
+ time_t lasttime, maxctime;
+ u_char buf[BUFSIZ];
+#ifdef POSIX_SIGNALS
+ struct sigaction sact;
+#else
+#ifndef SYSV
+ struct sigvec vec;
+#endif
+#endif
+#ifdef NeXT
+ int old_sigmask;
+#endif
+ fd_set tmpmask;
+ struct timeval t, *tp;
+ struct qstream *candidate = QSTREAM_NULL;
+ char **argp;
+#ifdef PID_FIX
+ char oldpid[10];
+#endif
+#ifdef WANT_PIDFILE
+ FILE *fp; /* file descriptor for pid file */
+#endif
+#ifdef IP_OPTIONS
+ u_char ip_opts[50]; /* arbitrary size */
+#endif
+
+ local_ns_port = ns_port = htons(NAMESERVER_PORT);
+
+ /* BSD has a better random number generator but it's not clear
+ * that we need it here.
+ */
+ gettime(&tt);
+ srand(((unsigned)getpid()) + (unsigned)tt.tv_usec);
+
+ /*
+ ** Save start and extent of argv for ns_setproctitle().
+ */
+
+ Argv = argp = argv;
+ while (*argp)
+ argp++;
+ LastArg = argp[-1] + strlen(argp[-1]);
+
+ (void) umask(022);
+ /* XXX - should use getopt here */
+ while (--argc > 0) {
+ arg = *++argv;
+ if (*arg == '-') {
+ while (*++arg)
+ switch (*arg) {
+ case 'b':
+ if (--argc <= 0)
+ usage();
+ bootfile = savestr(*++argv);
+ break;
+
+ case 'd':
+ ++argv;
+
+ if (*argv != 0) {
+ if (**argv == '-') {
+ argv--;
+ break;
+ }
+#ifdef DEBUG
+ debug = atoi(*argv);
+#endif
+ --argc;
+ }
+#ifdef DEBUG
+ if (debug <= 0)
+ debug = 1;
+ setdebug(1);
+#endif
+ break;
+
+ case 'p':
+ /* use nonstandard port number.
+ * usage: -p remote/local
+ * remote is the port number to which
+ * we send queries. local is the port
+ * on which we listen for queries.
+ * local defaults to same as remote.
+ */
+ if (--argc <= 0)
+ usage();
+ ns_port = htons((u_int16_t)
+ atoi(*++argv));
+ {
+ char *p = strchr(*argv, '/');
+ if (p) {
+ local_ns_port =
+ htons((u_int16_t)
+ atoi(p+1));
+ } else {
+ local_ns_port = ns_port;
+ }
+ }
+ break;
+
+#ifdef QRYLOG
+ case 'q':
+ qrylog = 1;
+ break;
+#endif
+
+ case 'r':
+ NoRecurse = 1;
+ break;
+
+ default:
+ usage();
+ }
+ } else
+ bootfile = savestr(*argv);
+ }
+
+#ifdef DEBUG
+ if (!debug)
+#endif
+ for (n = getdtablesize() - 1; n > 2; n--)
+ (void) close(n); /* don't use my_close() here */
+#ifdef DEBUG
+ else {
+ fprintf(ddt, "Debug turned ON, Level %d\n",debug);
+ fprintf(ddt, "Version = %s\n", Version);
+ fprintf(ddt, "bootfile = %s\n", bootfile);
+ }
+#endif
+
+ n = 0;
+#if defined(DEBUG) && defined(LOG_PERROR)
+ if (debug)
+ n = LOG_PERROR;
+#endif
+#ifdef LOG_DAEMON
+ openlog("named", LOG_PID|LOG_CONS|LOG_NDELAY|n, LOGFAC);
+#else
+ openlog("named", LOG_PID);
+#endif
+
+#ifdef WANT_PIDFILE
+ /* tuck my process id away */
+#ifdef PID_FIX
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ (void) fgets(oldpid, sizeof(oldpid), fp);
+ (void) rewind(fp);
+ fprintf(fp, "%ld\n", (long)getpid());
+ (void) my_fclose(fp);
+ }
+#else /*PID_FIX*/
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) my_fclose(fp);
+ }
+#endif /*PID_FIX*/
+#endif /*WANT_PIDFILE*/
+
+ syslog(LOG_NOTICE, "starting. %s", Version);
+
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+
+ nsaddr.sin_family = AF_INET;
+ nsaddr.sin_addr.s_addr = INADDR_ANY;
+ nsaddr.sin_port = local_ns_port;
+ nsid_init();
+
+ /*
+ ** Open stream port.
+ */
+ for (n = 0; ; n++) {
+ if ((vs = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket(SOCK_STREAM): %m");
+ exit(1);
+ }
+ if (setsockopt(vs, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+ sizeof(on)) != 0)
+ {
+ syslog(LOG_NOTICE, "setsockopt(vs, reuseaddr): %m");
+ (void) my_close(vs);
+ continue;
+ }
+ if (bind(vs, (struct sockaddr *)&nsaddr, sizeof(nsaddr)) == 0)
+ break;
+
+ if (errno != EADDRINUSE || n > 4) {
+ if (errno == EADDRINUSE) {
+ syslog(LOG_NOTICE,
+ "There may be a name server already running");
+ syslog(LOG_ERR, "exiting");
+ } else {
+ syslog(LOG_ERR, "bind(vs, [%s].%d): %m",
+ inet_ntoa(nsaddr.sin_addr),
+ ntohs(nsaddr.sin_port));
+ }
+#if defined(WANT_PIDFILE) && defined(PID_FIX)
+ /* put old pid back */
+ if (atoi(oldpid) && (fp = fopen(PidFile, "w"))) {
+ fprintf(fp, "%s", oldpid);
+ (void) my_fclose(fp);
+ _exit(1);
+ }
+#endif /*WANT_PIDFILE && PID_FIX*/
+ exit(1);
+ }
+ /* Retry opening the socket a few times */
+ my_close(vs);
+ sleep(3);
+ }
+ if (listen(vs, 5) != 0) {
+ syslog(LOG_ERR, "listen(vs, 5): %m");
+ exit(1);
+ }
+
+ /*
+ * named would be terminated if one of these is sent and no handler.
+ */
+ setsignal(SIGINT, -1, setdumpflg);
+ setsignal(SIGQUIT, -1, setchkptflg);
+ setsignal(SIGIOT, -1, setstatsflg);
+ setsignal(SIGUSR1, -1, setIncrDbgFlg);
+ setsignal(SIGUSR2, -1, setNoDbgFlg);
+
+#if defined(SIGWINCH) && defined(QRYLOG)
+ setsignal(SIGWINCH, -1, setQrylogFlg);
+#endif
+
+ /*
+ * Get list of local addresses and set up datagram sockets.
+ */
+ FD_ZERO(&mask);
+ FD_SET(vs, &mask);
+ getnetconf();
+
+ /*
+ ** Initialize and load database.
+ */
+ gettime(&tt);
+ buildservicelist();
+ buildprotolist();
+ ns_init(bootfile);
+#ifdef DEBUG
+ if (debug) {
+ fprintf(ddt, "Network and sort list:\n");
+ printnetinfo(nettab);
+ }
+#endif
+
+ time(&boottime);
+ resettime = boottime;
+
+ setsignal(SIGALRM, SIGCHLD, maint_alarm);
+ setsignal(SIGCHLD, SIGALRM, reapchild);
+ setsignal(SIGPIPE, -1, (SIG_FN (*)())SIG_IGN);
+ setsignal(SIGHUP, -1, onhup);
+
+#if defined(SIGXFSZ)
+ /* Wierd DEC Hesiodism, harmless. */
+ setsignal(SIGXFSZ, -1, onhup);
+#endif
+
+#ifdef SIGSYS
+ setsignal(SIGSYS, -1, sigprof);
+#endif /* SIGSYS */
+
+#ifdef ALLOW_UPDATES
+ /* Catch SIGTERM so we can dump the database upon shutdown if it
+ has changed since it was last dumped/booted */
+ setsignal(SIGTERM, -1, onintr);
+#endif
+
+#ifdef XSTATS
+ /* Catch SIGTERM so we can write stats before exiting. */
+ setsignal(SIGTERM, -1, onintr);
+#endif
+
+ dprintf(1, (ddt, "database initialized\n"));
+ t.tv_usec = 0;
+
+ /*
+ * Fork and go into background now that
+ * we've done any slow initialization
+ * and are ready to answer queries.
+ */
+#ifdef USE_SETSID
+ if (
+#ifdef DEBUG
+ !debug ||
+#endif
+ !isatty(0)) {
+ if (fork() > 0)
+ exit(0);
+ setsid();
+#ifdef DEBUG
+ if (!debug)
+#endif
+ {
+ n = open(_PATH_DEVNULL, O_RDONLY);
+ (void) dup2(n, 0);
+ (void) dup2(n, 1);
+ (void) dup2(n, 2);
+ if (n > 2)
+ (void) my_close(n);
+ }
+ }
+#else
+#ifdef DEBUG
+ if (!debug)
+#endif
+ {
+#ifdef HAVE_DAEMON
+ daemon(1, 0);
+#else
+ switch (fork()) {
+ case -1:
+ syslog(LOG_ERR, "fork: %m");
+ exit(1);
+ /*FALLTHROUGH*/
+ case 0:
+ /* child */
+ break;
+ default:
+ /* parent */
+ exit(0);
+ }
+ n = open(_PATH_DEVNULL, O_RDONLY);
+ (void) dup2(n, 0);
+ (void) dup2(n, 1);
+ (void) dup2(n, 2);
+ if (n > 2)
+ (void) my_close(n);
+#if defined(SYSV) || defined(hpux)
+ setpgrp();
+#else
+ {
+ struct itimerval ival;
+
+ /*
+ * The open below may hang on pseudo ttys if the person
+ * who starts named logs out before this point.
+ *
+ * needmaint may get set inapropriately if the open
+ * hangs, but all that will happen is we will see that
+ * no maintenance is required.
+ */
+ bzero((char *)&ival, sizeof(ival));
+ ival.it_value.tv_sec = 120;
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+ n = open(_PATH_TTY, O_RDWR);
+ ival.it_value.tv_sec = 0;
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+ if (n > 0) {
+ (void) ioctl(n, TIOCNOTTY, (char *)NULL);
+ (void) my_close(n);
+ }
+ }
+#endif /* SYSV */
+#endif /* HAVE_DAEMON */
+ }
+#endif /* USE_SETSID */
+#ifdef WANT_PIDFILE
+ /* tuck my process id away again */
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%ld\n", (long)getpid());
+ (void) my_fclose(fp);
+ }
+#endif
+
+ syslog(LOG_NOTICE, "Ready to answer queries.\n");
+ prime_cache();
+ nfds = getdtablesize(); /* get the number of file descriptors */
+ if (nfds > FD_SETSIZE) {
+ nfds = FD_SETSIZE; /* Bulletproofing */
+ syslog(LOG_NOTICE, "Return from getdtablesize() > FD_SETSIZE");
+ }
+#ifdef NeXT
+ old_sigmask = sigblock(sigmask(SIGCHLD));
+#endif
+ for (;;) {
+#ifdef DEBUG
+ if (ddt && debug == 0) {
+ fprintf(ddt,"Debug turned OFF\n");
+ (void) my_fclose(ddt);
+ ddt = 0;
+ }
+#endif
+#ifdef ALLOW_UPDATES
+ if (needToExit) {
+ struct zoneinfo *zp;
+ sigblock(~0); /*
+ * Block all blockable signals
+ * to ensure a consistant
+ * state during final dump
+ */
+ dprintf(1, (ddt, "Received shutdown signal\n"));
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->z_flags & Z_CHANGED)
+ zonedump(zp);
+ }
+ exit(0);
+ }
+#endif /* ALLOW_UPDATES */
+#ifdef XSTATS
+ if (needToExit) {
+ ns_logstats();
+ exit(0);
+ }
+#endif /* XSTATS */
+ if (needreload) {
+ needreload = 0;
+ db_reload();
+ }
+ if (needStatsDump) {
+ needStatsDump = 0;
+ ns_stats();
+ }
+ if (needendxfer) {
+ holdsigchld();
+ needendxfer = 0; /* should be safe even if not held */
+ endxfer(); /* releases SIGCHLD */
+ }
+ releasesigchld();
+ if (needzoneload) {
+ needzoneload = 0;
+ loadxfer();
+ }
+ if (needmaint) {
+ needmaint = 0;
+ ns_maint();
+ }
+ if(needToChkpt) {
+ needToChkpt = 0;
+ doachkpt();
+ }
+ if(needToDoadump) {
+ needToDoadump = 0;
+ doadump();
+ }
+ /*
+ ** Wait until a query arrives
+ */
+ if (retryqp != NULL) {
+ gettime(&tt);
+ /*
+ ** The tv_sec field might be unsigned
+ ** and thus cannot be negative.
+ */
+ if ((int32_t) retryqp->q_time <= tt.tv_sec) {
+ retry(retryqp);
+ continue;
+ }
+ t.tv_sec = (int32_t) retryqp->q_time - tt.tv_sec;
+ tp = &t;
+ } else
+ tp = NULL;
+ tmpmask = mask;
+#ifdef NeXT
+ sigsetmask(old_sigmask); /* Let queued signals run. */
+#endif
+ n = select(nfds, &tmpmask, (fd_set *)NULL, (fd_set *)NULL, tp);
+#ifdef NeXT
+ old_sigmask = sigblock(sigmask(SIGCHLD));
+#endif
+ if (n < 0 && errno != EINTR) {
+ syslog(LOG_ERR, "select: %m");
+ sleep(60);
+ }
+ if (n <= 0)
+ continue;
+
+ for (dqp = datagramq;
+ dqp != QDATAGRAM_NULL;
+ dqp = dqp->dq_next) {
+ if (FD_ISSET(dqp->dq_dfd, &tmpmask))
+ for (udpcnt = 0; udpcnt < 42; udpcnt++) { /*XXX*/
+ int from_len = sizeof(from_addr);
+
+ if ((n = recvfrom(dqp->dq_dfd, (char *)buf,
+ MIN(PACKETSZ, sizeof buf), 0,
+ (struct sockaddr *)&from_addr, &from_len)) < 0)
+ {
+#if defined(SPURIOUS_ECONNREFUSED)
+ if ((n < 0) && (errno == ECONNREFUSED))
+ break;
+#endif
+ if ((n < 0) && (errno == PORT_WOULDBLK))
+ break;
+ syslog(LOG_INFO, "recvfrom: %m");
+ break;
+ }
+ if (n == 0)
+ break;
+ gettime(&tt);
+ dprintf(1, (ddt,
+ "\ndatagram from [%s].%d, fd %d, len %d; now %s",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ dqp->dq_dfd, n,
+ ctimel(tt.tv_sec)));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_nquery(buf, n, ddt);
+#endif
+ /*
+ * Consult database to get the answer.
+ */
+ gettime(&tt);
+ ns_req(buf, n, PACKETSZ, QSTREAM_NULL, &from_addr,
+ dqp->dq_dfd);
+ }
+ }
+ /*
+ ** Process stream connection.
+ **
+ ** Note that a "continue" in here takes us back to the select()
+ ** which, if our accept() failed, will bring us back here.
+ */
+ if (FD_ISSET(vs, &tmpmask)) {
+ int from_len = sizeof(from_addr);
+
+ rfd = accept(vs,
+ (struct sockaddr *)&from_addr,
+ &from_len);
+ if (rfd < 0 && errno == EINTR)
+ continue;
+ if (rfd < 0 && errno == EMFILE && streamq) {
+ maxctime = 0;
+ candidate = NULL;
+ for (sp = streamq; sp; sp = nextsp) {
+ nextsp = sp->s_next;
+ if (sp->s_refcnt)
+ continue;
+ gettime(&tt);
+ lasttime = tt.tv_sec - sp->s_time;
+ if (lasttime >= VQEXPIRY)
+ sqrm(sp);
+ else if (lasttime > maxctime) {
+ candidate = sp;
+ maxctime = lasttime;
+ }
+ }
+ if (candidate)
+ sqrm(candidate);
+ continue;
+ }
+ if (rfd < 0) {
+ syslog(LOG_INFO, "accept: %m");
+ continue;
+ }
+ if ((n = fcntl(rfd, F_GETFL, 0)) < 0) {
+ syslog(LOG_INFO, "fcntl(rfd, F_GETFL): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) != 0) {
+ syslog(LOG_INFO, "fcntl(rfd, NONBLOCK): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+#if defined(IP_OPTIONS)
+ len = sizeof ip_opts;
+ if (getsockopt(rfd, IPPROTO_IP, IP_OPTIONS,
+ (char *)ip_opts, &len) < 0) {
+ syslog(LOG_INFO,
+ "getsockopt(rfd, IP_OPTIONS): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if (len != 0) {
+ nameserIncr(from_addr.sin_addr, nssRcvdOpts);
+ if (!haveComplained((char*)
+ from_addr.sin_addr.s_addr,
+ "rcvd ip options")) {
+ syslog(LOG_INFO,
+ "rcvd IP_OPTIONS from [%s].%d (ignored)",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port));
+ }
+ if (setsockopt(rfd, IPPROTO_IP, IP_OPTIONS,
+ NULL, 0) < 0) {
+ syslog(LOG_INFO,
+ "setsockopt(!IP_OPTIONS): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ }
+#endif
+ if (setsockopt(rfd, SOL_SOCKET, SO_SNDBUF,
+ (char*)&sbufsize, sizeof(sbufsize)) < 0){
+ syslog(LOG_INFO,
+ "setsockopt(rfd, SO_SNDBUF, %d): %m",
+ sbufsize);
+ (void) my_close(rfd);
+ continue;
+ }
+ if (setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof(on)) < 0) {
+ syslog(LOG_INFO,
+ "setsockopt(rfd, KEEPALIVE): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if ((sp = sqadd()) == QSTREAM_NULL) {
+ (void) my_close(rfd);
+ continue;
+ }
+ sp->s_rfd = rfd; /* stream file descriptor */
+ sp->s_size = -1; /* amount of data to receive */
+ gettime(&tt);
+ sp->s_time = tt.tv_sec; /* last transaction time */
+ sp->s_from = from_addr; /* address to respond to */
+ sp->s_bufp = (u_char *)&sp->s_tempsize;
+ FD_SET(rfd, &mask);
+ FD_SET(rfd, &tmpmask);
+ dprintf(1, (ddt,
+ "\nTCP connection from [%s].%d (fd %d)\n",
+ inet_ntoa(sp->s_from.sin_addr),
+ ntohs(sp->s_from.sin_port), rfd));
+ }
+ if (streamq)
+ dprintf(3, (ddt, "streamq = 0x%lx\n",
+ (u_long)streamq));
+ for (sp = streamq; sp != QSTREAM_NULL; sp = nextsp) {
+ nextsp = sp->s_next;
+ if (!FD_ISSET(sp->s_rfd, &tmpmask))
+ continue;
+ dprintf(5, (ddt,
+ "sp x%lx rfd %d size %d time %d next x%lx\n",
+ (u_long)sp, sp->s_rfd, sp->s_size,
+ sp->s_time, (u_long)sp->s_next));
+ dprintf(5, (ddt,
+ "\tbufsize %d buf x%lx bufp x%lx\n",
+ sp->s_bufsize,
+ (u_long)sp->s_buf, (u_long)sp->s_bufp));
+ if (sp->s_size < 0) {
+ size = INT16SZ
+ - (sp->s_bufp - (u_char *)&sp->s_tempsize);
+ while (size > 0 &&
+ (n = read(sp->s_rfd, sp->s_bufp, size)) > 0
+ ) {
+ sp->s_bufp += n;
+ size -= n;
+ }
+ if ((n < 0) && (errno == PORT_WOULDBLK))
+ continue;
+ if (n <= 0) {
+ sqrm(sp);
+ continue;
+ }
+ if ((sp->s_bufp - (u_char *)&sp->s_tempsize) ==
+ INT16SZ) {
+ sp->s_size = ntohs(sp->s_tempsize);
+ if (sp->s_bufsize == 0) {
+ if (!(sp->s_buf = (u_char *)
+ malloc(rbufsize))
+ ) {
+ sp->s_buf = buf;
+ sp->s_size = sizeof(buf);
+ } else {
+ sp->s_bufsize = rbufsize;
+ }
+ }
+ if (sp->s_size > sp->s_bufsize &&
+ sp->s_bufsize != 0
+ ) {
+ sp->s_buf = (u_char *)
+ realloc((char *)sp->s_buf,
+ (unsigned)sp->s_size);
+ if (sp->s_buf == NULL) {
+ sp->s_buf = buf;
+ sp->s_bufsize = 0;
+ sp->s_size = sizeof(buf);
+ } else {
+ sp->s_bufsize = sp->s_size;
+ }
+ }
+ sp->s_bufp = sp->s_buf;
+ }
+ }
+ gettime(&tt);
+ sp->s_time = tt.tv_sec;
+ while (sp->s_size > 0 &&
+ (n = read(sp->s_rfd,
+ sp->s_bufp,
+ sp->s_size)
+ ) > 0
+ ) {
+ sp->s_bufp += n;
+ sp->s_size -= n;
+ }
+ /*
+ * we don't have enough memory for the query.
+ * if we have a query id, then we will send an
+ * error back to the user.
+ */
+ if (sp->s_bufsize == 0 &&
+ (sp->s_bufp - sp->s_buf > INT16SZ)) {
+ HEADER *hp;
+
+ hp = (HEADER *)sp->s_buf;
+ hp->qr = 1;
+ hp->ra = (NoRecurse == 0);
+ hp->ancount = 0;
+ hp->qdcount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = SERVFAIL;
+ (void) writemsg(sp->s_rfd, sp->s_buf,
+ HFIXEDSZ);
+ continue;
+ }
+ if ((n == -1) && (errno == PORT_WOULDBLK))
+ continue;
+ if (n <= 0) {
+ sqrm(sp);
+ continue;
+ }
+ /*
+ * Consult database to get the answer.
+ */
+ if (sp->s_size == 0) {
+#ifdef XSTATS
+ nameserIncr(sp->s_from.sin_addr, nssRcvdTCP);
+#endif
+ sq_query(sp);
+ ns_req(sp->s_buf,
+ sp->s_bufp - sp->s_buf,
+ sp->s_bufsize, sp,
+ &sp->s_from, -1);
+ /* ns_req() can call sqrm() - check for it */
+ if (sq_here(sp)) {
+ sp->s_bufp = (u_char *)&sp->s_tempsize;
+ sp->s_size = -1;
+ }
+ continue;
+ }
+ }
+ }
+ /* NOTREACHED */
+}
+
+void
+getnetconf()
+{
+ register struct netinfo *ntp;
+ struct netinfo *ontp;
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ struct qdatagram *dqp;
+ static int first = 1;
+ char buf[32768], *cp, *cplim;
+ u_int32_t nm;
+ time_t my_generation = time(NULL);
+
+ ifc.ifc_len = sizeof buf;
+ ifc.ifc_buf = buf;
+ if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) {
+ syslog(LOG_ERR, "get interface configuration: %m - exiting");
+ exit(1);
+ }
+ ntp = NULL;
+#if defined(AF_LINK) && !defined(RISCOS_BSD) && !defined(M_UNIX)
+#define my_max(a, b) (a > b ? a : b)
+#define my_size(p) my_max((p).sa_len, sizeof(p))
+#else
+#define my_size(p) (sizeof (p))
+#endif
+ cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */
+ for (cp = buf;
+ cp < cplim;
+ cp += sizeof (ifr->ifr_name) + my_size(ifr->ifr_addr)) {
+#undef my_size
+ ifr = (struct ifreq *)cp;
+ if (ifr->ifr_addr.sa_family != AF_INET ||
+ ((struct sockaddr_in *)
+ &ifr->ifr_addr)->sin_addr.s_addr == 0) {
+ continue;
+ }
+ ifreq = *ifr;
+ /*
+ * Don't test IFF_UP, packets may still be received at this
+ * address if any other interface is up.
+ */
+#if !defined(BSD) || (BSD < 199103)
+ if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_NOTICE, "get interface addr: %m");
+ continue;
+ }
+#endif
+ dprintf(1, (ddt, "considering [%s]\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr)));
+ /* build datagram queue */
+ /*
+ * look for an already existing source interface address.
+ * This happens mostly when reinitializing. Also, if
+ * the machine has multiple point to point interfaces, then
+ * the local address may appear more than once.
+ */
+ if (dqp = aIsUs(((struct sockaddr_in *)&ifreq.ifr_addr)
+ ->sin_addr)) {
+ dprintf(1, (ddt,
+ "dup interface address %s on %s\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr),
+ ifreq.ifr_name));
+ dqp->dq_gen = my_generation;
+ continue;
+ }
+
+ /*
+ * Skip over address 0.0.0.0 since this will conflict
+ * with binding to wildcard address later. Interfaces
+ * which are not completely configured can have this addr.
+ */
+ if (((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr
+ == 0x00000000) { /* XXX */
+ dprintf(1, (ddt, "skipping address 0.0.0.0 on %s\n",
+ ifreq.ifr_name));
+ continue;
+ }
+ if ((dqp = (struct qdatagram *)
+ calloc(1, sizeof(struct qdatagram))
+ ) == NULL) {
+ syslog(LOG_ERR, "getnetconf: malloc: %m");
+ exit(12);
+ }
+ dqp->dq_next = datagramq;
+ datagramq = dqp;
+ dqp->dq_addr = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr;
+ dqp->dq_gen = my_generation;
+ opensocket(dqp);
+ dprintf(1, (ddt, "listening [%s]\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr)));
+
+ /*
+ * Add interface to list of directly-attached (sub)nets
+ * for use in sorting addresses.
+ */
+ if (ntp == NULL) {
+ ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ if (!ntp)
+ panic(errno, "malloc(netinfo)");
+ }
+ ntp->my_addr = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr;
+#ifdef SIOCGIFNETMASK
+ if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ syslog(LOG_NOTICE, "get netmask: %m");
+ ntp->mask = net_mask(ntp->my_addr);
+ } else
+ ntp->mask = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+#else
+ /* 4.2 does not support subnets */
+ ntp->mask = net_mask(ntp->my_addr);
+#endif
+ if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+ syslog(LOG_NOTICE, "get interface flags: %m");
+ continue;
+ }
+#ifdef IFF_LOOPBACK
+ if (ifreq.ifr_flags & IFF_LOOPBACK)
+#else
+ /* test against 127.0.0.1 (yuck!!) */
+ if (ntp->my_addr.s_addr == inet_addr("127.0.0.1")) /* XXX */
+#endif
+ {
+ if (netloop.my_addr.s_addr == 0) {
+ netloop.my_addr = ntp->my_addr;
+ netloop.mask = 0xffffffff;
+ netloop.addr = ntp->my_addr.s_addr;
+ dprintf(1, (ddt, "loopback address: x%lx\n",
+ (u_long)netloop.my_addr.s_addr));
+ }
+ continue;
+ } else if ((ifreq.ifr_flags & IFF_POINTOPOINT)) {
+ if (ioctl(vs, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_NOTICE, "get dst addr: %m");
+ continue;
+ }
+ ntp->mask = 0xffffffff;
+ ntp->addr = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+ } else {
+ ntp->addr = ntp->mask & ntp->my_addr.s_addr;
+ }
+ /*
+ * Place on end of list of locally-attached (sub)nets,
+ * but before logical nets for subnetted nets.
+ */
+ ntp->next = *elocal;
+ *elocal = ntp;
+ if (elocal == enettab)
+ enettab = &ntp->next;
+ elocal = &ntp->next;
+ ntp = NULL;
+ }
+ if (ntp)
+ free((char *)ntp);
+
+ /*
+ * now go through the datagramq and delete anything that
+ * does not have the current generation number. this is
+ * how we catch interfaces that go away or change their
+ * addresses. note that 0.0.0.0 is the wildcard element
+ * and should never be deleted by this code.
+ *
+ * XXX - need to update enettab/elocal as well.
+ */
+ dqflush(my_generation); /* With apologies to The Who. */
+
+ /*
+ * Create separate qdatagram structure for socket
+ * wildcard address.
+ */
+ if (first) {
+ if (!(dqp = (struct qdatagram *)calloc(1, sizeof(*dqp))))
+ panic(errno, "malloc(qdatagram)");
+ dqp->dq_next = datagramq;
+ datagramq = dqp;
+ dqp->dq_addr.s_addr = INADDR_ANY;
+ opensocket(dqp);
+ ds = dqp->dq_dfd;
+ }
+
+ /*
+ * Compute logical networks to which we're connected
+ * based on attached subnets;
+ * used for sorting based on network configuration.
+ */
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ nm = net_mask(ntp->my_addr);
+ if (nm != ntp->mask) {
+ if (findnetinfo(ntp->my_addr))
+ continue;
+ ontp = (struct netinfo *)
+ malloc(sizeof(struct netinfo));
+ if (!ontp)
+ panic(errno, "malloc(netinfo)");
+ ontp->my_addr = ntp->my_addr;
+ ontp->mask = nm;
+ ontp->addr = ontp->my_addr.s_addr & nm;
+ ontp->next = *enettab;
+ *enettab = ontp;
+ enettab = &ontp->next;
+ }
+ }
+ first = 0;
+}
+
+/*
+ * Find netinfo structure for logical network implied by address "addr",
+ * if it's on list of local/favored networks.
+ */
+struct netinfo *
+findnetinfo(addr)
+ struct in_addr addr;
+{
+ register struct netinfo *ntp;
+ u_int32_t net, mask;
+
+ mask = net_mask(addr);
+ net = addr.s_addr & mask;
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+ if (ntp->addr == net && ntp->mask == mask)
+ return (ntp);
+ return ((struct netinfo *) NULL);
+}
+
+#ifdef DEBUG
+static void
+printnetinfo(ntp)
+ register struct netinfo *ntp;
+{
+ for ( ; ntp != NULL; ntp = ntp->next) {
+ fprintf(ddt, "addr x%lx mask x%lx",
+ (u_long)ntp->addr, (u_long)ntp->mask);
+ fprintf(ddt, " my_addr x%lx", ntp->my_addr.s_addr);
+ fprintf(ddt, " %s\n", inet_ntoa(ntp->my_addr));
+ }
+}
+#endif
+
+static void
+opensocket(dqp)
+ register struct qdatagram *dqp;
+{
+ int m, n;
+ int on = 1;
+
+ /*
+ * Open datagram sockets bound to interface address.
+ */
+ if ((dqp->dq_dfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket(SOCK_DGRAM): %m - exiting");
+ exit(1);
+ }
+ dprintf(1, (ddt, "dqp->dq_addr %s d_dfd %d\n",
+ inet_ntoa(dqp->dq_addr), dqp->dq_dfd));
+ if (setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on)) != 0)
+ {
+ syslog(LOG_NOTICE, "setsockopt(dqp->dq_dfd, reuseaddr): %m");
+ /* XXX press on regardless, this is not too serious. */
+ }
+#ifdef SO_RCVBUF
+ m = sizeof(n);
+ if ((getsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF, (char*)&n, &m) >= 0)
+ && (m == sizeof(n))
+ && (n < rbufsize)) {
+ (void) setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF,
+ (char *)&rbufsize, sizeof(rbufsize));
+ }
+#endif /* SO_RCVBUF */
+ if ((n = fcntl(dqp->dq_dfd, F_GETFL, 0)) < 0) {
+ syslog(LOG_NOTICE, "fcntl(dfd, F_GETFL): %m");
+ /* XXX press on regardless, but this really is a problem. */
+ } else if (fcntl(dqp->dq_dfd, F_SETFL, n|PORT_NONBLOCK) != 0) {
+ syslog(LOG_NOTICE, "fcntl(dqp->dq_dfd, non-blocking): %m");
+ /* XXX press on regardless, but this really is a problem. */
+ }
+ /*
+ * NOTE: Some versions of SunOS have problems with the following
+ * call to bind. Bind still seems to function on these systems
+ * if you comment out the exit inside the if. This may cause
+ * Suns with multiple interfaces to reply strangely.
+ */
+ nsaddr.sin_addr = dqp->dq_addr;
+ if (bind(dqp->dq_dfd, (struct sockaddr *)&nsaddr, sizeof(nsaddr))) {
+ syslog(LOG_NOTICE, "bind(dfd=%d, [%s].%d): %m",
+ dqp->dq_dfd, inet_ntoa(nsaddr.sin_addr),
+ ntohs(nsaddr.sin_port));
+#if !defined(sun)
+ syslog(LOG_ERR, "exiting");
+ exit(1);
+#endif
+ }
+ FD_SET(dqp->dq_dfd, &mask);
+}
+
+/*
+** Set flag saying to reload database upon receiving SIGHUP.
+** Must make sure that someone isn't walking through a data
+** structure at the time.
+*/
+
+static SIG_FN
+onhup()
+{
+ int save_errno = errno;
+
+ resignal(SIGHUP, -1, onhup);
+ needreload = 1;
+ errno = save_errno;
+}
+
+/*
+** Set flag saying to call ns_maint()
+** Must make sure that someone isn't walking through a data
+** structure at the time.
+*/
+
+static SIG_FN
+maint_alarm()
+{
+ int save_errno = errno;
+
+ resignal(SIGALRM, SIGCHLD, maint_alarm);
+ needmaint = 1;
+ errno = save_errno;
+}
+
+
+#ifdef ALLOW_UPDATES
+/*
+ * Signal handler to schedule shutdown. Just set flag, to ensure a consistent
+ * state during dump.
+ */
+static SIG_FN
+onintr()
+{
+ int save_errno = errno;
+
+ resignal(SIGTERM, -1, onintr);
+ needToExit = 1;
+ errno = save_errno;
+}
+#endif /* ALLOW_UPDATES */
+
+#ifdef XSTATS
+/*
+ * Signal handler to write log information
+ */
+static SIG_FN
+onintr()
+{
+ int save_errno = errno;
+
+ resignal(SIGTERM, -1, onintr);
+ needToExit = 1; /* XXX variable reuse */
+ errno = save_errno;
+}
+#endif /* XSTATS */
+
+/*
+ * Signal handler to schedule a data base dump. Do this instead of dumping the
+ * data base immediately, to avoid seeing it in a possibly inconsistent state
+ * (due to updates), and to avoid long disk I/O delays at signal-handler
+ * level
+ */
+static SIG_FN
+setdumpflg()
+{
+ int save_errno = errno;
+
+ resignal(SIGINT, -1, setdumpflg);
+ needToDoadump = 1;
+ errno = save_errno;
+}
+
+/*
+** Turn on or off debuging by open or closeing the debug file
+*/
+
+static void
+setdebug(code)
+ int code;
+{
+#if defined(lint) && !defined(DEBUG)
+ code = code;
+#endif
+#ifdef DEBUG
+
+ if (code) {
+ int n;
+
+ ddt = freopen(debugfile, "w+", stderr);
+ if ( ddt == NULL) {
+ syslog(LOG_NOTICE, "can't open debug file %s: %m",
+ debugfile);
+ debug = 0;
+ } else {
+#if defined(HAVE_SETVBUF)
+ setvbuf(ddt, NULL, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(ddt);
+#endif
+ if ((n = fcntl(fileno(ddt), F_GETFL, 0)) < 0) {
+ syslog(LOG_INFO,
+ "fcntl(ddt, F_GETFL): %m");
+ } else {
+ (void) fcntl(fileno(ddt), F_SETFL, n|O_APPEND);
+ }
+ }
+ } else
+ debug = 0;
+ /* delay closing ddt, we might interrupt someone */
+#endif
+}
+
+/*
+** Catch a special signal and set debug level.
+**
+** If debuging is off then turn on debuging else increment the level.
+**
+** Handy for looking in on long running name servers.
+*/
+
+static SIG_FN
+setIncrDbgFlg()
+{
+ int save_errno = errno;
+
+ resignal(SIGUSR1, -1, setIncrDbgFlg);
+#ifdef DEBUG
+ if (debug == 0) {
+ debug++;
+ setdebug(1);
+ } else {
+ debug++;
+ }
+ if (debug)
+ fprintf(ddt, "Debug turned ON, Level %d\n", debug);
+#endif
+ errno = save_errno;
+}
+
+/*
+** Catch a special signal to turn off debugging
+*/
+
+static SIG_FN
+setNoDbgFlg()
+{
+ int save_errno = errno;
+
+ resignal(SIGUSR2, -1, setNoDbgFlg);
+ setdebug(0);
+ errno = save_errno;
+}
+
+#if defined(QRYLOG) && defined(SIGWINCH)
+/*
+** Set flag for query logging
+*/
+static SIG_FN
+setQrylogFlg()
+{
+ int save_errno = errno;
+
+ resignal(SIGWINCH, -1, setQrylogFlg);
+ qrylog = !qrylog;
+ syslog(LOG_NOTICE, "query log %s\n", qrylog ?"on" :"off");
+ errno = save_errno;
+}
+#endif /*QRYLOG && SIGWINCH*/
+
+/*
+** Set flag for statistics dump
+*/
+static SIG_FN
+setstatsflg()
+{
+ int save_errno = errno;
+
+ resignal(SIGIOT, -1, setstatsflg);
+ needStatsDump = 1;
+ errno = save_errno;
+}
+
+static SIG_FN
+setchkptflg()
+{
+ int save_errno = errno;
+
+ resignal(SIGQUIT, -1, setchkptflg);
+ needToChkpt = 1;
+ errno = save_errno;
+}
+
+/*
+** Catch a special signal SIGSYS
+**
+** this is setup to fork and exit to drop to /usr/tmp/gmon.out
+** and keep the server running
+*/
+
+#ifdef SIGSYS
+static SIG_FN
+sigprof()
+{
+ int save_errno = errno;
+
+ resignal(SIGSYS, -1, sigprof);
+ dprintf(1, (ddt, "sigprof()\n"));
+ if (fork() == 0)
+ {
+ (void) chdir(_PATH_TMPDIR);
+ exit(1);
+ }
+ errno = save_errno;
+}
+#endif /* SIGSYS */
+
+/*
+** Routines for managing stream queue
+*/
+
+static struct qstream *
+sqadd()
+{
+ register struct qstream *sqp;
+
+ if (!(sqp = (struct qstream *)calloc(1, sizeof(struct qstream)))) {
+ syslog(LOG_ERR, "sqadd: calloc: %m");
+ return (QSTREAM_NULL);
+ }
+ dprintf(3, (ddt, "sqadd(x%lx)\n", (u_long)sqp));
+
+ sqp->s_next = streamq;
+ streamq = sqp;
+ return (sqp);
+}
+
+/* sqrm(qp)
+ * remove stream queue structure `qp'.
+ * no current queries may refer to this stream when it is removed.
+ * side effects:
+ * memory is deallocated. sockets are closed. lists are relinked.
+ */
+void
+sqrm(qp)
+ register struct qstream *qp;
+{
+ register struct qstream *qsp;
+
+ dprintf(2, (ddt, "sqrm(%#lx, %d) rfcnt=%d\n",
+ (u_long)qp, qp->s_rfd, qp->s_refcnt));
+
+ if (qp->s_bufsize != 0)
+ free(qp->s_buf);
+ FD_CLR(qp->s_rfd, &mask);
+ (void) my_close(qp->s_rfd);
+ if (qp == streamq) {
+ streamq = qp->s_next;
+ } else {
+ for (qsp = streamq;
+ qsp && (qsp->s_next != qp);
+ qsp = qsp->s_next)
+ ;
+ if (qsp) {
+ qsp->s_next = qp->s_next;
+ }
+ }
+ free((char *)qp);
+}
+
+/* void
+ * sqflush(allbut)
+ * call sqrm() on all open streams except `allbut'
+ * side effects:
+ * global list `streamq' modified
+ * idiocy:
+ * is N^2 due to the scan inside of sqrm()
+ */
+void
+sqflush(allbut)
+ register struct qstream *allbut;
+{
+ register struct qstream *sp, *spnext;
+
+ for (sp = streamq; sp != NULL; sp = spnext) {
+ spnext = sp->s_next;
+ if (sp != allbut)
+ sqrm(sp);
+ }
+}
+
+/* void
+ * dqflush(gen)
+ * close/deallocate all the udp sockets, unless `gen' != (time_t)0
+ * in which case all those not from this generation (except 0.0.0.0)
+ * will be deleted, and syslog() will be called.
+ * known bugs:
+ * the above text is impenetrable.
+ * side effects:
+ * global list `datagramq' is modified.
+ */
+void
+dqflush(gen)
+ register time_t gen;
+{
+ register struct qdatagram *this, *prev, *next;
+
+ prev = NULL;
+ for (this = datagramq; this != NULL; this = next) {
+ next = this->dq_next;
+ if (gen != (time_t)0) {
+ if (this->dq_addr.s_addr == INADDR_ANY ||
+ this->dq_gen == gen) {
+ prev = this;
+ continue;
+ }
+ syslog(LOG_NOTICE, "interface [%s] missing; deleting",
+ inet_ntoa(this->dq_addr));
+ }
+ FD_CLR(this->dq_dfd, &mask);
+ my_close(this->dq_dfd);
+ free(this);
+ if (prev == NULL)
+ datagramq = next;
+ else
+ prev->dq_next = next;
+ }
+}
+
+/* int
+ * sq_here(sp)
+ * determine whether stream 'sp' is still on the streamq
+ * return:
+ * boolean: is it here?
+ */
+static int
+sq_here(sp)
+ register struct qstream *sp;
+{
+ register struct qstream *t;
+
+ for (t = streamq; t != NULL; t = t->s_next)
+ if (t == sp)
+ return (1);
+ return (0);
+}
+
+/*
+ * Initiate query on stream;
+ * mark as referenced and stop selecting for input.
+ */
+static void
+sq_query(sp)
+ register struct qstream *sp;
+{
+ sp->s_refcnt++;
+ FD_CLR(sp->s_rfd, &mask);
+}
+
+/*
+ * Note that the current request on a stream has completed,
+ * and that we should continue looking for requests on the stream.
+ */
+void
+sq_done(sp)
+ register struct qstream *sp;
+{
+
+ sp->s_refcnt = 0;
+ sp->s_time = tt.tv_sec;
+ FD_SET(sp->s_rfd, &mask);
+}
+
+void
+ns_setproctitle(a, s)
+ char *a;
+ int s;
+{
+ int size;
+ register char *cp;
+ struct sockaddr_in sin;
+ char buf[80];
+
+ cp = Argv[0];
+ size = sizeof(sin);
+ if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
+ (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
+ else {
+ syslog(LOG_DEBUG, "getpeername: %m");
+ (void) sprintf(buf, "-%s", a);
+ }
+ (void) strncpy(cp, buf, LastArg - cp);
+ cp += strlen(cp);
+ while (cp < LastArg)
+ *cp++ = ' ';
+}
+
+u_int32_t
+net_mask(in)
+ struct in_addr in;
+{
+ register u_int32_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (htonl(IN_CLASSA_NET));
+ else if (IN_CLASSB(i))
+ return (htonl(IN_CLASSB_NET));
+ else
+ return (htonl(IN_CLASSC_NET));
+}
+
+/*
+ * These are here in case we ever want to get more clever, like perhaps
+ * using a bitmap to keep track of outstanding queries and a random
+ * allocation scheme to make it a little harder to predict them. Note
+ * that the resolver will need the same protection so the cleverness
+ * should be put there rather than here; this is just an interface layer.
+ */
+
+void
+nsid_init()
+{
+ nsid_state = res_randomid();
+}
+
+u_int16_t
+nsid_next()
+{
+ if (nsid_state == 65535)
+ nsid_state = 0;
+ else
+ nsid_state++;
+ return (nsid_state);
+}
+
+#if defined(BSD43_BSD43_NFS)
+/* junk needed for old Sun NFS licensees */
+#undef dn_skipname
+extern char *dn_skipname();
+char *(*hack_skipname)() = dn_skipname;
+#endif
OpenPOWER on IntegriCloud