/contrib/bind9/lib/dns/zone.c
https://bitbucket.org/freebsd/freebsd-head/ · C · 14592 lines · 11254 code · 1786 blank · 1552 comment · 3275 complexity · d13f256320707749935465f4f1a2a4ac MD5 · raw file
Large files are truncated click here to view the full file
- /*
- * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC")
- * Copyright (C) 1999-2003 Internet Software Consortium.
- *
- * Permission to use, copy, modify, and/or 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$ */
- /*! \file */
- #include <config.h>
- #include <errno.h>
- #include <isc/file.h>
- #include <isc/mutex.h>
- #include <isc/print.h>
- #include <isc/random.h>
- #include <isc/ratelimiter.h>
- #include <isc/refcount.h>
- #include <isc/rwlock.h>
- #include <isc/serial.h>
- #include <isc/strerror.h>
- #include <isc/stats.h>
- #include <isc/stdtime.h>
- #include <isc/string.h>
- #include <isc/taskpool.h>
- #include <isc/timer.h>
- #include <isc/util.h>
- #include <dns/acache.h>
- #include <dns/acl.h>
- #include <dns/adb.h>
- #include <dns/callbacks.h>
- #include <dns/db.h>
- #include <dns/dbiterator.h>
- #include <dns/dnssec.h>
- #include <dns/events.h>
- #include <dns/journal.h>
- #include <dns/keydata.h>
- #include <dns/keytable.h>
- #include <dns/keyvalues.h>
- #include <dns/log.h>
- #include <dns/master.h>
- #include <dns/masterdump.h>
- #include <dns/message.h>
- #include <dns/name.h>
- #include <dns/nsec.h>
- #include <dns/nsec3.h>
- #include <dns/peer.h>
- #include <dns/private.h>
- #include <dns/rbt.h>
- #include <dns/rcode.h>
- #include <dns/rdataclass.h>
- #include <dns/rdatalist.h>
- #include <dns/rdataset.h>
- #include <dns/rdatasetiter.h>
- #include <dns/rdatastruct.h>
- #include <dns/rdatatype.h>
- #include <dns/request.h>
- #include <dns/resolver.h>
- #include <dns/result.h>
- #include <dns/rriterator.h>
- #include <dns/soa.h>
- #include <dns/ssu.h>
- #include <dns/stats.h>
- #include <dns/time.h>
- #include <dns/tsig.h>
- #include <dns/xfrin.h>
- #include <dns/zone.h>
- #include <dst/dst.h>
- #define ZONE_MAGIC ISC_MAGIC('Z', 'O', 'N', 'E')
- #define DNS_ZONE_VALID(zone) ISC_MAGIC_VALID(zone, ZONE_MAGIC)
- #define NOTIFY_MAGIC ISC_MAGIC('N', 't', 'f', 'y')
- #define DNS_NOTIFY_VALID(notify) ISC_MAGIC_VALID(notify, NOTIFY_MAGIC)
- #define STUB_MAGIC ISC_MAGIC('S', 't', 'u', 'b')
- #define DNS_STUB_VALID(stub) ISC_MAGIC_VALID(stub, STUB_MAGIC)
- #define ZONEMGR_MAGIC ISC_MAGIC('Z', 'm', 'g', 'r')
- #define DNS_ZONEMGR_VALID(stub) ISC_MAGIC_VALID(stub, ZONEMGR_MAGIC)
- #define LOAD_MAGIC ISC_MAGIC('L', 'o', 'a', 'd')
- #define DNS_LOAD_VALID(load) ISC_MAGIC_VALID(load, LOAD_MAGIC)
- #define FORWARD_MAGIC ISC_MAGIC('F', 'o', 'r', 'w')
- #define DNS_FORWARD_VALID(load) ISC_MAGIC_VALID(load, FORWARD_MAGIC)
- #define IO_MAGIC ISC_MAGIC('Z', 'm', 'I', 'O')
- #define DNS_IO_VALID(load) ISC_MAGIC_VALID(load, IO_MAGIC)
- /*%
- * Ensure 'a' is at least 'min' but not more than 'max'.
- */
- #define RANGE(a, min, max) \
- (((a) < (min)) ? (min) : ((a) < (max) ? (a) : (max)))
- #define NSEC3REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0)
- /*%
- * Key flags
- */
- #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
- #define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
- #define ALG(x) dst_key_alg(x)
- /*
- * Default values.
- */
- #define DNS_DEFAULT_IDLEIN 3600 /*%< 1 hour */
- #define DNS_DEFAULT_IDLEOUT 3600 /*%< 1 hour */
- #define MAX_XFER_TIME (2*3600) /*%< Documented default is 2 hours */
- #define RESIGN_DELAY 3600 /*%< 1 hour */
- #ifndef DNS_MAX_EXPIRE
- #define DNS_MAX_EXPIRE 14515200 /*%< 24 weeks */
- #endif
- #ifndef DNS_DUMP_DELAY
- #define DNS_DUMP_DELAY 900 /*%< 15 minutes */
- #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;
- typedef ISC_LIST(dns_forward_t) dns_forwardlist_t;
- typedef struct dns_io dns_io_t;
- typedef ISC_LIST(dns_io_t) dns_iolist_t;
- typedef struct dns_signing dns_signing_t;
- typedef ISC_LIST(dns_signing_t) dns_signinglist_t;
- typedef struct dns_nsec3chain dns_nsec3chain_t;
- typedef ISC_LIST(dns_nsec3chain_t) dns_nsec3chainlist_t;
- typedef struct dns_keyfetch dns_keyfetch_t;
- #define DNS_ZONE_CHECKLOCK
- #ifdef DNS_ZONE_CHECKLOCK
- #define LOCK_ZONE(z) \
- do { LOCK(&(z)->lock); \
- INSIST((z)->locked == ISC_FALSE); \
- (z)->locked = ISC_TRUE; \
- } while (0)
- #define UNLOCK_ZONE(z) \
- do { (z)->locked = ISC_FALSE; UNLOCK(&(z)->lock); } while (0)
- #define LOCKED_ZONE(z) ((z)->locked)
- #else
- #define LOCK_ZONE(z) LOCK(&(z)->lock)
- #define UNLOCK_ZONE(z) UNLOCK(&(z)->lock)
- #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;
- isc_mutex_t lock;
- #ifdef DNS_ZONE_CHECKLOCK
- isc_boolean_t locked;
- #endif
- isc_mem_t *mctx;
- isc_refcount_t erefs;
- #ifdef ISC_RWLOCK_USEATOMIC
- isc_rwlock_t dblock;
- #else
- isc_mutex_t dblock;
- #endif
- dns_db_t *db; /* Locked by dblock */
- /* Locked */
- dns_zonemgr_t *zmgr;
- ISC_LINK(dns_zone_t) link; /* Used by zmgr. */
- isc_timer_t *timer;
- unsigned int irefs;
- dns_name_t origin;
- char *masterfile;
- dns_masterformat_t masterformat;
- char *journal;
- isc_int32_t journalsize;
- dns_rdataclass_t rdclass;
- dns_zonetype_t type;
- unsigned int flags;
- unsigned int options;
- unsigned int db_argc;
- char **db_argv;
- isc_time_t expiretime;
- isc_time_t refreshtime;
- isc_time_t dumptime;
- isc_time_t loadtime;
- isc_time_t notifytime;
- isc_time_t resigntime;
- isc_time_t keywarntime;
- isc_time_t signingtime;
- isc_time_t nsec3chaintime;
- isc_time_t refreshkeytime;
- isc_uint32_t refreshkeycount;
- isc_uint32_t refresh;
- isc_uint32_t retry;
- isc_uint32_t expire;
- isc_uint32_t minimum;
- isc_stdtime_t key_expiry;
- isc_stdtime_t log_key_expired_timer;
- char *keydirectory;
- isc_uint32_t maxrefresh;
- isc_uint32_t minrefresh;
- isc_uint32_t maxretry;
- isc_uint32_t minretry;
- isc_sockaddr_t *masters;
- dns_name_t **masterkeynames;
- isc_boolean_t *mastersok;
- unsigned int masterscnt;
- unsigned int curmaster;
- isc_sockaddr_t masteraddr;
- dns_notifytype_t notifytype;
- isc_sockaddr_t *notify;
- unsigned int notifycnt;
- isc_sockaddr_t notifyfrom;
- isc_task_t *task;
- isc_sockaddr_t notifysrc4;
- isc_sockaddr_t notifysrc6;
- isc_sockaddr_t xfrsource4;
- isc_sockaddr_t xfrsource6;
- isc_sockaddr_t altxfrsource4;
- isc_sockaddr_t altxfrsource6;
- isc_sockaddr_t sourceaddr;
- dns_xfrin_ctx_t *xfr; /* task locked */
- dns_tsigkey_t *tsigkey; /* key used for xfr */
- /* Access Control Lists */
- dns_acl_t *update_acl;
- dns_acl_t *forward_acl;
- dns_acl_t *notify_acl;
- dns_acl_t *query_acl;
- dns_acl_t *queryon_acl;
- dns_acl_t *xfr_acl;
- isc_boolean_t update_disabled;
- isc_boolean_t zero_no_soa_ttl;
- dns_severity_t check_names;
- ISC_LIST(dns_notify_t) notifies;
- dns_request_t *request;
- dns_loadctx_t *lctx;
- dns_io_t *readio;
- dns_dumpctx_t *dctx;
- dns_io_t *writeio;
- isc_uint32_t maxxfrin;
- isc_uint32_t maxxfrout;
- isc_uint32_t idlein;
- isc_uint32_t idleout;
- isc_event_t ctlevent;
- dns_ssutable_t *ssutable;
- isc_uint32_t sigvalidityinterval;
- isc_uint32_t sigresigninginterval;
- dns_view_t *view;
- dns_acache_t *acache;
- dns_checkmxfunc_t checkmx;
- dns_checksrvfunc_t checksrv;
- dns_checknsfunc_t checkns;
- /*%
- * 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.
- */
- ISC_LINK(dns_zone_t) statelink;
- dns_zonelist_t *statelist;
- /*%
- * Statistics counters about zone management.
- */
- isc_stats_t *stats;
- /*%
- * Optional per-zone statistics counters. Counted outside of this
- * module.
- */
- isc_boolean_t requeststats_on;
- isc_stats_t *requeststats;
- isc_uint32_t notifydelay;
- dns_isselffunc_t isself;
- void *isselfarg;
- char * strnamerd;
- char * strname;
- char * strrdclass;
- char * strviewname;
- /*%
- * Serial number for deferred journal compaction.
- */
- isc_uint32_t compact_serial;
- /*%
- * Keys that are signing the zone for the first time.
- */
- dns_signinglist_t signing;
- dns_nsec3chainlist_t nsec3chain;
- /*%
- * Signing / re-signing quantum stopping parameters.
- */
- isc_uint32_t signatures;
- isc_uint32_t nodes;
- dns_rdatatype_t privatetype;
- /*%
- * Autosigning/key-maintenance options
- */
- isc_uint32_t keyopts;
- /*%
- * True if added by "rndc addzone"
- */
- isc_boolean_t added;
- /*%
- * whether a rpz radix was needed when last loaded
- */
- isc_boolean_t rpz_zone;
- /*%
- * Outstanding forwarded UPDATE requests.
- */
- dns_forwardlist_t forwards;
- };
- #define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
- #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 */
- #define DNS_ZONEFLG_REFRESH 0x00000001U /*%< refresh check in progress */
- #define DNS_ZONEFLG_NEEDDUMP 0x00000002U /*%< zone need consolidation */
- #define DNS_ZONEFLG_USEVC 0x00000004U /*%< use tcp for refresh query */
- #define DNS_ZONEFLG_DUMPING 0x00000008U /*%< a dump is in progress */
- #define DNS_ZONEFLG_HASINCLUDE 0x00000010U /*%< $INCLUDE in zone file */
- #define DNS_ZONEFLG_LOADED 0x00000020U /*%< database has loaded */
- #define DNS_ZONEFLG_EXITING 0x00000040U /*%< zone is being destroyed */
- #define DNS_ZONEFLG_EXPIRED 0x00000080U /*%< zone has expired */
- #define DNS_ZONEFLG_NEEDREFRESH 0x00000100U /*%< refresh check needed */
- #define DNS_ZONEFLG_UPTODATE 0x00000200U /*%< zone contents are
- * uptodate */
- #define DNS_ZONEFLG_NEEDNOTIFY 0x00000400U /*%< need to send out notify
- * messages */
- #define DNS_ZONEFLG_DIFFONRELOAD 0x00000800U /*%< generate a journal diff on
- * reload */
- #define DNS_ZONEFLG_NOMASTERS 0x00001000U /*%< an attempt to refresh a
- * zone with no masters
- * occurred */
- #define DNS_ZONEFLG_LOADING 0x00002000U /*%< load from disk in progress*/
- #define DNS_ZONEFLG_HAVETIMERS 0x00004000U /*%< timer values have been set
- * from SOA (if not set, we
- * are still using
- * default timer values) */
- #define DNS_ZONEFLG_FORCEXFER 0x00008000U /*%< Force a zone xfer */
- #define DNS_ZONEFLG_NOREFRESH 0x00010000U
- #define DNS_ZONEFLG_DIALNOTIFY 0x00020000U
- #define DNS_ZONEFLG_DIALREFRESH 0x00040000U
- #define DNS_ZONEFLG_SHUTDOWN 0x00080000U
- #define DNS_ZONEFLAG_NOIXFR 0x00100000U /*%< IXFR failed, force AXFR */
- #define DNS_ZONEFLG_FLUSH 0x00200000U
- #define DNS_ZONEFLG_NOEDNS 0x00400000U
- #define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U
- #define DNS_ZONEFLG_SOABEFOREAXFR 0x01000000U
- #define DNS_ZONEFLG_NEEDCOMPACT 0x02000000U
- #define DNS_ZONEFLG_REFRESHING 0x04000000U /*%< Refreshing keydata */
- #define DNS_ZONEFLG_THAW 0x08000000U
- /* #define DNS_ZONEFLG_XXXXX 0x10000000U XXXMPA unused. */
- #define DNS_ZONEFLG_NODELAY 0x20000000U
- #define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
- #define DNS_ZONEKEY_OPTION(z,o) (((z)->keyopts & (o)) != 0)
- /* Flags for zone_load() */
- #define DNS_ZONELOADFLAG_NOSTAT 0x00000001U /* Do not stat() master files */
- #define DNS_ZONELOADFLAG_THAW 0x00000002U /* Thaw the zone on successful
- load. */
- #define UNREACH_CHACHE_SIZE 10U
- #define UNREACH_HOLD_TIME 600 /* 10 minutes */
- #define CHECK(op) \
- do { result = (op); \
- if (result != ISC_R_SUCCESS) goto failure; \
- } while (0)
- struct dns_unreachable {
- isc_sockaddr_t remote;
- isc_sockaddr_t local;
- isc_uint32_t expire;
- isc_uint32_t last;
- };
- struct dns_zonemgr {
- unsigned int magic;
- isc_mem_t * mctx;
- int refs; /* Locked by rwlock */
- isc_taskmgr_t * taskmgr;
- isc_timermgr_t * timermgr;
- isc_socketmgr_t * socketmgr;
- isc_taskpool_t * zonetasks;
- isc_task_t * task;
- isc_ratelimiter_t * rl;
- isc_rwlock_t rwlock;
- isc_mutex_t iolock;
- isc_rwlock_t urlock;
- /* Locked by rwlock. */
- dns_zonelist_t zones;
- dns_zonelist_t waiting_for_xfrin;
- dns_zonelist_t xfrin_in_progress;
- /* Configuration data. */
- isc_uint32_t transfersin;
- isc_uint32_t transfersperns;
- unsigned int serialqueryrate;
- /* Locked by iolock */
- isc_uint32_t iolimit;
- isc_uint32_t ioactive;
- dns_iolist_t high;
- dns_iolist_t low;
- /* Locked by urlock. */
- /* LRU cache */
- struct dns_unreachable unreachable[UNREACH_CHACHE_SIZE];
- };
- /*%
- * Hold notify state.
- */
- struct dns_notify {
- unsigned int magic;
- unsigned int flags;
- isc_mem_t *mctx;
- dns_zone_t *zone;
- dns_adbfind_t *find;
- dns_request_t *request;
- dns_name_t ns;
- isc_sockaddr_t dst;
- ISC_LINK(dns_notify_t) link;
- };
- #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;
- isc_mem_t *mctx;
- dns_zone_t *zone;
- dns_db_t *db;
- dns_dbversion_t *version;
- };
- /*%
- * Hold load state.
- */
- struct dns_load {
- unsigned int magic;
- isc_mem_t *mctx;
- dns_zone_t *zone;
- dns_db_t *db;
- isc_time_t loadtime;
- dns_rdatacallbacks_t callbacks;
- };
- /*%
- * Hold forward state.
- */
- struct dns_forward {
- unsigned int magic;
- isc_mem_t *mctx;
- dns_zone_t *zone;
- isc_buffer_t *msgbuf;
- dns_request_t *request;
- isc_uint32_t which;
- isc_sockaddr_t addr;
- dns_updatecallback_t callback;
- void *callback_arg;
- ISC_LINK(dns_forward_t) link;
- };
- /*%
- * Hold IO request state.
- */
- struct dns_io {
- unsigned int magic;
- dns_zonemgr_t *zmgr;
- isc_boolean_t high;
- isc_task_t *task;
- ISC_LINK(dns_io_t) link;
- isc_event_t *event;
- };
- /*%
- * Hold state for when we are signing a zone with a new
- * DNSKEY as result of an update.
- */
- struct dns_signing {
- unsigned int magic;
- dns_db_t *db;
- dns_dbiterator_t *dbiterator;
- dns_secalg_t algorithm;
- isc_uint16_t keyid;
- isc_boolean_t delete;
- isc_boolean_t done;
- ISC_LINK(dns_signing_t) link;
- };
- struct dns_nsec3chain {
- unsigned int magic;
- dns_db_t *db;
- dns_dbiterator_t *dbiterator;
- dns_rdata_nsec3param_t nsec3param;
- unsigned char salt[255];
- isc_boolean_t done;
- isc_boolean_t seen_nsec;
- isc_boolean_t delete_nsec;
- isc_boolean_t save_delete_nsec;
- ISC_LINK(dns_nsec3chain_t) link;
- };
- /*%<
- * 'dbiterator' contains a iterator for the database. If we are creating
- * a NSEC3 chain only the non-NSEC3 nodes will be iterated. If we are
- * removing a NSEC3 chain then both NSEC3 and non-NSEC3 nodes will be
- * iterated.
- *
- * 'nsec3param' contains the parameters of the NSEC3 chain being created
- * or removed.
- *
- * 'salt' is buffer space and is referenced via 'nsec3param.salt'.
- *
- * 'seen_nsec' will be set to true if, while iterating the zone to create a
- * NSEC3 chain, a NSEC record is seen.
- *
- * 'delete_nsec' will be set to true if, at the completion of the creation
- * of a NSEC3 chain, 'seen_nsec' is true. If 'delete_nsec' is true then we
- * are in the process of deleting the NSEC chain.
- *
- * 'save_delete_nsec' is used to store the initial state of 'delete_nsec'
- * so it can be recovered in the event of a error.
- */
- struct dns_keyfetch {
- dns_fixedname_t name;
- dns_rdataset_t keydataset;
- dns_rdataset_t dnskeyset;
- dns_rdataset_t dnskeysigset;
- dns_zone_t *zone;
- dns_db_t *db;
- dns_fetch_t *fetch;
- };
- #define HOUR 3600
- #define DAY (24*HOUR)
- #define MONTH (30*DAY)
- #define SEND_BUFFER_SIZE 2048
- static void zone_settimer(dns_zone_t *, isc_time_t *);
- static void cancel_refresh(dns_zone_t *);
- static void zone_debuglog(dns_zone_t *zone, const char *, int debuglevel,
- const char *msg, ...) ISC_FORMAT_PRINTF(4, 5);
- static void notify_log(dns_zone_t *zone, int level, const char *fmt, ...)
- ISC_FORMAT_PRINTF(3, 4);
- static void queue_xfrin(dns_zone_t *zone);
- static isc_result_t update_one_rr(dns_db_t *db, dns_dbversion_t *ver,
- dns_diff_t *diff, dns_diffop_t op,
- dns_name_t *name, dns_ttl_t ttl,
- dns_rdata_t *rdata);
- static void zone_unload(dns_zone_t *zone);
- static void zone_expire(dns_zone_t *zone);
- static void zone_iattach(dns_zone_t *source, dns_zone_t **target);
- static void zone_idetach(dns_zone_t **zonep);
- static isc_result_t zone_replacedb(dns_zone_t *zone, dns_db_t *db,
- isc_boolean_t dump);
- static inline void zone_attachdb(dns_zone_t *zone, dns_db_t *db);
- static inline void zone_detachdb(dns_zone_t *zone);
- static isc_result_t default_journal(dns_zone_t *zone);
- static void zone_xfrdone(dns_zone_t *zone, isc_result_t result);
- static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db,
- isc_time_t loadtime, isc_result_t result);
- static void zone_needdump(dns_zone_t *zone, unsigned int delay);
- static void zone_shutdown(isc_task_t *, isc_event_t *);
- static void zone_loaddone(void *arg, isc_result_t result);
- static isc_result_t zone_startload(dns_db_t *db, dns_zone_t *zone,
- isc_time_t loadtime);
- static void zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length);
- static void zone_name_tostr(dns_zone_t *zone, char *buf, size_t length);
- static void zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length);
- static void zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length);
- #if 0
- /* ondestroy example */
- static void dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event);
- #endif
- static void refresh_callback(isc_task_t *, isc_event_t *);
- static void stub_callback(isc_task_t *, isc_event_t *);
- static void queue_soa_query(dns_zone_t *zone);
- static void soa_query(isc_task_t *, isc_event_t *);
- static void ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset,
- dns_stub_t *stub);
- static int message_count(dns_message_t *msg, dns_section_t section,
- dns_rdatatype_t type);
- static void notify_cancel(dns_zone_t *zone);
- static void notify_find_address(dns_notify_t *notify);
- static void notify_send(dns_notify_t *notify);
- static isc_result_t notify_createmessage(dns_zone_t *zone,
- unsigned int flags,
- dns_message_t **messagep);
- static void notify_done(isc_task_t *task, isc_event_t *event);
- static void notify_send_toaddr(isc_task_t *task, isc_event_t *event);
- static isc_result_t zone_dump(dns_zone_t *, isc_boolean_t);
- static void got_transfer_quota(isc_task_t *task, isc_event_t *event);
- static isc_result_t zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr,
- dns_zone_t *zone);
- static void zmgr_resume_xfrs(dns_zonemgr_t *zmgr, isc_boolean_t multi);
- static void zonemgr_free(dns_zonemgr_t *zmgr);
- static isc_result_t zonemgr_getio(dns_zonemgr_t *zmgr, isc_boolean_t high,
- isc_task_t *task, isc_taskaction_t action,
- void *arg, dns_io_t **iop);
- static void zonemgr_putio(dns_io_t **iop);
- static void zonemgr_cancelio(dns_io_t *io);
- static isc_result_t
- zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount,
- unsigned int *soacount, isc_uint32_t *serial,
- isc_uint32_t *refresh, isc_uint32_t *retry,
- isc_uint32_t *expire, isc_uint32_t *minimum,
- unsigned int *errors);
- static void zone_freedbargs(dns_zone_t *zone);
- static void forward_callback(isc_task_t *task, isc_event_t *event);
- static void zone_saveunique(dns_zone_t *zone, const char *path,
- const char *templat);
- static void zone_maintenance(dns_zone_t *zone);
- static void zone_notify(dns_zone_t *zone, isc_time_t *now);
- static void dump_done(void *arg, isc_result_t result);
- static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
- isc_uint16_t keyid, isc_boolean_t delete);
- static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver,
- dns_dbnode_t *node, dns_name_t *name,
- dns_diff_t *diff);
- static void zone_rekey(dns_zone_t *zone);
- static isc_boolean_t delsig_ok(dns_rdata_rrsig_t *rrsig_ptr,
- dst_key_t **keys, unsigned int nkeys);
- #define ENTER zone_debuglog(zone, me, 1, "enter")
- 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; \
- _j = isc_random_jitter((b), (b)/4); \
- isc_interval_set(&_i, _j, 0); \
- if (isc_time_add((a), &_i, (c)) != ISC_R_SUCCESS) { \
- dns_zone_log(zone, ISC_LOG_WARNING, \
- "epoch approaching: upgrade required: " \
- "now + %s failed", #b); \
- isc_interval_set(&_i, _j/2, 0); \
- (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); \
- if (isc_time_add((a), &_i, (c)) != ISC_R_SUCCESS) { \
- dns_zone_log(zone, ISC_LOG_WARNING, \
- "epoch approaching: upgrade required: " \
- "now + %s failed", #b); \
- isc_interval_set(&_i, (b)/2, 0); \
- (void)isc_time_add((a), &_i, (c)); \
- } \
- } while (0)
- /*%
- * Increment resolver-related statistics counters. Zone must be locked.
- */
- static inline void
- inc_stats(dns_zone_t *zone, isc_statscounter_t counter) {
- if (zone->stats != NULL)
- isc_stats_increment(zone->stats, counter);
- }
- /***
- *** Public functions.
- ***/
- isc_result_t
- dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
- isc_result_t result;
- dns_zone_t *zone;
- isc_time_t now;
- REQUIRE(zonep != NULL && *zonep == NULL);
- REQUIRE(mctx != NULL);
- TIME_NOW(&now);
- zone = isc_mem_get(mctx, sizeof(*zone));
- if (zone == NULL)
- return (ISC_R_NOMEMORY);
- zone->mctx = NULL;
- isc_mem_attach(mctx, &zone->mctx);
- result = isc_mutex_init(&zone->lock);
- if (result != ISC_R_SUCCESS)
- goto free_zone;
- result = ZONEDB_INITLOCK(&zone->dblock);
- if (result != ISC_R_SUCCESS)
- goto free_mutex;
- /* XXX MPA check that all elements are initialised */
- #ifdef DNS_ZONE_CHECKLOCK
- zone->locked = ISC_FALSE;
- #endif
- zone->db = NULL;
- zone->zmgr = NULL;
- ISC_LINK_INIT(zone, link);
- result = isc_refcount_init(&zone->erefs, 1); /* Implicit attach. */
- if (result != ISC_R_SUCCESS)
- goto free_dblock;
- zone->irefs = 0;
- dns_name_init(&zone->origin, NULL);
- zone->strnamerd = NULL;
- zone->strname = NULL;
- zone->strrdclass = NULL;
- zone->strviewname = NULL;
- zone->masterfile = NULL;
- zone->masterformat = dns_masterformat_none;
- zone->keydirectory = NULL;
- zone->journalsize = -1;
- zone->journal = NULL;
- zone->rdclass = dns_rdataclass_none;
- zone->type = dns_zone_none;
- zone->flags = 0;
- zone->options = 0;
- zone->keyopts = 0;
- zone->db_argc = 0;
- zone->db_argv = NULL;
- isc_time_settoepoch(&zone->expiretime);
- isc_time_settoepoch(&zone->refreshtime);
- isc_time_settoepoch(&zone->dumptime);
- isc_time_settoepoch(&zone->loadtime);
- zone->notifytime = now;
- isc_time_settoepoch(&zone->resigntime);
- isc_time_settoepoch(&zone->keywarntime);
- isc_time_settoepoch(&zone->signingtime);
- isc_time_settoepoch(&zone->nsec3chaintime);
- isc_time_settoepoch(&zone->refreshkeytime);
- zone->refreshkeycount = 0;
- zone->refresh = DNS_ZONE_DEFAULTREFRESH;
- zone->retry = DNS_ZONE_DEFAULTRETRY;
- zone->expire = 0;
- zone->minimum = 0;
- zone->maxrefresh = DNS_ZONE_MAXREFRESH;
- zone->minrefresh = DNS_ZONE_MINREFRESH;
- zone->maxretry = DNS_ZONE_MAXRETRY;
- zone->minretry = DNS_ZONE_MINRETRY;
- zone->masters = NULL;
- zone->masterkeynames = NULL;
- zone->mastersok = NULL;
- zone->masterscnt = 0;
- zone->curmaster = 0;
- zone->notify = NULL;
- zone->notifytype = dns_notifytype_yes;
- zone->notifycnt = 0;
- zone->task = NULL;
- zone->update_acl = NULL;
- zone->forward_acl = NULL;
- zone->notify_acl = NULL;
- zone->query_acl = NULL;
- zone->queryon_acl = NULL;
- zone->xfr_acl = NULL;
- zone->update_disabled = ISC_FALSE;
- zone->zero_no_soa_ttl = ISC_TRUE;
- zone->check_names = dns_severity_ignore;
- zone->request = NULL;
- zone->lctx = NULL;
- zone->readio = NULL;
- zone->dctx = NULL;
- zone->writeio = NULL;
- zone->timer = NULL;
- zone->idlein = DNS_DEFAULT_IDLEIN;
- zone->idleout = DNS_DEFAULT_IDLEOUT;
- zone->log_key_expired_timer = 0;
- ISC_LIST_INIT(zone->notifies);
- isc_sockaddr_any(&zone->notifysrc4);
- isc_sockaddr_any6(&zone->notifysrc6);
- isc_sockaddr_any(&zone->xfrsource4);
- isc_sockaddr_any6(&zone->xfrsource6);
- isc_sockaddr_any(&zone->altxfrsource4);
- isc_sockaddr_any6(&zone->altxfrsource6);
- zone->xfr = NULL;
- zone->tsigkey = NULL;
- zone->maxxfrin = MAX_XFER_TIME;
- zone->maxxfrout = MAX_XFER_TIME;
- zone->ssutable = NULL;
- zone->sigvalidityinterval = 30 * 24 * 3600;
- zone->sigresigninginterval = 7 * 24 * 3600;
- zone->view = NULL;
- zone->acache = NULL;
- zone->checkmx = NULL;
- zone->checksrv = NULL;
- zone->checkns = NULL;
- ISC_LINK_INIT(zone, statelink);
- zone->statelist = NULL;
- zone->stats = NULL;
- zone->requeststats_on = ISC_FALSE;
- zone->requeststats = NULL;
- zone->notifydelay = 5;
- zone->isself = NULL;
- zone->isselfarg = NULL;
- ISC_LIST_INIT(zone->signing);
- ISC_LIST_INIT(zone->nsec3chain);
- zone->signatures = 10;
- zone->nodes = 100;
- zone->privatetype = (dns_rdatatype_t)0xffffU;
- zone->added = ISC_FALSE;
- zone->rpz_zone = ISC_FALSE;
- ISC_LIST_INIT(zone->forwards);
- zone->magic = ZONE_MAGIC;
- /* Must be after magic is set. */
- result = dns_zone_setdbtype(zone, dbargc_default, dbargv_default);
- if (result != ISC_R_SUCCESS)
- goto free_erefs;
- ISC_EVENT_INIT(&zone->ctlevent, sizeof(zone->ctlevent), 0, NULL,
- DNS_EVENT_ZONECONTROL, zone_shutdown, zone, zone,
- NULL, NULL);
- *zonep = zone;
- return (ISC_R_SUCCESS);
- free_erefs:
- isc_refcount_decrement(&zone->erefs, NULL);
- isc_refcount_destroy(&zone->erefs);
- free_dblock:
- ZONEDB_DESTROYLOCK(&zone->dblock);
- free_mutex:
- DESTROYLOCK(&zone->lock);
- free_zone:
- isc_mem_putanddetach(&zone->mctx, zone, sizeof(*zone));
- return (result);
- }
- /*
- * Free a zone. Because we require that there be no more
- * outstanding events or references, no locking is necessary.
- */
- static void
- zone_free(dns_zone_t *zone) {
- isc_mem_t *mctx = NULL;
- dns_signing_t *signing;
- dns_nsec3chain_t *nsec3chain;
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(isc_refcount_current(&zone->erefs) == 0);
- REQUIRE(zone->irefs == 0);
- REQUIRE(!LOCKED_ZONE(zone));
- REQUIRE(zone->timer == NULL);
- /*
- * Managed objects. Order is important.
- */
- if (zone->request != NULL)
- dns_request_destroy(&zone->request); /* XXXMPA */
- INSIST(zone->readio == NULL);
- INSIST(zone->statelist == NULL);
- INSIST(zone->writeio == NULL);
- if (zone->task != NULL)
- isc_task_detach(&zone->task);
- if (zone->zmgr != NULL)
- dns_zonemgr_releasezone(zone->zmgr, zone);
- /* Unmanaged objects */
- for (signing = ISC_LIST_HEAD(zone->signing);
- signing != NULL;
- signing = ISC_LIST_HEAD(zone->signing)) {
- ISC_LIST_UNLINK(zone->signing, signing, link);
- dns_db_detach(&signing->db);
- dns_dbiterator_destroy(&signing->dbiterator);
- isc_mem_put(zone->mctx, signing, sizeof *signing);
- }
- for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
- nsec3chain != NULL;
- nsec3chain = ISC_LIST_HEAD(zone->nsec3chain)) {
- ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link);
- dns_db_detach(&nsec3chain->db);
- dns_dbiterator_destroy(&nsec3chain->dbiterator);
- isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
- }
- if (zone->masterfile != NULL)
- isc_mem_free(zone->mctx, zone->masterfile);
- zone->masterfile = NULL;
- if (zone->keydirectory != NULL)
- isc_mem_free(zone->mctx, zone->keydirectory);
- zone->keydirectory = NULL;
- zone->journalsize = -1;
- if (zone->journal != NULL)
- isc_mem_free(zone->mctx, zone->journal);
- zone->journal = NULL;
- if (zone->stats != NULL)
- isc_stats_detach(&zone->stats);
- if (zone->requeststats != NULL)
- isc_stats_detach(&zone->requeststats);
- if (zone->db != NULL)
- zone_detachdb(zone);
- if (zone->acache != NULL)
- dns_acache_detach(&zone->acache);
- zone_freedbargs(zone);
- RUNTIME_CHECK(dns_zone_setmasterswithkeys(zone, NULL, NULL, 0)
- == ISC_R_SUCCESS);
- RUNTIME_CHECK(dns_zone_setalsonotify(zone, NULL, 0)
- == ISC_R_SUCCESS);
- zone->check_names = dns_severity_ignore;
- if (zone->update_acl != NULL)
- dns_acl_detach(&zone->update_acl);
- if (zone->forward_acl != NULL)
- dns_acl_detach(&zone->forward_acl);
- if (zone->notify_acl != NULL)
- dns_acl_detach(&zone->notify_acl);
- if (zone->query_acl != NULL)
- dns_acl_detach(&zone->query_acl);
- if (zone->queryon_acl != NULL)
- dns_acl_detach(&zone->queryon_acl);
- if (zone->xfr_acl != NULL)
- dns_acl_detach(&zone->xfr_acl);
- if (dns_name_dynamic(&zone->origin))
- dns_name_free(&zone->origin, zone->mctx);
- if (zone->strnamerd != NULL)
- isc_mem_free(zone->mctx, zone->strnamerd);
- if (zone->strname != NULL)
- isc_mem_free(zone->mctx, zone->strname);
- if (zone->strrdclass != NULL)
- isc_mem_free(zone->mctx, zone->strrdclass);
- if (zone->strviewname != NULL)
- isc_mem_free(zone->mctx, zone->strviewname);
- if (zone->ssutable != NULL)
- dns_ssutable_detach(&zone->ssutable);
- /* last stuff */
- ZONEDB_DESTROYLOCK(&zone->dblock);
- DESTROYLOCK(&zone->lock);
- isc_refcount_destroy(&zone->erefs);
- zone->magic = 0;
- mctx = zone->mctx;
- isc_mem_put(mctx, zone, sizeof(*zone));
- isc_mem_detach(&mctx);
- }
- /*
- * Single shot.
- */
- void
- dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) {
- char namebuf[1024];
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(rdclass != dns_rdataclass_none);
- /*
- * Test and set.
- */
- LOCK_ZONE(zone);
- REQUIRE(zone->rdclass == dns_rdataclass_none ||
- zone->rdclass == rdclass);
- zone->rdclass = rdclass;
- if (zone->strnamerd != NULL)
- isc_mem_free(zone->mctx, zone->strnamerd);
- if (zone->strrdclass != NULL)
- isc_mem_free(zone->mctx, zone->strrdclass);
- zone_namerd_tostr(zone, namebuf, sizeof namebuf);
- zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf);
- zone_rdclass_tostr(zone, namebuf, sizeof namebuf);
- zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf);
- UNLOCK_ZONE(zone);
- }
- dns_rdataclass_t
- dns_zone_getclass(dns_zone_t *zone) {
- REQUIRE(DNS_ZONE_VALID(zone));
- return (zone->rdclass);
- }
- void
- dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) {
- REQUIRE(DNS_ZONE_VALID(zone));
- LOCK_ZONE(zone);
- zone->notifytype = notifytype;
- UNLOCK_ZONE(zone);
- }
- isc_result_t
- dns_zone_getserial2(dns_zone_t *zone, isc_uint32_t *serialp) {
- isc_result_t result;
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(serialp != NULL);
- LOCK_ZONE(zone);
- ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
- if (zone->db != NULL) {
- result = zone_get_from_db(zone, zone->db, NULL, NULL, serialp,
- NULL, NULL, NULL, NULL, NULL);
- } else
- result = DNS_R_NOTLOADED;
- ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
- UNLOCK_ZONE(zone);
- return (result);
- }
- isc_uint32_t
- dns_zone_getserial(dns_zone_t *zone) {
- isc_result_t result;
- isc_uint32_t serial;
- result = dns_zone_getserial2(zone, &serial);
- if (result != ISC_R_SUCCESS)
- serial = 0; /* XXX: not really correct, but no other choice */
- return (serial);
- }
- /*
- * Single shot.
- */
- void
- dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type) {
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(type != dns_zone_none);
- /*
- * Test and set.
- */
- LOCK_ZONE(zone);
- REQUIRE(zone->type == dns_zone_none || zone->type == type);
- zone->type = type;
- UNLOCK_ZONE(zone);
- }
- static void
- zone_freedbargs(dns_zone_t *zone) {
- unsigned int i;
- /* Free the old database argument list. */
- if (zone->db_argv != NULL) {
- for (i = 0; i < zone->db_argc; i++)
- isc_mem_free(zone->mctx, zone->db_argv[i]);
- isc_mem_put(zone->mctx, zone->db_argv,
- zone->db_argc * sizeof(*zone->db_argv));
- }
- zone->db_argc = 0;
- zone->db_argv = NULL;
- }
- isc_result_t
- dns_zone_getdbtype(dns_zone_t *zone, char ***argv, isc_mem_t *mctx) {
- size_t size = 0;
- unsigned int i;
- isc_result_t result = ISC_R_SUCCESS;
- void *mem;
- char **tmp, *tmp2;
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(argv != NULL && *argv == NULL);
- LOCK_ZONE(zone);
- size = (zone->db_argc + 1) * sizeof(char *);
- for (i = 0; i < zone->db_argc; i++)
- size += strlen(zone->db_argv[i]) + 1;
- mem = isc_mem_allocate(mctx, size);
- if (mem != NULL) {
- tmp = mem;
- tmp2 = mem;
- tmp2 += (zone->db_argc + 1) * sizeof(char *);
- for (i = 0; i < zone->db_argc; i++) {
- *tmp++ = tmp2;
- strcpy(tmp2, zone->db_argv[i]);
- tmp2 += strlen(tmp2) + 1;
- }
- *tmp = NULL;
- } else
- result = ISC_R_NOMEMORY;
- UNLOCK_ZONE(zone);
- *argv = mem;
- return (result);
- }
- isc_result_t
- dns_zone_setdbtype(dns_zone_t *zone,
- unsigned int dbargc, const char * const *dbargv) {
- isc_result_t result = ISC_R_SUCCESS;
- char **new = NULL;
- unsigned int i;
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(dbargc >= 1);
- REQUIRE(dbargv != NULL);
- LOCK_ZONE(zone);
- /* Set up a new database argument list. */
- new = isc_mem_get(zone->mctx, dbargc * sizeof(*new));
- if (new == NULL)
- goto nomem;
- for (i = 0; i < dbargc; i++)
- new[i] = NULL;
- for (i = 0; i < dbargc; i++) {
- new[i] = isc_mem_strdup(zone->mctx, dbargv[i]);
- if (new[i] == NULL)
- goto nomem;
- }
- /* Free the old list. */
- zone_freedbargs(zone);
- zone->db_argc = dbargc;
- zone->db_argv = new;
- result = ISC_R_SUCCESS;
- goto unlock;
- nomem:
- if (new != NULL) {
- for (i = 0; i < dbargc; i++)
- if (new[i] != NULL)
- isc_mem_free(zone->mctx, new[i]);
- isc_mem_put(zone->mctx, new, dbargc * sizeof(*new));
- }
- result = ISC_R_NOMEMORY;
- unlock:
- UNLOCK_ZONE(zone);
- return (result);
- }
- void
- dns_zone_setview(dns_zone_t *zone, dns_view_t *view) {
- char namebuf[1024];
- REQUIRE(DNS_ZONE_VALID(zone));
- LOCK_ZONE(zone);
- if (zone->view != NULL)
- dns_view_weakdetach(&zone->view);
- dns_view_weakattach(view, &zone->view);
- if (zone->strviewname != NULL)
- isc_mem_free(zone->mctx, zone->strviewname);
- if (zone->strnamerd != NULL)
- isc_mem_free(zone->mctx, zone->strnamerd);
- zone_namerd_tostr(zone, namebuf, sizeof namebuf);
- zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf);
- zone_viewname_tostr(zone, namebuf, sizeof namebuf);
- zone->strviewname = isc_mem_strdup(zone->mctx, namebuf);
- UNLOCK_ZONE(zone);
- }
- dns_view_t *
- dns_zone_getview(dns_zone_t *zone) {
- REQUIRE(DNS_ZONE_VALID(zone));
- return (zone->view);
- }
- isc_result_t
- dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) {
- isc_result_t result;
- char namebuf[1024];
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(origin != NULL);
- LOCK_ZONE(zone);
- if (dns_name_dynamic(&zone->origin)) {
- dns_name_free(&zone->origin, zone->mctx);
- dns_name_init(&zone->origin, NULL);
- }
- result = dns_name_dup(origin, zone->mctx, &zone->origin);
- if (zone->strnamerd != NULL)
- isc_mem_free(zone->mctx, zone->strnamerd);
- if (zone->strname != NULL)
- isc_mem_free(zone->mctx, zone->strname);
- zone_namerd_tostr(zone, namebuf, sizeof namebuf);
- zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf);
- zone_name_tostr(zone, namebuf, sizeof namebuf);
- zone->strname = isc_mem_strdup(zone->mctx, namebuf);
- UNLOCK_ZONE(zone);
- return (result);
- }
- void
- dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache) {
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(acache != NULL);
- LOCK_ZONE(zone);
- if (zone->acache != NULL)
- dns_acache_detach(&zone->acache);
- dns_acache_attach(acache, &zone->acache);
- ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
- if (zone->db != NULL) {
- isc_result_t result;
- /*
- * 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.
- */
- result = dns_acache_setdb(acache, zone->db);
- if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "dns_acache_setdb() failed: %s",
- isc_result_totext(result));
- }
- }
- ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
- UNLOCK_ZONE(zone);
- }
- static isc_result_t
- dns_zone_setstring(dns_zone_t *zone, char **field, const char *value) {
- char *copy;
- if (value != NULL) {
- copy = isc_mem_strdup(zone->mctx, value);
- if (copy == NULL)
- return (ISC_R_NOMEMORY);
- } else {
- copy = NULL;
- }
- if (*field != NULL)
- isc_mem_free(zone->mctx, *field);
- *field = copy;
- return (ISC_R_SUCCESS);
- }
- isc_result_t
- dns_zone_setfile(dns_zone_t *zone, const char *file) {
- return (dns_zone_setfile2(zone, file, dns_masterformat_text));
- }
- isc_result_t
- dns_zone_setfile2(dns_zone_t *zone, const char *file,
- dns_masterformat_t format) {
- isc_result_t result = ISC_R_SUCCESS;
- REQUIRE(DNS_ZONE_VALID(zone));
- LOCK_ZONE(zone);
- result = dns_zone_setstring(zone, &zone->masterfile, file);
- if (result == ISC_R_SUCCESS) {
- zone->masterformat = format;
- result = default_journal(zone);
- }
- UNLOCK_ZONE(zone);
- return (result);
- }
- const char *
- dns_zone_getfile(dns_zone_t *zone) {
- REQUIRE(DNS_ZONE_VALID(zone));
- return (zone->masterfile);
- }
- static isc_result_t
- default_journal(dns_zone_t *zone) {
- isc_result_t result;
- char *journal;
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(LOCKED_ZONE(zone));
- if (zone->masterfile != NULL) {
- /* Calculate string length including '\0'. */
- int len = strlen(zone->masterfile) + sizeof(".jnl");
- journal = isc_mem_allocate(zone->mctx, len);
- if (journal == NULL)
- return (ISC_R_NOMEMORY);
- strcpy(journal, zone->masterfile);
- strcat(journal, ".jnl");
- } else {
- journal = NULL;
- }
- result = dns_zone_setstring(zone, &zone->journal, journal);
- if (journal != NULL)
- isc_mem_free(zone->mctx, journal);
- return (result);
- }
- isc_result_t
- dns_zone_setjournal(dns_zone_t *zone, const char *journal) {
- isc_result_t result = ISC_R_SUCCESS;
- REQUIRE(DNS_ZONE_VALID(zone));
- LOCK_ZONE(zone);
- result = dns_zone_setstring(zone, &zone->journal, journal);
- UNLOCK_ZONE(zone);
- return (result);
- }
- char *
- dns_zone_getjournal(dns_zone_t *zone) {
- REQUIRE(DNS_ZONE_VALID(zone));
- return (zone->journal);
- }
- /*
- * 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, key 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
- zone_isdynamic(dns_zone_t *zone) {
- REQUIRE(DNS_ZONE_VALID(zone));
- return (ISC_TF(zone->type == dns_zone_slave ||
- zone->type == dns_zone_stub ||
- zone->type == dns_zone_key ||
- (!zone->update_disabled && zone->ssutable != NULL) ||
- (!zone->update_disabled && zone->update_acl != NULL &&
- !dns_acl_isnone(zone->update_acl))));
- }
- static isc_result_t
- zone_load(dns_zone_t *zone, unsigned int flags) {
- isc_result_t result;
- isc_time_t now;
- isc_time_t loadtime, filetime;
- dns_db_t *db = NULL;
- isc_boolean_t rbt;
- REQUIRE(DNS_ZONE_VALID(zone));
- LOCK_ZONE(zone);
- TIME_NOW(&now);
- INSIST(zone->type != dns_zone_none);
- if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) {
- if ((flags & DNS_ZONELOADFLAG_THAW) != 0)
- DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW);
- result = DNS_R_CONTINUE;
- goto cleanup;
- }
- INSIST(zone->db_argc >= 1);
- rbt = strcmp(zone->db_argv[0], "rbt") == 0 ||
- strcmp(zone->db_argv[0], "rbt64") == 0;
- if (zone->db != NULL && zone->masterfile == NULL && rbt) {
- /*
- * The zone has no master file configured.
- */
- result = ISC_R_SUCCESS;
- goto cleanup;
- }
- if (zone->db != NULL && zone_isdynamic(zone)) {
- /*
- * 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.
- */
- if (zone->type == dns_zone_master)
- result = DNS_R_DYNAMIC;
- else
- result = ISC_R_SUCCESS;
- 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.
- */
- TIME_NOW(&loadtime);
- /*
- * 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.
- */
- if (zone->masterfile != NULL) {
- /*
- * The file is already loaded. If we are just doing a
- * "rndc reconfig", we are done.
- */
- if (!isc_time_isepoch(&zone->loadtime) &&
- (flags & DNS_ZONELOADFLAG_NOSTAT) != 0 &&
- zone->rpz_zone == dns_rpz_needed()) {
- result = ISC_R_SUCCESS;
- goto cleanup;
- }
- result = isc_file_getmodtime(zone->masterfile, &filetime);
- if (result == ISC_R_SUCCESS) {
- if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) &&
- !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE) &&
- isc_time_compare(&filetime, &zone->loadtime) <= 0 &&
- zone->rpz_zone == dns_rpz_needed()) {
- dns_zone_log(zone, ISC_LOG_DEBUG(1),
- "skipping load: master file "
- "older than last load");
- result = DNS_R_UPTODATE;
- goto cleanup;
- }
- loadtime = filetime;
- zone->rpz_zone = dns_rpz_needed();
- }
- }
- /*
- * Built in zones (with the exception of empty zones) don't need
- * to be reloaded.
- */
- if (zone->type == dns_zone_master &&
- strcmp(zone->db_argv[0], "_builtin") == 0 &&
- (zone->db_argc < 2 || strcmp(zone->db_argv[1], "empty") != 0) &&
- DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
- result = ISC_R_SUCCESS;
- goto cleanup;
- }
- if ((zone->type == dns_zone_slave || zone->type == dns_zone_stub) &&
- rbt) {
- if (zone->masterfile == NULL ||
- !isc_file_exists(zone->masterfile)) {
- if (zone->masterfile != NULL) {
- dns_zone_log(zone, ISC_LOG_DEBUG(1),
- "no master file");
- }
- zone->refreshtime = now;
- if (zone->task != NULL)
- zone_settimer(zone, &now);
- result = ISC_R_SUCCESS;
- goto cleanup;
- }
- }
- dns_zone_log(zone, ISC_LOG_DEBUG(1), "starting load");
- result = dns_db_create(zone->mctx, zone->db_argv[0],
- &zone->origin, (zone->type == dns_zone_stub) ?
- dns_dbtype_stub : dns_dbtype_zone,
- zone->rdclass,
- zone->db_argc - 1, zone->db_argv + 1,
- &db);
- if (result != ISC_R_SUCCESS) {
- dns_zone_log(zone, ISC_LOG_ERROR,
- "loading zone: creating database: %s",
- isc_result_totext(result));
- goto cleanup;
- }
- dns_db_settask(db, zone->task);
- if (! dns_db_ispersistent(db)) {
- if (zone->masterfile != NULL) {
- result = zone_startload(db, zone, loadtime);
- } else {
- result = DNS_R_NOMASTERFILE;
- if (zone->type == dns_zone_master) {
- dns_zone_log(zone, ISC_LOG_ERROR,
- "loading zone: "
- "no master file configured");
- goto cleanup;
- }
- dns_zone_log(zone, ISC_LOG_INFO, "loading zone: "
- "no master file configured: continuing");
- }
- }
- if (result == DNS_R_CONTINUE) {
- DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADING);
- if ((flags & DNS_ZONELOADFLAG_THAW) != 0)
- DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW);
- goto cleanup;
- }
- result = zone_postload(zone, db, loadtime, result);
- cleanup:
- UNLOCK_ZONE(zone);
- if (db != NULL)
- dns_db_detach(&db);
- return (result);
- }
- isc_result_t
- dns_zone_load(dns_zone_t *zone) {
- return (zone_load(zone, 0));
- }
- isc_result_t
- dns_zone_loadnew(dns_zone_t *zone) {
- return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT));
- }
- isc_result_t
- dns_zone_loadandthaw(dns_zone_t *zone) {
- isc_result_t result;
- result = zone_load(zone, DNS_ZONELOADFLAG_THAW);
- switch (result) {
- case DNS_R_CONTINUE:
- /* Deferred thaw. */
- break;
- case ISC_R_SUCCESS:
- case DNS_R_UPTODATE:
- case DNS_R_SEENINCLUDE:
- zone->update_disabled = ISC_FALSE;
- break;
- case DNS_R_NOMASTERFILE:
- zone->update_disabled = ISC_FALSE;
- break;
- default:
- /* Error, remain in disabled state. */
- break;
- }
- return (result);
- }
- static unsigned int
- get_master_options(dns_zone_t *zone) {
- unsigned int options;
- options = DNS_MASTER_ZONE;
- if (zone->type == dns_zone_slave)
- options |= DNS_MASTER_SLAVE;
- if (zone->type == dns_zone_key)
- options |= DNS_MASTER_KEY;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS))
- options |= DNS_MASTER_CHECKNS;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS))
- options |= DNS_MASTER_FATALNS;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES))
- options |= DNS_MASTER_CHECKNAMES;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL))
- options |= DNS_MASTER_CHECKNAMESFAIL;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX))
- options |= DNS_MASTER_CHECKMX;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL))
- options |= DNS_MASTER_CHECKMXFAIL;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD))
- options |= DNS_MASTER_CHECKWILDCARD;
- if (zone->type == dns_zone_master &&
- ((zone->update_acl != NULL && !dns_acl_isnone(zone->update_acl)) ||
- zone->ssutable != NULL))
- options |= DNS_MASTER_RESIGN;
- return (options);
- }
- static void
- zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
- dns_load_t *load = event->ev_arg;
- isc_result_t result = ISC_R_SUCCESS;
- unsigned int options;
- REQUIRE(DNS_LOAD_VALID(load));
- if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0)
- result = ISC_R_CANCELED;
- isc_event_free(&event);
- if (result == ISC_R_CANCELED)
- goto fail;
- options = get_master_options(load->zone);
- result = dns_master_loadfileinc3(load->zone->masterfile,
- dns_db_origin(load->db),
- dns_db_origin(load->db),
- load->zone->rdclass,
- options,
- load->zone->sigresigninginterval,
- &load->callbacks, task,
- zone_loaddone, load,
- &load->zone->lctx, load->zone->mctx,
- load->zone->masterformat);
- if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE &&
- result != DNS_R_SEENINCLUDE)
- goto fail;
- return;
- fail:
- zone_loaddone(load, result);
- }
- static void
- zone_gotwritehandle(isc_task_t *task, isc_event_t *event) {
- const char me[] = "zone_gotwritehandle";
- dns_zone_t *zone = event->ev_arg;
- isc_result_t result = ISC_R_SUCCESS;
- dns_dbversion_t *version = NULL;
- REQUIRE(DNS_ZONE_VALID(zone));
- INSIST(task == zone->task);
- ENTER;
- if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0)
- result = ISC_R_CANCELED;
- isc_event_free(&event);
- if (result == ISC_R_CANCELED)
- goto fail;
- LOCK_ZONE(zone);
- ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
- if (zone->db != NULL) {
- dns_db_currentversion(zone->db, &version);
- result = dns_master_dumpinc2(zone->mctx, zone->db, version,
- &dns_master_style_default,
- zone->masterfile, zone->task,
- dump_done, zone, &zone->dctx,
- zone->masterformat);
- dns_db_closeversion(zone->db, &version, ISC_FALSE);
- } else
- result = ISC_R_CANCELED;
- ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
- UNLOCK_ZONE(zone);
- if (result != DNS_R_CONTINUE)
- goto fail;
- return;
- fail:
- dump_done(zone, result);
- }
- static isc_result_t
- zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
- dns_load_t *load;
- isc_result_t result;
- isc_result_t tresult;
- unsigned int options;
- options = get_master_options(zone);
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS))
- options |= DNS_MASTER_MANYERRORS;
- if (zone->zmgr != NULL && zone->db != NULL && zone->task != NULL) {
- load = isc_mem_get(zone->mctx, sizeof(*load));
- if (load == NULL)
- return (ISC_R_NOMEMORY);
- load->mctx = NULL;
- load->zone = NULL;
- load->db = NULL;
- load->loadtime = loadtime;
- load->magic = LOAD_MAGIC;
- isc_mem_attach(zone->mctx, &load->mctx);
- zone_iattach(zone, &load->zone);
- dns_db_attach(db, &load->db);
- dns_rdatacallbacks_init(&load->callbacks);
- result = dns_db_beginload(db, &load->callbacks.add,
- &load->callbacks.add_private);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- result = zonemgr_getio(zone->zmgr, ISC_TRUE, zone->task,
- zone_gotreadhandle, load,
- &zone->readio);
- if (result != ISC_R_SUCCESS) {
- /*
- * We can't report multiple errors so ignore
- * the result of dns_db_endload().
- */
- (void)dns_db_endload(load->db,
- &load->callbacks.add_private);
- goto cleanup;
- } else
- result = DNS_R_CONTINUE;
- } else {
- dns_rdatacallbacks_t callbacks;
- dns_rdatacallbacks_init(&callbacks);
- result = dns_db_beginload(db, &callbacks.add,
- &callbacks.add_private);
- if (result != ISC_R_SUCCESS)
- return (result);
- result = dns_master_loadfile3(zone->masterfile, &zone->origin,
- &zone->origin, zone->rdclass,
- options, zone->sigresigninginterval,
- &callbacks, zone->mctx,
- zone->masterformat);
- tresult = dns_db_endload(db, &callbacks.add_private);
- if (result == ISC_R_SUCCESS)
- result = tresult;
- }
- return (result);
- cleanup:
- load->magic = 0;
- dns_db_detach(&load->db);
- zone_idetach(&load->zone);
- isc_mem_detach(&load->mctx);
- isc_mem_put(zone->mctx, load, sizeof(*load));
- return (result);
- }
- static isc_boolean_t
- zone_check_mx(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
- dns_name_t *owner)
- {
- isc_result_t result;
- char ownerbuf[DNS_NAME_FORMATSIZE];
- char namebuf[DNS_NAME_FORMATSIZE];
- char altbuf[DNS_NAME_FORMATSIZE];
- dns_fixedname_t fixed;
- dns_name_t *foundname;
- int level;
- /*
- * "." means the services does not exist.
- */
- if (dns_name_equal(name, dns_rootname))
- return (ISC_TRUE);
- /*
- * Outside of zone.
- */
- if (!dns_name_issubdomain(name, &zone->origin)) {
- if (zone->checkmx != NULL)
- return ((zone->checkmx)(zone, name, owner));
- return (ISC_TRUE);
- }
- if (zone->type == dns_zone_master)
- level = ISC_LOG_ERROR;
- else
- level = ISC_LOG_WARNING;
- dns_fixedname_init(&fixed);
- foundname = dns_fixedname_name(&fixed);
- result = dns_db_find(db, name, NULL, dns_rdatatype_a,
- 0, 0, NULL, foundname, NULL, NULL);
- if (result == ISC_R_SUCCESS)
- return (ISC_TRUE);
- if (result == DNS_R_NXRRSET) {
- result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,…