zone.c revision 186e7f37c9fc985a7a7264cc8170e48a25bed434
/*
* Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/* $Id: zone.c,v 1.461 2006/12/21 06:02:30 marka Exp $ */
/*! \file */
#include <config.h>
#include <isc/ratelimiter.h>
#include <isc/refcount.h>
#include <isc/taskpool.h>
#include <dns/callbacks.h>
#include <dns/dbiterator.h>
#include <dns/masterdump.h>
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#include <dns/resolver.h>
/*%
* Ensure 'a' is at least 'min' but not more than 'max'.
*/
/*
* Default values.
*/
#ifndef DNS_MAX_EXPIRE
#endif
#ifndef DNS_DUMP_DELAY
#endif
typedef struct dns_notify dns_notify_t;
typedef struct dns_stub dns_stub_t;
typedef struct dns_load dns_load_t;
typedef struct dns_forward dns_forward_t;
#define DNS_ZONE_CHECKLOCK
#ifdef DNS_ZONE_CHECKLOCK
#define LOCK_ZONE(z) \
} while (0)
#define UNLOCK_ZONE(z) \
#define LOCKED_ZONE(z) ((z)->locked)
#else
#define LOCKED_ZONE(z) ISC_TRUE
#endif
#ifdef ISC_RWLOCK_USEATOMIC
#define ZONEDB_INITLOCK(l) isc_rwlock_init((l), 0, 0)
#define ZONEDB_DESTROYLOCK(l) isc_rwlock_destroy(l)
#define ZONEDB_LOCK(l, t) RWLOCK((l), (t))
#define ZONEDB_UNLOCK(l, t) RWUNLOCK((l), (t))
#else
#define ZONEDB_INITLOCK(l) isc_mutex_init(l)
#define ZONEDB_DESTROYLOCK(l) DESTROYLOCK(l)
#define ZONEDB_LOCK(l, t) LOCK(l)
#define ZONEDB_UNLOCK(l, t) UNLOCK(l)
#endif
struct dns_zone {
/* Unlocked */
unsigned int magic;
#ifdef DNS_ZONE_CHECKLOCK
#endif
#ifdef ISC_RWLOCK_USEATOMIC
#else
#endif
/* Locked */
unsigned int irefs;
char *masterfile;
char *journal;
unsigned int flags;
unsigned int options;
unsigned int db_argc;
char **db_argv;
char *keydirectory;
unsigned int masterscnt;
unsigned int curmaster;
unsigned int notifycnt;
/* Access Control Lists */
/*%
* Zones in certain states such as "waiting for zone transfer"
* or "zone transfer in progress" are kept on per-state linked lists
* in the zone manager using the 'statelink' field. The 'statelist'
* field points at the list the zone is currently on. It the zone
* is not on any such list, statelist is NULL.
*/
/*%
* Optional per-zone statistics counters (NULL if not present).
*/
void *isselfarg;
char * strnamerd;
char * strname;
char * strrdclass;
char * strviewname;
};
#define DNS_ZONE_SETFLAG(z,f) do { \
INSIST(LOCKED_ZONE(z)); \
(z)->flags |= (f); \
} while (0)
#define DNS_ZONE_CLRFLAG(z,f) do { \
INSIST(LOCKED_ZONE(z)); \
(z)->flags &= ~(f); \
} while (0)
/* XXX MPA these may need to go back into zone.h */
* uptodate */
* messages */
* reload */
* zone with no masters
* occured */
* from SOA (if not set, we
* are still using
* default timer values) */
#define DNS_ZONEFLG_NOREFRESH 0x00010000U
#define DNS_ZONEFLG_DIALNOTIFY 0x00020000U
#define DNS_ZONEFLG_DIALREFRESH 0x00040000U
#define DNS_ZONEFLG_SHUTDOWN 0x00080000U
#define DNS_ZONEFLG_FLUSH 0x00200000U
#define DNS_ZONEFLG_NOEDNS 0x00400000U
#define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U
#define DNS_ZONEFLG_SOABEFOREAXFR 0x01000000U
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
/* Flags for zone_load() */
#define UNREACH_CHACHE_SIZE 10U
struct dns_unreachable {
};
struct dns_zonemgr {
unsigned int magic;
int refs; /* Locked by rwlock */
isc_task_t * task;
/* Locked by rwlock. */
/* Configuration data. */
unsigned int serialqueryrate;
/* Locked by iolock */
/* Locked by rwlock. */
/* LRU cache */
};
/*%
* Hold notify state.
*/
struct dns_notify {
unsigned int magic;
unsigned int flags;
};
#define DNS_NOTIFY_NOSOA 0x0001U
/*%
* dns_stub holds state while performing a 'stub' transfer.
* 'db' is the zone's 'db' or a new one if this is the initial
* transfer.
*/
struct dns_stub {
unsigned int magic;
};
/*%
* Hold load state.
*/
struct dns_load {
unsigned int magic;
};
/*%
* Hold forward state.
*/
struct dns_forward {
unsigned int magic;
void *callback_arg;
};
/*%
* Hold IO request state.
*/
struct dns_io {
unsigned int magic;
};
#define SEND_BUFFER_SIZE 2048
static void cancel_refresh(dns_zone_t *);
#if 0
/* ondestroy example */
#endif
dns_stub_t *stub);
unsigned int flags,
dns_zone_t *zone);
static isc_result_t
unsigned int *errors);
const char *templat);
isc_time_t *now);
static const unsigned int dbargc_default = 1;
static const char *dbargv_default[] = { "rbt" };
#define DNS_ZONE_JITTER_ADD(a, b, c) \
do { \
isc_interval_t _i; \
isc_uint32_t _j; \
"epoch approaching: upgrade required: " \
"now + %s failed", #b); \
(void)isc_time_add((a), &_i, (c)); \
} \
} while (0)
#define DNS_ZONE_TIME_ADD(a, b, c) \
do { \
isc_interval_t _i; \
isc_interval_set(&_i, (b), 0); \
"epoch approaching: upgrade required: " \
"now + %s failed", #b); \
(void)isc_time_add((a), &_i, (c)); \
} \
} while (0)
/***
*** Public functions.
***/
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS)
goto free_zone;
if (result != ISC_R_SUCCESS)
goto free_mutex;
/* XXX MPA check that all elements are initialised */
#ifdef DNS_ZONE_CHECKLOCK
#endif
if (result != ISC_R_SUCCESS)
goto free_dblock;
zone->masterscnt = 0;
/* Must be after magic is set. */
if (result != ISC_R_SUCCESS)
goto free_erefs;
return (ISC_R_SUCCESS);
return (result);
}
/*
* Free a zone. Because we require that there be no more
* outstanding events or references, no locking is necessary.
*/
static void
/*
* Managed objects. Order is important.
*/
/* Unmanaged objects */
== ISC_R_SUCCESS);
== ISC_R_SUCCESS);
/* last stuff */
}
/*
* Single shot.
*/
void
char namebuf[1024];
/*
* Test and set.
*/
}
}
void
}
/*
* Single shot.
*/
void
/*
* Test and set.
*/
}
static void
unsigned int i;
/* Free the old database argument list. */
}
}
unsigned int i;
void *mem;
}
} else
return (result);
}
unsigned int i;
/* Set up a new database argument list. */
goto nomem;
for (i = 0; i < dbargc; i++)
for (i = 0; i < dbargc; i++) {
goto nomem;
}
/* Free the old list. */
goto unlock;
for (i = 0; i < dbargc; i++)
}
return (result);
}
void
char namebuf[1024];
}
}
char namebuf[1024];
}
return (result);
}
void
/*
* If the zone reuses an existing DB, the DB needs to be
* set in the acache explicitly. We can safely ignore the
* case where the DB is already set. If other error happens,
* the acache will not work effectively.
*/
"dns_acache_setdb() failed: %s",
}
}
}
static isc_result_t
char *copy;
return (ISC_R_NOMEMORY);
} else {
}
return (ISC_R_SUCCESS);
}
}
if (result == ISC_R_SUCCESS) {
}
return (result);
}
const char *
return (zone->masterfile);
}
static isc_result_t
char *journal;
/* Calculate string length including '\0'. */
return (ISC_R_NOMEMORY);
} else {
}
return (result);
}
return (result);
}
char *
}
/*
* Return true iff the zone is "dynamic", in the sense that the zone's
* master file (if any) is written by the server, rather than being
* updated manually and read by the server.
*
* This is true for slave zones, stub zones, and zones that allow
* dynamic updates either by having an update policy ("ssutable")
* or an "allow-update" ACL with a value other than exactly "{ none; }".
*/
static isc_boolean_t
&&
}
static isc_result_t
goto cleanup;
}
/*
* The zone has no master file configured, but it already
* has a database. It could be the built-in
* version.bind. CH zone, a zone with a persistent
* database being reloaded, or maybe a zone that
* used to have a master file but whose configuration
* was changed so that it no longer has one. Do nothing.
*/
goto cleanup;
}
/*
* This is a slave, stub, or dynamically updated
* zone being reloaded. Do nothing - the database
* we already have is guaranteed to be up-to-date.
*/
else
goto cleanup;
}
/*
* Store the current time before the zone is loaded, so that if the
* file changes between the time of the load and the time that
* zone->loadtime is set, then the file will still be reloaded
* the next time dns_zone_load is called.
*/
/*
* Don't do the load if the file that stores the zone is older
* than the last time the zone was loaded. If the zone has not
* been loaded yet, zone->loadtime will be the epoch.
*/
/*
* The file is already loaded. If we are just doing a
* "rndc reconfig", we are done.
*/
(flags & DNS_ZONELOADFLAG_NOSTAT) != 0) {
goto cleanup;
}
if (result == ISC_R_SUCCESS) {
"skipping load: master file "
"older than last load");
goto cleanup;
}
}
}
/*
* Built in zones don't need to be reloaded.
*/
goto cleanup;
}
"no master file");
}
goto cleanup;
}
}
&db);
if (result != ISC_R_SUCCESS) {
"loading zone: creating database: %s",
goto cleanup;
}
if (! dns_db_ispersistent(db)) {
} else {
"loading zone: "
"no master file configured");
goto cleanup;
}
"no master file configured: continuing");
}
}
if (result == DNS_R_CONTINUE) {
goto cleanup;
}
dns_db_detach(&db);
return (result);
}
}
}
static void
unsigned int options;
if (result == ISC_R_CANCELED)
goto fail;
goto fail;
return;
fail:
}
static void
const char me[] = "zone_gotwritehandle";
if (result == ISC_R_CANCELED)
goto fail;
if (result != DNS_R_CONTINUE)
goto fail;
return;
fail:
}
static isc_result_t
unsigned int options;
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS) {
/*
* We can't report multiple errors so ignore
* the result of dns_db_endload().
*/
goto cleanup;
} else
} else {
if (result != ISC_R_SUCCESS)
return (result);
zone->masterformat);
if (result == ISC_R_SUCCESS)
}
return (result);
return (result);
}
static isc_boolean_t
{
char ownerbuf[DNS_NAME_FORMATSIZE];
char namebuf[DNS_NAME_FORMATSIZE];
char altbuf[DNS_NAME_FORMATSIZE];
int level;
/*
* Outside of zone.
*/
return (ISC_TRUE);
}
else
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
if (result == DNS_R_NXRRSET) {
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
}
result == DNS_R_EMPTYNAME) {
/* XXX950 make fatal for 9.5.0. */
return (ISC_TRUE);
}
if (result == DNS_R_CNAME) {
}
if (result == DNS_R_DNAME) {
altbuf);
}
}
return (ISC_TRUE);
}
static isc_boolean_t
{
char ownerbuf[DNS_NAME_FORMATSIZE];
char namebuf[DNS_NAME_FORMATSIZE];
char altbuf[DNS_NAME_FORMATSIZE];
int level;
/*
* "." means the services does not exist.
*/
return (ISC_TRUE);
/*
* Outside of zone.
*/
return (ISC_TRUE);
}
else
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
if (result == DNS_R_NXRRSET) {
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
}
result == DNS_R_EMPTYNAME) {
/* XXX950 make fatal for 9.5.0. */
return (ISC_TRUE);
}
if (result == DNS_R_CNAME) {
}
if (result == DNS_R_DNAME) {
altbuf);
}
}
return (ISC_TRUE);
}
static isc_boolean_t
{
char ownerbuf[DNS_NAME_FORMATSIZE];
char namebuf[DNS_NAME_FORMATSIZE];
char altbuf[DNS_NAME_FORMATSIZE];
int level;
/*
* Outside of zone.
*/
return (ISC_TRUE);
}
else
dns_rdataset_init(&a);
DNS_DBFIND_GLUEOK, 0, NULL,
if (result == ISC_R_SUCCESS) {
return (ISC_TRUE);
} else if (result == DNS_R_DELEGATION)
result == DNS_R_GLUE) {
DNS_DBFIND_GLUEOK, 0, NULL,
if (tresult == ISC_R_SUCCESS) {
return (ISC_TRUE);
}
if (tresult == DNS_R_DELEGATION)
/*
* Check glue against child zone.
*/
&a, &aaaa);
if (dns_rdataset_isassociated(&a))
if (dns_rdataset_isassociated(&aaaa))
return (answer);
}
} else
const char *what;
what = "REQUIRED GLUE ";
else if (result == DNS_R_DELEGATION)
what = "SIBLING GLUE ";
else
what = "";
if (result != DNS_R_DELEGATION ||
"address records (A or AAAA)",
/*
* Log missing address record.
*/
&a, &aaaa);
/* XXX950 make fatal for 9.5.0. */
/* answer = ISC_FALSE; */
}
} else if (result == DNS_R_CNAME) {
/* XXX950 make fatal for 9.5.0. */
/* answer = ISC_FALSE; */
} else if (result == DNS_R_DNAME) {
/* XXX950 make fatal for 9.5.0. */
/* answer = ISC_FALSE; */
}
if (dns_rdataset_isassociated(&a))
if (dns_rdataset_isassociated(&aaaa))
return (answer);
}
static isc_boolean_t
if (result != ISC_R_SUCCESS)
return (ISC_TRUE);
while (result == ISC_R_SUCCESS) {
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* Is this name visible in the zone?
*/
(dns_name_countlabels(bottom) > 0 &&
goto next;
/*
* Don't check the NS records at the origin.
*/
goto checkmx;
if (result != ISC_R_SUCCESS)
goto checkmx;
/*
* Remember bottom of zone.
*/
while (result == ISC_R_SUCCESS) {
}
if (result != ISC_R_SUCCESS)
goto checksrv;
while (result == ISC_R_SUCCESS) {
}
goto next;
if (result != ISC_R_SUCCESS)
goto next;
while (result == ISC_R_SUCCESS) {
}
next:
}
return (ok);
}
/*
* OpenSSL verification of RSA keys with exponent 3 is known to be
* broken prior OpenSSL 0.9.8c/0.9.7k. Look for such keys and warn
* if they are in use.
*/
static void
const char *algorithm;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
result == ISC_R_SUCCESS;
{
{
algorithm = "RSASHA1";
} else {
algorithm = "RSAMD5";
}
if (logit)
"weak %s (%u) key found "
"(exponent=3)", algorithm,
break;
}
}
}
static isc_result_t
{
unsigned int soacount = 0;
unsigned int nscount = 0;
unsigned int errors = 0;
/*
* Initiate zone transfer? We may need a error code that
* indicates that the "permanent" form does not exist.
* XXX better error feedback to log.
*/
if (result == ISC_R_FILENOTFOUND)
"no master file");
else if (result != DNS_R_NOMASTERFILE)
"loading from master file %s "
"failed: %s",
} else
"loading from master file %s failed: %s",
goto cleanup;
}
"number of nodes in database: %u",
if (result == DNS_R_SEENINCLUDE)
else
/*
* Apply update log, if any, on initial load.
*/
{
result != ISC_R_RANGE) {
"journal rollforward failed: %s",
goto cleanup;
}
"journal rollforward failed: "
"journal out of sync with zone");
goto cleanup;
}
"journal rollforward completed "
"successfully: %s",
if (result == ISC_R_SUCCESS)
}
/*
* Obtain ns, soa and cname counts for top of zone.
*/
&errors);
if (result != ISC_R_SUCCESS) {
}
/*
* Master / Slave / Stub zones require both NS and SOA records at
* the top of the zone.
*/
case dns_zone_master:
case dns_zone_slave:
case dns_zone_stub:
if (soacount != 1) {
"has %d SOA records", soacount);
}
if (nscount == 0) {
"has no NS records");
}
if (result != ISC_R_SUCCESS)
goto cleanup;
goto cleanup;
}
goto cleanup;
}
/*
* This is checked in zone_replacedb() for slave zones
* as they don't reload from disk.
*/
0xffffffffU;
"ixfr-from-differences: "
"new serial (%u) out of range "
goto cleanup;
"zone serial has gone backwards");
"zone serial unchanged. "
"zone may fail to transfer "
"to slaves.");
}
isc_time_t t;
if (result != ISC_R_SUCCESS)
&t);
if (result == ISC_R_SUCCESS)
&zone->expiretime);
else
&zone->expiretime);
&zone->expiretime) >= 0)
}
break;
default:
goto cleanup;
}
/*
* Check for weak DNSKEY's.
*/
#if 0
/* destroy notification example. */
{
zone,
sizeof(isc_event_t));
}
#endif
if (result != ISC_R_SUCCESS)
goto cleanup;
} else {
}
if (needdump)
if (! dns_db_ispersistent(db))
return (result);
/* Mark the zone for immediate refresh. */
}
return (result);
}
static isc_boolean_t
{
/*
* DNS_ZONEFLG_SHUTDOWN can only be set if erefs == 0.
*/
return (ISC_TRUE);
}
return (ISC_FALSE);
}
static isc_boolean_t
char namebuf[DNS_NAME_FORMATSIZE];
char altbuf[DNS_NAME_FORMATSIZE];
int level;
return (ISC_TRUE);
else
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
if (result == DNS_R_NXRRSET) {
if (result == ISC_R_SUCCESS)
return (ISC_TRUE);
}
result == DNS_R_EMPTYNAME) {
"NS '%s' has no address records (A or AAAA)",
namebuf);
/* XXX950 Make fatal ISC_FALSE for 9.5.0. */
return (ISC_TRUE);
}
if (result == DNS_R_CNAME) {
namebuf);
/* XXX950 Make fatal ISC_FALSE for 9.5.0. */
return (ISC_TRUE);
}
if (result == DNS_R_DNAME) {
"NS '%s' is below a DNAME '%s' (illegal)",
/* XXX950 Make fatal ISC_FALSE for 9.5.0. */
return (ISC_TRUE);
}
return (ISC_TRUE);
}
static isc_result_t
unsigned int *errors)
{
unsigned int count = 0;
unsigned int ecount = 0;
if (result == ISC_R_NOTFOUND)
goto success;
if (result != ISC_R_SUCCESS)
goto invalidate_rdataset;
while (result == ISC_R_SUCCESS) {
ecount++;
}
count++;
}
return (result);
}
static isc_result_t
unsigned int *soacount,
{
unsigned int count;
if (result == ISC_R_NOTFOUND) {
*soacount = 0;
*serial = 0;
*refresh = 0;
*retry = 0;
*expire = 0;
*minimum = 0;
goto invalidate_rdataset;
}
if (result != ISC_R_SUCCESS)
goto invalidate_rdataset;
count = 0;
while (result == ISC_R_SUCCESS) {
count++;
if (count == 1) {
}
}
if (count > 0) {
}
return (result);
}
/*
* zone must be locked.
*/
static isc_result_t
unsigned int *errors)
{
if (result != ISC_R_SUCCESS) {
goto closeversion;
}
if (result != ISC_R_SUCCESS)
}
minimum);
if (result != ISC_R_SUCCESS)
}
return (answer);
}
void
}
void
unsigned int refs;
if (refs == 0) {
/*
* We just detached the last external reference.
*/
/*
* This zone is being managed. Post
* its control event and let it clean
* up synchronously in the context of
* its task.
*/
} else {
/*
* This zone is not being managed; it has
* no task and can have no outstanding
* events. Free it immediately.
*/
/*
* Unmanaged zones should not have non-null views;
* we have no way of detaching from the view here
* without causing deadlock because this code is called
* with the view already locked.
*/
}
}
if (free_now)
}
void
}
static void
/*
* 'source' locked by caller.
*/
}
static void
/*
* 'zone' locked by caller.
*/
}
void
if (free_needed)
}
}
}
void
if (value)
else
}
void
{
if (value)
else
}
unsigned int
}
return (ISC_R_SUCCESS);
}
return (&zone->xfrsource4);
}
return (ISC_R_SUCCESS);
}
return (&zone->xfrsource6);
}
const isc_sockaddr_t *altxfrsource)
{
return (ISC_R_SUCCESS);
}
return (&zone->altxfrsource4);
}
const isc_sockaddr_t *altxfrsource)
{
return (ISC_R_SUCCESS);
}
return (&zone->altxfrsource6);
}
return (ISC_R_SUCCESS);
}
return (&zone->notifysrc4);
}
return (ISC_R_SUCCESS);
}
return (&zone->notifysrc6);
}
{
}
if (count != 0) {
return (ISC_R_NOMEMORY);
}
}
return (ISC_R_SUCCESS);
}
{
return (result);
}
static isc_boolean_t
{
unsigned int i;
for (i = 0; i < count; i++)
return (ISC_FALSE);
return (ISC_TRUE);
}
static isc_boolean_t
unsigned int i;
return (ISC_TRUE);
return (ISC_FALSE);
for (i = 0; i < count; i++) {
continue;
return (ISC_FALSE);
}
return (ISC_TRUE);
}
const isc_sockaddr_t *masters,
{
unsigned int i;
}
/*
* The refresh code assumes that 'masters' wouldn't change under it.
* If it will change then kill off any current refresh in progress
* and update the masters info. If it won't change then we can just
* unlock and exit.
*/
} else
goto unlock;
}
for (i = 0; i < zone->masterscnt; i++) {
zone->masterkeynames[i],
sizeof(dns_name_t));
}
}
}
}
zone->masterscnt = 0;
/*
* If count == 0, don't allocate any space for masters, mastersok or
* keynames so internally, those pointers are NULL if count == 0
*/
if (count == 0)
goto unlock;
/*
* masters must countain count elements!
*/
goto unlock;
}
/*
* Similarly for mastersok.
*/
goto unlock;
};
for (i = 0; i < count; i++)
/*
* if keynames is non-NULL, it must contain count elements!
*/
goto unlock;
}
for (i = 0; i < count; i++)
for (i = 0; i < count; i++) {
sizeof(dns_name_t));
goto allocfail;
newname[i]);
if (result != ISC_R_SUCCESS) {
for (i = 0; i < count; i++)
newname[i],
goto unlock;
}
}
}
}
/*
* Everything is ok so attach to the zone.
*/
return (result);
}
else
return (result);
}
/*
* Co-ordinates the starting of routine jobs.
*/
void
const char me[] = "dns_zone_maintenance";
}
static inline isc_boolean_t
if (!dumping) {
}
return (dumping);
}
static void
const char me[] = "zone_maintenance";
/*
* Configuring the view of this zone may have
* failed, for example because the config file
* had a syntax error. In that case, the view
* adb or resolver, and we had better not try
* to do maintenance on it.
*/
return;
/*
* Expire check.
*/
case dns_zone_slave:
case dns_zone_stub:
}
break;
default:
break;
}
/*
* Up to date check.
*/
case dns_zone_slave:
case dns_zone_stub:
break;
default:
break;
}
/*
* Do we need to consolidate the backing store?
*/
case dns_zone_master:
case dns_zone_slave:
} else
if (!dumping) {
if (result != ISC_R_SUCCESS)
"dump failed: %s",
}
break;
default:
break;
}
/*
* Do we need to send out notify messages?
*/
case dns_zone_master:
case dns_zone_slave:
break;
default:
break;
}
}
void
}
void
}
static void
/*
* 'zone' locked by caller.
*/
}
void
unsigned int j;
return;
/*
* Set DNS_ZONEFLG_REFRESH so that there is only one refresh operation
* in progress at a time.
*/
if (zone->masterscnt == 0) {
if ((oldflags & DNS_ZONEFLG_NOMASTERS) == 0)
"cannot refresh: no masters");
goto unlock;
}
goto unlock;
/*
* Set the next refresh time as if refresh check has failed.
* Setting this to the retry time will do that. XXXMLG
* If we are successful it will be reset using zone->refresh.
*/
0);
if (result |= ISC_R_SUCCESS)
"isc_time_nowplusinterval() failed: %s",
/*
* When lacking user-specified timer values from the SOA,
* do exponential backoff of the retry time up to a
* maximum of six hours.
*/
for (j = 0; j < zone->masterscnt; j++)
/* initiate soa query */
}
} else
if (!dumping)
return (result);
}
if (!dumping)
return (result);
}
static void
/*
* 'zone' locked by caller
*/
/*
* Do we have a place to dump to and are we loaded?
*/
return;
/* add some noise */
}
static void
const char me[] = "dump_done";
/*
* We don't own these, zone->dctx must stay valid.
*/
if (tresult == ISC_R_SUCCESS) {
zone->journalsize);
switch (tresult) {
case ISC_R_SUCCESS:
case ISC_R_NOSPACE:
case ISC_R_NOTFOUND:
"dns_journal_compact: %s",
break;
default:
"dns_journal_compact failed: %s",
break;
}
}
}
/*
* Try again in a short while.
*/
} else if (result == ISC_R_SUCCESS &&
} else if (result == ISC_R_SUCCESS)
if (again)
}
static isc_result_t
const char me[] = "zone_dump";
char *masterfile = NULL;
/*
* 'compact' MUST only be set if we are task locked.
*/
redo:
}
goto fail;
}
if (masterfile == NULL) {
goto fail;
}
if (compact) {
if (result != ISC_R_SUCCESS)
else
} else {
}
fail:
dns_db_detach(&db);
if (masterfile != NULL)
masterfile = NULL;
if (result == DNS_R_CONTINUE)
return (ISC_R_SUCCESS); /* XXXMPA */
if (result != ISC_R_SUCCESS) {
/*
* Try again in a short while.
*/
} else
if (again)
goto redo;
return (result);
}
static isc_result_t
{
return (DNS_R_NOTLOADED);
dns_db_detach(&db);
return (result);
}
const dns_master_style_t *style) {
}
}
}
void
}
static void
/*
* 'zone' locked by caller.
*/
}
}
static void
/*
* 'zone' locked by caller.
*/
}
void
}
void
}
void
}
void
}
static isc_boolean_t
continue;
return (ISC_TRUE);
return (ISC_TRUE);
}
return (ISC_FALSE);
}
static isc_boolean_t
return (ISC_FALSE);
switch (isc_sockaddr_pf(dst)) {
case PF_INET:
break;
case PF_INET6:
break;
default:
return (ISC_FALSE);
}
/*
* When sending from any the kernel will assign a source address
* that matches the destination address.
*/
return (isself);
}
static void
/*
* Caller holds zone lock.
*/
if (!locked)
if (!locked)
if (locked)
else
}
}
static isc_result_t
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
/*
* XXXAG should check for DNS_ZONEFLG_EXITING
*/
static void
isc_event_free(&ev);
if (result == DNS_EVENT_ADBMOREADDRESSES) {
return;
}
if (result == DNS_EVENT_ADBNOMOREADDRESSES) {
}
}
static void
unsigned int options;
goto destroy;
/* Something failed? */
if (result != ISC_R_SUCCESS)
goto destroy;
/* More addresses pending? */
return;
/* We have as many addresses as we can get. */
}
static isc_result_t
isc_event_t *e;
notify, sizeof(isc_event_t));
if (e == NULL)
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS)
isc_event_free(&e);
return (result);
}
static void
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
int timeout;
goto cleanup;
}
goto cleanup;
}
/*
* The raw IPv4 address should also exist. Don't send to the
* mapped form.
*/
"notify: ignoring IPv6 mapped IPV4 address: %s",
addrbuf);
goto cleanup;
}
if (result != ISC_R_SUCCESS)
goto cleanup;
addrbuf);
if (result == ISC_R_SUCCESS) {
if (result == ISC_R_SUCCESS)
}
}
case PF_INET:
if (!have_notifysource)
break;
case PF_INET6:
if (!have_notifysource)
break;
default:
goto cleanup_key;
}
timeout = 15;
timeout = 30;
if (result != ISC_R_SUCCESS)
}
static void
/*
* Zone lock held by caller.
*/
continue;
continue;
&new);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
}
}
void
}
static void
unsigned int i;
unsigned int flags = 0;
return;
if (notifytype == dns_notifytype_no)
return;
if (notifytype == dns_notifytype_masteronly &&
return;
/*
* If the zone is dialup we are done as we don't want to send
* the current soa so as to force a refresh query.
*/
/*
* Get SOA RRset.
*/
return;
if (result != ISC_R_SUCCESS)
goto cleanup1;
if (result != ISC_R_SUCCESS)
goto cleanup2;
/*
* Find serial and master server's name.
*/
if (result != ISC_R_SUCCESS)
goto cleanup3;
if (result != ISC_R_SUCCESS)
goto cleanup3;
/*
* Enqueue notify requests for 'also-notify' servers.
*/
continue;
if (result != ISC_R_SUCCESS)
continue;
if (result != ISC_R_SUCCESS)
if (!loggednotify) {
"sending notifies (serial %u)",
serial);
}
}
if (notifytype == dns_notifytype_explicit)
goto cleanup3;
/*
* Process NS RRset to generate notifies.
*/
if (result != ISC_R_SUCCESS)
goto cleanup3;
while (result == ISC_R_SUCCESS) {
/*
* don't notify the master server.
*/
continue;
}
if (!loggednotify) {
"sending notifies (serial %u)",
serial);
}
if (isqueued) {
continue;
}
if (result != ISC_R_SUCCESS)
continue;
if (result != ISC_R_SUCCESS) {
continue;
}
}
if (dns_name_dynamic(&master))
}
/***
*** Private
***/
static inline isc_result_t
{
/*
* Extract NS RRset from message.
*/
NULL, &nsrdataset);
if (result != ISC_R_SUCCESS)
goto fail;
/*
* Add NS rdataset.
*/
if (result != ISC_R_SUCCESS)
goto fail;
nsrdataset, 0, NULL);
if (result != ISC_R_SUCCESS)
goto fail;
/*
* Add glue rdatasets.
*/
result == ISC_R_SUCCESS;
continue;
&rdataset);
if (result == ISC_R_SUCCESS) {
if (result != ISC_R_SUCCESS)
goto fail;
if (result != ISC_R_SUCCESS)
goto fail;
}
&rdataset);
if (result == ISC_R_SUCCESS) {
if (result != ISC_R_SUCCESS)
goto fail;
if (result != ISC_R_SUCCESS)
goto fail;
}
}
if (result != ISC_R_NOMORE)
goto fail;
return (ISC_R_SUCCESS);
fail:
return (result);
}
static void
const char me[] = "stub_callback";
char master[ISC_SOCKADDR_FORMATSIZE];
char source[ISC_SOCKADDR_FORMATSIZE];
unsigned int j;
goto next_master;
}
"refreshing stub: timeout retrying "
" without EDNS master %s (source %s)",
goto same_master;
}
"could not refresh stub from master %s"
goto next_master;
}
if (result != ISC_R_SUCCESS)
goto next_master;
if (result != ISC_R_SUCCESS)
goto next_master;
/*
* Unexpected rcode.
*/
char rcode[128];
"refreshing stub: rcode (%.*s) retrying "
"without EDNS master %s (source %s)",
goto same_master;
}
"refreshing stub: "
"unexpected rcode (%.*s) from %s (source %s)",
goto next_master;
}
/*
* We need complete messages.
*/
"refreshing stub: truncated TCP "
"response from master %s (source %s)",
goto next_master;
}
goto same_master;
}
/*
* If non-auth log and next master.
*/
"non-authoritative answer from "
goto next_master;
}
/*
* Sanity checks.
*/
if (cnamecnt != 0) {
"refreshing stub: unexpected CNAME response "
goto next_master;
}
if (nscnt == 0) {
"refreshing stub: no NS records in response "
goto next_master;
}
/*
* Save answer.
*/
if (result != ISC_R_SUCCESS) {
"refreshing stub: unable to save NS records "
goto next_master;
}
/*
* Tidy up.
*/
}
goto free_stub;
/*
* Skip to next failed / untried master.
*/
do {
if (!exiting &&
/*
* Did we get a good answer from all the masters?
*/
for (j = 0; j < zone->masterscnt; j++)
break;
}
} else
if (!done) {
/*
* Find the next failed master.
*/
} else {
goto free_stub;
}
}
goto free_stub;
goto done;
done:
return;
}
/*
* An SOA query has finished (successfully or not).
*/
static void
const char me[] = "refresh_callback";
char master[ISC_SOCKADDR_FORMATSIZE];
char source[ISC_SOCKADDR_FORMATSIZE];
unsigned int j;
/*
* if timeout log and next master;
*/
"refresh: timeout retrying without EDNS "
goto same_master;
}
"refresh: retry limit for "
"master %s exceeded (source %s)",
/* Try with slave with TCP. */
&zone->masteraddr,
&zone->sourceaddr,
&now)) {
goto tcp_transfer;
}
"refresh: skipped tcp fallback"
"as master %s (source %s) is "
"unreachable (cached)",
}
} else
"refresh: failure trying master "
goto next_master;
}
if (result != ISC_R_SUCCESS)
goto next_master;
if (result != ISC_R_SUCCESS) {
"refresh: failure trying master "
goto next_master;
}
/*
* Unexpected rcode.
*/
char rcode[128];
"refresh: rcode (%.*s) retrying without "
"EDNS master %s (source %s)",
goto same_master;
}
"refresh: unexpected rcode (%.*s) from "
/*
*/
goto tcp_transfer;
goto next_master;
}
/*
* If truncated punt to zone transfer which will query again.
*/
"refresh: truncated UDP answer, "
"initiating TCP zone xfer "
"for master %s (source %s)",
goto tcp_transfer;
} else {
"refresh: truncated TCP response "
"from master %s (source %s)",
goto next_master;
}
goto same_master;
}
}
/*
* if non-auth log and next master;
*/
"refresh: non-authoritative answer from "
goto next_master;
}
/*
* There should not be a CNAME record at top of zone.
*/
if (cnamecnt != 0) {
"refresh: CNAME at top of zone "
goto next_master;
}
/*
* if referral log and next master;
*/
"refresh: referral response "
goto next_master;
}
/*
* if nodata log and next master;
*/
"refresh: NODATA response "
goto next_master;
}
/*
* Only one soa at top of zone.
*/
if (soacnt != 1) {
"refresh: answer SOA count (%d) != 1 "
"from master %s (source %s)",
goto next_master;
}
/*
* Extract serial
*/
if (result != ISC_R_SUCCESS) {
"refresh: unable to get SOA record "
goto next_master;
}
if (result != ISC_R_SUCCESS) {
"refresh: dns_rdataset_first() failed");
goto next_master;
}
"refresh: skipping %s as master %s "
"(source %s) is unreachable (cached)",
"zone transfer" : "NS query",
goto next_master;
}
} else {
}
if (result == ISC_R_SUCCESS &&
&now);
} else if (result != ISC_R_SUCCESS)
&now);
/* Someone removed the file from underneath us! */
if (result == ISC_R_FILENOTFOUND) {
} else if (result != ISC_R_SUCCESS)
"refresh: could not set file "
"modification time of '%s': %s",
}
goto next_master;
} else {
"received from master %s < ours (%u)",
else
goto next_master;
}
goto detach;
/*
* Skip to next failed / untried master.
*/
do {
/*
* Did we get a good answer from all the masters?
*/
for (j = 0; j < zone->masterscnt; j++)
break;
}
} else
if (!done) {
/*
* Find the next failed master.
*/
goto requeue;
}
}
goto detach;
}
goto detach;
return;
}
static void
const char me[] = "queue_soa_query";
isc_event_t *e;
/*
* Locked by caller
*/
return;
}
if (e == NULL) {
return;
}
/*
* Attach so that we won't clean up
* until the event is delivered.
*/
if (result != ISC_R_SUCCESS) {
isc_event_free(&e);
}
}
static inline isc_result_t
{
&message);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* Make question.
*/
return (ISC_R_SUCCESS);
return (result);
}
static isc_result_t
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* Set Maximum UDP buffer size.
*/
/*
* Set EXTENDED-RCODE, VERSION, DO and Z to 0.
*/
/*
* No EDNS options.
*/
== ISC_R_SUCCESS);
return (result);
}
static void
const char me[] = "soa_query";
int timeout;
goto cleanup;
}
/*
* XXX Optimisation: Create message when zone is setup and reuse.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* First, look for a tsig key in the master statement, then
* try for a server key.
*/
if (result != ISC_R_SUCCESS) {
char namebuf[DNS_NAME_FORMATSIZE];
"unable to find key: %s", namebuf);
}
}
if (result == ISC_R_SUCCESS) {
&zone->sourceaddr);
if (result == ISC_R_SUCCESS)
udpsize =
}
}
case PF_INET:
&zone->xfrsource4))
goto skip_master;
} else if (!have_xfrsource)
break;
case PF_INET6:
&zone->xfrsource6))
goto skip_master;
} else if (!have_xfrsource)
break;
default:
goto cleanup;
}
DNS_REQUESTOPT_TCP : 0;
if (result != ISC_R_SUCCESS)
"unable to add opt record: %s",
}
timeout = 15;
timeout = 30;
if (result != ISC_R_SUCCESS) {
"dns_request_createvia2() failed: %s",
goto cleanup;
}
if (result != ISC_R_SUCCESS)
if (cancel)
return;
/*
* Skip to next failed / untried master.
*/
do {
goto again;
goto cleanup;
}
static void
const char me[] = "ns_query";
int timeout;
goto cleanup;
/*
* Attach so that the zone won't disappear from under us.
*/
/*
* If a db exists we will update it, otherwise we create a
* new one and attach it to the zone once we have the NS
* RRset and glue.
*/
} else {
if (result != ISC_R_SUCCESS) {
"refreshing stub: "
"could not create "
"database: %s",
goto cleanup;
}
}
/*
* Update SOA record.
*/
&node);
if (result != ISC_R_SUCCESS) {
"refreshing stub: "
"dns_db_findnode() failed: %s",
goto cleanup;
}
soardataset, 0, NULL);
if (result != ISC_R_SUCCESS) {
"refreshing stub: "
"dns_db_addrdataset() failed: %s",
goto cleanup;
}
}
/*
* XXX Optimisation: Create message when zone is setup and reuse.
*/
/*
* First, look for a tsig key in the master statement, then
* try for a server key.
*/
if (result != ISC_R_SUCCESS) {
char namebuf[DNS_NAME_FORMATSIZE];
"unable to find key: %s", namebuf);
}
}
if (result == ISC_R_SUCCESS) {
&zone->sourceaddr);
if (result == ISC_R_SUCCESS)
udpsize =
}
}
if (result != ISC_R_SUCCESS)
"unable to add opt record: %s",
}
/*
* Always use TCP so that we shouldn't truncate in additional section.
*/
case PF_INET:
else if (!have_xfrsource)
break;
case PF_INET6:
else if (!have_xfrsource)
break;
default:
goto cleanup;
}
timeout = 15;
timeout = 30;
if (result != ISC_R_SUCCESS) {
"dns_request_createvia() failed: %s",
goto cleanup;
}
goto unlock;
}
return;
}
/*
* Handle the control event. Note that although this event causes the zone
* to shut down, it is not a shutdown event in the sense of the task library.
*/
static void
/*
* Stop things being restarted after we cancel them below.
*/
/*
* If we were waiting for xfrin quota, step out of
* the queue.
* If there's no zone manager, we can't be waiting for the
* xfrin quota
*/
}
}
/*
* In task context, no locking required. See zone_xfrdone().
*/
if (linked) {
}
}
}
}
/*
* We have now canceled everything set the flag to allow exit_check()
* to succeed. We must not unlock between setting this flag and
* calling exit_check().
*/
if (free_needed)
}
static void
const char me[] = "zone_timer";
}
static void
const char me[] = "zone_settimer";
return;
case dns_zone_master:
if (isc_time_isepoch(&next) ||
}
break;
case dns_zone_slave:
/*FALLTHROUGH*/
case dns_zone_stub:
if (isc_time_isepoch(&next) ||
}
if (isc_time_isepoch(&next) ||
}
if (isc_time_isepoch(&next) ||
}
break;
default:
break;
}
if (isc_time_isepoch(&next)) {
if (result != ISC_R_SUCCESS)
"could not deactivate zone timer: %s",
} else {
if (result != ISC_R_SUCCESS)
"could not reset zone timer: %s",
}
}
static void
const char me[] = "cancel_refresh";
/*
* 'zone' locked by caller.
*/
}
static isc_result_t
{
isc_region_t r;
isc_buffer_t *b = NULL;
&message);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* Make question.
*/
temprdataset = NULL;
if ((flags & DNS_NOTIFY_NOSOA) != 0)
goto done;
if (result != ISC_R_SUCCESS)
goto soa_cleanup;
if (result != ISC_R_SUCCESS)
goto soa_cleanup;
if (result != ISC_R_SUCCESS)
goto soa_cleanup;
if (result != ISC_R_SUCCESS)
goto soa_cleanup;
if (result != ISC_R_SUCCESS)
goto soa_cleanup;
dns_rdatatype_none, 0, &rdataset,
NULL);
if (result != ISC_R_SUCCESS)
goto soa_cleanup;
if (result != ISC_R_SUCCESS)
goto soa_cleanup;
dns_rdata_toregion(&rdata, &r);
if (result != ISC_R_SUCCESS)
goto soa_cleanup;
isc_buffer_usedregion(b, &r);
if (result != ISC_R_NOMORE)
goto soa_cleanup;
temprdatalist->covers = 0;
if (result != ISC_R_SUCCESS)
goto soa_cleanup;
temprdataset = NULL;
if (temprdataset != NULL)
if (temprdatalist != NULL)
done:
return (ISC_R_SUCCESS);
if (temprdataset != NULL)
return (result);
}
{
unsigned int i;
char fromtext[ISC_SOCKADDR_FORMATSIZE];
int match = 0;
/*
* If type != T_SOA return DNS_R_REFUSED. We don't yet support
* ROLLOVER.
*
* SOA: RFC1996
* Check that 'from' is a valid notify source, (zone->masters).
* Return DNS_R_REFUSED if not.
*
* If the notify message contains a serial number check it
* against the zones serial and return if <= current serial
*
* If a refresh check is progress, if so just record the
* fact we received a NOTIFY and from where and return.
* We will perform a new refresh check when the current one
* completes. Return ISC_R_SUCCESS.
*
* Otherwise initiate a refresh check using 'from' as the
* first address to check. Return ISC_R_SUCCESS.
*/
/*
* We only handle NOTIFY (SOA) at the present.
*/
"NOTIFY with no "
"question section from: %s", fromtext);
return (DNS_R_FORMERR);
}
"NOTIFY zone does not match");
return (DNS_R_NOTIMP);
}
/*
* If we are a master zone just succeed.
*/
return (ISC_R_SUCCESS);
}
for (i = 0; i < zone->masterscnt; i++) {
break;
break;
}
}
/*
* Accept notify requests from non masters if they are on
* 'zone->notify_acl'.
*/
match > 0)
{
/* Accept notify. */
} else if (i >= zone->masterscnt) {
"refused notify from non-master: %s", fromtext);
return (DNS_R_REFUSED);
}
/*
* If the zone is loaded and there are answers check the serial
* to see if we need to do a refresh. Do not worry about this
* check if we are a dialup zone as we use the notify request
* to trigger a refresh check.
*/
&rdataset);
if (result == ISC_R_SUCCESS)
if (result == ISC_R_SUCCESS) {
isc_uint32_t serial = 0;
"notify from %s: "
"zone is up to date",
fromtext);
return (ISC_R_SUCCESS);
}
}
}
/*
* If we got this far and there was a refresh in progress just
* let it complete. Record where we got the notify from so we
* can perform a refresh check when the current one completes
*/
"notify from %s: refresh in progress, "
"refresh check queued",
fromtext);
return (ISC_R_SUCCESS);
}
return (ISC_R_SUCCESS);
}
void
}
void
}
void
}
void
}
void
}
return (zone->notify_acl);
}
}
return (zone->update_acl);
}
return (zone->forward_acl);
}
}
void
}
void
}
void
}
void
}
void
}
return (zone->update_disabled);
}
void
}
return (zone->zero_no_soa_ttl);
}
void
}
void
}
return (zone->check_names);
}
void
}
return (zone->journalsize);
}
static void
/*
* Leave space for terminating '\0'.
*/
if (result != ISC_R_SUCCESS &&
if (isc_buffer_availablelength(&buffer) > 0)
}
}
static void
/*
* Leave space for terminating '\0'.
*/
if (result != ISC_R_SUCCESS &&
}
static void
/*
* Leave space for terminating '\0'.
*/
}
static void
/*
* Leave space for terminating '\0'.
*/
< isc_buffer_availablelength(&buffer)) {
} else {
}
}
void
}
static void
char message[4096];
return;
}
void
char message[4096];
return;
}
void
char message[4096];
return;
}
static void
const char *fmt, ...)
{
char message[4096];
return;
}
static int
{
int count = 0;
while (result == ISC_R_SUCCESS) {
count++;
}
}
return (count);
}
void
}
}
void
}
}
}
}
void
}
void
}
void
if (idlein == 0)
}
}
void
}
}
static void
char rcode[128];
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
if (result == ISC_R_SUCCESS)
if (result == ISC_R_SUCCESS)
if (result == ISC_R_SUCCESS)
if (result == ISC_R_SUCCESS)
"notify response from %s: %.*s",
else
"notify to %s failed: %s", addrbuf,
/*
* Old bind's return formerr if they see a soa record. Retry w/o
* the soa if we see a formerr and had sent a SOA.
*/
if (result != ISC_R_SUCCESS)
} else {
if (result == ISC_R_TIMEDOUT)
"notify to %s: retries exceeded", addrbuf);
}
}
return (result);
}
static isc_result_t
unsigned int soacount = 0;
unsigned int nscount = 0;
/*
* 'zone' and 'zonedb' locked by caller.
*/
if (result == ISC_R_SUCCESS) {
if (soacount != 1) {
"has %d SOA records", soacount);
}
if (nscount == 0) {
}
if (result != ISC_R_SUCCESS)
return (result);
} else {
"retrieving SOA and NS records failed: %s",
return (result);
}
/*
* The initial version of a slave zone is always dumped;
* subsequent versions may be journalled instead if this
* is enabled in the configuration.
*/
if (result != ISC_R_SUCCESS) {
"ixfr-from-differences: unable to get "
"new serial");
goto fail;
}
/*
* This is checked in zone_postload() for master zones.
*/
"ixfr-from-differences: failed: "
"new serial (%u) out of range [%u - %u]",
goto fail;
}
if (result != ISC_R_SUCCESS)
goto fail;
if (dump)
switch (result) {
case ISC_R_SUCCESS:
case ISC_R_NOSPACE:
case ISC_R_NOTFOUND:
"dns_journal_compact: %s",
break;
default:
"dns_journal_compact failed: %s",
break;
}
}
} else {
"dumping new zone version");
zone->masterformat);
if (result != ISC_R_SUCCESS)
goto fail;
/*
* Update the time the zone was updated, so
* dns_zone_load can avoid loading it when
* the server is reloaded. If isc_time_now
* fails for some reason, all that happens is
* the timestamp is not updated.
*/
}
/*
* The in-memory database just changed, and
* because 'dump' is set, it didn't change by
* being loaded from disk. Also, we have not
* journalled diffs for this change.
* Therefore, the on-disk journal is missing
* the deltas for this change. Since it can
* no longer be used to bring the zone
* up-to-date, it is useless and should be
* removed.
*/
"removing journal file");
}
}
"replacing zone database");
return (ISC_R_SUCCESS);
fail:
return (result);
}
/* The caller must hold the dblock as a writer. */
static inline void
"dns_acache_setdb() failed: %s",
}
}
}
/* The caller must hold the dblock as a writer. */
static inline void
}
static void
unsigned int soacount;
unsigned int nscount;
switch (result) {
case ISC_R_SUCCESS:
/*FALLTHROUGH*/
case DNS_R_UPTODATE:
/*
* Has the zone expired underneath us?
*/
goto same_master;
}
/*
* Update the zone structure's data from the actual
* SOA received.
*/
nscount = 0;
soacount = 0;
if (result == ISC_R_SUCCESS) {
if (soacount != 1)
"transferred zone "
"has %d SOA record%s", soacount,
if (nscount == 0) {
"transferred zone "
"has no NS records");
if (DNS_ZONE_FLAG(zone,
}
goto next_master;
}
zone->maxrefresh);
}
/*
*/
&zone->expiretime);
} else {
&zone->refreshtime);
&zone->expiretime);
}
char namebuf[DNS_NAME_FORMATSIZE];
sizeof(namebuf));
namebuf);
} else
buf[0] = '\0';
"transferred serial %u%s",
}
/*
* This is not neccessary if we just performed a AXFR
* however it is necessary for an IXFR / UPTODATE and
* won't hurt with an AXFR.
*/
if (result != ISC_R_SUCCESS &&
&now);
/* Someone removed the file from underneath us! */
if (result == ISC_R_FILENOTFOUND &&
else if (result != ISC_R_SUCCESS)
"transfer: could not set file "
"modification time of '%s': %s",
}
break;
case DNS_R_BADIXFR:
/* Force retry with AXFR. */
goto same_master;
default:
/*
* Skip to next failed / untried master.
*/
do {
/* FALLTHROUGH */
} else
} else {
}
break;
}
/*
* If creating the transfer object failed, zone->xfr is NULL.
* Otherwise, we are called as the done callback of a zone
* transfer object that just entered its shutting-down
* state. Since we are no longer responsible for shutting
* it down, we can detach our reference.
*/
/*
* This transfer finishing freed up a transfer quota slot.
* Let any other zones waiting for quota have it.
*/
/*
* Retry with a different server if necessary.
*/
if (free_needed)
}
static void
static char me[] = "zone_loaddone";
if (tresult != ISC_R_SUCCESS &&
}
void
}
void
}
void
}
return (zone->sigvalidityinterval);
}
static void
const char me[] = "queue_xfrin";
if (result == ISC_R_QUOTA) {
"zone transfer deferred due to quota");
} else if (result != ISC_R_SUCCESS) {
"starting zone transfer: %s",
}
}
/*
* This event callback is called when a zone has received
* any necessary zone transfer quota. This is the time
* to go ahead and start the transfer.
*/
static void
char master[ISC_SOCKADDR_FORMATSIZE];
char source[ISC_SOCKADDR_FORMATSIZE];
goto cleanup;
}
"got_transfer_quota: skipping zone transfer as "
"master %s (source %s) is unreachable (cached)",
goto cleanup;
}
/*
* Decide whether we should request IXFR or AXFR.
*/
"no database exists yet, requesting AXFR of "
"initial version from %s", master);
"set, requesting AXFR from %s", master);
"forced reload, requesting AXFR of "
"initial version from %s", master);
"retrying with AXFR from %s due to "
"previous IXFR failure", master);
} else {
; /* Using peer setting */
} else {
}
"IXFR disabled, requesting AXFR from %s",
master);
else
} else {
"requesting IXFR from %s", master);
}
}
/*
* Determine if we should attempt to sign the request with TSIG.
*/
/*
* First, look for a tsig key in the master statement, then
* try for a server key.
*/
}
"could not get TSIG key for zone transfer: %s",
}
/*
* Any failure in this function is handled like a failed
* zone transfer. This ensures that we get removed from
* zmgr->xfrin_in_progress.
*/
if (result != ISC_R_SUCCESS)
}
/*
* Update forwarding support.
*/
static void
}
static isc_result_t
return (ISC_R_NOMORE);
}
/*
* Always use TCP regardless of whether the original update
* used TCP.
* XXX The timeout may but a bit small if we are far down a
* transfer graph and the master has to try several masters.
*/
case PF_INET:
break;
case PF_INET6:
break;
default:
goto unlock;
}
return (result);
}
static void
const char me[] = "forward_callback";
char master[ISC_SOCKADDR_FORMATSIZE];
"could not forward dynamic update to %s: %s",
goto next_master;
}
if (result != ISC_R_SUCCESS)
goto next_master;
if (result != ISC_R_SUCCESS)
goto next_master;
/*
* Pass these rcodes back to client.
*/
case dns_rcode_noerror:
case dns_rcode_yxdomain:
case dns_rcode_yxrrset:
case dns_rcode_nxrrset:
case dns_rcode_refused:
case dns_rcode_nxdomain:
break;
case dns_rcode_notzone:
case dns_rcode_notauth: {
char rcode[128];
"forwarding dynamic update: "
"unexpected response: master %s returned: %.*s",
goto next_master;
}
/* Try another server for these rcodes. */
case dns_rcode_formerr:
case dns_rcode_servfail:
case dns_rcode_notimp:
case dns_rcode_badvers:
default:
goto next_master;
}
/* call callback */
return;
if (result != ISC_R_SUCCESS) {
/* call callback */
"exhausted dynamic update forwarder list");
}
}
{
return (ISC_R_NOMEMORY);
goto cleanup;
}
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS) {
}
return (result);
}
return (ISC_R_NOMORE);
else
return (ISC_R_SUCCESS);
}
return (ISC_R_NOMORE);
else
return (ISC_R_SUCCESS);
}
/***
*** Zone manager.
***/
{
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS)
goto free_mem;
/* Create the zone task pool. */
if (result != ISC_R_SUCCESS)
goto free_rwlock;
/* Create a single task for queueing of SOA queries. */
if (result != ISC_R_SUCCESS)
goto free_taskpool;
if (result != ISC_R_SUCCESS)
goto free_task;
/* default to 20 refresh queries / notifies per second. */
if (result != ISC_R_SUCCESS)
goto free_rl;
return (ISC_R_SUCCESS);
#if 0
#endif
return (result);
}
/*
* Set the task name. The tag will arbitrarily point to one
* of the zones sharing the task (in practice, the one
* to be managed last).
*/
if (result != ISC_R_SUCCESS)
goto cleanup_task;
/*
* The timer "holds" a iref.
*/
goto unlock;
return (result);
}
void
if (free_now)
}
void
}
void
if (free_now)
}
dns_zone_t *p;
p != NULL;
p = ISC_LIST_NEXT(p, link))
{
}
/*
* Recent configuration changes may have increased the
* amount of available transfers quota. Make sure any
* transfers currently blocked on quota get started if
* possible.
*/
return (ISC_R_SUCCESS);
}
void
}
void
}
static void
}
void
}
return (zmgr->transfersin);
}
void
}
return (zmgr->transfersperns);
}
/*
* Try to start a new incoming zone transfer to fill a quota
* slot that was just vacated.
*
* Requires:
* The zone manager is locked by the caller.
*/
static void
{
if (result == ISC_R_SUCCESS) {
if (multi)
continue;
/*
* We successfully filled the slot. We're done.
*/
break;
} else if (result == ISC_R_QUOTA) {
/*
* Not enough quota. This is probably the per-server
* quota, because we usually get called when a unit of
* global quota has just been freed. Try the next
* zone, it may succeed if it uses another master.
*/
continue;
} else {
"starting zone transfer: %s",
break;
}
}
}
/*
* Try to start an incoming zone transfer for 'zone', quota permitting.
*
* Requires:
* The zone manager is locked by the caller.
*
* Returns:
* ISC_R_SUCCESS There was enough quota and we attempted to
* start a transfer. zone_xfrdone() has been or will
* be called.
* ISC_R_QUOTA Not enough quota.
* Others Failure.
*/
static isc_result_t
dns_zone_t *x;
isc_event_t *e;
/*
* Find any configured information about the server we'd
* like to transfer this zone from.
*/
/*
* Determine the total maximum number of simultaneous
* transfers allowed, and the maximum for this specific
* master.
*/
/*
* Count the total number of transfers that are in progress,
* and the number of transfers in progress from this master.
* We linearly scan a list of all transfers; if this turns
* out to be too slow, we could hash on the master address.
*/
nxfrsin = nxfrsperns = 0;
x != NULL;
x = ISC_LIST_NEXT(x, statelink))
{
nxfrsin++;
nxfrsperns++;
}
/* Enforce quota. */
if (nxfrsin >= maxtransfersin)
return (ISC_R_QUOTA);
if (nxfrsperns >= maxtransfersperns)
return (ISC_R_QUOTA);
/*
* We have sufficient quota. Move the zone to the "xfrin_in_progress"
* list and send it an event to let it start the actual transfer in the
* context of its own task.
*/
sizeof(isc_event_t));
if (e == NULL)
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
void
}
}
/*
* Get permission to request a file handle from the OS.
* An event will be sent to action when one is available.
* There are two queues available (high and low), the high
* queue will be serviced before the low one.
*
* zonemgr_putio() must be called after the event is delivered to
* 'action'.
*/
static isc_result_t
{
return (ISC_R_NOMEMORY);
return (ISC_R_NOMEMORY);
}
if (queue) {
else
}
if (!queue) {
}
return (ISC_R_SUCCESS);
}
static void
else
}
}
static void
/*
* If we are queued to be run then dequeue.
*/
else
}
if (send_event) {
}
}
static void
char *buf;
int buflen;
return;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
}
#if 0
/* Hook for ondestroy notifcation from a database. */
static void
"database (%p) destroyed", (void*) db);
}
#endif
void
isc_uint32_t s, ns;
if (value == 0)
value = 1;
if (value == 1) {
s = 1;
ns = 0;
pertic = 1;
} else if (value <= 10) {
s = 0;
pertic = 1;
} else {
s = 0;
pertic = 10;
}
}
unsigned int
return (zmgr->serialqueryrate);
}
static isc_boolean_t
{
unsigned int i;
for (i = 0; i < UNREACH_CHACHE_SIZE; i++) {
if (result == ISC_R_SUCCESS) {
}
break;
}
}
return (ISC_TF(i < UNREACH_CHACHE_SIZE));
}
void
{
for (i = 0; i < UNREACH_CHACHE_SIZE; i++) {
/* Existing entry? */
break;
/* Empty slot? */
slot = i;
/* Least recently used slot? */
oldest = i;
}
}
if (i < UNREACH_CHACHE_SIZE) {
/*
* Found a existing entry. Update the expire timer and
* last usage timestamps.
*/
} else if (slot != UNREACH_CHACHE_SIZE) {
/*
* Found a empty slot. Add a new entry to the cache.
*/
} else {
/*
* Replace the least recently used entry in the cache.
*/
}
}
void
return;
}
}
if (on) {
goto done;
} else {
goto done;
}
done:
return (result);
}
}
void
"notify = %d, refresh = %d",
}
void
switch (dialup) {
case dns_dialuptype_no:
break;
case dns_dialuptype_yes:
break;
case dns_dialuptype_notify:
break;
break;
case dns_dialuptype_refresh:
break;
case dns_dialuptype_passive:
break;
default:
INSIST(0);
}
}
return (result);
}
const char *
return (zone->keydirectory);
}
unsigned int
unsigned int count = 0;
switch (state) {
count++;
break;
count++;
break;
case DNS_ZONESTATE_SOAQUERY:
count++;
break;
case DNS_ZONESTATE_ANY:
continue;
count++;
}
break;
default:
INSIST(0);
}
return (count);
}
char namebuf[DNS_NAME_FORMATSIZE];
char namebuf2[DNS_NAME_FORMATSIZE];
char typebuf[DNS_RDATATYPE_FORMATSIZE];
int level = ISC_LOG_WARNING;
return (ISC_R_SUCCESS);
}
if (!ok) {
if (fail)
return (DNS_R_BADOWNERNAME);
}
if (!ok) {
if (fail)
return (DNS_R_BADNAME);
}
return (ISC_R_SUCCESS);
}
void
}
void
}
void
}
void
}
void
}
return (zone->notifydelay);
}
#ifdef HAVE_LIBXML2
{
int i;
/* XXXMLG render config data here */
if ((flags & ISC_XML_RENDERSTATS) != 0) {
for (i = 0 ; i < DNS_STATS_NCOUNTERS ; i++) {
}
}
}
return (ISC_R_SUCCESS);
}
#endif /* HAVE_LIBXML2 */