summaryrefslogtreecommitdiffstats
path: root/contrib/bind/bin/named/ns_maint.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/bin/named/ns_maint.c')
-rw-r--r--contrib/bind/bin/named/ns_maint.c2092
1 files changed, 0 insertions, 2092 deletions
diff --git a/contrib/bind/bin/named/ns_maint.c b/contrib/bind/bin/named/ns_maint.c
deleted file mode 100644
index 0618ab9..0000000
--- a/contrib/bind/bin/named/ns_maint.c
+++ /dev/null
@@ -1,2092 +0,0 @@
-#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.137.8.1 2003/06/02 05:34:25 marka Exp $";
-#endif /* not lint */
-
-/*
- * Copyright (c) 1986, 1988
- * 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
- * are met:
- * 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
- * SUCH DAMAGE.
- */
-
-/*
- * 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
- * SOFTWARE.
- */
-
-/*
- * Portions Copyright (c) 1996-2000 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
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM 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.
- */
-
-/*
- * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
- *
- * 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 Check Point Software Technologies 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 CHECK POINT SOFTWARE TECHNOLOGIES
- * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
- * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES 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.
- */
-
-#include "port_before.h"
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <signal.h>
-#include <resolv.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-
-#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 *),
- bottom_of_zone(struct databuf *, int);
-
-static void startxfer(struct zoneinfo *),
- abortxfer(struct zoneinfo *),
- purge_z_2(struct hashbuf *, int);
-static int purge_nonglue_2(const char *, struct hashbuf *,
- int, int, int, int);
-
-#ifndef HAVE_SPAWNXFER
-static pid_t spawnxfer(char **, struct zoneinfo *);
-#endif
-
- /* State of all running zone transfers */
-static struct {
- 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
-#define XFER_RUNNING 1
-#define XFER_DONE 2
-
-
-/*
- * Perform routine zone maintenance.
- */
-void
-zone_maint(struct zoneinfo *zp) {
- gettime(&tt);
-
- ns_debug(ns_log_maint, 1, "zone_maint('%s'); now %lu",
- zp->z_origin[0] == '\0' ? "." : zp->z_origin,
- (u_long)tt.tv_sec);
-
-#ifdef DEBUG
- if (debug >= 2)
- printzoneinfo((zp - zones), ns_log_maint, 2);
-#endif
-
- switch (zp->z_type) {
-
- case Z_SECONDARY:
- /*FALLTHROUGH*/
-#ifdef STUBS
- case Z_STUB:
-#endif
- if (zp->z_serial != 0 &&
- ((zp->z_lastupdate+zp->z_expire) < (u_int32_t)tt.tv_sec)) {
- if ((zp->z_flags & Z_NOTIFY) != 0)
- ns_stopnotify(zp->z_origin, zp->z_class);
- /* calls purge_zone */
- do_reload(zp, 0);
- /* reset zone state */
- if (!haveComplained((u_long)zp, (u_long)stale)) {
- ns_notice(ns_log_default,
- "%s zone \"%s\" expired",
- zoneTypeString(zp->z_type),
- zp->z_origin);
- }
- zp->z_flags &= ~Z_AUTH;
- zp->z_flags |= Z_EXPIRED;
- zp->z_refresh = INIT_REFRESH;
- zp->z_retry = INIT_REFRESH;
- zp->z_serial = 0;
- }
- if ((zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) != 0)
- {
- ns_retrytime(zp, tt.tv_sec);
- break;
- }
- if (zp->z_flags & Z_XFER_RUNNING) {
- abortxfer(zp);
- /*
- * Check again in 30 seconds in case the first
- * abort doesn't work.
- */
- if (zp->z_time != 0 && zp->z_time <= tt.tv_sec)
- zp->z_time = tt.tv_sec + 30;
- break;
- }
- /*
- * If we don't have the zone loaded or dialup is off
- * or we attempted a qserial_query before and the queue was
- * full attempt to verify / load the zone.
- */
- if ((zp->z_serial == 0) || (zp->z_flags & Z_NEED_QSERIAL) ||
- (zp->z_dialup == zdialup_no) ||
- (zp->z_dialup == zdialup_use_default &&
- NS_OPTION_P(OPTION_NODIALUP)))
- qserial_query(zp);
- else {
- ns_info(ns_log_default, "Suppressed qserial_query(%s)",
- *(zp->z_origin) ? zp->z_origin : ".");
- ns_refreshtime(zp, tt.tv_sec);
- }
- break;
-
-#ifdef BIND_UPDATE
- case Z_PRIMARY:
- if ((zp->z_flags & Z_DYNAMIC) == 0)
- break;
- if (tt.tv_sec >= zp->z_soaincrtime &&
- zp->z_soaincrintvl > 0 &&
- zp->z_flags & Z_NEED_SOAUPDATE) {
- if (incr_serial(zp) < 0) {
- /* Try again later. */
- ns_error(ns_log_maint,
- "error updating serial number for %s from %d",
- zp->z_origin,
- zp->z_serial);
- zp->z_soaincrtime = 0;
- (void)schedule_soa_update(zp, 0);
- }
-
- }
- if (tt.tv_sec >= zp->z_dumptime &&
- zp->z_dumpintvl > 0 &&
- zp->z_flags & Z_NEED_DUMP) {
- if (zonedump(zp, ISNOTIXFR) < 0) {
- /* Try again later. */
- ns_error(ns_log_maint,
- "zone dump for '%s' failed, rescheduling",
- zp->z_origin);
- zp->z_dumptime = 0;
- (void)schedule_dump(zp);
- }
- }
- if (zp->z_maintain_ixfr_base)
- ixfr_log_maint(zp);
- break;
-#endif /* BIND_UPDATE */
-
- default:
- break;
- }
-
- if (zp->z_time != 0 && zp->z_time < tt.tv_sec)
- zp->z_time = tt.tv_sec;
-
- sched_zone_maint(zp);
-}
-
-static void
-do_zone_maint(evContext ctx, void *uap, struct timespec due,
- struct timespec inter) {
- ztimer_info zti = uap;
- struct zoneinfo *zp;
-
- UNUSED(ctx);
- UNUSED(due);
- UNUSED(inter);
-
- INSIST(zti != NULL);
-
- ns_debug(ns_log_maint, 1, "do_zone_maint for zone %s (class %s)",
- zti->name, p_class(zti->class));
- zp = find_zone(zti->name, zti->class);
- if (zp == NULL) {
- ns_error(ns_log_maint,
- "do_zone_maint: %s zone '%s' (class %s) is not authoritative",
- zoneTypeString(zti->type), zti->name,
- p_class(zti->class));
- return;
- }
- if (zp->z_type != zti->type) {
- ns_error(ns_log_maint,
- "do_zone_maint: %s zone '%s' (class %s) has changed its type",
- zoneTypeString(zti->type), zti->name,
- p_class(zti->class));
- return;
- }
-
- free_zone_timerinfo(zp);
-
- zp->z_flags &= ~Z_TIMER_SET;
- zone_maint(zp);
-}
-
-/*
- * Figure out the next maintenance time for the zone and set a timer.
- */
-void
-sched_zone_maint(struct zoneinfo *zp) {
- time_t next_maint = (time_t)0;
- ztimer_info zti;
-
- if (zp->z_time != 0)
- next_maint = zp->z_time;
-#ifdef BIND_UPDATE
- if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC) != 0) {
- if (zp->z_soaincrintvl > 0 &&
- (next_maint == 0 || next_maint > zp->z_soaincrtime))
- next_maint = zp->z_soaincrtime;
- if (zp->z_dumpintvl > 0 &&
- (next_maint == 0 || next_maint > zp->z_dumptime))
- next_maint = zp->z_dumptime;
- }
-#endif
-
- if (next_maint != 0) {
- if (next_maint < tt.tv_sec)
- next_maint = tt.tv_sec;
-
- if (zp->z_flags & Z_TIMER_SET) {
- if (next_maint == zp->z_nextmaint) {
- ns_debug(ns_log_maint, 1,
- "no schedule change for zone '%s'",
- zp->z_origin[0] == '\0' ? "." :
- zp->z_origin);
- return;
- }
-
- if (evResetTimer(ev, zp->z_timer,
- do_zone_maint, zp->z_timerinfo,
- evConsTime(next_maint, 0),
- evConsTime(0, 0)) < 0) {
- ns_error(ns_log_maint,
- "evChangeTimer failed in sched_zone_maint for zone '%s': %s",
- zp->z_origin[0] == '\0' ? "." :
- zp->z_origin,
- strerror(errno));
- return;
- }
- } else {
- zti = (ztimer_info)memget(sizeof *zti);
- if (zti == NULL)
- ns_panic(ns_log_maint, 1,
- "memget failed in sched_zone_maint");
- zti->name = savestr(zp->z_origin, 1);
- zti->class = zp->z_class;
- zti->type = zp->z_type;
- if (evSetTimer(ev, do_zone_maint, zti,
- evConsTime(next_maint, 0),
- evConsTime(0, 0), &zp->z_timer) < 0) {
- ns_error(ns_log_maint,
- "evSetTimer failed in sched_zone_maint for zone '%s': %s",
- zp->z_origin[0] == '\0' ? "." :
- zp->z_origin,
- strerror(errno));
- return;
- }
- zp->z_flags |= Z_TIMER_SET;
- zp->z_timerinfo = zti;
- }
- ns_debug(ns_log_maint, 1,
- "next maintenance for zone '%s' in %lu sec",
- zp->z_origin[0] == '\0' ? "." : zp->z_origin,
- (u_long)(next_maint - tt.tv_sec));
- } else {
- if (zp->z_flags & Z_TIMER_SET) {
- free_zone_timerinfo(zp);
- if (evClearTimer(ev, zp->z_timer) < 0)
- ns_error(ns_log_maint,
- "evClearTimer failed in sched_zone_maint for zone '%s': %s",
- zp->z_origin[0] == '\0' ? "." :
- zp->z_origin,
- strerror(errno));
- zp->z_flags &= ~Z_TIMER_SET;
- }
- ns_debug(ns_log_maint, 1,
- "no scheduled maintenance for zone '%s'",
- zp->z_origin[0] == '\0' ? "." : zp->z_origin);
- }
- zp->z_nextmaint = next_maint;
-}
-
-void
-ns_cleancache(evContext ctx, void *uap,
- struct timespec due,
- struct timespec inter)
-{
- int deleted;
-
- UNUSED(ctx);
- UNUSED(due);
- UNUSED(inter);
-
- gettime(&tt);
- INSIST(uap == NULL);
- deleted = clean_cache(hashtab, 0);
- ns_info(ns_log_maint, "Cleaned cache of %d RRset%s",
- deleted, (deleted==1) ? "" : "s");
-}
-
-void
-ns_heartbeat(evContext ctx, void *uap, struct timespec due,
- struct timespec inter)
-{
- struct zoneinfo *zp;
-
- UNUSED(ctx);
- UNUSED(due);
- UNUSED(inter);
-
- gettime(&tt);
- INSIST(uap == NULL);
-
- for (zp = zones; zp < &zones[nzones]; zp++) {
- enum zonetype zt = zp->z_type;
-
- if ((zt == z_nil) ||
- (zp->z_dialup == zdialup_no) ||
- (zp->z_dialup == zdialup_use_default &&
- NS_OPTION_P(OPTION_NODIALUP)))
- continue;
- /*
- * Perform the refresh query that was suppressed.
- */
- if ((zt == z_slave || zt == z_stub) &&
- (zp->z_flags &
- (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING)
- ) == 0) {
- ns_info(ns_log_default,
- "Heartbeat: qserial \"%s\"",
- *(zp->z_origin) ? zp->z_origin : ".");
- qserial_query(zp);
- }
-#ifdef BIND_NOTIFY
- /*
- * Trigger a refresh query while the link is up by
- * sending a notify.
- */
- if (((zp->z_notify == notify_yes) ||
- (zp->z_notify == notify_explicit) ||
- ((zp->z_notify == notify_use_default) &&
- server_options->notify != notify_no)) &&
- (zt == z_master || zt == z_slave) && !loading &&
- ((zp->z_flags & Z_AUTH) != 0))
- ns_notify(zp->z_origin, zp->z_class, ns_t_soa);
-#endif
- }
-}
-
-
-/*
- * Mark a zone "up to date" after named-xfer tells us this or we
- * discover it through the qserial_*() logic.
- * The caller is responsible for calling sched_zone_maint(zp).
- */
-static void
-markUpToDate(struct zoneinfo *zp) {
- struct stat f_time;
-
- zp->z_flags &= ~Z_SYSLOGGED;
- zp->z_lastupdate = tt.tv_sec;
- ns_refreshtime(zp, tt.tv_sec);
- /*
- * Restore Z_AUTH in case expired,
- * but only if there were no errors
- * in the zone file.
- */
- if ((zp->z_flags & Z_DB_BAD) == 0) {
- zp->z_flags |= Z_AUTH;
- zp->z_flags &= ~Z_EXPIRED;
- }
- if (zp->z_source) {
- struct timeval t[2];
-
- t[0] = tt;
- t[1] = tt;
- (void) utimes(zp->z_source, t);
- }
- /* we use "stat" to set zp->z_ftime instead of just
- setting it to tt.tv_sec in order to avoid any
- possible rounding problems in utimes(). */
- if (stat(zp->z_source, &f_time) != -1)
- zp->z_ftime = f_time.st_mtime;
- /* XXX log if stat fails? */
-}
-
-void
-qserial_retrytime(struct zoneinfo *zp, time_t timebase) {
- zp->z_time = timebase + 5 + (rand() % 25);
-}
-
-/*
- * Query for the serial number of a zone, so that we can check to see if
- * we need to transfer it. If there are too many outstanding serial
- * number queries, we'll try again later.
- * The caller is responsible for calling sched_zone_maint(zp).
- */
-void
-qserial_query(struct zoneinfo *zp) {
- struct qinfo *qp;
-
- ns_debug(ns_log_default, 1, "qserial_query(%s)", zp->z_origin);
-
- if (qserials_running >= server_options->serial_queries) {
- qserial_retrytime(zp, tt.tv_sec);
- zp->z_flags |= Z_NEED_QSERIAL;
- return;
- }
-
- qp = sysquery(zp->z_origin, zp->z_class, T_SOA,
- zp->z_addr, zp->z_keys, zp->z_addrcnt,
- ntohs(zp->z_port) ? zp->z_port : ns_port,
- QUERY, 0);
- if (qp == NULL) {
- ns_debug(ns_log_default, 1,
- "qserial_query(%s): sysquery FAILED",
- zp->z_origin);
- /* XXX - this is bad, we should do something */
- qserial_retrytime(zp, tt.tv_sec);
- zp->z_flags |= Z_NEED_QSERIAL;
- return;
- }
- qp->q_flags |= Q_ZSERIAL;
- qp->q_zquery = zp;
- zp->z_flags |= Z_QSERIAL;
- zp->z_flags &= ~Z_NEED_QSERIAL;
- zp->z_xaddrcnt = 0;
- ns_refreshtime(zp, tt.tv_sec);
- qserials_running++;
- ns_debug(ns_log_default, 1, "qserial_query(%s) QUEUED", zp->z_origin);
-}
-
-static int
-qserv_compare(const void *a, const void *b) {
- const struct qserv *qs1 = a, *qs2 = b;
- u_int32_t s1 = qs1->serial, s2 = qs2->serial;
-
- /* Note that we sort the "best" serial numbers to the front. */
- if (s1 == s2)
- return (0);
- if (s1 == 0)
- return (-1);
- if (s2 == 0)
- return (1);
- if (!SEQ_GT(s1, s2))
- return (1);
- assert(SEQ_GT(s1, s2));
- return (-1);
-}
-
-void
-qserial_answer(struct qinfo *qp) {
- struct zoneinfo *zp = qp->q_zquery;
- struct qserv *qs = NULL;
- u_int32_t serial = 0;
- int n, cnt = 0;
-
- /* Take this query out of the global quotas. */
- zp->z_flags &= ~Z_QSERIAL;
- qp->q_flags &= ~Q_ZSERIAL; /* keeps us from being called twice */
- qserials_running--;
-
- /* Find best serial among those returned. */
- for (n = 0; n < qp->q_naddr; n++) {
- qs = &qp->q_addr[n];
- ns_debug(ns_log_default, 1, "qserial_answer(%s): [%s] -> %lu",
- zp->z_origin, inet_ntoa(qs->ns_addr.sin_addr),
- (unsigned long)qs->serial);
- /* Don't consider serials which weren't set by a response. */
- if (qs->serial == 0)
- continue;
- /* Count valid answers. */
- cnt++;
- /* Remove from consideration serials which aren't "better." */
- if (zp->z_serial != 0 && !SEQ_GT(qs->serial, zp->z_serial)) {
- if (serial == 0 && qs->serial == zp->z_serial)
- serial = qs->serial;
-
- if (qs->serial != zp->z_serial)
- ns_notice(ns_log_xfer_in,
- "Zone \"%s\" (%s) SOA serial# (%lu) rcvd from [%s] is < ours (%lu)%s",
- zp->z_origin, p_class(zp->z_class),
- (u_long) qs->serial,
- inet_ntoa(qs->ns_addr.sin_addr),
- (u_long) zp->z_serial,
- qp->q_naddr!=1 ? ": skipping" : "");
- qs->serial = 0;
- continue;
- }
- if (serial == 0 || SEQ_GT(qs->serial, serial))
- serial = qs->serial;
- }
-
- /* If we have an existing serial number, then sort by "better." */
- if (zp->z_serial != 0) {
- qsort(qp->q_addr, qp->q_naddr, sizeof(struct qserv),
- qserv_compare);
- for (n = 0; n < qp->q_naddr; n++) {
- qs = &qp->q_addr[n];
- ns_debug(ns_log_default, 1,
- "qserial_answer after sort: [%s] -> %lu",
- inet_ntoa(qs->ns_addr.sin_addr),
- (unsigned long)qs->serial);
- }
- }
-
- /* Now see about kicking off an inbound transfer. */
- if (serial == 0) {
- /* An error occurred, or the all queries timed out. */
- if (qp->q_naddr != cnt)
- ns_info(ns_log_xfer_in,
- "Err/TO getting serial# for \"%s\"",
- zp->z_origin);
- addxfer(zp);
- } else if (zp->z_serial == 0 || SEQ_GT(serial, zp->z_serial)) {
- ns_debug(ns_log_xfer_in, 1,
- "qserial_answer: zone is out of date");
- /* Use all servers whose serials are better than ours. */
- zp->z_xaddrcnt = 0;
- for (n = 0; n < qp->q_naddr; n++) {
- qs = &qp->q_addr[n];
- if (qs->serial != 0)
- zp->z_xaddr[zp->z_xaddrcnt++] =
- qs->ns_addr.sin_addr;
- }
- addxfer(zp);
- } else if (zp->z_serial == serial) {
- ns_debug(ns_log_xfer_in, 1,
- "qserial_answer: zone serial is still OK");
- markUpToDate(zp);
- sched_zone_maint(zp);
- }
-}
-
-/*
- * 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 zoneinfo *zp, struct in_addr addr, char *name, int *fd) {
- server_info si;
- DST_KEY *dst_key = NULL;
- int tsig_fd = *fd;
- char tsig_str[1024], secret_buf64[172];
- u_char secret_buf[128];
- int secret_len, len;
- int i;
-
- for (i = 0; i < zp->z_addrcnt ; i++)
- if (memcmp(&addr, &zp->z_addr[i], sizeof(addr)) == 0) {
- dst_key = zp->z_keys[i];
- break;
- }
-
- if (dst_key == NULL) {
- 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 == -1) {
- *fd = tsig_fd = mkstemp(name);
- if (tsig_fd < 0) {
- ns_warning(ns_log_default,
- "write_tsig_info: mkstemp(%s) for TSIG info failed",
- name);
- return(-1);
- }
- (void) fchown(tsig_fd, user_id, group_id);
- }
-
- memset(secret_buf, 0, sizeof(secret_buf));
- secret_len = dst_key_to_buffer(dst_key, secret_buf, sizeof(secret_buf));
- 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);
- 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(zp, 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
- * being in tt. Caller must do a sched_zone_maint(zp) after we return.
- */
-static void
-startxfer(struct zoneinfo *zp) {
- char *argv[NSMAX*2 + 20];
- char argv_ns[NSMAX][MAXDNAME];
- int argc = 0, argc_ns = 0, i;
- pid_t pid;
- u_int cnt;
- char debug_str[10];
- char serial_str[10];
- char port_str[10];
- char class_str[10];
- char src_str[20];
- char tsig_name[MAXPATHLEN+1];
- int tsig_ret = 0;
-
- ns_debug(ns_log_default, 1, "startxfer() %s",
- zp->z_origin[0] != '\0' ? zp->z_origin : ".");
-
- argv[argc++] = server_options->named_xfer;
- DE_CONST("-z", argv[argc++]);
- DE_CONST(*zp->z_origin ? zp->z_origin : ".", argv[argc++]);
- DE_CONST("-f", argv[argc++]);
- argv[argc++] = zp->z_source;
-#ifdef BIND_IXFR
- if (supports_ixfr(zp) && zp->z_ixfr_tmp != NULL) {
- DE_CONST("-i", argv[argc++]);
- argv[argc++] = zp->z_ixfr_tmp;
- }
-#endif
- if (zp->z_serial != 0) {
- DE_CONST("-s", argv[argc++]);
- sprintf(serial_str, "%u", zp->z_serial);
- argv[argc++] = serial_str;
- }
- if (zp->z_axfr_src.s_addr != 0 ||
- server_options->axfr_src.s_addr != 0) {
- DE_CONST("-x", argv[argc++]);
- argv[argc++] = strcpy(src_str, inet_ntoa(
- (zp->z_axfr_src.s_addr != 0) ? zp->z_axfr_src :
- server_options->axfr_src));
- }
- DE_CONST("-C", argv[argc++]);
- sprintf(class_str, "%d", zp->z_class);
- argv[argc++] = class_str;
- if (zp->z_flags & Z_SYSLOGGED)
- DE_CONST("-q", argv[argc++]);
- DE_CONST("-P", argv[argc++]);
- sprintf(port_str, "%d", ntohs(zp->z_port) != 0 ? zp->z_port : ns_port);
- argv[argc++] = port_str;
-#ifdef STUBS
- if (zp->z_type == Z_STUB)
- DE_CONST("-S", argv[argc++]);
-#endif
-#ifdef DEBUG
- if (debug) {
- DE_CONST("-d", argv[argc++]);
- sprintf(debug_str, "%d", debug);
- argv[argc++] = debug_str;
- DE_CONST("-l", argv[argc++]);
- DE_CONST(_PATH_XFERDDT, argv[argc++]);
- if (debug > 5) {
- DE_CONST("-t", argv[argc++]);
- DE_CONST(_PATH_XFERTRACE, argv[argc++]);
- }
- }
-#endif
-
- if (zp->z_xaddrcnt == 0) {
- for (zp->z_xaddrcnt = 0;
- zp->z_xaddrcnt < zp->z_addrcnt;
- zp->z_xaddrcnt++)
- 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) {
- DE_CONST("-T", argv[argc++]);
- argv[argc++] = tsig_name;
- }
-
- /*
- * Copy the server ip addresses into argv, after converting
- * to ascii and saving the static inet_ntoa result.
- * Also, send TSIG key info into a file for the child.
- */
- for (cnt = 0; cnt < zp->z_xaddrcnt; cnt++) {
- struct in_addr a;
-
- a = zp->z_xaddr[cnt];
- if (aIsUs(a) && ns_port == zp->z_port) {
- if (!haveComplained((u_long)zp, (u_long)startxfer))
- ns_notice(ns_log_default,
- "attempted to fetch zone %s from self (%s)",
- zp->z_origin, inet_ntoa(a));
- continue;
- }
- argv[argc++] = strcpy(argv_ns[argc_ns++], inet_ntoa(a));
-#ifdef BIND_IXFR
- if (zp->z_ixfr_tmp != NULL) {
- server_info si = find_server(a);
-
- if (si != NULL &&
- (si->flags & SERVER_INFO_SUPPORT_IXFR) != 0)
- DE_CONST("ixfr", argv[argc++]);
- else
- DE_CONST("axfr", argv[argc++]);
- }
-#endif
- }
-
- argv[argc] = NULL;
-
-#ifdef DEBUG
- if (debug >= 1) {
- char buffer[1024];
- char *curr, *last;
- int len;
-
- curr = buffer;
- last = &buffer[sizeof buffer - 1]; /* leave room for \0 */
- for (i = 0; i < argc; i++) {
- len = strlen(argv[i]);
- if (len + 1 >= last - curr) {
- ns_debug(ns_log_xfer_in, 1,
- "xfer args debug printout truncated");
- break;
- }
- strncpy(curr, argv[i], len);
- curr += len;
- *curr = ' ';
- curr++;
- }
- *curr = '\0';
- ns_debug(ns_log_xfer_in, 1, "%s", buffer);
- }
-#endif /* DEBUG */
-
- gettime(&tt);
- for (i = 0; i < MAX_XFERS_RUNNING; i++)
- if (xferstatus[i].xfer_pid == 0)
- break;
- if (i == MAX_XFERS_RUNNING) {
- ns_warning(ns_log_default,
- "startxfer: too many xfers running");
- zp->z_time = tt.tv_sec + 10;
- return;
- }
-
- if ((pid = spawnxfer(argv, zp)) == -1) {
- unlink(tsig_name);
- return;
- }
-
- 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;
- zp->z_xferpid = pid;
- xfers_running++;
- xfers_deferred--;
- if (zp->z_max_transfer_time_in)
- zp->z_time = tt.tv_sec + zp->z_max_transfer_time_in;
- else
- zp->z_time = tt.tv_sec + server_options->max_transfer_time_in;
-}
-
-const char *
-zoneTypeString(u_int type) {
- static char ret[sizeof "(4294967296?)"]; /* 2^32 */
-
- switch (type) {
- case Z_MASTER: return ("master");
- case Z_SLAVE: return ("slave");
-#ifdef STUBS
- case Z_STUB: return ("stub");
-#endif
- case Z_HINT: return ("hint");
- case Z_CACHE: return ("cache");
- case Z_FORWARD: return ("forward");
- default:
- sprintf(ret, "(%u?)", type);
- return (ret);
- }
-}
-
-#ifdef DEBUG
-void
-printzoneinfo(int zonenum, int category, int level) {
- struct timeval tt;
- struct zoneinfo *zp = &zones[zonenum];
-
- if (debug == 0)
- return;
-
- if (!zp->z_origin)
- return;
-
- gettime(&tt);
-
- ns_debug(category, level, "zone %d: %s, class %s, type %s", zonenum,
- zp->z_origin[0] ? zp->z_origin : ".",
- p_class(zp->z_class), zoneTypeString(zp->z_type));
- if (zp->z_source)
- ns_debug(category, level, "\tsource %s", zp->z_source);
- ns_debug(category, level, "\tflags %lx, serial %u, minimum %u",
- (u_long)zp->z_flags, zp->z_serial, zp->z_minimum);
- ns_debug(category, level, "\trefresh %u, retry %u, expire %u",
- zp->z_refresh, zp->z_retry, zp->z_expire);
- if (zp->z_time)
- ns_debug(category, level, "\tz_time %lu (now %lu, left: %lu)",
- zp->z_time, (u_long)tt.tv_sec,
- (u_long)(zp->z_time - tt.tv_sec));
- else
- ns_debug(category, level, "\tz_time %lu", zp->z_time);
-#ifdef BIND_UPDATE
- if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC) != 0) {
- ns_debug(category, level,
- "\tdumpintvl %lu, soaincrintvl %lu deferupdcnt %lu",
- (unsigned long)zp->z_dumpintvl,
- (unsigned long)zp->z_soaincrintvl,
- (unsigned long)zp->z_deferupdcnt);
- if (zp->z_soaincrtime)
- ns_debug(category, level,
- "\tz_soaincrtime %lu (now %lu, left: %lu)",
- zp->z_soaincrtime, (u_long)tt.tv_sec,
- (u_long)(zp->z_soaincrtime - tt.tv_sec));
- else
- ns_debug(category, level, "\tz_soaincrtime %lu",
- zp->z_soaincrtime);
- if (zp->z_dumptime)
- ns_debug(category, level,
- "\tz_dumptime %lu (now %lu, left: %lu)",
- zp->z_dumptime, (u_long)tt.tv_sec,
- (u_long)(zp->z_dumptime - tt.tv_sec));
- else
- ns_debug(category, level, "\tz_dumptime %lu",
- zp->z_dumptime);
- }
-#endif
-}
-#endif /* DEBUG */
-
-/*
- * Remove all cached data below dname, class independent.
- */
-void
-clean_cache_from(char *dname, struct hashbuf *htp) {
- const char *fname;
- struct databuf *dp, *pdp;
- struct namebuf *np;
- struct hashbuf *phtp = htp;
- int root_zone = 0;
-
- ns_debug(ns_log_default, 1, "clean_cache_from(%s)", dname);
- if ((np = nlookup(dname, &phtp, &fname, 0)) && dname == fname &&
- !ns_wildcard(NAME(*np))) {
- for (pdp = NULL, dp = np->n_data; dp != NULL; (void)NULL) {
- if (dp->d_zone == DB_Z_CACHE)
- dp = rm_datum(dp, np, pdp, NULL);
- else {
- pdp = dp;
- dp = dp->d_next;
- }
- }
-
- if (*dname == '\0')
- root_zone = 1;
-
- if (np->n_hash != NULL || root_zone) {
- struct hashbuf *h;
-
- if (root_zone)
- h = htp;
- else
- h = np->n_hash;
- (void)clean_cache(h, 1);
- if (h->h_cnt == 0 && !root_zone) {
- rm_hash(np->n_hash);
- np->n_hash = NULL;
- }
- }
-
- if (!root_zone && np->n_hash == NULL && np->n_data == NULL)
- (void) purge_node(htp, np);
- }
-}
-
-/* clean_cache(htp, all)
- * Scan the entire cache looking for expired TTL's on nonauthoritative
- * data, and remove it. if `all' is true, ignore TTL and rm everything.
- * notes:
- * this should be lazy and eventlib driven.
- * return:
- * number of deleted RRs (all=1) or RRsets (all=0).
- */
-int
-clean_cache(struct hashbuf *htp, int all) {
- struct databuf *dp, *pdp;
- struct namebuf *np, *pnp, *npn;
- struct namebuf **npp, **nppend;
- int deleted = 0;
-
- nppend = htp->h_tab + htp->h_size;
- for (npp = htp->h_tab; npp < nppend; npp++) {
- for (pnp = NULL, np = *npp; np != NULL; np = npn) {
- again:
- for (pdp = NULL, dp = np->n_data; dp != NULL;
- (void)NULL) {
- if (all && dp->d_zone == DB_Z_CACHE) {
- dp = rm_datum(dp, np, pdp, NULL);
- deleted++;
- } else if (dp->d_zone == DB_Z_CACHE &&
- stale(dp)) {
- delete_all(np, dp->d_class, dp->d_type);
- deleted++;
- goto again;
- } else {
- pdp = dp;
- dp = dp->d_next;
- }
- } /*for(pdp)*/
-
- if (np->n_hash) {
- /* Call recursively to remove subdomains. */
- deleted += clean_cache(np->n_hash, all);
-
- /* If now empty, free it */
- if (np->n_hash->h_cnt == 0) {
- rm_hash(np->n_hash);
- np->n_hash = NULL;
- }
- }
-
- if (np->n_hash == NULL && np->n_data == NULL) {
- npn = rm_name(np, npp, pnp);
- htp->h_cnt--;
- } else {
- npn = np->n_next;
- pnp = np;
- }
- } /*for(pnp)*/
- } /*for(npp)*/
- return (deleted);
-}
-
-/* struct namebuf *
- * purge_node(htp, np)
- * Remove entry from cache.
- * Prerequisites:
- * Node is empty and has no children.
- * Paramters:
- * htp - root of recursive hash table this node is part of.
- * np - the node to be deleted.
- * Return:
- * pointer to parent.
- */
-struct namebuf *
-purge_node(struct hashbuf *htp, struct namebuf *np) {
- struct namebuf **npp, **nppend;
- struct namebuf *npn, *pnp, *nnp, *parent;
- struct hashbuf *phtp;
-
- ns_debug(ns_log_default, 3, "purge_node: cleaning cache");
- INSIST(np->n_hash == NULL && np->n_data == NULL);
-
- /* Walk parent hashtable looking for ourself. */
- parent = np->n_parent;
- if (parent != NULL)
- phtp = parent->n_hash;
- else
- phtp = htp;
-
- if (phtp == NULL) {
- /* XXX why shouldn't we panic? */
- } else {
- nppend = phtp->h_tab + phtp->h_size;
- for (npp = phtp->h_tab; npp < nppend; npp++) {
- for (pnp = NULL, nnp = *npp; nnp != NULL; nnp = npn) {
- if (nnp == np) {
- ns_debug(ns_log_default, 3,
- "purge_node: found ourself");
- npn = rm_name(nnp, npp, pnp);
- phtp->h_cnt--;
- } else {
- npn = nnp->n_next;
- pnp = nnp;
- }
- }
- }
- }
- return (parent);
-}
-
-void
-remove_zone(struct zoneinfo *zp, const char *verb) {
-#ifdef BIND_UPDATE
- /*
- * A dynamic zone might have changed, so we
- * need to dump it before removing it.
- */
- if ((zp->z_flags & Z_DYNAMIC) != 0 &&
- ((zp->z_flags & Z_NEED_SOAUPDATE) != 0 ||
- (zp->z_flags & Z_NEED_DUMP) != 0))
- (void) zonedump(zp, ISNOTIXFR);
-#endif
- if ((zp->z_flags & Z_NOTIFY) != 0)
- ns_stopnotify(zp->z_origin, zp->z_class);
- if ((zp->z_flags & Z_NEED_XFER) != 0) {
- zp->z_flags &= ~Z_NEED_XFER;
- xfers_deferred--;
- }
- ns_stopxfrs(zp);
- if ((zp->z_flags & Z_XFER_RUNNING) != 0) {
- int i;
- /* Kill and abandon the current transfer. */
- for (i = 0; i < MAX_XFERS_RUNNING; i++) {
- if (xferstatus[i].xfer_pid == zp->z_xferpid) {
- xferstatus[i].xfer_pid = 0;
- xferstatus[i].xfer_state = XFER_IDLE;
- xfers_running--;
- break;
- }
- }
- (void)kill(zp->z_xferpid, SIGTERM);
- zp->z_flags &= ~(Z_XFER_RUNNING|Z_XFER_ABORTED|Z_XFER_GONE);
- zp->z_xferpid = 0;
- ns_need(main_need_tryxfer);
- }
- do_reload(zp, 1);
- ns_notice(ns_log_config, "%s zone \"%s\" (%s) %s",
- zoneTypeString(zp->z_type), zp->z_origin,
- p_class(zp->z_class), verb);
- free_zone_contents(zp, 1);
- 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(struct zoneinfo *zp, struct hashbuf *htp, int log) {
- const char *dname = zp->z_origin;
- const char *fname;
- struct namebuf *np;
- struct hashbuf *phtp = htp;
- int root_zone = 0;
- int errs = 0;
- int zone = zp - zones;
- struct databuf *pdp, *dp;
- int class = zp->z_class;
-
- ns_debug(ns_log_default, 1, "purge_nonglue(%s/%d)", dname, class);
- if ((np = nlookup(dname, &phtp, &fname, 0)) && dname == fname &&
- !ns_wildcard(NAME(*np))) {
-
- for (pdp = NULL, dp = np->n_data; dp != NULL; (void)NULL) {
- if (dp->d_class == class && dp->d_zone != zone)
- dp = rm_datum(dp, np, pdp, NULL);
- else {
- pdp = dp;
- dp = dp->d_next;
- }
- }
-
- if (*dname == '\0')
- root_zone = 1;
-
- if (np->n_hash != NULL || root_zone) {
- struct hashbuf *h;
-
- if (root_zone)
- h = htp;
- else
- h = np->n_hash;
- errs += purge_nonglue_2(dname, h, class, 0, log, zone);
- if (h->h_cnt == 0 && !root_zone) {
- rm_hash(np->n_hash);
- np->n_hash = NULL;
- }
- }
- }
- return (errs);
-}
-
-static int
-valid_glue(struct databuf *dp, char *name, int belowcut) {
-
- /* NS records are only valid glue at the zone cut */
- if (belowcut && dp->d_type == T_NS)
- return(0);
-
- if (ISVALIDGLUE(dp)) /* T_NS/T_A/T_AAAA/T_A6 */
- return (1);
-
- if (belowcut)
- return (0);
-
- /* Parent NXT record? */
- if (dp->d_type == T_NXT && !ns_samedomain((char*)dp->d_data, name) &&
- ns_samedomain((char*)dp->d_data, zones[dp->d_zone].z_origin))
- return (1);
-
- /* KEY RRset may be in the parent */
- if (dp->d_type == T_KEY)
- return (1);
-
- /* NXT & KEY records may be signed */
- if (!belowcut && dp->d_type == T_SIG &&
- (SIG_COVERS(dp) == T_NXT || SIG_COVERS(dp) == T_KEY))
- return (1);
- return (0);
-}
-
-static int
-purge_nonglue_2(const char *dname, struct hashbuf *htp, int class,
- int belowcut, int log, int zone)
-{
- struct databuf *dp, *pdp;
- struct namebuf *np, *pnp, *npn;
- struct namebuf **npp, **nppend;
- int errs = 0;
- int zonecut;
- char name[MAXDNAME];
-
- nppend = htp->h_tab + htp->h_size;
- for (npp = htp->h_tab; npp < nppend; npp++) {
- for (pnp = NULL, np = *npp; np != NULL; np = npn) {
- if (!bottom_of_zone(np->n_data, class)) {
- zonecut = belowcut;
- for (dp = np->n_data; dp != NULL;
- dp = dp->d_next) {
- if (match(dp, class, ns_t_ns)) {
- zonecut = 1;
- break;
- }
- }
- getname(np, name, sizeof name);
- for (pdp = NULL, dp = np->n_data;
- dp != NULL;
- (void)NULL) {
- int delete = 0;
- if (!zonecut &&
- dp->d_class == class &&
- dp->d_zone != zone)
- delete = 1;
- if (zonecut &&
- dp->d_class == class &&
- !valid_glue(dp, name, belowcut)) {
- if (log &&
- dp->d_zone == zone) {
- ns_error(ns_log_load,
- "zone: %s/%s: non-glue record %s bottom of zone: %s/%s",
- *dname ? dname : ".",
- p_class(dp->d_class),
- belowcut ? "below" :
- "at",
- *name ? name : ".",
- p_type(dp->d_type));
- errs++;
- }
- delete = 1;
- }
- if (delete)
- dp = rm_datum(dp, np, pdp,
- NULL);
- else {
- pdp = dp;
- dp = dp->d_next;
- }
- }
- if (np->n_hash) {
- /*
- * call recursively to clean
- * subdomains
- */
- errs += purge_nonglue_2(dname,
- np->n_hash,
- class,
- zonecut ||
- belowcut,
- log, zone);
-
- /* if now empty, free it */
- if (np->n_hash->h_cnt == 0) {
- rm_hash(np->n_hash);
- np->n_hash = NULL;
- }
- }
- }
-
- if (np->n_hash == NULL && np->n_data == NULL) {
- npn = rm_name(np, npp, pnp);
- htp->h_cnt--;
- } else {
- npn = np->n_next;
- pnp = np;
- }
- }
- }
- return (errs);
-}
-
-void
-purge_zone(struct zoneinfo *zp, struct hashbuf *htp) {
- const char *fname;
- struct databuf *dp, *pdp;
- struct namebuf *np;
- struct hashbuf *phtp = htp;
- int root_zone = 0;
- int zone = zp - zones;
- char *dname = zp->z_origin;
-
- ns_debug(ns_log_default, 1, "purge_zone(%s)", dname);
- if ((np = nlookup(dname, &phtp, &fname, 0)) && dname == fname &&
- !ns_wildcard(NAME(*np))) {
- for (pdp = NULL, dp = np->n_data; dp != NULL; (void)NULL) {
- if (dp->d_zone == zone)
- dp = rm_datum(dp, np, pdp, NULL);
- else {
- pdp = dp;
- dp = dp->d_next;
- }
- }
-
- if (*dname == '\0')
- root_zone = 1;
-
- if (np->n_hash != NULL || root_zone) {
- struct hashbuf *h;
-
- if (root_zone)
- h = htp;
- else
- h = np->n_hash;
- purge_z_2(h, zone);
- if (h->h_cnt == 0 && !root_zone) {
- rm_hash(np->n_hash);
- np->n_hash = NULL;
- }
- }
-
- if (!root_zone && np->n_hash == NULL && np->n_data == NULL)
- (void) purge_node(htp, np);
- }
-}
-
-static void
-purge_z_2(struct hashbuf *htp, int zone) {
- struct databuf *dp, *pdp;
- struct namebuf *np, *pnp, *npn;
- struct namebuf **npp, **nppend;
-
- nppend = htp->h_tab + htp->h_size;
- for (npp = htp->h_tab; npp < nppend; npp++) {
- for (pnp = NULL, np = *npp; np != NULL; np = npn) {
- for (pdp = NULL, dp = np->n_data;
- dp != NULL;
- (void)NULL) {
- if (dp->d_zone == zone)
- dp = rm_datum(dp, np, pdp,
- NULL);
- else {
- pdp = dp;
- dp = dp->d_next;
- }
- }
- if (np->n_hash) {
- /* call recursively to rm subdomains */
- purge_z_2(np->n_hash, zone);
-
- /* if now empty, free it */
- if (np->n_hash->h_cnt == 0) {
- rm_hash(np->n_hash);
- np->n_hash = NULL;
- }
- }
-
- if (np->n_hash == NULL && np->n_data == NULL) {
- npn = rm_name(np, npp, pnp);
- htp->h_cnt--;
- } else {
- npn = np->n_next;
- pnp = np;
- }
- }
- }
-}
-
-static int
-bottom_of_zone(struct databuf *dp, int class) {
- int ret = 0;
-
- for ((void)NULL; dp; dp = dp->d_next) {
- if (dp->d_class != class)
- continue;
- if (dp->d_zone == DB_Z_CACHE)
- continue;
- if (dp->d_rcode) /* This should not occur. */
- continue;
- if (dp->d_type != T_SOA)
- continue;
- ret = 1;
- break;
- }
- ns_debug(ns_log_default, 3, "bottom_of_zone() == %d", ret);
- return (ret);
-}
-
-/*
- * Handle XFER limit for a nameserver.
- */
-
-
-static int
-nxfers(struct zoneinfo *zp) {
- struct in_addr nsa;
- int ret;
- int i;
-
- if (zp->z_xaddrcnt != 0)
- nsa = zp->z_xaddr[0]; /* first ns holds zone's xfer limit */
- else if (zp->z_addrcnt != 0)
- nsa = zp->z_addr[0]; /* first ns holds zone's xfer limit */
- else
- return (-1);
-
- 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);
-}
-
-/*
- * Abort an xfer that has taken too long.
- */
-static void
-abortxfer(struct zoneinfo *zp) {
- if (zp->z_flags & (Z_XFER_GONE|Z_XFER_ABORTED)) {
- int i;
-
- for (i = 0; i < MAX_XFERS_RUNNING; i++) {
- if (xferstatus[i].xfer_pid == zp->z_xferpid) {
- xferstatus[i].xfer_pid = 0;
- xferstatus[i].xfer_state = XFER_IDLE;
- break;
- }
- }
-
- if (zp->z_flags & Z_XFER_GONE)
- ns_warning(ns_log_default,
- "zone transfer timeout for \"%s\"; pid %lu missing",
- zp->z_origin, (u_long)zp->z_xferpid);
- else if (kill(zp->z_xferpid, SIGKILL) == -1)
- ns_warning(ns_log_default,
- "zone transfer timeout for \"%s\"; kill pid %lu: %s",
- zp->z_origin, (u_long)zp->z_xferpid,
- strerror(errno));
- else
- ns_warning(ns_log_default,
-"zone transfer timeout for \"%s\"; second kill \
-pid %lu - forgetting, processes may accumulate",
- zp->z_origin, (u_long)zp->z_xferpid);
-
- zp->z_xferpid = 0;
- xfers_running--;
- zp->z_flags &= ~(Z_XFER_RUNNING|Z_XFER_ABORTED|Z_XFER_GONE);
- } else if (kill(zp->z_xferpid, SIGTERM) == -1) {
- if (errno == ESRCH)
- /* No warning on first time, it may have just exited */
- zp->z_flags |= Z_XFER_GONE;
- else {
- ns_warning(ns_log_default,
- "zone transfer timeout for \"%s\"; pid %lu kill failed %s",
- zp->z_origin, (u_long)zp->z_xferpid,
- strerror(errno));
- zp->z_flags |= Z_XFER_ABORTED;
- }
- } else {
- ns_notice(ns_log_default,
- "zone transfer timeout for \"%s\"; pid %lu killed",
- zp->z_origin, (u_long)zp->z_xferpid);
- zp->z_flags |= Z_XFER_ABORTED;
- }
-}
-
-/*
- * Process exit of xfer's.
- */
-void
-reapchild(void) {
- int i;
- pid_t pid;
- WAIT_T status;
-
- gettime(&tt);
- while ((pid = (pid_t)waitpid(-1, &status, WNOHANG)) > 0) {
- for (i = 0; i < MAX_XFERS_RUNNING; i++) {
- if (xferstatus[i].xfer_pid == pid) {
- xferstatus[i].xfer_status = status;
- xferstatus[i].xfer_state = XFER_DONE;
- ns_need(main_need_endxfer);
- break;
- }
- }
- }
-}
-
-/*
- * Finish processing of of finished xfers
- */
-void
-endxfer() {
- struct zoneinfo *zp;
- int exitstatus, i;
- pid_t pid;
- WAIT_T status;
-
- gettime(&tt);
-
- for (i = 0; i < MAX_XFERS_RUNNING; i++) {
- if (xferstatus[i].xfer_state != XFER_DONE)
- continue;
- pid = xferstatus[i].xfer_pid;
- status = xferstatus[i].xfer_status;
- exitstatus = WIFEXITED(status) ? WEXITSTATUS(status) : 0;
-
- for (zp = zones; zp < &zones[nzones]; zp++) {
- if (zp->z_xferpid != pid)
- continue;
- xfers_running--;
- zp->z_xferpid = 0;
- zp->z_flags &=
- ~(Z_XFER_RUNNING|Z_XFER_ABORTED|Z_XFER_GONE);
- ns_debug(ns_log_default, 1,
- "\nendxfer: child %d zone %s returned status=%d termsig=%d",
- pid, zp->z_origin, exitstatus,
- WIFSIGNALED(status) ? WTERMSIG(status) : -1);
- if (WIFSIGNALED(status)) {
- if (WTERMSIG(status) != SIGKILL) {
- ns_notice(ns_log_default,
- "named-xfer \"%s\" exited with signal %d",
- zp->z_origin[0]?zp->z_origin:".",
- WTERMSIG(status));
- }
- ns_retrytime(zp, tt.tv_sec);
- sched_zone_maint(zp);
- } else {
- switch (exitstatus) {
- case XFER_UPTODATE:
- markUpToDate(zp);
- sched_zone_maint(zp);
- break;
-
- case XFER_SUCCESSAXFR:
- case XFER_SUCCESSAXFRIXFRFILE:
- zp->z_xferpid = XFER_ISAXFR;
- if (exitstatus == XFER_SUCCESSAXFRIXFRFILE) {
- zp->z_xferpid = XFER_ISAXFRIXFR;
- 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;
- ns_need(main_need_zoneload);
- break;
-
- case XFER_SUCCESSIXFR:
- zp->z_xferpid = XFER_ISIXFR;
- ns_notice(ns_log_default,
- "IXFR Success %s",
- zp->z_ixfr_tmp);
- if (merge_logs(zp, zp->z_ixfr_tmp) >= 0) {
- ns_notice(ns_log_default,
- "IXFR Merge success %s",
- zp->z_ixfr_tmp);
-
- (void)unlink(zp->z_updatelog);
- (void)unlink(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);
- ns_refreshtime(zp, tt.tv_sec);
- sched_zone_maint(zp);
- } else {
- ns_notice(ns_log_default,
- "IXFR Merge failed %s",
- zp->z_ixfr_tmp);
- ns_retrytime(zp, tt.tv_sec);
- sched_zone_maint(zp);
- }
- break;
-
- case XFER_TIMEOUT:
- if (!(zp->z_flags & Z_SYSLOGGED)) {
- zp->z_flags |= Z_SYSLOGGED;
- ns_notice(ns_log_default,
- "zoneref: Masters for slave zone \"%s\" unreachable",
- zp->z_origin);
- }
- ns_retrytime(zp, tt.tv_sec);
- sched_zone_maint(zp);
- break;
-
- case XFER_REFUSED:
- if (!(zp->z_flags & Z_SYSLOGGED)) {
- zp->z_flags |= Z_SYSLOGGED;
- ns_error(ns_log_xfer_in,
- "zoneref: Masters for slave zone \"%s\" REFUSED transfer",
- zp->z_origin);
- }
- ns_retrytime(zp, tt.tv_sec);
- sched_zone_maint(zp);
- break;
-
- default:
- if (!(zp->z_flags & Z_SYSLOGGED)) {
- zp->z_flags |= Z_SYSLOGGED;
- ns_notice(ns_log_default,
- "named-xfer for \"%s\" exited %d",
- zp->z_origin,
- exitstatus);
- }
- /* FALLTHROUGH */
- case XFER_FAIL:
- zp->z_flags |= Z_SYSLOGGED;
- ns_retrytime(zp, tt.tv_sec);
- sched_zone_maint(zp);
- break;
- }
- break;
- }
- }
- xferstatus[i].xfer_state = XFER_IDLE;
- xferstatus[i].xfer_pid = 0;
- }
- tryxfer();
-}
-
-/*
- * Try to start some xfers - new "fair scheduler" by Bob Halley @DEC (1995)
- */
-void
-tryxfer() {
- static struct zoneinfo *zp = NULL;
- static struct zoneinfo *lastzones = NULL;
- static int lastnzones = 0;
- struct zoneinfo *startzp, *stopzp;
-
- /* initialize, and watch out for changes in zones! */
- if (lastzones != zones) {
- if (lastzones != NULL)
- ns_debug(ns_log_default, 3, "zones changed: %p != %p",
- lastzones, zones);
- lastzones = zones;
- zp = zones;
- }
-
- /* did zones shrink? */
- if (lastnzones > nzones) {
- ns_debug(ns_log_default, 3, "zones shrunk");
- zp = zones;
- }
- lastnzones = nzones;
-
- if (zp == zones)
- stopzp = &zones[nzones-1];
- else
- stopzp = zp - 1;
-
- ns_debug(ns_log_default, 3,
- "tryxfer start zp=%p stopzp=%p def=%d running=%d",
- zp, stopzp, xfers_deferred, xfers_running);
-
- startzp = zp;
- for (;;) {
- int xfers;
-
- if (!xfers_deferred ||
- xfers_running >= server_options->transfers_in)
- break;
-
- if ((xfers = nxfers(zp)) != -1 &&
- xfers < server_options->transfers_per_ns &&
- (zp->z_flags & Z_NEED_XFER)) {
- startxfer(zp);
- sched_zone_maint(zp);
- }
-
- if (zp == stopzp) {
- ns_debug(ns_log_default, 3, "tryxfer stop mark");
- zp = startzp;
- break;
- }
-
- zp++;
- /* wrap around? */
- if (zp == &zones[nzones])
- zp = zones;
- }
- ns_debug(ns_log_default, 3, "tryxfer stop zp=%p", zp);
-}
-
-/*
- * Reload zones whose transfers have completed.
- */
-void
-loadxfer(void) {
- struct zoneinfo *zp;
- u_int32_t old_serial,new_serial;
- char *tmpnom;
- int isixfr;
-
- gettime(&tt);
- for (zp = zones; zp < &zones[nzones]; zp++) {
- if (zp->z_flags & Z_NEED_RELOAD) {
- ns_debug(ns_log_default, 1, "loadxfer() \"%s\"",
- zp->z_origin[0] ? zp->z_origin : ".");
- zp->z_flags &= ~(Z_NEED_RELOAD|Z_AUTH);
-/* XXX this is bad, should be done in ns_zreload() for primary changes. */
- ns_stopxfrs(zp);
- old_serial = zp->z_serial;
- if (zp->z_xferpid == XFER_ISIXFR) {
- tmpnom = zp->z_ixfr_tmp;
- isixfr = ISIXFR;
- } else {
- tmpnom = zp->z_source;
- purge_zone(zp, hashtab);
- isixfr = ISNOTIXFR;
- }
- if (zp->z_xferpid == XFER_ISAXFRIXFR) {
- tmpnom= zp->z_source;
- purge_zone(zp, hashtab);
- isixfr = ISNOTIXFR;
- }
-
- if (!db_load(tmpnom, zp->z_origin, zp, NULL, isixfr)) {
- zp->z_flags |= Z_AUTH;
- zp->z_flags &= ~Z_EXPIRED;
- if (isixfr == ISIXFR) {
- new_serial= zp ->z_serial;
- ns_warning(ns_log_db, "ISIXFR");
- ns_warning(ns_log_db, "error in updating ixfr data base file %s from %s", zp -> z_ixfr_base, 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);
-
- }
- }
- zp->z_xferpid = 0;
- if (zp->z_flags & Z_TMP_FILE)
- (void) unlink(zp->z_source);
- sched_zone_maint(zp);
- }
- }
-}
-
-/*
- * Add this zone to the set of those needing transfers.
- */
-void
-addxfer(struct zoneinfo *zp) {
- if (!(zp->z_flags & Z_NEED_XFER)) {
- zp->z_flags |= Z_NEED_XFER;
- xfers_deferred++;
- tryxfer();
- }
-}
-
-/*
- * Mark one zone as requiring a reload.
- * Note that it should be called with signals blocked,
- * and should not allocate memory (since it can be called from a sighandler).
- */
-const char *
-deferred_reload_unsafe(struct zoneinfo *zp) {
- INSIST(zp->z_type != z_nil);
- if (!zonefile_changed_p(zp))
- return ("Zone file has not changed.");
- if (LINKED(zp, z_reloadlink))
- return ("Zone is already scheduled for reloading.");
- APPEND(reloadingzones, zp, z_reloadlink);
- ns_need_unsafe(main_need_zreload);
- return ("Zone is now scheduled for reloading.");
-}
-
-/*
- * If we've loaded this file, and the file has not been modified and contains
- * no $INCLUDE, then there's no need to reload.
- */
-int
-zonefile_changed_p(struct zoneinfo *zp) {
- struct stat sb;
-
- INSIST(zp->z_type != z_nil);
- return ((zp->z_flags & Z_INCLUDE) != 0 ||
- stat(zp->z_source, &sb) == -1 ||
- zp->z_ftime != sb.st_mtime);
-}
-
-int
-reload_master(struct zoneinfo *zp) {
- INSIST(zp->z_type == z_master);
- zp->z_flags &= ~Z_AUTH;
- ns_stopxfrs(zp);
- /* XXX what about parent zones? */
-#ifdef BIND_UPDATE
- /*
- * A dynamic zone might have changed, so we
- * need to dump it before reloading it.
- */
- if ((zp->z_flags & Z_DYNAMIC) != 0 &&
- ((zp->z_flags & Z_NEED_SOAUPDATE) != 0 ||
- (zp->z_flags & Z_NEED_DUMP) != 0))
- (void) zonedump(zp, ISNOTIXFR);
-#endif
- purge_zone(zp, hashtab);
- ns_debug(ns_log_config, 1, "reloading zone");
-#ifdef BIND_UPDATE
- if ((zp->z_flags & Z_DYNAMIC) != 0) {
- struct stat sb;
-
- if (stat(zp->z_source, &sb) < 0)
- ns_error(ns_log_config, "stat(%s) failed: %s",
- zp->z_source, strerror(errno));
- else {
- if ((sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0)
- ns_warning(ns_log_config,
- "dynamic zone file '%s' is writable",
- zp->z_source);
- }
- }
-#endif
- if (!db_load(zp->z_source, zp->z_origin, zp, NULL, ISNOTIXFR))
- zp->z_flags |= Z_AUTH;
- zp->z_refresh = 0; /* no maintenance needed */
- zp->z_time = 0;
-#ifdef BIND_UPDATE
- zp->z_lastupdate = 0;
- if ((zp->z_flags & Z_DYNAMIC) != 0)
- if (merge_logs(zp, zp->z_updatelog) == 1)
- return (1);
-#endif
- return (0);
-}
-
-/*
- * Called by main() when main_need_zreload has been set. Should pull one
- * zone off of the reloadingzones list and reload it, then if the list is
- * not then empty, should turn main_need_zreload on again for the next call.
- * It is not an error to call this when the reloadingzones list is empty.
- */
-void
-ns_zreload(void) {
- struct zoneinfo *zp;
-
- block_signals();
- if (EMPTY(reloadingzones)) {
- unblock_signals();
- return;
- }
- zp = HEAD(reloadingzones);
- UNLINK(reloadingzones, zp, z_reloadlink);
- unblock_signals();
-
- reload_master(zp);
-
- block_signals();
- if (!EMPTY(reloadingzones))
- ns_need_unsafe(main_need_zreload);
- unblock_signals();
-}
-
-/*
- * Flush and reload configuration file and data base.
- */
-void
-ns_reload(void) {
- ns_notice(ns_log_default, "%s %snameserver",
- (reconfiging != 0) ? "reconfiguring" : "reloading",
- (noexpired == 1) ? "(-noexpired) " : "");
-
- INSIST(reloading == 0);
- qflush();
- sq_flush(NULL);
- reloading++; /* To force transfer if slave and backing up. */
- confmtime = ns_init(conffile);
- time(&resettime);
- reloading--;
- ns_notice(ns_log_default, "Ready to answer queries.");
-}
-
-/*
- * Reload configuration, look for new or deleted zones, not changed ones
- * also ignore expired zones.
- */
-void
-ns_noexpired(void) {
- INSIST(noexpired == 0);
- noexpired++; /* To ignore zones which are expired */
- ns_reconfig();
- noexpired--;
-}
-
-/*
- * Reload configuration, look for new or deleted zones, not changed ones.
- */
-void
-ns_reconfig(void) {
- INSIST(reconfiging == 0);
- reconfiging++; /* To ignore zones which aren't new or deleted. */
- ns_reload();
- reconfiging--;
-}
-
-void
-make_new_zones(void) {
- struct zoneinfo *zp;
- int n;
- int newzones = (nzones == 0) ? INITIALZONES : NEWZONES;
-
- ns_debug(ns_log_config, 1, "Adding %d template zones", NEWZONES);
- zp = (struct zoneinfo *)
- memget((nzones + newzones) * sizeof(struct zoneinfo));
- if (zp == NULL)
- panic("no memory for more zones", NULL);
- memset(zp, 0, (nzones + newzones) * sizeof(struct zoneinfo));
- if (zones != NULL) {
- memcpy(zp, zones, nzones * sizeof(struct zoneinfo));
- memput(zones, nzones * sizeof(struct zoneinfo));
- }
- zones = zp;
- 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++;
- }
- unblock_signals();
-}
-
-void
-free_zone(struct zoneinfo *zp) {
- if (LINKED(zp, z_reloadlink))
- panic("freeing reloading zone", NULL);
- if (zp->z_type != z_nil)
- panic("freeing unfree zone", NULL);
- APPEND(freezones, zp, z_freelink);
-}
-
-#ifndef HAVE_SPAWNXFER
-static pid_t
-spawnxfer(char **argv, struct zoneinfo *zp) {
- pid_t pid = (pid_t)vfork();
-
- if (pid == -1) {
- ns_error(ns_log_default, "xfer vfork: %s", strerror(errno));
- zp->z_time = tt.tv_sec + 10;
- return (pid);
- }
- if (pid == 0) {
- /* Child. */
- execv(server_options->named_xfer, argv);
- ns_error(ns_log_default, "can't exec %s: %s",
- server_options->named_xfer, strerror(errno));
- _exit(XFER_FAIL); /* Avoid duplicate buffer flushes. */
- }
- return (pid);
-}
-#endif
-
-struct zoneinfo *
-find_auth_zone(const char *zname, ns_class zclass) {
- struct zoneinfo *zp;
- struct hashbuf *htp;
- struct namebuf *np;
- const char *fname;
- int zn;
-
- zp = find_zone(zname, zclass);
- if (zp != NULL &&
- (zp->z_type == z_slave ||
- zp->z_type == z_master ||
- zp->z_type == z_stub))
- return (zp);
-
- htp = hashtab;
- np = nlookup(zname, &htp, &fname, 0);
- if (np != NULL && (zn = findMyZone(np, zclass)) != DB_Z_CACHE)
- return (&zones[zn]);
-
- return (NULL);
-}
OpenPOWER on IntegriCloud