diff options
Diffstat (limited to 'contrib/bind/bin/named/ns_maint.c')
-rw-r--r-- | contrib/bind/bin/named/ns_maint.c | 210 |
1 files changed, 148 insertions, 62 deletions
diff --git a/contrib/bind/bin/named/ns_maint.c b/contrib/bind/bin/named/ns_maint.c index 952774f..b5ed644 100644 --- a/contrib/bind/bin/named/ns_maint.c +++ b/contrib/bind/bin/named/ns_maint.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) static const char sccsid[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91"; -static const char rcsid[] = "$Id: ns_maint.c,v 8.105 2000/07/17 07:25:00 vixie Exp $"; +static const char rcsid[] = "$Id: ns_maint.c,v 8.117 2001/01/25 05:50:55 marka Exp $"; #endif /* not lint */ /* @@ -120,14 +120,14 @@ static const char rcsid[] = "$Id: ns_maint.c,v 8.105 2000/07/17 07:25:00 vixie E #include <isc/eventlib.h> #include <isc/logging.h> #include <isc/memcluster.h> - #include <isc/dst.h> +#include <isc/misc.h> #include "port_after.h" #include "named.h" -static int nxfers(struct zoneinfo *, int), +static int nxfers(struct zoneinfo *), bottom_of_zone(struct databuf *, int); static void startxfer(struct zoneinfo *), @@ -135,19 +135,18 @@ static void startxfer(struct zoneinfo *), tryxfer(void), purge_z_2(struct hashbuf *, int); static int purge_nonglue_2(const char *, struct hashbuf *, - int, int); + int, int, int); #ifndef HAVE_SPAWNXFER static pid_t spawnxfer(char **, struct zoneinfo *); #endif -static time_t stats_time; /* Redundant ??? XXX ogud */ - /* State of all running zone transfers */ static struct { - pid_t xfer_pid; - int xfer_state; /* see below */ - WAIT_T xfer_status; + pid_t xfer_pid; + int xfer_state; /* see below */ + WAIT_T xfer_status; + struct in_addr xfer_addr; } xferstatus[MAX_XFERS_RUNNING]; #define XFER_IDLE 0 @@ -642,41 +641,115 @@ qserial_answer(struct qinfo *qp) { /* * Writes TSIG key info for an address to a file, optionally opening it first. + * Returns: + * -1: Error. + * 0: No action taken. + * 1: Tsig info successfully written. */ static int -write_tsig_info(struct in_addr addr, char *name, int *fd, int creat_failed) { +write_tsig_info(struct in_addr addr, char *name, int *fd) { server_info si; DST_KEY *dst_key; int tsig_fd = *fd; char tsig_str[1024], secret_buf64[172]; u_char secret_buf[128]; - int secret_len; + int secret_len, len; si = find_server(addr); if (si == NULL || si->key_list == NULL || si->key_list->first == NULL) return(0); dst_key = si->key_list->first->key; - if (tsig_fd < 0 && creat_failed == 0) { - *fd = tsig_fd = creat(name, S_IRUSR); + if (tsig_fd == -1) { + *fd = tsig_fd = mkstemp(name); if (tsig_fd < 0) { ns_warning(ns_log_default, - "write_tsig_info: creat(%s) for TSIG info failed", + "write_tsig_info: mkstemp(%s) for TSIG info failed", name); return(-1); } (void) fchown(tsig_fd, user_id, group_id); } - if (creat_failed != 0) - return(-1); + memset(secret_buf, 0, sizeof(secret_buf)); secret_len = dst_key_to_buffer(dst_key, secret_buf, sizeof(secret_buf)); - b64_ntop(secret_buf, secret_len, secret_buf64, sizeof(secret_buf64)); + if (secret_len == 0) + return (-1); + len = b64_ntop(secret_buf, secret_len, secret_buf64, + sizeof(secret_buf64)); + if (len == -1) + return (-1); + /* We need snprintf! */ + if (strlen(dst_key->dk_key_name) + len + sizeof("XXX.XXX.XXX.XXX"), + sizeof("123") + 5 > sizeof(tsig_str)) + return (-1); sprintf(tsig_str, "%s\n%s\n%d\n%s\n", inet_ntoa(addr), dst_key->dk_key_name, dst_key->dk_alg, secret_buf64); - write(tsig_fd, tsig_str, strlen(tsig_str)); - return (0); + len = strlen(tsig_str); + if (write(tsig_fd, tsig_str, strlen(tsig_str)) != len) + return (-1); + return (1); +} + +/* + * Returns number of tsigs written or -1. + */ +static int +write_tsigs(struct zoneinfo *zp, char *tsig_name) { + struct in_addr a; + int tsig_ret; + int tsig_fd = -1; + int cnt; + int records = 0; + + for (cnt = 0; cnt < zp->z_xaddrcnt; cnt++) { + a = zp->z_xaddr[cnt]; + if (aIsUs(a) && ns_port == zp->z_port) + continue; + + tsig_ret = write_tsig_info(a, tsig_name, &tsig_fd); + switch (tsig_ret) { + case -1: + goto error; + case 0: + break; + case 1: + records++; + break; + } + } + + if (tsig_fd != -1) + close(tsig_fd); + return (records); + + error: + if (tsig_fd != -1) { + unlink(tsig_name); + close(tsig_fd); + } + return (-1); +} + +#ifdef BIND_IXFR +static int +supports_ixfr(struct zoneinfo *zp) { + int cnt = 0; + for (cnt = 0; cnt < zp->z_xaddrcnt; cnt++) { + struct in_addr a; + server_info si; + + a = zp->z_xaddr[cnt]; + if (aIsUs(a) && ns_port == zp->z_port) + continue; + si = find_server(a); + + if (si != NULL && (si->flags & SERVER_INFO_SUPPORT_IXFR) != 0) + return(1); + } + return(0); } +#endif /* * Start an asynchronous zone transfer for a zone. Depends on current time @@ -693,8 +766,7 @@ startxfer(struct zoneinfo *zp) { char port_str[10]; char class_str[10]; char src_str[20]; - int tsig_fd = -1; - char tsig_name[MAXPATHLEN+1], *s; + char tsig_name[MAXPATHLEN+1]; int tsig_ret = 0; ns_debug(ns_log_default, 1, "startxfer() %s", @@ -706,9 +778,9 @@ startxfer(struct zoneinfo *zp) { argv[argc++] = "-f"; argv[argc++] = zp->z_source; #ifdef BIND_IXFR - if (zp->z_ixfr_tmp) { - argv[argc++] = "-i"; - argv[argc++] = zp->z_ixfr_tmp; + if (supports_ixfr(zp) && zp->z_ixfr_tmp != NULL) { + argv[argc++] = "-i"; + argv[argc++] = zp->z_ixfr_tmp; } #endif if (zp->z_serial != 0) { @@ -731,12 +803,6 @@ startxfer(struct zoneinfo *zp) { argv[argc++] = "-P"; sprintf(port_str, "%d", ntohs(zp->z_port) != 0 ? zp->z_port : ns_port); argv[argc++] = port_str; - argv[argc++] = "-T"; - sprintf(tsig_name, "%s.%d", zp->z_origin, getpid()); - s = tsig_name; - while ((s = strchr(s, '/')) != NULL) - *s = '_'; - argv[argc++] = tsig_name; #ifdef STUBS if (zp->z_type == Z_STUB) argv[argc++] = "-S"; @@ -762,6 +828,22 @@ startxfer(struct zoneinfo *zp) { zp->z_xaddr[zp->z_xaddrcnt] = zp->z_addr[zp->z_xaddrcnt]; } + + /* + * Store TSIG keys if we have them. + */ + strcpy(tsig_name, "tsigs.XXXXXX"); + tsig_ret = write_tsigs(zp, tsig_name); + if (tsig_ret == -1) { + ns_error(ns_log_xfer_in, "unable to write tsig info: '%s'", + zp->z_origin); + return; + } + if (tsig_ret != 0) { + argv[argc++] = "-T"; + argv[argc++] = tsig_name; + } + /* * Copy the server ip addresses into argv, after converting * to ascii and saving the static inet_ntoa result. @@ -790,10 +872,7 @@ startxfer(struct zoneinfo *zp) { argv[argc++] = "axfr"; } #endif - tsig_ret = write_tsig_info(a, tsig_name, &tsig_fd, tsig_ret); } - if (tsig_fd > 0) - close(tsig_fd); argv[argc] = NULL; @@ -830,7 +909,6 @@ startxfer(struct zoneinfo *zp) { ns_warning(ns_log_default, "startxfer: too many xfers running"); zp->z_time = tt.tv_sec + 10; - (void)nxfers(zp, -1); return; } @@ -842,6 +920,7 @@ startxfer(struct zoneinfo *zp) { xferstatus[i].xfer_state = XFER_RUNNING; xferstatus[i].xfer_pid = pid; /* XXX - small race condition here if we * can't hold signals */ + xferstatus[i].xfer_addr = zp->z_xaddr[0]; ns_debug(ns_log_default, 1, "started xfer child %d", pid); zp->z_flags &= ~Z_NEED_XFER; zp->z_flags |= Z_XFER_RUNNING; @@ -1102,11 +1181,12 @@ remove_zone(struct zoneinfo *zp, const char *verb) { memset(zp, 0, sizeof(*zp)); zp->z_type = z_nil; /* Pedantic; memset() did it. */ INIT_LINK(zp, z_reloadlink); + INIT_LINK(zp, z_freelink); free_zone(zp); } int -purge_nonglue(const char *dname, struct hashbuf *htp, int class) { +purge_nonglue(const char *dname, struct hashbuf *htp, int class, int log) { const char *fname; struct namebuf *np; struct hashbuf *phtp = htp; @@ -1127,7 +1207,7 @@ purge_nonglue(const char *dname, struct hashbuf *htp, int class) { h = htp; else h = np->n_hash; - errs += purge_nonglue_2(dname, h, class, 0); + errs += purge_nonglue_2(dname, h, class, 0, log); if (h->h_cnt == 0 && !root_zone) { rm_hash(np->n_hash); np->n_hash = NULL; @@ -1157,7 +1237,7 @@ valid_glue(struct databuf *dp, char *name, int belowcut) { /* NOKEY is in parent zone otherwise child zone */ if (dp->d_type == T_KEY && dp->d_size == 4 && - (dp->d_data[0] & 0xc6) == 0xc2) + (dp->d_data[0] & 0xc3) == 0xc1) return (1); /* NXT & KEY records may be signed */ @@ -1169,7 +1249,7 @@ valid_glue(struct databuf *dp, char *name, int belowcut) { static int purge_nonglue_2(const char *dname, struct hashbuf *htp, int class, - int belowcut) + int belowcut, int log) { struct databuf *dp, *pdp; struct namebuf *np, *pnp, *npn; @@ -1197,7 +1277,8 @@ purge_nonglue_2(const char *dname, struct hashbuf *htp, int class, if (dp->d_class == class && zonecut && !valid_glue(dp, name, belowcut)) { - ns_error(ns_log_db, + if (log) + ns_error(ns_log_db, "zone: %s/%s: non-glue record %s bottom of zone: %s/%s", *dname ? dname : ".", p_class(dp->d_class), @@ -1207,7 +1288,8 @@ purge_nonglue_2(const char *dname, struct hashbuf *htp, int class, p_type(dp->d_type)); dp = rm_datum(dp, np, pdp, NULL); - errs++; + if (log) + errs++; } else { pdp = dp; dp = dp->d_next; @@ -1222,7 +1304,8 @@ purge_nonglue_2(const char *dname, struct hashbuf *htp, int class, np->n_hash, class, zonecut || - belowcut); + belowcut, + log); /* if now empty, free it */ if (np->n_hash->h_cnt == 0) { @@ -1356,11 +1439,13 @@ bottom_of_zone(struct databuf *dp, int class) { /* * Handle XFER limit for a nameserver. */ + + static int -nxfers(struct zoneinfo *zp, int delta) { +nxfers(struct zoneinfo *zp) { struct in_addr nsa; - struct nameser *nsp; int ret; + int i; if (zp->z_xaddrcnt != 0) nsa = zp->z_xaddr[0]; /* first ns holds zone's xfer limit */ @@ -1368,15 +1453,12 @@ nxfers(struct zoneinfo *zp, int delta) { nsa = zp->z_addr[0]; /* first ns holds zone's xfer limit */ else return (-1); - - if (!(nsp = nameserFind(nsa, NS_F_INSERT))) - return (-1); /* probably ENOMEM */ - - ret = nsp->xfers; - if (delta < 0 && -delta > ret) - return (-1); /* taking more than we have */ - - nsp->xfers += delta; + + ret = 0; + for (i = 0; i < MAX_XFERS_RUNNING; i++) + if (xferstatus[i].xfer_status == XFER_RUNNING && + xferstatus[i].xfer_addr.s_addr == nsa.s_addr) + ret++; return (ret); } @@ -1413,7 +1495,6 @@ pid %lu - forgetting, processes may accumulate", zp->z_xferpid = 0; xfers_running--; - (void)nxfers(zp, -1); zp->z_flags &= ~(Z_XFER_RUNNING|Z_XFER_ABORTED|Z_XFER_GONE); } else if (kill(zp->z_xferpid, SIGTERM) == -1) { if (errno == ESRCH) @@ -1479,7 +1560,6 @@ endxfer() { if (zp->z_xferpid != pid) continue; xfers_running--; - (void) nxfers(zp, -1); zp->z_xferpid = 0; zp->z_flags &= ~(Z_XFER_RUNNING|Z_XFER_ABORTED|Z_XFER_GONE); @@ -1509,7 +1589,9 @@ endxfer() { if (exitstatus == XFER_SUCCESSAXFRIXFRFILE) { zp->z_xferpid = XFER_ISAXFRIXFR; } - movefile(zp->z_ixfr_tmp, zp->z_source); + if (zp->z_ixfr_tmp != NULL) + isc_movefile(zp->z_ixfr_tmp, + zp->z_source); /* XXX should incorporate loadxfer() */ zp->z_flags |= Z_NEED_RELOAD; zp->z_flags &= ~Z_SYSLOGGED; @@ -1529,19 +1611,24 @@ endxfer() { (void)unlink(zp->z_updatelog); (void)unlink(zp->z_ixfr_base); - movefile(zp->z_ixfr_tmp, - zp->z_ixfr_base); + isc_movefile(zp->z_ixfr_tmp, + zp->z_ixfr_base); (void)unlink(zp->z_ixfr_tmp); if (zonedump(zp, ISIXFR) < 0) ns_warning(ns_log_db, "error in write ixfr updates to zone file %s", zp ->z_source); - } else + ns_refreshtime(zp, tt.tv_sec); + sched_zone_maint(zp); + } else { ns_notice(ns_log_default, "IXFR Merge failed %s", zp->z_ixfr_tmp); zp->z_flags &= ~(Z_XFER_RUNNING|Z_XFER_ABORTED|Z_XFER_GONE); + ns_retrytime(zp, tt.tv_sec); + sched_zone_maint(zp); + } break; case XFER_TIMEOUT: @@ -1622,10 +1709,9 @@ tryxfer() { xfers_running >= server_options->transfers_in) break; - if ((xfers = nxfers(zp, 0)) != -1 && + if ((xfers = nxfers(zp)) != -1 && xfers < server_options->transfers_per_ns && (zp->z_flags & Z_NEED_XFER)) { - nxfers(zp, 1); xfers_deferred--; startxfer(zp); sched_zone_maint(zp); @@ -1827,7 +1913,7 @@ ns_reload(void) { qflush(); sq_flush(NULL); reloading++; /* To force transfer if secondary and backing up. */ - ns_init(conffile); + confmtime = ns_init(conffile); time(&resettime); reloading--; ns_notice(ns_log_default, "Ready to answer queries."); @@ -1875,6 +1961,7 @@ make_new_zones(void) { block_signals(); for (n = 0; n < NEWZONES; n++) { INIT_LINK(&zones[nzones], z_reloadlink); + INIT_LINK(&zones[nzones], z_freelink); if (nzones != 0) free_zone(&zones[nzones]); nzones++; @@ -1906,7 +1993,6 @@ spawnxfer(char **argv, struct zoneinfo *zp) { execv(server_options->named_xfer, argv); ns_error(ns_log_default, "can't exec %s: %s", server_options->named_xfer, strerror(errno)); - (void)nxfers(zp, -1); _exit(XFER_FAIL); /* Avoid duplicate buffer flushes. */ } return (pid); |