1348 lines
32 KiB
C
1348 lines
32 KiB
C
/*
|
|
* Copyright (c) 1986 Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that this notice is preserved and that due credit is given
|
|
* to the University of California at Berkeley. The name of the University
|
|
* may not be used to endorse or promote products derived from this
|
|
* software without specific prior written permission. This software
|
|
* is provided ``as is'' without express or implied warranty.
|
|
*/
|
|
|
|
#ifndef lint
|
|
char copyright[] =
|
|
"@(#) Copyright (c) 1986 Regents of the University of California.\n\
|
|
All rights reserved.\n";
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)ns_main.c 1.1 94/10/31 SMI"; /* from UCB 4.30 3/7/88 */
|
|
#endif /* not lint */
|
|
|
|
/*
|
|
* Internet Name server (see rfc883 & others).
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#if defined(SYSV)
|
|
#include <fcntl.h>
|
|
#endif SYSV
|
|
#include <sys/file.h>
|
|
#include <sys/time.h>
|
|
#if !defined(SYSV)
|
|
#include <sys/wait.h>
|
|
#endif !SYSV
|
|
#include <sys/resource.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <net/if.h>
|
|
#include <stdio.h>
|
|
#include <syslog.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <netdb.h>
|
|
#include <arpa/nameser.h>
|
|
#include <arpa/inet.h>
|
|
#include <resolv.h>
|
|
#undef nsaddr /* XXX */
|
|
#include "ns.h"
|
|
#include "db.h"
|
|
|
|
#ifdef BOOTFILE /* default boot file */
|
|
char *bootfile = BOOTFILE;
|
|
#else
|
|
char *bootfile = "/etc/named.boot";
|
|
#endif
|
|
|
|
#ifdef DEBUGFILE /* default debug output file */
|
|
char *debugfile = DEBUGFILE;
|
|
#else
|
|
char *debugfile = "/usr/tmp/named.run";
|
|
#endif
|
|
|
|
#ifdef PIDFILE /* file to store current named PID */
|
|
char *PidFile = PIDFILE;
|
|
#else
|
|
char *PidFile = "/etc/named.pid";
|
|
#endif
|
|
|
|
#ifndef FD_SET
|
|
#define NFDBITS 32
|
|
#define FD_SETSIZE 32
|
|
#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
|
|
#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
|
|
#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
|
|
#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
|
|
#endif
|
|
|
|
FILE *fp; /* file descriptor for pid file */
|
|
|
|
#ifdef DEBUG
|
|
FILE *ddt;
|
|
#endif
|
|
|
|
int debug = 0; /* debugging flag */
|
|
int ds; /* datagram socket */
|
|
int read_interrupted = 0; /* flag for read timer */
|
|
int needreload = 0; /* received SIGHUP, need to reload db */
|
|
int needmaint = 0; /* need to call ns_maint()*/
|
|
int needToDoadump = 0; /* need to dump database */
|
|
int needToChkpt = 0; /* need to checkpoint cache */
|
|
int needStatsDump = 0; /* need to dump statistics */
|
|
#ifdef ALLOW_UPDATES
|
|
int needToExit = 0; /* need to exit (may need to doadump
|
|
* first, if database has changed since
|
|
* it was last dumped/booted). Gets
|
|
* set by shutdown signal handler
|
|
* (onintr)
|
|
*/
|
|
#endif ALLOW_UPDATES
|
|
|
|
/*
|
|
* indicates a need to load a zone after xfer is done. When not NULL, points
|
|
* to the zone to load. numZonesToLoad may have to be declared volatile.
|
|
*/
|
|
int numZonesToLoad = 0;
|
|
struct zoneinfo *needLoadZones[MAX_XFERS_RUNNING];
|
|
|
|
/*
|
|
* A flag indicating if an ns_xfer_update() should be called, values:
|
|
* 0 == no update needed
|
|
* 1 == update due to timer ringing
|
|
* 2 == update due to SIGCHLD (child finished) being received
|
|
*/
|
|
int needXferUpdate = 0;
|
|
|
|
int priming = 0; /* is cache being primed */
|
|
|
|
#ifdef SO_RCVBUF
|
|
int rbufsize = 8 * 1024; /* UDP recive buffer size */
|
|
#endif
|
|
|
|
struct qstream *streamq = QSTREAM_NULL; /* list of open streams */
|
|
struct qdatagram *datagramq = QDATAGRAM_NULL; /* list of datagram interfaces */
|
|
struct qdatagram *dqp, *sqp;
|
|
struct sockaddr_in nsaddr;
|
|
struct timeval tt;
|
|
struct netinfo *nettab = NULL;
|
|
struct netinfo *fnettab = NULL;
|
|
struct netinfo *onettab = NULL;
|
|
struct netinfo netloop;
|
|
short ns_port;
|
|
struct sockaddr_in from_addr; /* Source addr of last packet */
|
|
int from_len; /* Source addr size of last packet */
|
|
time_t boottime, resettime; /* Used by ns_stats */
|
|
fd_set mask; /* select mask of open descriptors */
|
|
|
|
char **Argv = NULL; /* pointer to argument vector */
|
|
char *LastArg = NULL; /* end of argv */
|
|
|
|
extern int errno;
|
|
|
|
#if defined(SYSV)
|
|
getdtablesize()
|
|
{
|
|
return(FD_SETSIZE);
|
|
}
|
|
#endif SYSV
|
|
|
|
main(argc, argv, envp)
|
|
int argc;
|
|
char *argv[], *envp[];
|
|
{
|
|
register int n, udpcnt;
|
|
register char *arg;
|
|
register struct qstream *sp;
|
|
int vs;
|
|
int nfds;
|
|
int on = 1;
|
|
int rfd, size;
|
|
u_long lasttime, maxctime;
|
|
u_long nnn, nm;
|
|
char buf[BUFSIZ];
|
|
|
|
fd_set tmpmask;
|
|
|
|
struct timeval t, *tp;
|
|
struct qstream *candidate = QSTREAM_NULL;
|
|
struct qstream *nextsp;
|
|
struct ifconf ifc;
|
|
struct ifreq ifreq, *ifr;
|
|
struct netinfo *ntp;
|
|
struct netinfo *ntip;
|
|
struct netinfo *ontp;
|
|
struct netinfo *ontip;
|
|
extern int onintr(), maint_alarm(), reapchild(), setdumpflg(), onhup();
|
|
extern int setIncrDbgFlg(), setNoDbgFlg(), sigprof();
|
|
extern int setchkptflg(), setstatsflg();
|
|
extern struct qstream *sqadd();
|
|
extern struct qinfo *qhead;
|
|
extern char Version[];
|
|
|
|
ns_port = htons(NAMESERVER_PORT);
|
|
_res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
|
|
|
|
/*
|
|
** Save start and extent of argv for setproctitle.
|
|
*/
|
|
|
|
Argv = argv;
|
|
if (envp == 0 || *envp == 0)
|
|
envp = argv;
|
|
while (*envp)
|
|
envp++;
|
|
LastArg = envp[-1] + strlen(envp[-1]);
|
|
|
|
(void) umask(022);
|
|
while (--argc > 0) {
|
|
arg = *++argv;
|
|
if (*arg == '-') {
|
|
while (*++arg)
|
|
switch (*arg) {
|
|
case 'b':
|
|
if (--argc <= 0)
|
|
usage();
|
|
bootfile = *++argv;
|
|
break;
|
|
|
|
case 'd':
|
|
++argv;
|
|
|
|
if (*argv != 0) {
|
|
if (**argv == '-') {
|
|
argv--;
|
|
break;
|
|
}
|
|
debug = atoi(*argv);
|
|
--argc;
|
|
}
|
|
if (debug <= 0)
|
|
debug = 1;
|
|
setdebug(1);
|
|
break;
|
|
|
|
case 'p':
|
|
if (--argc <= 0)
|
|
usage();
|
|
ns_port = htons((u_short)atoi(*++argv));
|
|
break;
|
|
|
|
default:
|
|
usage();
|
|
}
|
|
} else
|
|
bootfile = *argv;
|
|
}
|
|
|
|
if (!debug) {
|
|
if (fork())
|
|
exit(0);
|
|
for (n = getdtablesize() - 1; n >= 0; n--)
|
|
(void) close(n);
|
|
(void) open("/dev/null", O_RDONLY);
|
|
(void) dup2(0, 1);
|
|
(void) dup2(0, 2);
|
|
n = open("/dev/tty", O_RDWR);
|
|
if (n > 0) {
|
|
#ifndef SYSV
|
|
(void) ioctl(n, TIOCNOTTY, (char *)NULL);
|
|
#else
|
|
setpgrp();
|
|
#endif
|
|
(void) close(n);
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
else {
|
|
fprintf(ddt,"Debug turned ON, Level %d\n",debug);
|
|
fprintf(ddt,"Version = %s\t",Version);
|
|
fprintf(ddt,"bootfile = %s\n",bootfile);
|
|
}
|
|
#endif
|
|
|
|
#ifdef LOG_DAEMON
|
|
openlog("named", LOG_PID|LOG_CONS|LOG_NDELAY, LOG_DAEMON);
|
|
#else
|
|
openlog("named", LOG_PID);
|
|
#endif
|
|
|
|
/* tuck my process id away */
|
|
fp = fopen(PidFile, "w");
|
|
if (fp != NULL) {
|
|
fprintf(fp, "%d\n", getpid());
|
|
(void) fclose(fp);
|
|
}
|
|
syslog(LOG_NOTICE, "restarted\n");
|
|
|
|
nsaddr.sin_family = AF_INET;
|
|
nsaddr.sin_addr.s_addr = INADDR_ANY;
|
|
nsaddr.sin_port = ns_port;
|
|
/*
|
|
** Initialize and load database.
|
|
*/
|
|
gettime(&tt);
|
|
buildservicelist();
|
|
buildprotolist();
|
|
ns_init(bootfile);
|
|
time(&boottime);
|
|
resettime = boottime;
|
|
|
|
(void) signal(SIGALRM, maint_alarm);
|
|
(void) signal(SIGHUP, onhup);
|
|
#if defined(SYSV)
|
|
(void) signal(SIGCLD, reapchild);
|
|
#else
|
|
(void) signal(SIGCHLD, reapchild);
|
|
#endif SYSV
|
|
(void) signal(SIGPIPE, SIG_IGN);
|
|
(void) signal(SIGSYS, sigprof);
|
|
(void) signal(SIGINT, setdumpflg);
|
|
(void) signal(SIGQUIT, setchkptflg);
|
|
(void) signal(SIGIOT, setstatsflg);
|
|
|
|
#ifdef ALLOW_UPDATES
|
|
/* Catch SIGTERM so we can dump the database upon shutdown if it
|
|
has changed since it was last dumped/booted */
|
|
(void) signal(SIGTERM, onintr);
|
|
#endif ALLOW_UPDATES
|
|
|
|
#if defined(SIGUSR1) && defined(SIGUSR2)
|
|
(void) signal(SIGUSR1, setIncrDbgFlg);
|
|
(void) signal(SIGUSR2, setNoDbgFlg);
|
|
#else SIGUSR1&&SIGUSR2
|
|
(void) signal(SIGEMT, setIncrDbgFlg);
|
|
(void) signal(SIGFPE, setNoDbgFlg);
|
|
#endif SIGUSR1&&SIGUSR2
|
|
|
|
#ifdef DEBUG
|
|
if (debug) {
|
|
fprintf(ddt,"database initialized\n");
|
|
}
|
|
#endif
|
|
/*
|
|
** Open stream port.
|
|
*/
|
|
if ((vs = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
syslog(LOG_ERR, "socket(SOCK_STREAM): %m");
|
|
exit(1);
|
|
}
|
|
(void)setsockopt(vs, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
|
|
if (bind(vs, (struct sockaddr *)&nsaddr, sizeof(nsaddr))) {
|
|
syslog(LOG_ERR, "bind(vs, %s[%d]): %m",
|
|
inet_ntoa(nsaddr.sin_addr), ntohs(nsaddr.sin_port));
|
|
exit(1);
|
|
}
|
|
ifc.ifc_len = sizeof(buf);
|
|
ifc.ifc_buf = buf;
|
|
if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) {
|
|
syslog(LOG_ERR, "get interface configuration: %m");
|
|
exit(1);
|
|
}
|
|
n = ifc.ifc_len/sizeof(struct ifreq);
|
|
ntp = NULL;
|
|
for (ifr = ifc.ifc_req; n > 0; n--, ifr++) {
|
|
int dup_addr;
|
|
|
|
if (ifr->ifr_addr.sa_family != AF_INET)
|
|
continue;
|
|
ifreq = *ifr;
|
|
if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
|
|
syslog(LOG_ERR, "get interface flags: %m");
|
|
continue;
|
|
}
|
|
if ((ifreq.ifr_flags & (IFF_UP|IFF_RUNNING)) == 0)
|
|
continue;
|
|
if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) {
|
|
syslog(LOG_ERR, "get interface addr: %m");
|
|
continue;
|
|
}
|
|
/* build datagram queue */
|
|
if ((dqp = (struct qdatagram *)calloc(1,
|
|
sizeof(struct qdatagram))) == NULL) {
|
|
#ifdef DEBUG
|
|
if (debug >= 5)
|
|
fprintf(ddt,"main: malloc error\n");
|
|
#endif
|
|
syslog(LOG_ERR, "main: Out Of Memory");
|
|
exit(12);
|
|
}
|
|
dqp->dq_next = datagramq;
|
|
dqp->dq_addr = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
|
|
/*
|
|
* look for an already existing source interface address. If
|
|
* the machine has multiple point to point interfaces, then
|
|
* the local address may appear more than once.
|
|
*/
|
|
dup_addr = 0;
|
|
for (sqp=datagramq; sqp != NULL; sqp = sqp->dq_next)
|
|
if (dqp->dq_addr.s_addr == sqp->dq_addr.s_addr) {
|
|
dup_addr = 1;
|
|
break;
|
|
}
|
|
if (!dup_addr)
|
|
datagramq = dqp;
|
|
else {
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
fprintf(ddt, "main: dup interface address %s on %s\n",
|
|
inet_ntoa(dqp->dq_addr), ifreq.ifr_name);
|
|
#endif
|
|
free((char *) dqp);
|
|
}
|
|
|
|
if (ntp == NULL)
|
|
ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
|
|
ntp->my_addr =
|
|
((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
|
|
#ifdef SIOCGIFNETMASK
|
|
if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
|
|
syslog(LOG_ERR, "get netmask: %m (using default)");
|
|
ntp->mask = net_mask(ntp->my_addr);
|
|
}
|
|
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_ERR, "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 == htonl(0x7F000001))
|
|
#endif
|
|
{
|
|
netloop.my_addr = ntp->my_addr;
|
|
netloop.mask = 0xffffffff;
|
|
netloop.net = ntp->my_addr.s_addr;
|
|
netloop.next = NULL;
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
fprintf(ddt,"loopback address: x%lx\n",
|
|
netloop.my_addr.s_addr);
|
|
#endif DEBUG
|
|
continue;
|
|
} else if ((ifreq.ifr_flags & IFF_POINTOPOINT)) {
|
|
if (ioctl(vs, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
|
|
syslog(LOG_ERR, "get dst addr: %m");
|
|
continue;
|
|
}
|
|
ntp->mask = 0xffffffff;
|
|
ntp->net = ((struct sockaddr_in *)
|
|
&ifreq.ifr_addr)->sin_addr.s_addr;
|
|
} else {
|
|
ntp->net = ntp->mask & ntp->my_addr.s_addr;
|
|
}
|
|
ntp->next = NULL;
|
|
if (nettab == NULL)
|
|
nettab = ntip = ntp;
|
|
else {
|
|
ntip->next = ntp;
|
|
ntip = ntp;
|
|
}
|
|
ntp = NULL;
|
|
}
|
|
if (ntp)
|
|
(void) free((char *)ntp);
|
|
|
|
/*
|
|
* Create separate qdatagram structure for socket
|
|
* wildcard address.
|
|
*/
|
|
if ((dqp = (struct qdatagram *)calloc(1, sizeof(struct qdatagram)))
|
|
== NULL) {
|
|
#ifdef DEBUG
|
|
if (debug >= 5)
|
|
fprintf(ddt,"main: malloc error\n");
|
|
#endif
|
|
syslog(LOG_ERR, "main: Out Of Memory");
|
|
exit(12);
|
|
}
|
|
dqp->dq_next = datagramq;
|
|
datagramq = dqp;
|
|
dqp->dq_addr.s_addr = INADDR_ANY;
|
|
|
|
/*
|
|
* Compute other networks for sorting based on network configuration
|
|
*/
|
|
ontp = NULL;
|
|
for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
|
|
nm = net_mask(ntp->my_addr);
|
|
if (nm != ntp->mask) {
|
|
nnn = ntp->my_addr.s_addr & nm;
|
|
for (ontp=onettab; ontp != NULL; ontp=ontp->next) {
|
|
if ((ontp->net == nnn) &&
|
|
(ontp->mask == nm))
|
|
goto outerloop;
|
|
ontip = ontp;
|
|
}
|
|
ontp = (struct netinfo *)
|
|
malloc(sizeof(struct netinfo));
|
|
ontp->net = nnn;
|
|
ontp->mask = nm;
|
|
ontp->my_addr = ntp->my_addr;
|
|
ontp->next = NULL;
|
|
if (onettab == NULL )
|
|
onettab = ontp;
|
|
else
|
|
ontip->next = ontp;
|
|
}
|
|
outerloop:
|
|
;
|
|
}
|
|
/*
|
|
* Merge sort list from network configuration
|
|
* with list we computed from network configuration
|
|
*/
|
|
for (ntp = nettab; ntp != NULL; ntp = ntp->next){
|
|
if (ntp->next == NULL) {
|
|
ntp->next = onettab;
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* Merge sort list from boot file with list from
|
|
* network configuration
|
|
*/
|
|
for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
|
|
for (ontp = fnettab; ontp != NULL; ontp = ontp->next) {
|
|
if ((ontp->mask == ntp->mask) && (ontp->net == ntp->net)) {
|
|
if( fnettab == ontp ) {
|
|
ontip = ontp;
|
|
fnettab = ontp->next;
|
|
free((char *)ontip);
|
|
break;
|
|
} else {
|
|
for (ontip = fnettab; ontip != NULL;ontip = ontip->next)
|
|
if (ontip->next == ontp) break;
|
|
ontip->next = ontp->next;
|
|
free((char *)ontp);
|
|
ontp = ontip;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ntp->next == NULL)
|
|
break;
|
|
}
|
|
if (ntp) {
|
|
ntp->next = fnettab;
|
|
} else {
|
|
nettab = fnettab;
|
|
}
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
|
|
fprintf(ddt,"net x%lx mask x%lx", ntp->net, ntp->mask);
|
|
fprintf(ddt," my_addr x%lx", ntp->my_addr.s_addr);
|
|
fprintf(ddt," %s\n", inet_ntoa(ntp->my_addr));
|
|
}
|
|
#endif DEBUG
|
|
(void) listen(vs, 5);
|
|
|
|
/*
|
|
* Open datagram ports for each interface
|
|
* (the first is un-addressed datagram port).
|
|
*/
|
|
for (dqp = datagramq; dqp != QDATAGRAM_NULL; dqp = dqp->dq_next) {
|
|
nsaddr.sin_addr = dqp->dq_addr;
|
|
if ((dqp->dq_dfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
syslog(LOG_ERR, "socket(SOCK_DGRAM): %m");
|
|
exit(1);
|
|
}
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
fprintf(ddt,"dqp->dq_addr %s d_dfd %d\n",
|
|
inet_ntoa(dqp->dq_addr), dqp->dq_dfd);
|
|
#endif DEBUG
|
|
(void)setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_REUSEADDR,
|
|
(char *)&on, sizeof(on));
|
|
#ifdef SO_RCVBUF
|
|
(void)setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF,
|
|
(char *)&rbufsize, sizeof(rbufsize));
|
|
#endif SO_RCVBUF
|
|
(void) fcntl(dqp->dq_dfd, F_SETFL, FNDELAY);
|
|
/*
|
|
* 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.
|
|
*/
|
|
if (bind(dqp->dq_dfd, (struct sockaddr *)&nsaddr, sizeof(nsaddr))) {
|
|
syslog(LOG_ERR, "bind(dfd %d, %s[%d]): %m",
|
|
dqp->dq_dfd, inet_ntoa(nsaddr.sin_addr),
|
|
ntohs(nsaddr.sin_port));
|
|
#if !defined(sun)
|
|
exit(1);
|
|
#endif
|
|
}
|
|
}
|
|
ds = datagramq->dq_dfd;
|
|
|
|
t.tv_usec = 0;
|
|
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
fprintf(ddt,"Ready to answer queries.\n");
|
|
#endif
|
|
prime_cache();
|
|
nfds = getdtablesize(); /* get the number of file descriptors */
|
|
if (nfds > FD_SETSIZE) {
|
|
nfds = FD_SETSIZE; /* Bulletproofing */
|
|
syslog(LOG_ERR, "Return from getdtablesize() > FD_SETSIZE");
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
fprintf(ddt,"Return from getdtablesize() > FD_SETSIZE\n");
|
|
#endif
|
|
}
|
|
FD_ZERO(&mask);
|
|
FD_SET(vs, &mask);
|
|
FD_SET(ds, &mask);
|
|
for (dqp = datagramq; dqp != QDATAGRAM_NULL; dqp = dqp->dq_next)
|
|
FD_SET(dqp->dq_dfd, &mask);
|
|
for (;;) {
|
|
#ifdef ALLOW_UPDATES
|
|
if (needToExit) {
|
|
struct zoneinfo *zp;
|
|
sigblock(~0); /*
|
|
* Block all blockable signals
|
|
* to ensure a consistant
|
|
* state during final dump
|
|
*/
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
fprintf(ddt, "Received shutdown signal\n");
|
|
#endif DEBUG
|
|
for (zp = zones; zp < &zones[nzones]; zp++) {
|
|
if (zp->hasChanged)
|
|
zonedump(zp);
|
|
}
|
|
exit(0);
|
|
}
|
|
#endif ALLOW_UPDATES
|
|
if(needreload) {
|
|
needreload = 0;
|
|
db_reload();
|
|
}
|
|
#ifdef STATS
|
|
if(needStatsDump) {
|
|
needStatsDump = 0;
|
|
ns_stats();
|
|
}
|
|
#endif STATS
|
|
if(numZonesToLoad > 0) {
|
|
int res;
|
|
#if !defined(SYSV)
|
|
int omask;
|
|
again:
|
|
omask = sigblock(sigmask(SIGCHLD));
|
|
#endif /* SYSV */
|
|
for (n = 0; n < numZonesToLoad; n++) {
|
|
/* mark old RR's */
|
|
mark_zone(hashtab, needLoadZones[n] - zones, 1);
|
|
if (needLoadZones[n]->z_source==NULL) {
|
|
(void) syslog(LOG_ERR, "NULL z_source attempted!");
|
|
continue;
|
|
}
|
|
if (needLoadZones[n]->z_origin == NULL) {
|
|
(void) syslog(LOG_ERR, "NULL z_origin attempted!");
|
|
continue;
|
|
}
|
|
res = db_load(needLoadZones[n]->z_source,
|
|
needLoadZones[n]->z_origin,
|
|
needLoadZones[n]);
|
|
if (res == 0) {
|
|
needLoadZones[n]->z_auth = 1;
|
|
/* delete old RR's */
|
|
clean_zone(hashtab,
|
|
needLoadZones[n] - zones,1);
|
|
(void) syslog(LOG_INFO,
|
|
"reloaded zone %s",
|
|
needLoadZones[n]->z_origin);
|
|
} else {
|
|
/* delete new RR's */
|
|
clean_zone(hashtab,
|
|
needLoadZones[n] - zones,0);
|
|
/* mark old RR's current again */
|
|
mark_zone(hashtab,
|
|
needLoadZones[n] - zones,0);
|
|
(void)syslog(LOG_ERR,
|
|
"reload of xfer'd zone %s failed",
|
|
needLoadZones[n]->z_origin);
|
|
}
|
|
}
|
|
numZonesToLoad = 0;
|
|
#if !defined(SYSV)
|
|
(void)sigsetmask(omask & ~sigmask(SIGCHLD));
|
|
/*
|
|
* There may be some magic in here when we release
|
|
* the child interrupt, since reapchild() may be
|
|
* immediately called. Go back for more if so.
|
|
*/
|
|
if (numZonesToLoad > 0)
|
|
goto again;
|
|
#endif /* SYSV */
|
|
}
|
|
if(needXferUpdate) {
|
|
(void)ns_xfer_update(needXferUpdate);
|
|
needXferUpdate = 0;
|
|
}
|
|
/*
|
|
* Make sure a timer is on if any xfers are running
|
|
*/
|
|
if (xfer_running_cnt > 0)
|
|
timer_on(MAX_XFER_TIME, TIME_XFER);
|
|
|
|
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);
|
|
t.tv_sec = (long) retryqp->q_time - tt.tv_sec;
|
|
if (t.tv_sec <= 0) {
|
|
retry(retryqp);
|
|
continue;
|
|
}
|
|
tp = &t;
|
|
} else
|
|
tp = NULL;
|
|
tmpmask = mask;
|
|
n = select(nfds, &tmpmask, (fd_set *)NULL, (fd_set *)NULL, tp);
|
|
if (n < 0) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
syslog(LOG_ERR, "select: %m");
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
fprintf(ddt,"select error\n");
|
|
#endif
|
|
;
|
|
}
|
|
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 < 25; udpcnt++) {
|
|
from_len = sizeof(from_addr);
|
|
if ((n = recvfrom(dqp->dq_dfd, buf, sizeof(buf), 0,
|
|
(struct sockaddr *)&from_addr, &from_len)) < 0)
|
|
{
|
|
if ((n == -1) && (errno == EWOULDBLOCK))
|
|
break;
|
|
syslog(LOG_WARNING, "recvfrom: %m");
|
|
break;
|
|
}
|
|
#ifdef STATS
|
|
stats[S_INPKTS].cnt++;
|
|
#endif
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
fprintf(ddt,
|
|
"\ndatagram from %s port %d, fd %d, len %d\n",
|
|
inet_ntoa(from_addr.sin_addr),
|
|
ntohs(from_addr.sin_port), ds, n);
|
|
if (debug >= 10)
|
|
fp_query(buf, 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
|
|
*/
|
|
if (FD_ISSET(vs, &tmpmask)) {
|
|
from_len = sizeof(from_addr);
|
|
rfd = accept(vs, (struct sockaddr *)&from_addr, &from_len);
|
|
gettime(&tt);
|
|
if (rfd < 0 && errno == EMFILE && streamq != NULL) {
|
|
maxctime = 0;
|
|
candidate = QSTREAM_NULL;
|
|
for (sp = streamq; sp != QSTREAM_NULL;
|
|
sp = nextsp) {
|
|
nextsp = sp->s_next;
|
|
if (sp->s_refcnt != 0)
|
|
continue;
|
|
lasttime = tt.tv_sec - sp->s_time;
|
|
if (lasttime >= 900)
|
|
sqrm(sp, &mask);
|
|
else if (lasttime > maxctime) {
|
|
candidate = sp;
|
|
maxctime = lasttime;
|
|
}
|
|
}
|
|
rfd = accept(vs, (struct sockaddr *)&from_addr, &from_len);
|
|
if ((rfd < 0) && (errno == EMFILE) &&
|
|
candidate != QSTREAM_NULL) {
|
|
sqrm(candidate, &mask);
|
|
rfd = accept(vs, (struct sockaddr *)&from_addr, &from_len);
|
|
}
|
|
}
|
|
if (rfd < 0) {
|
|
syslog(LOG_WARNING, "accept: %m");
|
|
continue;
|
|
}
|
|
(void) fcntl(rfd, F_SETFL, FNDELAY);
|
|
(void) setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE,
|
|
(char *)&on, sizeof(on));
|
|
if ((sp = sqadd()) == QSTREAM_NULL) {
|
|
(void) 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_bufsize = 0;
|
|
sp->s_bufp = (char *)&sp->s_tempsize;
|
|
sp->s_refcnt = 0;
|
|
FD_SET(rfd, &mask);
|
|
FD_SET(rfd, &tmpmask);
|
|
#ifdef DEBUG
|
|
if (debug) {
|
|
fprintf(ddt,
|
|
"\nTCP connection from %s port %d (fd %d)\n",
|
|
inet_ntoa(sp->s_from.sin_addr),
|
|
ntohs(sp->s_from.sin_port), rfd);
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef DEBUG
|
|
if (debug > 2 && streamq)
|
|
fprintf(ddt,"streamq = x%x\n",streamq);
|
|
#endif
|
|
for (sp = streamq; sp != QSTREAM_NULL; sp = nextsp) {
|
|
nextsp = sp->s_next;
|
|
if (FD_ISSET(sp->s_rfd, &tmpmask)) {
|
|
#ifdef DEBUG
|
|
if (debug > 5) {
|
|
fprintf(ddt,
|
|
"sp x%x rfd %d size %d time %d ",
|
|
sp, sp->s_rfd, sp->s_size,
|
|
sp->s_time );
|
|
fprintf(ddt," next x%x \n", sp->s_next );
|
|
fprintf(ddt,"\tbufsize %d",sp->s_bufsize);
|
|
fprintf(ddt," buf x%x ",sp->s_buf);
|
|
fprintf(ddt," bufp x%x\n",sp->s_bufp);
|
|
}
|
|
#endif DEBUG
|
|
if (sp->s_size < 0) {
|
|
size = sizeof(u_short) -
|
|
(sp->s_bufp - (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 == -1) && (errno == EWOULDBLOCK))
|
|
continue;
|
|
if (n <= 0) {
|
|
sp->s_refcnt = 0;
|
|
sqrm(sp, &mask);
|
|
continue;
|
|
}
|
|
if ((sp->s_bufp - (char *)&sp->s_tempsize) ==
|
|
sizeof(u_short)) {
|
|
sp->s_size = htons(sp->s_tempsize);
|
|
if (sp->s_bufsize == 0) {
|
|
if ( (sp->s_buf = malloc(BUFSIZ))
|
|
== NULL) {
|
|
sp->s_buf = buf;
|
|
sp->s_size = sizeof(buf);
|
|
} else {
|
|
sp->s_bufsize = BUFSIZ;
|
|
}
|
|
}
|
|
if (sp->s_size > sp->s_bufsize &&
|
|
sp->s_bufsize != 0) {
|
|
if ((sp->s_buf = realloc(
|
|
(char *)sp->s_buf,
|
|
(unsigned)sp->s_size)) == 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 > sizeof(u_short))) {
|
|
HEADER *hp;
|
|
|
|
hp = (HEADER *)sp->s_buf;
|
|
hp->qr = 1;
|
|
hp->ra = 1;
|
|
hp->ancount = 0;
|
|
hp->qdcount = 0;
|
|
hp->nscount = 0;
|
|
hp->arcount = 0;
|
|
hp->rcode = SERVFAIL;
|
|
(void) writemsg(sp->s_rfd, sp->s_buf,
|
|
sizeof(HEADER));
|
|
continue;
|
|
}
|
|
if ((n == -1) && (errno == EWOULDBLOCK))
|
|
continue;
|
|
if (n <= 0) {
|
|
sp->s_refcnt = 0;
|
|
sqrm(sp, &mask);
|
|
continue;
|
|
}
|
|
/*
|
|
* Consult database to get the answer.
|
|
*/
|
|
if (sp->s_size == 0) {
|
|
sp->s_refcnt++;
|
|
ns_req(sp->s_buf,
|
|
sp->s_bufp - sp->s_buf,
|
|
sp->s_bufsize, sp,
|
|
&sp->s_from, -1);
|
|
sp->s_bufp = (char *)&sp->s_tempsize;
|
|
sp->s_size = -1;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
usage()
|
|
{
|
|
fprintf(stderr, "Usage: named [-d #] [-p port] [{-b} bootfile]\n");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
** Set flag saying to reload database upon receiving SIGHUP.
|
|
** Must make sure that someone isn't walking through a data
|
|
** structure at the time.
|
|
*/
|
|
|
|
onhup()
|
|
{
|
|
#if defined(SYSV)
|
|
(void)signal(SIGHUP, onhup);
|
|
#endif SYSV
|
|
needreload = 1;
|
|
}
|
|
|
|
/*
|
|
** Set flag saying to call ns_maint()
|
|
** Must make sure that someone isn't walking through a data
|
|
** structure at the time.
|
|
*/
|
|
|
|
maint_alarm()
|
|
{
|
|
#if defined(SYSV)
|
|
(void)signal(SIGALRM, maint_alarm);
|
|
#endif SYSV
|
|
int i = handle_timer();
|
|
if (i & TIME_XFER)
|
|
needXferUpdate = 1; /* indicate should update due to timer */
|
|
if (i & TIME_NS_MAINT)
|
|
needmaint = 1;
|
|
#ifdef DEBUG
|
|
if (i == 0)
|
|
if (debug) fprintf(ddt, "BUG! timer but nothing being timed\n");
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
#ifdef ALLOW_UPDATES
|
|
/*
|
|
* Signal handler to schedule shutdown. Just set flag, to ensure a consistent
|
|
* state during dump.
|
|
*/
|
|
onintr()
|
|
{
|
|
needToExit = 1;
|
|
}
|
|
#endif ALLOW_UPDATES
|
|
|
|
/*
|
|
* 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
|
|
*/
|
|
int setdumpflg()
|
|
{
|
|
#if defined(SYSV)
|
|
(void)signal(SIGINT, setdumpflg);
|
|
#endif SYSV
|
|
needToDoadump = 1;
|
|
}
|
|
|
|
/*
|
|
** Set flag saying to read was interrupted
|
|
** used for a read timer
|
|
*/
|
|
|
|
read_alarm()
|
|
{
|
|
extern int read_interrupted;
|
|
read_interrupted = 1;
|
|
}
|
|
|
|
reapchild()
|
|
{
|
|
#if defined(SYSV)
|
|
(void)wait(0);
|
|
(void)signal(SIGCLD, reapchild);
|
|
#else
|
|
union wait status;
|
|
register struct zoneinfo *zp;
|
|
int pid;
|
|
|
|
while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
|
|
#ifdef DEBUG
|
|
if (debug > 1)
|
|
fprintf(ddt, "child %d returned status=%d termsig=%d\n",
|
|
pid, status.w_retcode,status.w_termsig);
|
|
#endif /* DEBUG */
|
|
for (zp = zones; zp < &zones[nzones]; zp++) {
|
|
if (zp->xfer_pid == pid) {
|
|
/*
|
|
* The child that died was an xfer.
|
|
* Note that this child will never be a child that I
|
|
* killed with a kill(#,9).
|
|
* following exit codes are returned:
|
|
* 0 - everything went ok
|
|
* 1 - could not reach the servers for the xfer
|
|
* 2 - some other error
|
|
*
|
|
*/
|
|
xfer_running_cnt--;
|
|
zp->xfer_pid = 0;
|
|
if (needXferUpdate == 0)
|
|
needXferUpdate = 2; /* says: child died */
|
|
if (status.w_termsig != 0) {
|
|
#ifdef DEBUG
|
|
if (debug && status.w_termsig != 9)
|
|
fprintf(ddt, "\tBad child termination!\n");
|
|
#endif /* DEBUG */
|
|
} else if (status.w_retcode == 0) {
|
|
/*
|
|
* This assumes we will never have more than
|
|
* MAX_XFERS_RUNNING zones to load. Should give this
|
|
* some thought.
|
|
*/
|
|
needLoadZones[numZonesToLoad] = zp;
|
|
numZonesToLoad++;
|
|
} else if (status.w_retcode == 1) {
|
|
#ifdef DEBUG
|
|
if (debug) fprintf(ddt,
|
|
"zoneref: Masters for secondary zone %s unreachable\n",
|
|
zp->z_origin);
|
|
#endif /* DEBUG */
|
|
syslog(LOG_WARNING,
|
|
"zoneref: Masters for secondary zone %s unreachable",
|
|
zp->z_origin);
|
|
} else if (status.w_retcode == 2) {
|
|
struct timeval tt;
|
|
#ifdef DEBUG
|
|
if (debug) (void)fprintf(ddt,
|
|
"zoneref: secondary zone %s reported up to date\n",
|
|
zp->z_origin);
|
|
#endif /* DEBUG */
|
|
/*
|
|
* Must update time and refresh value. Do sanity
|
|
* check to make sure we should really be here.
|
|
*/
|
|
if (zp->z_auth && zp->z_soa_refresh != 0) {
|
|
gettime(&tt);
|
|
zp->z_lastupdate = tt.tv_sec;
|
|
zp->z_refresh = zp->z_soa_refresh;
|
|
}
|
|
#ifdef DEBUG
|
|
else if (debug) (void)fprintf(ddt,
|
|
"zoneref: secondary zone %s incorrectly reported up to date\n",
|
|
zp->z_origin);
|
|
#endif /* DEBUG */
|
|
} else {
|
|
#ifdef DEBUG
|
|
if (debug > 1) fprintf(ddt, "xfer returned %d",
|
|
status.w_retcode);
|
|
#endif /* DEBUG */
|
|
syslog(LOG_ERR,"xfer returned %d", status.w_retcode);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif SYSV
|
|
}
|
|
|
|
/*
|
|
** Turn on or off debuging by open or closeing the debug file
|
|
*/
|
|
|
|
setdebug(code)
|
|
int code;
|
|
{
|
|
#if defined(lint) && !defined(DEBUG)
|
|
code = code;
|
|
#endif
|
|
#ifdef DEBUG
|
|
|
|
if (code) {
|
|
ddt = freopen(debugfile, "w+", stderr);
|
|
if ( ddt == NULL) {
|
|
syslog(LOG_WARNING, "can't open debug file: %m");
|
|
debug = 0;
|
|
}
|
|
else {
|
|
#if defined(SYSV)
|
|
setvbuf(ddt, NULL, _IOLBF, BUFSIZ);
|
|
#else
|
|
setlinebuf(ddt);
|
|
#endif
|
|
(void) fcntl(fileno(ddt), F_SETFL, FAPPEND);
|
|
}
|
|
}
|
|
else {
|
|
if (ddt) {
|
|
fprintf(ddt,"Debug turned OFF, Level %d\n",debug);
|
|
(void) fclose(ddt);
|
|
}
|
|
debug = 0;
|
|
}
|
|
#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.
|
|
*/
|
|
|
|
setIncrDbgFlg()
|
|
{
|
|
#if defined(SYSV)
|
|
(void)signal(SIGUSR1, setIncrDbgFlg);
|
|
#endif SYSV
|
|
#ifdef DEBUG
|
|
if (debug == 0) {
|
|
debug++;
|
|
setdebug(1);
|
|
}
|
|
else {
|
|
debug++;
|
|
}
|
|
fprintf(ddt,"Debug turned ON, Level %d\n",debug);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
** Catch a special signal to turn off debugging
|
|
*/
|
|
|
|
setNoDbgFlg()
|
|
{
|
|
#if defined(SYSV)
|
|
(void)signal(SIGUSR2, setNoDbgFlg);
|
|
#endif SYSV
|
|
setdebug(0);
|
|
}
|
|
|
|
/*
|
|
** Set flag for statistics dump
|
|
*/
|
|
setstatsflg()
|
|
{
|
|
#if defined(SYSV)
|
|
(void)signal(SIGIOT, setstatsflg);
|
|
#endif SYSV
|
|
needStatsDump = 1;
|
|
}
|
|
|
|
int setchkptflg()
|
|
{
|
|
#if defined(SYSV)
|
|
(void)signal(SIGQUIT, setchkptflg);
|
|
#endif SYSV
|
|
needToChkpt = 1;
|
|
}
|
|
|
|
/*
|
|
** Catch a special signal SIGSYS
|
|
**
|
|
** this is setup to fork and exit to drop to /usr/tmp/gmon.out
|
|
** and keep the server running
|
|
*/
|
|
|
|
sigprof()
|
|
{
|
|
#if defined(SYSV)
|
|
(void)signal(SIGSYS, sigprof);
|
|
#endif SYSV
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
fprintf(ddt,"sigprof()\n");
|
|
#endif
|
|
if ( fork() == 0)
|
|
{
|
|
(void) chdir("/usr/tmp");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Routines for managing stream queue
|
|
*/
|
|
|
|
struct qstream *
|
|
sqadd()
|
|
{
|
|
register struct qstream *sqp;
|
|
|
|
if ((sqp = (struct qstream *)calloc(1, sizeof(struct qstream)))
|
|
== NULL ) {
|
|
#ifdef DEBUG
|
|
if (debug >= 5)
|
|
fprintf(ddt,"sqadd: malloc error\n");
|
|
#endif
|
|
syslog(LOG_ERR, "sqadd: Out Of Memory");
|
|
return(QSTREAM_NULL);
|
|
}
|
|
#ifdef DEBUG
|
|
if (debug > 3)
|
|
fprintf(ddt,"sqadd(x%x)\n", sqp);
|
|
#endif
|
|
|
|
sqp->s_next = streamq;
|
|
streamq = sqp;
|
|
return(sqp);
|
|
}
|
|
|
|
sqrm(qp, mask)
|
|
register struct qstream *qp;
|
|
fd_set *mask;
|
|
{
|
|
register struct qstream *qsp;
|
|
extern void qremove_stream();
|
|
|
|
#ifdef DEBUG
|
|
if (debug > 1) {
|
|
fprintf(ddt,"sqrm(%#x, %d ) rfcnt=%d\n",
|
|
qp, qp->s_rfd, qp->s_refcnt);
|
|
}
|
|
#endif
|
|
if (qp->s_refcnt != 0)
|
|
return;
|
|
|
|
qremove_stream(qp);
|
|
if (qp->s_bufsize != 0)
|
|
(void) free(qp->s_buf);
|
|
FD_CLR(qp->s_rfd, mask);
|
|
(void) close(qp->s_rfd);
|
|
if (qp == streamq) {
|
|
streamq = qp->s_next;
|
|
} else {
|
|
for (qsp = streamq; qsp->s_next != qp; qsp = qsp->s_next)
|
|
;
|
|
qsp->s_next = qp->s_next;
|
|
}
|
|
(void)free((char *)qp);
|
|
}
|
|
|
|
sqflush()
|
|
{
|
|
register struct qstream *sp, *spnext;
|
|
|
|
for (sp = streamq; sp != QSTREAM_NULL; sp = spnext) {
|
|
sp->s_refcnt = 0;
|
|
spnext = sp->s_next;
|
|
sqrm(sp, &mask);
|
|
}
|
|
}
|
|
|
|
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++ = ' ';
|
|
}
|
|
|
|
net_mask(in)
|
|
struct in_addr in;
|
|
{
|
|
register u_long 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));
|
|
}
|
|
|
|
gettime(ttp)
|
|
struct timeval *ttp;
|
|
{
|
|
if (gettimeofday(ttp, (struct timezone *)0) < 0)
|
|
syslog(LOG_ERR, "gettimeofday failed: %m");
|
|
return;
|
|
}
|