diff options
Diffstat (limited to 'contrib/bind/bin/named-xfer/named-xfer.c')
-rw-r--r-- | contrib/bind/bin/named-xfer/named-xfer.c | 1135 |
1 files changed, 952 insertions, 183 deletions
diff --git a/contrib/bind/bin/named-xfer/named-xfer.c b/contrib/bind/bin/named-xfer/named-xfer.c index 062cc33..d7db886 100644 --- a/contrib/bind/bin/named-xfer/named-xfer.c +++ b/contrib/bind/bin/named-xfer/named-xfer.c @@ -1,5 +1,6 @@ +/* $FreeBSD$ */ /* - * The original version of xfer by Kevin Dunlap. + * The original version of named-xfer by Kevin Dunlap. * Completed and integrated with named by David Waitzman * (dwaitzman@bbn.com) 3/14/88. * Modified by M. Karels and O. Kure 10-88. @@ -84,7 +85,8 @@ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -100,27 +102,45 @@ * SOFTWARE. */ +/* + * Portions Copyright (c) 1998 by MetaInfo, Incorporated. + * + * 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 MetaInfo Incorporated 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 METAINFO INCORPORATED DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL METAINFO INCORPRATED + * 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. + */ #if !defined(lint) && !defined(SABER) char copyright[] = "@(#) Copyright (c) 1988, 1990 The Regents of the University of California.\n\ portions Copyright (c) 1993 Digital Equipment Corporation\n\ + portions Copyright (c) 1998 MetaInfo, Inc.\n\ portions Copyright (c) 1995, 1996 Internet Software Consorium\n\ All rights reserved.\n"; #endif /* not lint */ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91"; -static char rcsid[] = "$Id: named-xfer.c,v 8.38 1998/03/27 00:19:28 halley Exp $"; +static const char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91"; +static const char rcsid[] = "$Id: named-xfer.c,v 8.89 1999/11/09 20:36:54 marka Exp $"; #endif /* not lint */ #include "port_before.h" -#include "fd_setsize.h" - #include <sys/types.h> #include <sys/param.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <netdb.h> @@ -141,26 +161,39 @@ static char rcsid[] = "$Id: named-xfer.c,v 8.38 1998/03/27 00:19:28 halley Exp $ #include <stdarg.h> #include <isc/eventlib.h> +#include <isc/list.h> #include <isc/logging.h> +/* This still uses malloc/free, but the tsig routines allocate memory with + * memget, and we free it with memput. + */ +#include <isc/memcluster.h> + +#include <isc/dst.h> #include "port_after.h" + #define MAIN_PROGRAM #include "../named/named.h" #undef MAIN_PROGRAM #define MAX_XFER_RESTARTS 2 +#define ENABLE_IXFR 0 + # ifdef SHORT_FNAMES extern long pathconf __P((const char *path, int name)); /* XXX */ # endif + static struct zoneinfo zone; /* zone information */ -static char ddtfilename[] = _PATH_TMPXFER, - *ddtfile = ddtfilename, - *tmpname, - *domain; /* domain being xfered */ +static char *ddtfilename = NULL, + *ddtfile = NULL; + +static char *tmpname = NULL, + *tmpiname = NULL, /* temporary file name for ixfr transaction file */ + *domain; /* domain being xfered */ static int quiet = 0, read_interrupted = 0, @@ -168,30 +201,48 @@ static int quiet = 0, domain_len; /* strlen(domain) */ static FILE *fp = NULL, - *dbfp = NULL; + *dbfp = NULL, + *ixfp = NULL; static char *ProgName; -static void usage(const char *); +static void usage(const char *), + tsig_init(const char *); static int getzone(struct zoneinfo *, u_int32_t, int), print_output(struct zoneinfo *, u_int32_t, u_char *, int, u_char *), netread(int, char *, int, int), writemsg(int, const u_char *, int); +static void ixfr_log(const u_char *msg, int len, int *delete, + FILE *file, struct sockaddr_in *sin, + char *domain, u_int32_t serial_no, int *); static SIG_FN read_alarm(void); static SIG_FN term_handler(void); -static const char *soa_zinfo(struct zoneinfo *, u_char *, u_char*); +static const char *soa_zinfo(struct zoneinfo *, u_char *, u_char*), + *tsig_rcode(int); struct zoneinfo zp_start, zp_finish; static int restarts = 0; +static int check_serial = 0; +static int xfr_qtype = T_AXFR; +static u_int32_t old_serial; FILE *ddt = NULL; +int servermethode[NSMAX]; +char *soa_buf; + +typedef struct _tsig_node { + struct in_addr addr; + DST_KEY *dst_key; + LINK(struct _tsig_node) link; +} tsig_node; + +LIST(tsig_node) tsig_list; /* * Debugging printf. */ -#ifdef DEBUG void dprintf(int level, const char *format, ...) { va_list ap; @@ -201,10 +252,9 @@ dprintf(int level, const char *format, ...) { (void) vfprintf(ddt, format, ap); va_end(ap); } -#endif /*DEBUG*/ -static -int init_xfer_logging() { +static int +init_xfer_logging() { log_channel chan; if (log_new_context(ns_log_max_category, NULL, &log_ctx) < 0) { @@ -243,7 +293,26 @@ void cleanup_for_exit(void) { #ifdef DEBUG if (!debug) #endif + { (void) unlink(tmpname); + if (tmpiname != NULL) + (void) unlink(tmpiname); + } + if(tmpiname) + free(tmpiname); + tmpiname = NULL; + if (ddtfilename != NULL) { + free(ddtfilename); + if (ddtfilename == ddtfile) + ddtfile = NULL; + ddtfilename = NULL; + } + if(tmpname) + free(tmpname); + tmpname = NULL; + if(ddtfile) + free(ddtfile); + ddtfile = NULL; } @@ -252,18 +321,22 @@ main(int argc, char *argv[]) { struct zoneinfo *zp; struct hostent *hp; struct in_addr axfr_src; - char *dbfile = NULL, *tracefile = NULL, *tm = NULL; - int dbfd, ddtd, result, c, fd, closed = 0; + char *dbfile = NULL, *tracefile = NULL, *tm = NULL, *tsigfile = NULL; + char *ixfrfile = NULL; + u_int32_t new_serial_no = 0; + int dbfd, ddtd, result, c, fd, ixfd; u_int32_t serial_no = 0; u_int port = htons(NAMESERVER_PORT); struct stat statbuf; -#ifdef STUBS int stub_only = 0; -#endif int class = C_IN; int n; long num_files; +#ifdef _AUX_SOURCE + set42sig(); +#endif + memset(&axfr_src, 0, sizeof axfr_src); ProgName = strrchr(argv[0], '/'); if (ProgName != NULL) ProgName++; @@ -272,10 +345,9 @@ main(int argc, char *argv[]) { (void) umask(022); - /* this is a hack; closing everything in the parent is hard. */ - num_files = MIN(sysconf(_SC_OPEN_MAX), FD_SETSIZE); - for (fd = num_files - 1; fd > STDERR_FILENO; fd--) - closed += (close(fd) == 0); + ddtfilename = (char *)malloc(strlen(_PATH_TMPXFER) + 1); + strcpy(ddtfilename, _PATH_TMPXFER); + ddtfile = ddtfilename; #ifdef RENICE nice(-40); /* this is the recommended procedure to */ @@ -283,24 +355,21 @@ main(int argc, char *argv[]) { nice(0); /* to "normal" (== 0) - see nice(3) */ #endif + n = LOG_PID; #ifdef LOG_PERROR - n = LOG_PERROR; -#else - n = 0; + n |= LOG_PERROR; #endif -#ifdef SYSLOG_42BSD - openlog(ProgName, LOG_PID); -#else - openlog(ProgName, LOG_PID|LOG_CONS|n, LOG_DAEMON); +#if defined(LOG_CONS) && defined(USE_LOG_CONS) + n |= LOG_CONS; #endif - axfr_src.s_addr = 0; -#ifdef STUBS - while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qx:S")) != EOF) +#ifdef SYSLOG_42BSD + openlog(ProgName, n); #else - while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qx:")) != EOF) + openlog(ProgName, n, LOG_DAEMON); #endif - switch (c) { - case 'C': + while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:i:p:P:qx:ST:Z")) != -1) + switch (c) { + case 'C': class = get_class(optarg); break; case 'd': @@ -322,6 +391,7 @@ main(int argc, char *argv[]) { break; case 's': serial_no = strtoul(optarg, (char **)NULL, 10); + check_serial++; break; case 't': tracefile = optarg; @@ -345,17 +415,29 @@ main(int argc, char *argv[]) { (void) strcpy(tmpname, optarg); #endif /* SHORT_FNAMES */ break; + case 'i': +#if ENABLE_IXFR + ixfrfile = optarg; + tmpiname = (char *) malloc(strlen(optarg) + + sizeof(".XXXXXX") + 1); + if (!tmpiname) + panic("malloc(tmpiname)", NULL); +#ifdef SHORT_FNAMES + filenamecpy(tmpiname, optarg); +#else + (void) strcpy(tmpiname, optarg); +#endif /* SHORT_FNAMES */ +#endif /* ENABLE_IXFR */ + break; case 'p': port = htons((u_int16_t)atoi(optarg)); break; case 'P': port = (u_int16_t)atoi(optarg); break; -#ifdef STUBS case 'S': stub_only = 1; break; -#endif case 'q': quiet++; break; @@ -363,13 +445,18 @@ main(int argc, char *argv[]) { if (!inet_aton(optarg, &axfr_src)) panic("bad -x addr: %s", optarg); break; + case 'T': + tsigfile = optarg; + break; + case 'Z': + xfr_qtype = ns_t_zxfr; + break; case '?': default: usage("unrecognized argument"); /* NOTREACHED */ - } - - if (!domain || !dbfile || optind >= argc) { + } + if (!domain || ((!dbfile) && (!ixfrfile)) || optind >= argc) { if (!domain) usage("no domain"); if (!dbfile) @@ -382,6 +469,14 @@ main(int argc, char *argv[]) { !S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) usage("dbfile must be a regular file or FIFO"); + if (ixfrfile && (stat(ixfrfile, &statbuf) != -1 && + !S_ISREG(statbuf.st_mode) && + !S_ISFIFO(statbuf.st_mode))) + usage("ixfrfile must be a regular file or FIFO"); + if (tsigfile && stat(tsigfile, &statbuf) != -1 && + !S_ISREG(statbuf.st_mode) && + !S_ISFIFO(statbuf.st_mode)) + usage("tsigfile must be a regular file or FIFO"); if (tracefile && (fp = fopen(tracefile, "w")) == NULL) perror(tracefile); (void) strcat(tmpname, ".XXXXXX"); @@ -389,8 +484,8 @@ main(int argc, char *argv[]) { if ((dbfd = mkstemp(tmpname)) == -1) { perror(tmpname); if (!quiet) - syslog(LOG_ERR, "can't make tmpfile (%s): %m\n", - tmpname); + syslog(LOG_ERR, "can't make tmpfile (%s): %s\n", + tmpname, strerror(errno)); exit(XFER_FAIL); } #ifdef HAVE_FCHMOD /* XXX */ @@ -401,8 +496,8 @@ main(int argc, char *argv[]) { { perror(tmpname); if (!quiet) - syslog(LOG_ERR, "can't [f]chmod tmpfile (%s): %m\n", - tmpname); + syslog(LOG_ERR, "can't [f]chmod tmpfile (%s): %s\n", + tmpname, strerror(errno)); exit(XFER_FAIL); } if ((dbfp = fdopen(dbfd, "r+")) == NULL) { @@ -411,6 +506,36 @@ main(int argc, char *argv[]) { syslog(LOG_ERR, "can't fdopen tmpfile (%s)", tmpname); exit(XFER_FAIL); } + if (ixfrfile) { + (void) strcat(tmpiname, ".XXXXXX"); + if ((ixfd = mkstemp(tmpiname)) == -1) { + perror(tmpiname); + if (!quiet) + syslog(LOG_ERR, + "can't make tmpifile (%s): %s\n", + tmpiname, strerror(errno)); + (void) fclose(dbfp); + (void) close(dbfd); + exit(XFER_FAIL); + } +#ifdef HAVE_FCHMOD /* XXX */ + if (fchmod(ixfd, 0644) == -1) +#else + if (chmod(tmpiname, 0644) == -1) +#endif + { + perror(tmpiname); + if (!quiet) + syslog(LOG_ERR, + "can't [f]chmod tmpifile (%s): %s\n", + tmpiname, strerror(errno)); + (void) fclose(dbfp); + (void) close(dbfd); + (void) close(ixfd); + exit(XFER_FAIL); + } + close(ixfd); + } #ifdef DEBUG if (debug) { /* ddtfile is now something like "/usr/tmp/xfer.ddt.XXXXXX" */ @@ -433,8 +558,8 @@ main(int argc, char *argv[]) { setvbuf(ddt, NULL, _IOLBF, 0); } #endif - if (!init_xfer_logging()) { + cleanup_for_exit(); perror("init_xfer_logging"); } @@ -464,20 +589,25 @@ main(int argc, char *argv[]) { (void) signal(SIGFPE, SIG_IGN); #endif /* SIGUSR1&&SIGUSR2 */ - dprintf(1, "domain `%s'; file `%s'; serial %u; closed %d\n", - domain, dbfile, serial_no, closed); + if (dbfile) + dprintf(1, "domain `%s'; file `%s'; serial %u\n", + domain, dbfile, serial_no); + + if (ixfrfile) + dprintf(1, "domain `%s'; ixfrfile `%s'; serial %u\n", + domain, ixfrfile, serial_no); buildservicelist(); buildprotolist(); + tsig_init(tsigfile); + /* init zone data */ zp = &zone; -#ifdef STUBS if (stub_only) zp->z_type = Z_STUB; else -#endif zp->z_type = Z_SECONDARY; zp->z_class = class; zp->z_origin = domain; @@ -490,8 +620,34 @@ main(int argc, char *argv[]) { zp->z_source); for (; optind != argc; optind++) { + int tmpsupportixfr; + tm = argv[optind]; + tmpsupportixfr = ISNOTIXFR; + if ((optind+1) != argc) { + if (strcasecmp("ixfr", argv[optind+1]) == 0) { +#if ENABLE_IXFR + tmpsupportixfr = ISIXFR; + servermethode[zp->z_addrcnt] = tmpsupportixfr; +#endif + optind++; + } else if (strcasecmp("axfr", argv[optind+1]) == 0) { + tmpsupportixfr = ISNOTIXFR; + optind++; + } + } if (!inet_aton(tm, &zp->z_addr[zp->z_addrcnt])) { + if (strcmp("-ixfr",tm)==0) { +#if ENABLE_IXFR + tmpsupportixfr = ISIXFR; + servermethode[zp->z_addrcnt-1] = tmpsupportixfr; +#endif + continue; + } else + if (strcmp("-axfr",tm)==0) { + tmpsupportixfr = ISNOTIXFR; + continue; + } hp = gethostbyname(tm); if (hp == NULL) { syslog(LOG_NOTICE, @@ -502,7 +658,7 @@ main(int argc, char *argv[]) { memcpy(&zp->z_addr[zp->z_addrcnt], hp->h_addr, INADDRSZ); - dprintf(1, "Arg: \"%s\"\n", tm); + dprintf(1, "Arg: \"%s\" %s\n", tm,((tmpsupportixfr) ? "IXFR":"AXFR")); } if (++zp->z_addrcnt >= NSMAX) { zp->z_addrcnt = NSMAX; @@ -512,24 +668,71 @@ main(int argc, char *argv[]) { } dprintf(1, "addrcnt = %d\n", zp->z_addrcnt); - res_init(); - _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); + res_ninit(&res); + res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); result = getzone(zp, serial_no, port); - (void) my_fclose(dbfp); + (void) fclose(dbfp); + (void) close(dbfd); + + if (ixfp) + (void) my_fclose(ixfp); + else + close(ixfd); + switch (result) { - case XFER_SUCCESS: /* ok exit */ - if (rename(tmpname, dbfile) == -1) { - perror("rename"); + case XFER_SUCCESSAXFR: /* ok exit */ + if (tmpiname != NULL) + unlink(tmpiname); + if (ixfrfile) { + /* + * An IXFR was requested but we performed an + * AXFR. Rename the temporary file to the IXFR + * name, named will rename it again to the dbname. + */ + if (movefile(tmpname, ixfrfile) == -1) { + perror("movefile"); +#ifdef DEBUG + if (debug) + (void) unlink(ddtfile); +#endif + if (!quiet) + syslog(LOG_ERR, + "rename %s to %s: %s", + tmpname, ixfrfile, strerror(errno)); + cleanup_for_exit(); + exit(XFER_FAIL); + }; + exit(XFER_SUCCESSAXFRIXFRFILE); + } + if (movefile(tmpname, dbfile) == -1) { + perror("movefile"); if (!quiet) - syslog(LOG_ERR, "rename %s to %s: %m", + syslog(LOG_ERR, "movefile %s to %s: %m", tmpname, dbfile); + cleanup_for_exit(); exit(XFER_FAIL); } - exit(XFER_SUCCESS); + exit(XFER_SUCCESSAXFR); + + case XFER_SUCCESSIXFR: + unlink(tmpname); + if (movefile(tmpiname, ixfrfile) == -1) { + perror("movefile"); + if (!quiet) + syslog(LOG_ERR, "movefile %s to %s: %m", + tmpiname, ixfrfile); + cleanup_for_exit(); + exit(XFER_FAIL); + } + cleanup_for_exit(); + exit(XFER_SUCCESSIXFR); case XFER_UPTODATE: /* the zone was already uptodate */ (void) unlink(tmpname); + if (tmpiname != NULL) + (void) unlink(tmpiname); + cleanup_for_exit(); exit(XFER_UPTODATE); default: @@ -537,6 +740,7 @@ main(int argc, char *argv[]) { /* fall through */ case XFER_TIMEOUT: case XFER_FAIL: + (void) unlink(tmpname); cleanup_for_exit(); exit(result); /* error or timeout */ } @@ -547,17 +751,17 @@ main(int argc, char *argv[]) { static char *UsageText[] = { "\t-z zone_to_transfer\n", "\t-f db_file\n", - "\t-s serial_no\n", + "\t[-i ixfr_file]\n", + "\t[-s serial_no]\n", "\t[-d debug_level]\n", "\t[-l debug_log_file]\n", "\t[-t trace_file]\n", "\t[-p port]\n", -#ifdef STUBS - "\t[-S]\n", -#endif + "\t[-S] [-Z]\n", "\t[-C class]\n", "\t[-x axfr-src]\n", - "\tservers...\n", + "\t[-T tsig_info_file]\n", + "\tservers [-ixfr|-axfr]...\n", NULL }; @@ -572,13 +776,66 @@ usage(const char *msg) { exit(XFER_FAIL); } +static void +tsig_init(const char *file) { + char buf[1024]; + int n; + FILE *fp; + char *s; + + if (file == NULL) + return; + fp = fopen(file, "r"); + if (fp == NULL) + return; + dst_init(); + INIT_LIST(tsig_list); + while (1) { + tsig_node *n = malloc(sizeof(tsig_node)); + int alg, secret_len; + char *address, *name; + char *cp; + u_char secret[128]; + + s = fgets(buf, sizeof(buf), fp); + if (s == NULL) + break; + buf[strlen(buf)-1] = 0; + inet_aton(buf, &n->addr); + + fgets(buf, sizeof(buf), fp); + buf[strlen(buf)-1] = 0; + name = strdup(buf); + + fscanf(fp, "%d", &alg); + fgets(buf, sizeof(buf), fp); + + fgets(buf, sizeof(buf), fp); + buf[strlen(buf)-1] = 0; + cp = buf; + while (isspace(*cp)) + cp++; + + secret_len = b64_pton(cp, secret, sizeof(secret)); + n->dst_key = dst_buffer_to_key(name, alg, 0, 0, + secret, secret_len); + + free(name); + APPEND(tsig_list, n, link); + } + fclose(fp); + unlink(file); +} + #define DEF_DNAME '\001' /* '\0' means the root domain */ /* XXX: The following variables should probably all be "static" */ u_int32_t minimum_ttl = 0; -int soa_cnt = 0; -#ifdef STUBS +int soa_cnt = 0, scdsoa = 0, methode = ISNOTIXFR; +int delete_soa = 1; +u_int32_t final_serial = 0; +int ixfr_soa = 0; +int firstsoa = 1; int ns_cnt = 0; -#endif int query_type = 0; int prev_comment = 0; /* was previous record a comment? */ char zone_top[MAXDNAME]; /* the top of the zone */ @@ -592,19 +849,32 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { u_int len; u_int32_t serial; int s, n, l, error = 0; + int was_ixfr = 0; u_int cnt; u_char *cp, *nmp, *eom, *tmp ; - u_char *buf = NULL; + u_char *buf = NULL, *cpp = NULL; u_int bufsize = 0; char name[MAXDNAME], name2[MAXDNAME]; struct sockaddr_in sin; + struct sockaddr_in local; + int locallen; #ifdef POSIX_SIGNALS struct sigaction sv, osv; #else struct sigvec sv, osv; #endif - int qdcount, ancount, aucount, class, type; + int qdcount, ancount, aucount, arcount, class, type; const char *badsoa_msg = "Nil"; + struct sockaddr_in my_addr; + char my_addr_text[30]; + int alen, ret, tsig_req; + DST_KEY *tsig_key; + ns_tcp_tsig_state tsig_state; + int tsig_signed = 0; + u_char sig[64]; + int siglen; + int ixfr_first = 1; + time_t timesigned; #ifdef DEBUG if (debug) { @@ -648,9 +918,23 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { if ((l = strlen(zone_top)) != 0 && zone_top[l - 1] == '.') zone_top[l - 1] = '\0'; strcpy(prev_origin, zone_top); + for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { + methode = servermethode[cnt]; + sin.sin_addr = zp->z_addr[cnt]; + dprintf(3, "address [%s] %s\n", + inet_ntoa(sin.sin_addr), + (methode == ISIXFR) ? "IXFR":"AXFR"); + } for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { + methode = ISNOTIXFR; curclass = zp->z_class; + /* + * If we have been given a serial number and a ixfr log + * file name then set methode. + */ + if (check_serial && tmpiname != NULL) + methode = servermethode[cnt]; error = 0; if (buf == NULL) { if ((buf = (u_char *)malloc(2 * PACKETSZ)) == NULL) { @@ -661,6 +945,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { } bufsize = 2 * PACKETSZ; } + try_again: if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { syslog(LOG_INFO, "socket: %m"); error++; @@ -684,20 +969,72 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { dprintf(2, "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) { + if (zp->z_axfr_src.s_addr != 0) { + dprintf(2, "connect failed, trying w/o -x"); + zp->z_axfr_src.s_addr = 0; + (void) my_close(s); + goto try_again; + } if (!quiet) syslog(LOG_INFO, - "connect(%s) for zone %s failed: %m", - inet_ntoa(sin.sin_addr), zp->z_origin); + "connect(%s) for zone %s failed: %s", + inet_ntoa(sin.sin_addr), zp->z_origin, strerror(errno)); error++; (void) my_close(s); continue; } - n = res_mkquery(QUERY, zp->z_origin, curclass, - T_SOA, NULL, 0, NULL, buf, bufsize); + if (methode == ISIXFR) { + hp = (HEADER *) buf; + cpp = buf; + n = res_nmkquery(&res, QUERY, zp->z_origin, curclass, + T_IXFR, NULL, 0, NULL, buf, bufsize); + dprintf(1, "len = %d\n", n); + if (n < 0) { + if (!quiet) + syslog(LOG_INFO, + "zone %s: dn_comp for ixfr failed", + zp->z_origin); + (void) my_close(s); +#ifdef POSIX_SIGNALS + sigaction(SIGALRM, + &osv, + (struct sigaction*)0); +#else + sigvec(SIGALRM, + &osv, + (struct sigvec *)0); +#endif + return (XFER_FAIL); + } + hp->nscount = htons(1+ntohs(hp->nscount)); + cpp += n; + n = dn_comp(zp->z_origin, cpp, bufsize-(cpp-buf), + NULL, NULL); + if (n > 0) + cpp += n; + PUTSHORT(T_SOA, cpp); /* type */ + PUTSHORT(C_IN, cpp); /* class */ + PUTLONG(0, cpp); /* ttl */ + PUTSHORT(22, cpp); /* dlen */ + *cpp++ = 0; /* mname */ + *cpp++ = 0; /* rname */ + PUTLONG(serial_no, cpp); + PUTLONG(0xDEAD, cpp); /* Refresh */ + PUTLONG(0xBEEF, cpp); /* Retry */ + PUTLONG(0xABCD, cpp); /* Expire */ + PUTLONG(0x1776, cpp); /* Min TTL */ + n = cpp-buf; + dprintf(1, "len = %d\n", cpp-buf); + if (debug) + res_pquery(&res, buf, n, ddt); + } + else { + n = res_nmkquery(&res, QUERY, zp->z_origin, curclass, + T_SOA, NULL, 0, NULL, buf, bufsize); if (n < 0) { if (!quiet) syslog(LOG_INFO, - "zone %s: res_mkquery T_SOA failed", + "zone %s: res_nmkquery T_SOA failed", zp->z_origin); (void) my_close(s); #ifdef POSIX_SIGNALS @@ -707,6 +1044,19 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #endif return (XFER_FAIL); } + } + /* + * Append TSIG to SOA query if desired + */ + tsig_key = tsig_key_from_addr(sin.sin_addr); + if (tsig_key != NULL) { + siglen = sizeof(sig); + ret = ns_sign(buf, &n, bufsize, NOERROR, tsig_key, + NULL, 0, sig, &siglen, timesigned); + if (ret == 0) + tsig_signed = 1; + } + /* * Send length & message for SOA query */ @@ -719,6 +1069,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { /* * Get out your butterfly net and catch the SOA */ + if (netread(s, (char *)buf, INT16SZ, XFER_TIMER) < 0) { error++; (void) my_close(s); @@ -745,16 +1096,52 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { (void) my_close(s); continue; } + /* + * Verify the TSIG if expected + */ + if (tsig_signed != 0) { + ret = ns_verify(buf, (int *)&len, tsig_key, sig, siglen, + NULL, NULL, ×igned, 0); + if (ret != 0) { + syslog(LOG_NOTICE, + "SOA TSIG verification from server [%s], zone %s: %s (%d)\n", + inet_ntoa(sin.sin_addr), zp->z_origin, + tsig_rcode(ret), ret); + error++; + continue; + } + } + #ifdef DEBUG if (debug >= 3) { (void)fprintf(ddt,"len = %d\n", len); - fp_nquery(buf, len, ddt); + res_pquery(&res, buf, len, ddt); } #endif + if ((methode == ISIXFR) && (ixfp == NULL)) { + delete_soa = 1; + firstsoa = 1; + ixfr_soa = 0; + old_serial = serial_no; + if (ixfp != NULL) { + fflush(ixfp); + /* XXX error */ + ftruncate(fileno(ixfp), 0); + } else if ((ixfp = fopen(tmpiname, "w+")) == NULL) { + perror(tmpiname); + if (!quiet) + syslog(LOG_ERR, + "can't fdopen ixfr log (%s)", + tmpname); + exit(XFER_FAIL); + } + } + hp = (HEADER *) buf; qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); aucount = ntohs(hp->nscount); + arcount = ntohs(hp->arcount); /* * close socket if any of these apply: @@ -809,8 +1196,8 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { } NS_GET16(type, tmp); NS_GET16(class, tmp); - if (class != curclass || type != T_SOA || - strcasecmp(zp->z_origin, name2) != 0) { + if (class != curclass || ((type != T_SOA) && type != T_IXFR) || + ns_samename(zp->z_origin, name2) != 1) { syslog(LOG_INFO, "wrong query in resp from [%s], zone %s: [%s %s %s]\n", inet_ntoa(sin.sin_addr), zp->z_origin, @@ -857,7 +1244,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { tmp = cp4 + dlen; } while (1); - if (strcasecmp(zp->z_origin, name2) != 0) { + if (ns_samename(zp->z_origin, name2) != 1) { syslog(LOG_INFO, "wrong answer in resp from [%s], zone %s: [%s %s %s]\n", inet_ntoa(sin.sin_addr), zp->z_origin, @@ -869,16 +1256,35 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { badsoa_msg = soa_zinfo(&zp_start, tmp, eom); if (badsoa_msg) goto badsoa; - if (SEQ_GT(zp_start.z_serial, serial_no) || !serial_no) { - const char *l, *nl; + if (SEQ_GT(zp_start.z_serial, serial_no) || !check_serial) { + const char *l, *nl, *t; + dprintf(1, "need update, serial %u\n", zp_start.z_serial); hp = (HEADER *) buf; - soa_cnt = 0; -#ifdef STUBS + if ((methode == ISIXFR) && (soa_cnt == 0)) { + if (type == T_IXFR) { + if (ixfp) + ixfr_log(buf, len, &delete_soa, ixfp, + &sin, domain, serial_no, + &ixfr_first); + soa_cnt = 2; + } else { + dprintf(1, + "server %s rejected IXFR and responded with AXFR\n", + inet_ntoa(sin.sin_addr)); + methode = ISNOTIXFR; + was_ixfr++; + soa_cnt++; + } + } ns_cnt = 0; -#endif gettime(&tt); + locallen = sizeof local; + if (getsockname(s, (struct sockaddr *)&local, + &locallen) < 0) { + memset(&local, 0, sizeof local); + } for (l = Version; l; l = nl) { size_t len; if ((nl = strchr(l, '\n')) != NULL) { @@ -894,41 +1300,62 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { fprintf(dbfp, "; BIND version %.*s\n", (int)len, l); } - fprintf(dbfp, "; zone '%s' last serial %u\n", + fprintf(dbfp, check_serial? + "; zone '%s' last serial %u\n": + "; zone '%s' first transfer\n", domain, serial_no); - fprintf(dbfp, "; from %s at %s", - inet_ntoa(sin.sin_addr), + t = strdup(inet_ntoa(sin.sin_addr)); + fprintf(dbfp, "; from %s:%d (local %s) using %s at %s", + t, ntohs(sin.sin_port), + inet_ntoa(local.sin_addr), + (methode == ISIXFR) ? "IXFR":"AXFR", ctimel(tt.tv_sec)); + free((void *)t); for (;;) { if ((soa_cnt == 0) || (zp->z_type == Z_STUB)) { -#ifdef STUBS if (zp->z_type == Z_STUB) { if (soa_cnt == 1 && ns_cnt == 0) query_type = T_NS; else query_type = T_SOA; - } else -#endif - query_type = T_AXFR; - n = res_mkquery(QUERY, zp->z_origin, - curclass, query_type, - NULL, 0, - NULL, buf, bufsize); + } else if (methode == ISIXFR) + query_type = T_IXFR; + else + query_type = xfr_qtype; + n = res_nmkquery(&res, QUERY, + zp->z_origin, + curclass, query_type, + NULL, 0, + NULL, buf, bufsize); + syslog(LOG_INFO, + "send %s query %d to %s", + (query_type == T_IXFR) ? "IXFR" : + (query_type == T_AXFR) ? "AXFR" : + (query_type == ns_t_zxfr) ? "ZXFR" : + (query_type == T_SOA) ? "SOA" : "NS", + cnt, inet_ntoa(sin.sin_addr)); + dprintf(1, + "send %s query to %s\n", + (query_type == T_IXFR) ? "IXFR" : + (query_type == T_AXFR) ? "AXFR" : + (query_type == ns_t_zxfr) ? "ZXFR" : + (query_type == T_SOA) ? "SOA" : "NS", + inet_ntoa(sin.sin_addr)); + dprintf(1,"bufsize = %d\n", bufsize); if (n < 0) { if (!quiet) { -#ifdef STUBS if (zp->z_type == Z_STUB) syslog(LOG_INFO, (query_type == T_SOA) - ? "zone %s: res_mkquery T_SOA failed" - : "zone %s: res_mkquery T_NS failed", + ? "zone %s: res_nmkquery T_SOA failed" + : "zone %s: res_nmkquery T_NS failed", zp->z_origin); else -#endif syslog(LOG_INFO, - "zone %s: res_mkquery T_AXFR failed", - zp->z_origin); + "zone %s: res_nmkquery %s failed", + zp->z_origin, + p_type(query_type)); } (void) my_close(s); #ifdef POSIX_SIGNALS @@ -940,10 +1367,25 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #endif return (XFER_FAIL); } + cpp = buf + n; + /* + * Append TSIG to AXFR query if desired + */ + if (tsig_signed != 0) { + siglen = sizeof(sig); + ns_sign(buf, &n, bufsize, + NOERROR, tsig_key, + NULL, 0, sig, &siglen, + timesigned); + cpp = buf + n; + ns_verify_tcp_init(tsig_key, + sig, siglen, + &tsig_state); + } /* * Send length & msg for zone transfer */ - if (writemsg(s, buf, n) < 0) { + if (writemsg(s, buf, cpp - buf) < 0) { syslog(LOG_INFO, "writemsg: %m"); error++; @@ -951,6 +1393,8 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { break; } } +/*XXX ZXFR*/ + if (methode == ISNOTIXFR && !was_ixfr) { /* * Receive length & response */ @@ -966,7 +1410,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { buf = (u_char *)realloc(buf, len); if (buf == NULL) { syslog(LOG_INFO, - "malloc(%u) failed for packet from server [%s], zone %s\n", + "malloc(%u) failed for packet from server [%s], zone %s\n", len, inet_ntoa(sin.sin_addr), zp->z_origin); @@ -982,18 +1426,36 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { error++; break; } + } #ifdef DEBUG if (debug >= 3) { (void)fprintf(ddt,"len = %d\n", len); - fp_nquery(buf, len, ddt); + res_pquery(&res, buf, len, ddt); } if (fp) - fp_nquery(buf, len, fp); + res_pquery(&res, buf, len, fp); #endif + /* + * Verify the TSIG if expected + */ + if (tsig_signed != 0) { + tsig_req = (soa_cnt == 0); + ret = ns_verify_tcp(buf, (int *)&len, + &tsig_state, + tsig_req); + eom = buf + len; + + if (ret != 0) { + syslog(LOG_NOTICE, + "TSIG verification from server [%s], zone %s: %s (%d)\n", + inet_ntoa(sin.sin_addr), + zp->z_origin, + tsig_rcode(ret), ret); + error++; + break; + } + } if (len < HFIXEDSZ) { - struct sockaddr_in my_addr; - char my_addr_text[30]; - int alen; badrec: error++; @@ -1009,25 +1471,54 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { sin_addr), ntohs(my_addr.sin_port) ); - syslog(LOG_INFO, + if ((hp->rcode == REFUSED) && + (len >= HFIXEDSZ)) { + syslog(LOG_INFO, + "[%s] transfer refused from [%s], zone %s\n", + my_addr_text, + inet_ntoa(sin.sin_addr), + zp->z_origin); + } else { + syslog(LOG_INFO, "[%s] record too short from [%s], zone %s\n", - my_addr_text, - inet_ntoa(sin.sin_addr), - zp->z_origin); + my_addr_text, + inet_ntoa(sin.sin_addr), + zp->z_origin); + } break; } + if (query_type == T_IXFR) + if (hp->rcode != NOERROR) { + dprintf(1, + "server %s did not support IXFR\n", + inet_ntoa(sin.sin_addr)); + methode = ISNOTIXFR; + continue; + }; cp = buf + HFIXEDSZ; - if (hp->qdcount) { - if ((n = dn_skipname(cp, eom)) == -1 - || n + QFIXEDSZ >= eom - cp) + if (ntohs(hp->qdcount) == 1) { + if ((query_type == T_IXFR) && (methode == ISIXFR)) { + dprintf(1, + "server %s rejected IXFR and responded with AXFR\n", + inet_ntoa(sin.sin_addr)); + methode = ISNOTIXFR; + } + n = dn_skipname(cp, eom); + if ((n == -1) || + ((n + QFIXEDSZ) >= (eom - cp))) goto badrec; cp += n + QFIXEDSZ; + } else { + if (methode == ISIXFR && ixfp) + ixfr_log(buf, len, &delete_soa, ixfp, + &sin, domain, serial_no, + &ixfr_first); + } nmp = cp; if ((n = dn_skipname(cp, eom)) == -1) goto badrec; tmp = cp + n; -#ifdef STUBS if (zp->z_type == Z_STUB) { ancount = ntohs(hp->ancount); n = 0; @@ -1091,11 +1582,8 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { break; } } else { -#endif /*STUBS*/ ancount = ntohs(hp->ancount); - for (n = cnt = 0; - cnt < (u_int)ancount; - cnt++) { + for (n = cnt = 0; cnt < (u_int)ancount; cnt++) { n = print_output(zp, serial_no, buf, len, cp); if (n < 0) @@ -1117,13 +1605,12 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { error++; break; } -#ifdef STUBS } -#endif - if (soa_cnt >= 2) + if ((soa_cnt >= 2) && (methode == ISNOTIXFR)) + break; + if ((soa_cnt == -1) && (methode == ISIXFR)) break; - } (void) my_close(s); if (error == 0) { @@ -1133,21 +1620,43 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #else (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); #endif - return (XFER_SUCCESS); + if (methode == ISIXFR) { + fprintf(ixfp, "update:\t{add} "); + if (soa_buf) + fputs(soa_buf, ixfp); + fprintf(ixfp, "[END_DELTA]\n"); + (void) my_close(s); + return (XFER_SUCCESSIXFR); + } else { + if (ixfp) { + (void) fclose(ixfp); + ixfp = NULL; + } + return (XFER_SUCCESSAXFR); + } + } + if (ixfp) { + (void) fclose(ixfp); + ixfp = NULL; } dprintf(2, "error receiving zone transfer\n"); } else if (zp_start.z_serial == serial_no) { - (void) my_close(s); - dprintf(1, "zone up-to-date, serial %u\n", zp_start.z_serial); - return (XFER_UPTODATE); + (void) my_close(s); + dprintf(1, "zone up-to-date, serial %u\n", zp_start.z_serial); + if (ixfp) { + (void) unlink (tmpiname); + (void) fclose(ixfp); + ixfp = NULL; + } + return (XFER_UPTODATE); } else { - (void) my_close(s); - if (!quiet) - syslog(LOG_NOTICE, + (void) my_close(s); + if (!quiet) + syslog(LOG_NOTICE, "serial from [%s], zone %s: %u lower than current: %u\n", inet_ntoa(sin.sin_addr), zp->z_origin, zp_start.z_serial, serial_no); - return (XFER_FAIL); + return (XFER_FAIL); } } #ifdef POSIX_SIGNALS @@ -1155,6 +1664,11 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #else (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); #endif + if (ixfp) { + (void) unlink (tmpiname); + (void) my_fclose(ixfp); + ixfp = 0; + } if (!error) return (XFER_TIMEOUT); return (XFER_FAIL); @@ -1382,6 +1896,7 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, case T_NSAP: case T_AAAA: case T_KEY: + case ns_t_cert: cp1 = cp; n = dlen; cp += n; @@ -1640,14 +2155,14 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, */ if (type == T_SOA) { - if (strcasecmp(dname, zp->z_origin) != 0) { + if (ns_samename(dname, zp->z_origin) != 1) { syslog(LOG_INFO, - "wrong zone name in AXFR (wanted \"%s\", got \"%s\")", + "wrong zone name in XFR (wanted \"%s\", got \"%s\")", zp->z_origin, dname); hp->rcode = FORMERR; return (-1); } - if (!soa_cnt) { + if (soa_cnt == 0) { badsoa_msg = soa_zinfo(&zp_start, rr_type_ptr, eom); if (badsoa_msg) { syslog(LOG_INFO, @@ -1657,13 +2172,33 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, return (-1); } if (SEQ_GT(zp_start.z_serial, serial_no) || - !serial_no) + !check_serial) { soa_cnt++; - else { + } else { syslog(LOG_INFO, "serial went backwards after transfer started"); return (-1); } + } else if (soa_cnt == 1) { + badsoa_msg = soa_zinfo(&zp_finish, rr_type_ptr, eom); + if (badsoa_msg) { + syslog(LOG_INFO, + "malformed SOA for zone %s: %s", + zp->z_origin, badsoa_msg); + hp->rcode = FORMERR; + return (-1); + } + if (zp_start.z_serial == zp_finish.z_serial) { + methode = ISNOTIXFR; + } else if (zp_finish.z_serial != serial_no) { + syslog(LOG_INFO, + "Unexpected serial number for zone %s: %u", + zp->z_origin, zp_finish.z_serial); + } + soa_cnt++; + if ((methode == ISIXFR) || (soa_cnt >= 2)) { + return (result); + } } else { badsoa_msg = soa_zinfo(&zp_finish, rr_type_ptr, eom); if (badsoa_msg) { @@ -1673,45 +2208,56 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, hp->rcode = FORMERR; return (-1); } - dprintf(2, "SOA, serial %u\n", zp_finish.z_serial); - if (zp_start.z_serial != zp_finish.z_serial) { - dprintf(1, "serial changed, restart\n"); - restarts++; - if (restarts > MAX_XFER_RESTARTS) { - syslog(LOG_INFO, - "too many transfer restarts for zone %s", - zp->z_origin); - hp->rcode = FORMERR; - return (-1); - } - soa_cnt = 0; -#ifdef STUBS - ns_cnt = 0; -#endif - minimum_ttl = 0; - strcpy(prev_origin, zp->z_origin); - prev_dname[0] = DEF_DNAME; - /* - * Flush buffer, truncate file - * and seek to beginning to restart. - */ - fflush(dbfp); - if (ftruncate(fileno(dbfp), 0) != 0) { - if (!quiet) + if (methode == ISIXFR) { + if (zp_start.z_serial == zp_finish.z_serial) { + if (scdsoa) { + soa_cnt = -1; + return (result); + } else { + scdsoa = 1; + soa_cnt++; + }; + } else + soa_cnt++; + } else { + dprintf(2, "SOA, serial %u\n", + zp_finish.z_serial); + if (zp_start.z_serial != zp_finish.z_serial) { + dprintf(1, "serial changed, restart\n"); + restarts++; + if (restarts > MAX_XFER_RESTARTS) { syslog(LOG_INFO, - "ftruncate %s: %m\n", - tmpname); - return (-1); + "too many transfer restarts for zone %s", + zp->z_origin); + hp->rcode = FORMERR; + return (-1); + } + soa_cnt = 0; + ns_cnt = 0; + minimum_ttl = 0; + strcpy(prev_origin, zp->z_origin); + prev_dname[0] = DEF_DNAME; + /* + * Flush buffer, truncate file + * and seek to beginning to restart. + */ + fflush(dbfp); + if (ftruncate(fileno(dbfp), 0) != 0) { + if (!quiet) + syslog(LOG_INFO, + "ftruncate %s: %m\n", + tmpname); + return (-1); + } + fseek(dbfp, 0L, 0); + return (result); } - fseek(dbfp, 0L, 0); + soa_cnt++; return (result); } - soa_cnt++; - return (result); } } -#ifdef STUBS if (zp->z_type == Z_STUB) { if (query_type == T_NS && type == T_NS) ns_cnt++; @@ -1724,9 +2270,8 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, if (query_type == T_SOA && type != T_SOA) return (result); } -#endif - if (!soa_cnt || soa_cnt >= 2) { + if ((!soa_cnt || soa_cnt > 2) && methode == ISNOTIXFR) { char *gripe; if (!soa_cnt) @@ -1756,17 +2301,21 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, * where the remote server sends MX records soon after the * NS records for a particular domain. If sent earlier, we lose. XXX */ - if (!samedomain(dname, domain)) { + if (!ns_samedomain(dname, domain)) { (void) fprintf(dbfp, "; Ignoring info about %s, not in zone %s.\n", dname, domain); ignore = "; "; } else if (type != T_NS && type != T_A && - strcasecmp(zone_top, dname) != 0 && - strcasecmp(prev_ns_dname, dname) == 0) + ns_samename(zone_top, dname) != 1 && + ns_samename(prev_ns_dname, dname) == 1) { (void) fprintf(dbfp, "; Ignoring extra info about %s, invalid after NS delegation.\n", dname); ignore = "; "; + } else if (class != zp->z_class) { + (void) fprintf(dbfp, "; Ignoring info about %s, not class %s\n", + dname, p_class(zp->z_class)); + ignore = "; "; } /* @@ -1794,13 +2343,13 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, /* * If the origin has changed, print the new origin */ - if (strcasecmp(prev_origin, origin)) { + if (ns_samename(prev_origin, origin) != 1) { (void) strcpy(prev_origin, origin); (void) fprintf(dbfp, "%s$ORIGIN %s.\n", ignore, origin); } tab = 0; - if (strcasecmp(prev_dname, dname)) { + if (ns_samename(prev_dname, dname) != 1) { /* * set the prev_dname to be the current dname, then cut off all * characters of dname after (and including) the first '.' @@ -1837,10 +2386,7 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, tab = 1; } - if (ttl != minimum_ttl) - (void) fprintf(dbfp, "%d\t", (int) ttl); - else if (tab) - (void) putc('\t', dbfp); + (void) fprintf(dbfp, "%d\t", (int) ttl); (void) fprintf(dbfp, "%s\t%s\t", p_class(class), p_type(type)); cp = cdata; @@ -2085,8 +2631,8 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, /* algorithm id */ (void) fprintf(dbfp," %d",*cp++); - /* labels (# of labels in name) - skip in textual record */ - cp++; + /* labels (# of labels in name) */ + (void) fprintf(dbfp," %d",*cp++); /* orig time to live (TTL)) */ (void) fprintf(dbfp," %u", (u_int32_t)ns_get32((u_char*)cp)); @@ -2128,6 +2674,33 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, fprintf(dbfp,"\n"); break; + case ns_t_cert: { + int databufsize = n * 4 / 3 + 4; + char *databuf = malloc(databufsize); + + if (databuf == NULL) + panic("cert malloc failed", NULL); + + /* Object id */ + (void) fprintf(dbfp,"%d ", ns_get16((u_char*)cp)); + cp += INT16SZ; + + /* Key tag */ + (void) fprintf(dbfp,"%d ", ns_get16((u_char*)cp)); + cp += INT16SZ; + + /* Algorithm id */ + (void) fprintf(dbfp,"%d ", (u_char)*cp); + cp += 1; + + n = b64_ntop(cp, n - 2 * INT16SZ - 1, databuf, databufsize); + if (n < 0) + panic ("cert b64_ntop failed", NULL); + fprintf (dbfp, "%s\n", databuf); + free(databuf); + break; + } + default: cp1 = cp + n; while (cp < cp1) @@ -2175,3 +2748,199 @@ filenamecpy(char *ddtfile, char *optarg) { (void) strcpy(ddtfile, optarg); } #endif /* SHORT_FNAMES */ + +DST_KEY * +tsig_key_from_addr(struct in_addr addr) { + tsig_node *n; + for (n = HEAD(tsig_list); n != NULL; n = NEXT(n, link)) + if (memcpy(&addr, &n->addr, sizeof(struct in_addr))) + return n->dst_key; + return NULL; +} + +static void +do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file, int *delete) { + int n, sflag, rrnum; + char buf[2048]; /* XXX need to malloc */ + ns_opcode opcode; + ns_rr rr; + const unsigned char *cp; + const unsigned char *eom; + u_int32_t serial; + time_t now; + + time(&now); + + /* + * Print answer records. + */ + sflag = (_res.pfcode & pflag); + if (_res.pfcode && !sflag) + return; + + opcode = (ns_opcode)ns_msg_getflag(*handle, ns_f_opcode); + rrnum = 0; + for (;;) { + if (ns_parserr(handle, section, rrnum, &rr)) { + if (errno != ENODEV) + fprintf(file, ";; ns_parserr: %s\n", + strerror(errno)); + else if (rrnum > 0 && sflag != 0 && + (_res.pfcode & RES_PRF_HEAD1)) + putc('\n', file); + return; + } + if (rrnum == 0 && sflag != 0 && (_res.pfcode & RES_PRF_HEAD1)) + fprintf(file, ";; %s SECTION:\n", + p_section(section, opcode)); + if (section == ns_s_qd) + fprintf(file, ";;\t%s, type = %s, class = %s\n", + ns_rr_name(rr), + p_type(ns_rr_type(rr)), + p_class(ns_rr_class(rr))); + else { + int print_record = 1; + if (rr.type == ns_t_soa) { + print_record = 0; + *delete = !*delete; + cp = ns_rr_rdata(rr); + eom = cp + ns_rr_rdlen(rr); + if ((n = dn_skipname(cp, eom)) < 0) { + rrnum++; + continue; + } + cp += n; + if ((n = dn_skipname(cp, eom)) < 0) { + rrnum++; + continue; + } + cp += n; + NS_GET32(serial, cp); + if (*delete && serial != old_serial) + /*XXX*/; + old_serial = serial; + switch (++ixfr_soa) { + case 1: + final_serial = serial; + if (soa_buf == NULL) { + if ((soa_buf = (char *)malloc(2 * PACKETSZ)) == NULL) { + syslog(LOG_INFO, "malloc(%u) failed", 2 * PACKETSZ); + return; + } + n = ns_sprintrr(handle, &rr, NULL, NULL, + soa_buf, 2*PACKETSZ); + if (n < 0) { + fprintf(file, ";; ns_sprintrr: %s\n", + strerror(errno)); + return; + } + } + print_record = 0; + break; + case 2: + fprintf(file, + "zone:\torigin %s class %s serial %u\n", + ns_rr_name(rr), + p_class(ns_rr_class(rr)), + serial); + print_record = 0; + break; + default: + print_record = 0; + break; + } + + } + + if (print_record) { + if (rr.type != ns_t_soa) { + fprintf(file, "update:\t{%s} ", + *delete ? "delete" : "add"); + + n = ns_sprintrr(handle, &rr, NULL, NULL, + buf, sizeof buf); + if (n < 0) { + fprintf(file, ";; ns_sprintrr: %s\n", + strerror(errno)); + return; + } + fputs(buf, file); + fputc('\n', file); + } + } + + } + rrnum++; + } +} + +static void +ixfr_log(const u_char *msg, int len, int *delete, FILE *file, + struct sockaddr_in *sin, char *domain, u_int32_t serial_no, + int *first_rr) +{ + ns_msg handle; + ns_type type; + ns_class class; + ns_opcode opcode; + ns_rcode rcode; + u_int id, n; + char time[25]; + ns_rr rr; + char *cp; + HEADER *hp; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return; + + if (ns_initparse(msg, len, &handle) < 0) { + fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); + return; + } + opcode = (ns_opcode) ns_msg_getflag(handle, ns_f_opcode); + rcode = (ns_rcode) ns_msg_getflag(handle, ns_f_rcode); + id = ns_msg_id(handle); + + if (ns_parserr(&handle, ns_s_an, 0, &rr)) + { + + (void) fprintf(file,"ns_parserr() failed"); + return; + } + type = (ns_type)rr.type; + class = (ns_class)rr.rr_class; + + if (*first_rr == 1) { + gettime(&tt); + (void) fprintf(file,"%s", LogSignature); + sprintf(time, "at %lu", (u_long)tt.tv_sec); + fprintf(file, + "[IXFR_UPDATE] id %u from [%s].%d %s (named-xfr pid %ld):\n", + id, inet_ntoa(sin->sin_addr), + ntohs(sin->sin_port), time, (long)getpid()); + (*first_rr)++; + } + do_section(&handle, ns_s_an, RES_PRF_ANS, file, delete); +} + +static const char * +tsig_rcode(int rcode) { + static char buffer[64]; + + switch (rcode) { + case ns_r_badkey: + case ns_r_badsig: + case ns_r_badtime: + sprintf(buffer, "message had %s set", p_rcode(rcode)); + return (buffer); + case -ns_r_badkey: + case -ns_r_badsig: + case -ns_r_badtime: + return (p_rcode(-rcode)); + case NS_TSIG_ERROR_NO_TSIG: + return ("no TSIG present"); + default: + break; + } + return ("FORMERR"); +} |