#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 4.9.1.8 1993/12/06 00:43:02 vixie Exp $";
* ++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
* 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
* 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
#if !defined(lint) && !defined(SABER)
"@(#) Copyright (c) 1986, 1989, 1990 The Regents of the University of California.\n\
portions Copyright (c) 1993 Digital Equipment Corporation\n\
portions Copyright (c) 1993 Berkeley Network Software Consortium\n\
* Internet Name server (see rfc883 & others).
#if !defined(SYSV) && defined(XXX)
#include <sys/resource.h>
#define _SOCKADDR_LEN /* XXX - should be in portability.h but that
* would need to be included before socket.h
#include <arpa/nameser.h>
#if defined(sun) && defined (SYSV) /* Solaris 2 */
static int rbufsize
= 8 * 1024; /* UDP recive buffer size */
static struct sockaddr_in nsaddr
;
static u_int16_t local_ns_port
; /* our service port */
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
*)),
printnetinfo
__P((struct netinfo
*)),
static int sq_here
__P((struct qstream
*));
static SIG_FN onintr
__P(()),
#if defined(QRYLOG) && defined(SIGWINCH)
"Usage: named [-d #] [-q] [-r] [-p port[/localport]] [[-b] bootfile]\n");
register struct qstream
*sp
;
register struct qdatagram
*dqp
;
time_t lasttime
, maxctime
;
struct qstream
*candidate
= QSTREAM_NULL
;
FILE *fp
; /* file descriptor for pid file */
local_ns_port
= ns_port
= htons(NAMESERVER_PORT
);
** Save start and extent of argv for setproctitle.
LastArg
= argp
[-1] + strlen(argp
[-1]);
/* XXX - should use getopt here */
bootfile
= savestr(*++argv
);
/* use nonstandard port number.
* 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.
ns_port
= htons((u_int16_t
)
char *p
= strchr(*argv
, '/');
bootfile
= savestr(*argv
);
for (n
= getdtablesize() - 1; n
> 2; n
--)
(void) close(n
); /* don't use my_close() here */
fprintf(ddt
,"Debug turned ON, Level %d\n",debug
);
fprintf(ddt
,"Version = %s\t",Version
);
fprintf(ddt
,"bootfile = %s\n",bootfile
);
openlog("named", LOG_PID
|LOG_CONS
|LOG_NDELAY
, LOGFAC
);
openlog("named", LOG_PID
);
/* tuck my process id away */
fp
= fopen(PidFile
, "r+");
(void) fgets(oldpid
, sizeof(oldpid
), fp
);
fprintf(fp
, "%d\n", getpid());
fp
= fopen(PidFile
, "w");
fprintf(fp
, "%d\n", getpid());
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
;
if ((vs
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
syslog(LOG_ERR
, "socket(SOCK_STREAM): %m");
if (setsockopt(vs
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&on
,
syslog(LOG_ERR
, "setsockopt(vs, reuseaddr): %m");
if (bind(vs
, (struct sockaddr
*)&nsaddr
, sizeof(nsaddr
)) == 0)
if (errno
!= EADDRINUSE
|| n
> 4) {
if (errno
== EADDRINUSE
) {
"There may be a name server already running");
syslog(LOG_ERR
, "exiting");
syslog(LOG_ERR
, "bind(vs, [%s].%d): %m",
inet_ntoa(nsaddr
.sin_addr
),
#if defined(WANT_PIDFILE) && defined(PID_FIX)
if (atoi(oldpid
) && (fp
= fopen(PidFile
, "w"))) {
fprintf(fp
, "%s", oldpid
);
#endif /*WANT_PIDFILE && PID_FIX*/
} else { /* Retry opening the socket a few times */
if (listen(vs
, 5) != 0) {
syslog(LOG_ERR
, "listen(vs, 5): %m");
* Get list of local addresses and set up datagram sockets.
** Initialize and load database.
fprintf(ddt
, "Network and sort list:\n");
(void) signal(SIGHUP
, onhup
);
(void) signal(SIGXFSZ
, onhup
); /* wierd DEC Hesiodism, harmless */
(void) signal(SIGCLD
, endxfer
);
(void) signal(SIGALRM
, maint_alarm
);
bzero((char *)&vec
, sizeof(vec
));
vec
.sv_handler
= maint_alarm
;
vec
.sv_mask
= sigmask(SIGCHLD
);
(void) sigvec(SIGALRM
, &vec
, (struct sigvec
*)NULL
);
vec
.sv_handler
= endxfer
;
vec
.sv_mask
= sigmask(SIGALRM
);
(void) sigvec(SIGCHLD
, &vec
, (struct sigvec
*)NULL
);
(void) signal(SIGPIPE
, SIG_IGN
);
(void) signal(SIGSYS
, sigprof
);
(void) signal(SIGINT
, setdumpflg
);
(void) signal(SIGQUIT
, setchkptflg
);
(void) signal(SIGIOT
, setstatsflg
);
/* Catch SIGTERM so we can dump the database upon shutdown if it
has changed since it was last dumped/booted */
(void) signal(SIGTERM
, onintr
);
#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 */
#if defined(SIGWINCH) && defined(QRYLOG)
(void) signal(SIGWINCH
, setQrylogFlg
);
fprintf(ddt
,"database initialized\n");
* Fork and go into background now that
* we've done any slow initialization
* and are ready to answer queries.
if (!debug
|| !isatty(0)) {
n
= open(_PATH_DEVNULL
, O_RDONLY
);
syslog(LOG_ERR
, "fork: %m");
n
= open(_PATH_DEVNULL
, O_RDONLY
);
* 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
);
(void) ioctl(n
, TIOCNOTTY
, (char *)NULL
);
/* tuck my process id away again */
fp
= fopen(PidFile
, "w");
fprintf(fp
, "%d\n", getpid());
fprintf(ddt
,"Ready to answer queries.\n");
syslog(LOG_NOTICE
, "Ready to answer queries.\n");
nfds
= getdtablesize(); /* get the number of file descriptors */
nfds
= FD_SETSIZE
; /* Bulletproofing */
syslog(LOG_ERR
, "Return from getdtablesize() > FD_SETSIZE");
fprintf(ddt
,"Return from getdtablesize() > FD_SETSIZE\n");
for (dqp
= datagramq
; dqp
!= QDATAGRAM_NULL
; dqp
= dqp
->dq_next
)
FD_SET(dqp
->dq_dfd
, &mask
);
fprintf(ddt
,"Debug turned OFF\n");
* Block all blockable signals
* state during final dump
fprintf(ddt
, "Received shutdown signal\n");
for (zp
= zones
; zp
< &zones
[nzones
]; zp
++) {
if (zp
->z_state
& Z_CHANGED
)
#endif /* ALLOW_UPDATES */
** Wait until a query arrives
** The tv_sec field might be unsigned
** and thus cannot be negative.
if ((int32_t) retryqp
->q_time
<= tt
.tv_sec
) {
t
.tv_sec
= (int32_t) retryqp
->q_time
- tt
.tv_sec
;
n
= select(nfds
, &tmpmask
, (fd_set
*)NULL
, (fd_set
*)NULL
, tp
);
syslog(LOG_ERR
, "select: %m");
fprintf(ddt
,"select error\n");
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
< 0) && (errno
== PORT_WOULDBLK
))
syslog(LOG_WARNING
, "recvfrom: %m");
"\ndatagram from [%s].%d, fd %d, len %d; now %s",
inet_ntoa(from_addr
.sin_addr
),
ntohs(from_addr
.sin_port
),
fp_query((char *)buf
, ddt
);
* Consult database to get the answer.
ns_req(buf
, n
, PACKETSZ
, QSTREAM_NULL
, &from_addr
,
** Process stream connection
if (FD_ISSET(vs
, &tmpmask
)) {
from_len
= sizeof(from_addr
);
(struct sockaddr
*)&from_addr
,
if (rfd
< 0 && errno
== EMFILE
&& streamq
!= NULL
) {
candidate
= QSTREAM_NULL
;
for (sp
= streamq
; sp
!= QSTREAM_NULL
;
lasttime
= tt
.tv_sec
- sp
->s_time
;
else if (lasttime
> maxctime
) {
(struct sockaddr
*)&from_addr
,
if ((rfd
< 0) && (errno
== EMFILE
) &&
candidate
!= QSTREAM_NULL
) {
syslog(LOG_WARNING
, "accept: %m");
if ((n
= fcntl(rfd
, F_GETFL
, 0)) < 0) {
"fcntl(rfd, F_GETFL): %m");
if (fcntl(rfd
, F_SETFL
, n
|PORT_NONBLOCK
) != 0) {
"fcntl(rfd, non-blocking): %m");
if (setsockopt(rfd
, SOL_SOCKET
, SO_KEEPALIVE
,
(char *)&on
, sizeof(on
)) != 0)
"setsockopt(rfd, keepalive): %m");
if ((sp
= sqadd()) == QSTREAM_NULL
) {
sp
->s_rfd
= rfd
; /* stream file descriptor */
sp
->s_size
= -1; /* amount of data to receive */
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
;
"\nTCP connection from [%s].%d (fd %d)\n",
inet_ntoa(sp
->s_from
.sin_addr
),
ntohs(sp
->s_from
.sin_port
), rfd
));
dprintf(3, (ddt
, "streamq = x%x\n",streamq
));
for (sp
= streamq
; sp
!= QSTREAM_NULL
; sp
= nextsp
) {
if (!FD_ISSET(sp
->s_rfd
, &tmpmask
))
"sp x%x rfd %d size %d time %d next x%x\n",
sp
, sp
->s_rfd
, sp
->s_size
,
sp
->s_time
, sp
->s_next
));
"\tbufsize %d buf x%x bufp x%x\n",
sp
->s_bufsize
, sp
->s_buf
, sp
->s_bufp
));
- (sp
->s_bufp
- (u_char
*)&sp
->s_tempsize
);
(n
= read(sp
->s_rfd
, sp
->s_bufp
, size
)) > 0
if ((n
< 0) && (errno
== PORT_WOULDBLK
))
if ((sp
->s_bufp
- (u_char
*)&sp
->s_tempsize
) ==
sp
->s_size
= htons(sp
->s_tempsize
);
if (sp
->s_bufsize
== 0) {
if ( (sp
->s_buf
= (u_char
*)
sp
->s_size
= sizeof(buf
);
if (sp
->s_size
> sp
->s_bufsize
&&
realloc((char *)sp
->s_buf
,
sp
->s_size
= sizeof(buf
);
sp
->s_bufsize
= sp
->s_size
;
* 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_int16_t
))) {
hp
= (HEADER
*)sp
->s_buf
;
(void) writemsg(sp
->s_rfd
, sp
->s_buf
,
if ((n
== -1) && (errno
== PORT_WOULDBLK
))
* Consult database to get the answer.
/* ns_req() can call sqrm() - check for it */
sp
->s_bufp
= (u_char
*)&sp
->s_tempsize
;
register struct netinfo
*ntp
;
struct ifreq ifreq
, *ifr
;
struct qdatagram
*dqp
, *pqp
, *nqp
;
char buf
[BUFSIZ
], *cp
, *cplim
;
time_t my_generation
= time(NULL
);
ifc
.ifc_len
= sizeof(buf
);
if (ioctl(vs
, SIOCGIFCONF
, (char *)&ifc
) < 0) {
syslog(LOG_ERR
, "get interface configuration: %m - exiting");
#if defined(AF_LINK) && !defined(RISCOS_BSD)
#define my_max(a, b) (a > b ? a : b)
#define my_size(p) my_max((p).sa_len, sizeof(p))
#define my_size(p) (sizeof (p))
cplim
= buf
+ ifc
.ifc_len
; /*skip over if's with big ifr_addr's */
cp
+= sizeof (ifr
->ifr_name
) + my_size(ifr
->ifr_addr
)) {
ifr
= (struct ifreq
*)cp
;
if (ifr
->ifr_addr
.sa_family
!= AF_INET
||
&ifr
->ifr_addr
)->sin_addr
.s_addr
== 0) {
* 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_ERR
, "get interface addr: %m");
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
)
"dup interface address %s on %s\n",
inet_ntoa(((struct sockaddr_in
*)
&ifreq
.ifr_addr
)->sin_addr
),
dqp
->dq_gen
= my_generation
;
* 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",
if ((dqp
= (struct qdatagram
*)
calloc(1, sizeof(struct qdatagram
))
dprintf(5, (ddt
, "getnetconf: malloc error\n"));
syslog(LOG_ERR
, "getnetconf: Out Of Memory");
dqp
->dq_next
= datagramq
;
dqp
->dq_addr
= ((struct sockaddr_in
*)
&ifreq
.ifr_addr
)->sin_addr
;
dqp
->dq_gen
= my_generation
;
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.
ntp
= (struct netinfo
*)malloc(sizeof(struct netinfo
));
ntp
->my_addr
= ((struct sockaddr_in
*)
&ifreq
.ifr_addr
)->sin_addr
;
if (ioctl(vs
, SIOCGIFNETMASK
, (char *)&ifreq
) < 0) {
syslog(LOG_ERR
, "get netmask: %m");
ntp
->mask
= net_mask(ntp
->my_addr
);
ntp
->mask
= ((struct sockaddr_in
*)
&ifreq
.ifr_addr
)->sin_addr
.s_addr
;
/* 4.2 does not support subnets */
ntp
->mask
= net_mask(ntp
->my_addr
);
if (ioctl(vs
, SIOCGIFFLAGS
, (char *)&ifreq
) < 0) {
syslog(LOG_ERR
, "get interface flags: %m");
if (ifreq
.ifr_flags
& IFF_LOOPBACK
)
/* test against 127.0.0.1 (yuck!!) */
if (ntp
->my_addr
.s_addr
== inet_addr("127.0.0.1")) /* XXX */
if (netloop
.my_addr
.s_addr
== 0) {
netloop
.my_addr
= ntp
->my_addr
;
netloop
.mask
= 0xffffffff;
netloop
.net
= ntp
->my_addr
.s_addr
;
dprintf(1, (ddt
, "loopback address: x%lx\n",
netloop
.my_addr
.s_addr
));
} else if ((ifreq
.ifr_flags
& IFF_POINTOPOINT
)) {
if (ioctl(vs
, SIOCGIFDSTADDR
, (char *)&ifreq
) < 0) {
syslog(LOG_ERR
, "get dst addr: %m");
ntp
->net
= ((struct sockaddr_in
*)
&ifreq
.ifr_addr
)->sin_addr
.s_addr
;
ntp
->net
= ntp
->mask
& ntp
->my_addr
.s_addr
;
* Place on end of list of locally-attached (sub)nets,
* but before logical nets for subnetted nets.
(void) 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.
for (pqp
= NULL
, dqp
= datagramq
;
if ((dqp
->dq_addr
.s_addr
!= INADDR_ANY
)
&& (dqp
->dq_gen
!= my_generation
)
dprintf(1, (ddt
, "bye, bye, interface [%s]",
inet_ntoa(dqp
->dq_addr
)));
syslog(LOG_CRIT
, "interface [%s] missing; deleting",
inet_ntoa(dqp
->dq_addr
));
pqp
->dq_next
= dqp
->dq_next
;
datagramq
= dqp
->dq_next
;
* Create separate qdatagram structure for socket
if ((dqp
= (struct qdatagram
*)calloc(1, sizeof(*dqp
)))
dprintf(1, (ddt
, "getnetconf: malloc error\n"));
syslog(LOG_ERR
, "getnetconf: Out Of Memory");
dqp
->dq_next
= datagramq
;
dqp
->dq_addr
.s_addr
= INADDR_ANY
;
* 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 (findnetinfo(ntp
->my_addr
))
ontp
= (struct netinfo
*)
malloc(sizeof(struct netinfo
));
"getnetconf: malloc error\n"));
syslog(LOG_ERR
, "getnetconf: Out Of Memory");
ontp
->my_addr
= ntp
->my_addr
;
ontp
->net
= ontp
->my_addr
.s_addr
& nm
;
* Find netinfo structure for logical network implied by address "addr",
* if it's on list of local/favored networks.
register struct netinfo
*ntp
;
net
= addr
.s_addr
& mask
;
for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
)
if (ntp
->net
== net
&& ntp
->mask
== mask
)
return ((struct netinfo
*) NULL
);
register struct netinfo
*ntp
;
for ( ; 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
));
register struct qdatagram
*dqp
;
* 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");
fprintf(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_ERR
, "setsockopt(dqp->dq_dfd, reuseaddr): %m");
/* XXX press on regardless, this is not too serious. */
/* note: this depends on short-circuit evaluation, which is in the
* C standards, but tricky nonetheless. (vix)
if ((getsockopt(dqp
->dq_dfd
, SOL_SOCKET
, SO_RCVBUF
, &n
, &m
) >= 0)
(void) setsockopt(dqp
->dq_dfd
, SOL_SOCKET
, SO_RCVBUF
,
(char *)&rbufsize
, sizeof(rbufsize
));
if ((n
= fcntl(dqp
->dq_dfd
, F_GETFL
, 0)) < 0) {
syslog(LOG_ERR
, "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_ERR
, "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_ERR
, "bind(dfd=%d, [%s].%d): %m - exiting",
dqp
->dq_dfd
, inet_ntoa(nsaddr
.sin_addr
),
** Set flag saying to reload database upon receiving SIGHUP.
** Must make sure that someone isn't walking through a data
** structure at the time.
(void)signal(SIGHUP
, onhup
);
** Set flag saying to call ns_maint()
** Must make sure that someone isn't walking through a data
** structure at the time.
(void)signal(SIGALRM
, maint_alarm
);
* Signal handler to schedule shutdown. Just set flag, to ensure a consistent
#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
(void)signal(SIGINT
, setdumpflg
);
** Turn on or off debuging by open or closeing the debug file
#if defined(lint) && !defined(DEBUG)
ddt
= freopen(debugfile
, "w+", stderr
);
syslog(LOG_WARNING
, "can't open debug file %s: %m",
setvbuf(ddt
, NULL
, _IOLBF
, BUFSIZ
);
if ((n
= fcntl(fileno(ddt
), F_GETFL
, 0)) < 0) {
"fcntl(ddt, F_GETFL): %m");
(void) fcntl(fileno(ddt
), F_SETFL
, n
|O_APPEND
);
/* delay closing ddt, we might interrupt someone */
** 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.
(void)signal(SIGUSR1
, setIncrDbgFlg
);
fprintf(ddt
,"Debug turned ON, Level %d\n",debug
);
** Catch a special signal to turn off debugging
(void)signal(SIGUSR2
, setNoDbgFlg
);
#if defined(QRYLOG) && defined(SIGWINCH)
** Set flag for query logging
(void)signal(SIGWINCH
, setQrylogFlg
);
syslog(LOG_NOTICE
, "query log %s\n", qrylog
?"on" :"off");
#endif /*QRYLOG && SIGWINCH*/
** Set flag for statistics dump
(void)signal(SIGIOT
, setstatsflg
);
(void)signal(SIGQUIT
, setchkptflg
);
** Catch a special signal SIGSYS
** this is setup to fork and exit to drop to /usr/tmp/gmon.out
** and keep the server running
(void)signal(SIGSYS
, sigprof
);
fprintf(ddt
,"sigprof()\n");
(void) chdir(_PATH_TMPDIR
);
** Routines for managing stream queue
register struct qstream
*sqp
;
if (!(sqp
= (struct qstream
*)calloc(1, sizeof(struct qstream
)))) {
dprintf(5, (ddt
, "sqadd: calloc error\n"));
syslog(LOG_ERR
, "sqadd: Out Of Memory");
dprintf(3, (ddt
, "sqadd(x%x)\n", sqp
));
* remove stream queue structure `qp'.
* no current queries may refer to this stream when it is removed.
* memory is deallocated. sockets are closed. lists are relinked.
register struct qstream
*qp
;
register struct qstream
*qsp
;
dprintf(2, (ddt
, "sqrm(%#x, %d ) rfcnt=%d\n",
qp
, qp
->s_rfd
, qp
->s_refcnt
));
FD_CLR(qp
->s_rfd
, &mask
);
(void) my_close(qp
->s_rfd
);
qsp
&& (qsp
->s_next
!= qp
);
qsp
->s_next
= qp
->s_next
;
* call sqrm() on all open streams
* global list `streamq' becomes empty
register struct qstream
*sp
, *spnext
;
for (sp
= streamq
; sp
!= QSTREAM_NULL
; sp
= spnext
) {
* determine whether stream 'sp' is still on the streamq
register struct qstream
*sp
;
register struct qstream
*t
;
for (t
= streamq
; t
!= QSTREAM_NULL
; t
= t
->s_next
)
* Initiate query on stream;
* mark as referenced and stop selecting for input.
register struct qstream
*sp
;
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.
register struct qstream
*sp
;
FD_SET(sp
->s_rfd
, &mask
);
if (getpeername(s
, (struct sockaddr
*)&sin
, &size
) == 0)
(void) sprintf(buf
, "-%s [%s]", a
, inet_ntoa(sin
.sin_addr
));
syslog(LOG_DEBUG
, "getpeername: %m");
(void) sprintf(buf
, "-%s", a
);
(void) strncpy(cp
, buf
, LastArg
- cp
);
register u_int32_t i
= ntohl(in
.s_addr
);
return (htonl(IN_CLASSA_NET
));
return (htonl(IN_CLASSB_NET
));
return (htonl(IN_CLASSC_NET
));
#if defined(BSD43_BSD43_NFS)
/* junk needed for old Sun NFS licensees */
extern char *dn_skipname();
char *(*hack_skipname
)() = dn_skipname
;