* Copyright (c) 1988 Regents of the University of California.
* 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.
* The original version of xfer is by Kevin Dunlap.
* Completed and integrated with named by David Waitzman (dwaitzman@bbn.com)
* Modified by M. Karels and O. Kure 10-88.
"@(#) Copyright (c) 1988 Regents of the University of California.\n\
static char sccsid
[] = "@(#)xfer.c 4.3 (Berkeley) 2/27/89";
#include <sys/resource.h>
#include <arpa/nameser.h>
#define XFER /* modifies the ns.h include file */
/* max length of data in RR data field */
#define MAXDATA 256 /* from db.h */
int read_interrupted
= 0;
struct zoneinfo zones
; /* zone information */
static char *ddtfile
= "/usr/tmp/xfer.ddt.XXXXXX";
FILE *fp
= 0, *ddt
, *dbfp
;
char *domain
; /* domain being xfered */
int domain_len
; /* strlen(domain) */
register struct zoneinfo
*zp
;
register struct hostent
*hp
;
char *dbfile
= NULL
, *tracefile
= NULL
, *tm
= NULL
;
int dbfd
, ddtd
, result
, c
;
extern int optind
, getopt();
openlog("named-xfer", LOG_PID
|LOG_CONS
, LOG_DAEMON
);
openlog("named-xfer", LOG_PID
);
while ((c
= getopt(argc
, argv
, "d:l:s:t:z:f:q")) != EOF
)
ddtfile
= malloc(strlen(optarg
) +
(void) strcpy(ddtfile
, optarg
);
(void) strcat(ddtfile
, ".XXXXXX");
serial_no
= (u_long
) atol(optarg
);
case 'z': /* zone == domain */
domain_len
= strlen(domain
);
tmpname
= malloc((unsigned)strlen(optarg
) +
(void) strcpy(tmpname
, optarg
);
if (!domain
|| !dbfile
|| optind
>= argc
) {
if (tracefile
&& (fp
= fopen(tracefile
, "w")) == NULL
)
(void) strcat(tmpname
, ".XXXXXX");
/* tmpname is now something like "/etc/named/named.bu.db.XXXXXX" */
if ((dbfd
= mkstemp(tmpname
)) == NULL
) {
syslog(LOG_ERR
, "can't make tmpfile (%s): %m\n",
if (fchmod(dbfd
, 0644) == -1) {
syslog(LOG_ERR
, "can't fchmod tmpfile (%s): %m\n",
if ((dbfp
= fdopen(dbfd
, "r+")) == NULL
) {
syslog(LOG_ERR
, "can't fdopen tmpfile (%s)", tmpname
);
/* ddtfile is now something like "/usr/tmp/xfer.ddt.XXXXXX" */
if ((ddtd
= mkstemp(ddtfile
)) == NULL
) {
} else if (fchmod(ddtd
, 0644) == -1) {
} else if ((ddt
= fdopen(ddtd
, "w")) == NULL
) {
* Ignore many types of signals that named (assumed to be our parent)
* considers important- if not, the user controlling named with
* signals usually kills us.
(void) signal(SIGHUP
, SIG_IGN
);
(void) signal(SIGSYS
, SIG_IGN
);
(void) signal(SIGINT
, SIG_IGN
);
(void) signal(SIGQUIT
, SIG_IGN
);
(void) signal(SIGIOT
, SIG_IGN
);
#if defined(SIGUSR1) && defined(SIGUSR2)
(void) signal(SIGUSR1
, SIG_IGN
);
(void) signal(SIGUSR2
, SIG_IGN
);
(void) signal(SIGEMT
, SIG_IGN
);
(void) signal(SIGFPE
, SIG_IGN
);
if (debug
) (void)fprintf(ddt
, "domain `%s' file `%s' ser no %lu \n",
domain
, dbfile
,serial_no
);
zp
->z_type
= Z_SECONDARY
;
(void)fprintf(ddt
,"zone found (%d): ", zp
->z_type
);
if (zp
->z_origin
[0] == '\0')
(void)fprintf(ddt
,"'.'");
(void)fprintf(ddt
,"'%s'", zp
->z_origin
);
(void)fprintf(ddt
,", source = %s\n", zp
->z_source
);
for (; optind
!= argc
; optind
++,zp
->z_addrcnt
++) {
zp
->z_addr
[zp
->z_addrcnt
].s_addr
= inet_addr(tm
);
if (zp
->z_addr
[zp
->z_addrcnt
].s_addr
== (unsigned)-1) {
syslog(LOG_ERR
, "uninterpretable server %s\n",
(char *)&zp
->z_addr
[zp
->z_addrcnt
].s_addr
,
sizeof(zp
->z_addr
[zp
->z_addrcnt
].s_addr
));
(void)fprintf(ddt
,", %s",tm
);
if (zp
->z_addrcnt
>= NSMAX
) {
(void)fprintf(ddt
, "\nns.h NSMAX reached\n");
if (debug
) (void)fprintf(ddt
," (addrcnt) = %d\n", zp
->z_addrcnt
);
_res
.options
&= ~(RES_DEFNAMES
| RES_DNSRCH
| RES_RECURSE
);
result
= getzone(zp
, serial_no
);
case XFER_SUCCESS
: /* ok exit */
if (rename(tmpname
, dbfile
) == -1) {
syslog(LOG_ERR
, "rename %s to %s: %m",
case XFER_UPTODATE
: /* the zone was already uptodate */
exit(XFER_TIMEOUT
); /* servers not reachable exit */
exit(XFER_FAIL
); /* yuck exit */
\t[-l debug_log_file (default %s)]\n\
\tservers...\n", ddtfile
);
int minimum_ttl
= 0, got_soa
= 0;
char prev_origin
[MAXDNAME
];
char prev_dname
[MAXDNAME
];
int s
, n
, l
, cnt
, soacnt
, error
= 0;
u_char
*cp
, *nmp
, *eom
, *tmp
;
u_char name
[MAXDNAME
], name2
[MAXDNAME
];
struct zoneinfo zp_start
, zp_finish
;
struct itimerval ival
, zeroival
;
(void)fprintf(ddt
,"getzone() %s\n", zp
->z_origin
);
bzero((char *)&zeroival
, sizeof(zeroival
));
ival
.it_value
.tv_sec
= 30;
sv
.sv_handler
= read_alarm
;
(void) sigvec(SIGALRM
, &sv
, &osv
);
strcpy(prev_origin
, zp
->z_origin
);
for (cnt
= 0; cnt
< zp
->z_addrcnt
; cnt
++) {
if ((buf
= (u_char
*)malloc(2 * PACKETSZ
)) == NULL
) {
syslog(LOG_ERR
, "malloc(%u) failed",
bzero((char *)&sin
, sizeof(sin
));
sin
.sin_family
= AF_INET
;
sin
.sin_port
= htons(NAMESERVER_PORT
);
sin
.sin_addr
= zp
->z_addr
[cnt
];
if ((s
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
syslog(LOG_ERR
, "socket: %m");
(void)fprintf(ddt
,"connecting to server #%d %s, %d\n",
cnt
+1, inet_ntoa(sin
.sin_addr
), ntohs(sin
.sin_port
));
if (connect(s
, (struct sockaddr
*)&sin
, sizeof(sin
)) < 0) {
(void)fprintf(ddt
, "connect failed, errno %d\n", errno
);
if ((n
= res_mkquery(QUERY
, zp
->z_origin
, C_IN
,
T_SOA
, (char *)NULL
, 0, NULL
, buf
, bufsize
)) < 0) {
syslog(LOG_ERR
, "zone %s: res_mkquery T_SOA failed",
(void) sigvec(SIGALRM
, &osv
, (struct sigvec
*)0);
* Send length & message for zone transfer
if (writemsg(s
, buf
, n
) < 0) {
(void)fprintf(ddt
,"writemsg failed\n");
* Get out your butterfly net and catch the SOA
if (debug
> 10) (void)fprintf(ddt
,"Before setitimer\n");
(void) setitimer(ITIMER_REAL
, &ival
,
(struct itimerval
*)NULL
);
if (debug
> 10) (void)fprintf(ddt
,"Before recv(l = %d)\n",n
);
if ((n
= recv(s
, (char *)cp
, l
, 0)) > 0) {
"bad recv->%d, errno= %d, read_interrupt=%d\n", n
, errno
, read_interrupted
);
if (n
== -1 && errno
== EINTR
(void) setitimer(ITIMER_REAL
, &zeroival
,
(struct itimerval
*)NULL
);
if ((len
= htons(*(u_short
*)buf
)) == 0) {
if ((buf
= (u_char
*)realloc(buf
, len
)) == NULL
) {
"malloc(%u) failed for SOA from server %s, zone %s\n",
len
, inet_ntoa(sin
.sin_addr
), zp
->z_origin
);
(void) setitimer(ITIMER_REAL
, &ival
,
(struct itimerval
*)NULL
);
if ((n
= recv(s
, (char *)cp
, l
, 0)) > 0) {
if (errno
== EINTR
&& !read_interrupted
)
"recv failed: n= %d, errno = %d\n",
(void) setitimer(ITIMER_REAL
, &zeroival
,
(struct itimerval
*)NULL
);
(void)fprintf(ddt
,"len = %d\n", len
);
ancount
= ntohs(hp
->ancount
);
aucount
= ntohs(hp
->nscount
);
* 2) not an authority response
* 3) both the number of answers and authority count < 1)
if (hp
->rcode
!= NOERROR
|| !(hp
->aa
) ||
(ancount
< 1 && aucount
< 1)) {
"%s from %s, zone %s: rcode %d, aa %d, ancount %d, aucount %d\n",
"bad response to SOA query",
inet_ntoa(sin
.sin_addr
), zp
->z_origin
,
hp
->rcode
, hp
->aa
, ancount
, aucount
);
"%s from %s, zone %s: rcode %d, aa %d, ancount %d, aucount %d\n",
"bad response to SOA query",
inet_ntoa(sin
.sin_addr
), zp
->z_origin
,
hp
->rcode
, hp
->aa
, ancount
, aucount
);
if (len
< sizeof(HEADER
) + QFIXEDSZ
) {
"malformed SOA from %s, zone %s: too short\n",
inet_ntoa(sin
.sin_addr
), zp
->z_origin
);
"malformed SOA from %s: too short\n",
inet_ntoa(sin
.sin_addr
));
tmp
= buf
+ sizeof(HEADER
);
if ((n
= dn_skipname(tmp
, eom
)) == -1)
if ((n
= dn_skipname(tmp
, eom
)) == -1)
if (soa_zinfo(&zp_start
, tmp
, eom
) == -1)
if (zp_start
.z_serial
> serial_no
|| serial_no
== 0) {
(void)fprintf(ddt
, "need update, serial %d\n",
if ((n
= res_mkquery(QUERY
, zp
->z_origin
, C_IN
,
T_AXFR
, (char *)NULL
, 0, NULL
,
"zone %s: res_mkquery T_AXFR failed",
(void) sigvec(SIGALRM
, &osv
,
* Send length & message for zone transfer
if (writemsg(s
, buf
, n
) < 0) {
(void)fprintf(ddt
,"writemsg failed\n");
* Receive length & response
(void) setitimer(ITIMER_REAL
, &ival
,
(struct itimerval
*)NULL
);
if ((n
= recv(s
, (char *)cp
, l
, 0)) > 0) {
if (errno
== EINTR
&& !read_interrupted
)
"recv failed: n= %d, errno = %d\n",
(void) setitimer(ITIMER_REAL
, &zeroival
,
(struct itimerval
*)NULL
);
if ((len
= htons(*(u_short
*)buf
)) == 0)
(void) setitimer(ITIMER_REAL
, &ival
,
(struct itimerval
*)NULL
);
if ((n
= recv(s
, (char *)cp
, l
, 0)) > 0) {
if (errno
== EINTR
&& !read_interrupted
)
(void)fprintf(ddt
,"recv failed\n");
(void) setitimer(ITIMER_REAL
, &zeroival
,
(struct itimerval
*)NULL
);
(void)fprintf(ddt
,"len = %d\n", len
);
if (fp
) fp_query(buf
,fp
);
if (len
< sizeof(HEADER
)) {
"record too short from %s, zone %s\n",
"record too short from %s\n",
inet_ntoa(sin
.sin_addr
));
cp
= buf
+ sizeof(HEADER
);
if ((n
= dn_skipname(cp
, eom
)) == -1 ||
n
+ QFIXEDSZ
>= eom
- cp
)
if ((n
= dn_skipname(cp
, eom
)) == -1)
n
= print_output(buf
, bufsize
, cp
);
"getzone: print_update failed (%d, %d)\n",
if (dn_expand(buf
, buf
+ 512, nmp
,
name
, sizeof(name
)) == -1)
if (eom
- tmp
<= 2 * sizeof(u_short
) +
tmp
+= 2 * sizeof(u_short
)
if ((n
= dn_skipname(tmp
, eom
)) == -1)
if ((n
= dn_skipname(tmp
, eom
)) == -1)
if (eom
- tmp
<= sizeof(u_long
))
"first SOA for %s, serial %d\n",
if (dn_expand(buf
, buf
+ 512, nmp
, name2
,
if (strcasecmp((char *)name
, (char *)name2
) != 0) {
"extraneous SOA for %s\n",
if (soa_zinfo(&zp_finish
, tmp
, eom
) == -1)
"SOA, serial %d\n", zp_finish
.z_serial
);
if (serial
!= zp_finish
.z_serial
) {
strcpy(prev_origin
, zp
->z_origin
);
"serial changed, restart\n");
* Flush buffer, truncate file
* and seek to beginning to restart.
if (ftruncate(fileno(dbfp
), 0) != 0) {
(void) sigvec(SIGALRM
, &osv
, (struct sigvec
*)0);
(void)fprintf(ddt
,"error receiving zone transfer\n");
"zone up-to-date, serial %d\n", zp_start
.z_serial
);
(void) sigvec(SIGALRM
, &osv
, (struct sigvec
*)0);
* Set flag saying to read was interrupted
extern int read_interrupted
;
writemsg(rfd
, msg
, msglen
)
u_short len
= htons((u_short
)msglen
);
iov
[0].iov_base
= (caddr_t
)&len
;
iov
[0].iov_len
= sizeof(len
);
iov
[1].iov_base
= (caddr_t
)msg
;
if (writev(rfd
, iov
, 2) != sizeof(len
) + msglen
) {
(void)fprintf(ddt
,"write failed %d\n", errno
);
register struct zoneinfo
*zp
;
if (eom
- cp
< 3 * sizeof(u_short
) + sizeof(u_long
))
cp
+= 3 * sizeof(u_short
) + sizeof(u_long
);
if ((n
= dn_skipname(cp
, eom
)) == -1)
if ((n
= dn_skipname(cp
, eom
)) == -1)
if (eom
- cp
< 5 * sizeof(u_long
))
GETLONG(zp
->z_serial
, cp
);
GETLONG(zp
->z_refresh
, cp
);
zp
->z_time
= tt
.tv_sec
+ zp
->z_refresh
;
GETLONG(zp
->z_retry
, cp
);
GETLONG(zp
->z_expire
, cp
);
GETLONG(zp
->z_minimum
, cp
);
if (gettimeofday(ttp
, (struct timezone
*)0) < 0)
syslog(LOG_ERR
, "gettimeofday failed: %m");
* Parse the message, determine if it should be printed, and if so, print it
* Does minimal error checking on the message content.
print_output(msg
, msglen
, rrp
)
register HEADER
*hp
= (HEADER
*) msg
;
int n
, i
, j
, tab
, result
, class, type
, dlen
, n1
;
u_char
*cp1
, data
[BUFSIZ
];
u_char
*temp_ptr
; /* used to get ttl for RR */
char *cdata
, *origin
, *proto
, dname
[MAXDNAME
];
extern char *inet_ntoa(), *protocolname(), *servicename();
if ((n
= dn_expand(msg
, msg
+ msglen
, cp
, (u_char
*) dname
,
origin
= index(dname
, '.');
origin
++; /* move past the '.' */
(void) fprintf(ddt
, "print_output: dname %s type %d class %d ttl %d\n",
dname
, type
, class, ttl
);
* Convert the resource record data into the internal database format.
if ((n
= dn_expand(msg
, msg
+ msglen
, cp
, data
,
n
= strlen((char *) data
) + 1;
if ((n
= dn_expand(msg
, msg
+ msglen
, cp
, data
,
cp1
= data
+ (n
= strlen((char *) data
) + 1);
n1
-= 5 * sizeof(u_long
);
if ((n
= dn_expand(msg
, msg
+ msglen
, cp
, cp1
, n1
)) < 0) {
cp1
+= strlen((char *) cp1
) + 1;
temp_ptr
= cp
+ 4 * sizeof(u_long
);
GETLONG(minimum_ttl
, temp_ptr
);
bcopy((char *) cp
, (char *) cp1
,
bcopy((char *) cp
, (char *) data
, sizeof(u_short
));
cp1
= data
+ sizeof(u_short
);
if ((n
= dn_expand(msg
, msg
+ msglen
, cp
, cp1
,
sizeof(data
) - sizeof(u_short
))) < 0)
/* compute end of data */
cp1
+= strlen((char *) cp1
) + 1;
/* compute size of data */
(void) fprintf(ddt
, "unknown type %d\n", type
);
return ((cp
- rrp
) + dlen
);
"update type %d: %d bytes is too much data\n",
hp
->rcode
= NOCHANGE
; /* XXX - FORMERR ??? */
* Only print one SOA per db file
* If the origin has changed, print the new origin
if (strcasecmp(prev_origin
, origin
)) {
(void) strcpy(prev_origin
, origin
);
(void) fprintf(dbfp
, "$ORIGIN %s.\n", origin
);
if (strcasecmp(prev_dname
, dname
)) {
* set the prev_dname to be the current dname, then cut off all
* characters of dname after (and including) the first '.'
char *cutp
= index(dname
, '.');
(void) strcpy(prev_dname
, dname
);
(void) fprintf(dbfp
, ".\t");
(void) fprintf(dbfp
, ".%s.\t", origin
); /* ??? */
(void) fprintf(dbfp
, "%s\t", dname
);
if (ttl
!= 0 && ttl
!= minimum_ttl
)
(void) fprintf(dbfp
, "%d\t", (int) ttl
);
(void) fprintf(dbfp
, "%s\t%s\t", p_class(class), p_type(type
));
* Print type specific data
(void) fprintf(dbfp
, "%s",
inet_ntoa(*(struct in_addr
*) & n
));
(void) fprintf(dbfp
, "\n");
(void) fprintf(dbfp
, ".\n");
(void) fprintf(dbfp
, "%s.\n", cp
);
(void) fprintf(dbfp
, ".\t");
(void) fprintf(dbfp
, "%s.", cp
);
(void) fprintf(dbfp
, "\n");
(void) fprintf(dbfp
, "\"%.*s\"", (int) n
, cp
);
(void) fprintf(dbfp
, "\"\"");
(void) fprintf(dbfp
, " \"%.*s\"", (int) n
, cp
);
(void) fprintf(dbfp
, "\"\"");
(void) fprintf(dbfp
, "%s.", cp
);
cp
+= strlen((char *) cp
) + 1;
(void) fprintf(dbfp
, " %s. (\n", cp
);
cp
+= strlen((char *) cp
) + 1;
(void) fprintf(dbfp
, "\t\t%lu", n
);
(void) fprintf(dbfp
, " %lu", n
);
(void) fprintf(dbfp
, " %lu", n
);
(void) fprintf(dbfp
, " %lu", n
);
(void) fprintf(dbfp
, " %lu )\n", n
);
(void) fprintf(dbfp
, "%lu", n
);
(void) fprintf(dbfp
, " %s.\n", cp
);
(void) fprintf(dbfp
, "\"%s\"\n", cp
);
if (n
== sizeof(u_long
)) {
(void) fprintf(dbfp
, "%lu\n", n
);
(void) fprintf(dbfp
, "%s ",
inet_ntoa(*(struct in_addr
*) & addr
));
proto
= protocolname(*cp
);
(void) fprintf(dbfp
, "%s ", proto
);
while (cp
< (u_char
*) cdata
+ n
) {
(void) fprintf(dbfp
, " %s",
(void) fprintf(dbfp
, "\n");
(void) fprintf(dbfp
, "%s.", cp
);
cp
+= strlen((char *) cp
) + 1;
(void) fprintf(dbfp
, " %s.\n", cp
);
(void) fprintf(dbfp
, "???\n");
* Make a copy of a string and return a pointer to it.
cp
= malloc((unsigned)strlen(str
) + 1);
syslog(LOG_ERR
, "savestr: %m");