zone.c 174 KB
Newer Older
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
 * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
5 6 7
 * 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.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * 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.
16 17
 */

Mark Andrews's avatar
Mark Andrews committed
18
/* $Id: zone.c,v 1.428 2005/01/10 23:43:22 marka Exp $ */
19 20 21

#include <config.h>

22
#include <isc/file.h>
23
#include <isc/mutex.h>
Mark Andrews's avatar
Mark Andrews committed
24
#include <isc/print.h>
25
#include <isc/random.h>
Mark Andrews's avatar
Mark Andrews committed
26
#include <isc/ratelimiter.h>
27
#include <isc/refcount.h>
28
#include <isc/serial.h>
29
#include <isc/string.h>
30
#include <isc/taskpool.h>
31
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
32
#include <isc/util.h>
33

34
#include <dns/acache.h>
35
#include <dns/acl.h>
Mark Andrews's avatar
Mark Andrews committed
36
#include <dns/adb.h>
37
#include <dns/callbacks.h>
38
#include <dns/db.h>
39
#include <dns/events.h>
40
#include <dns/journal.h>
41
#include <dns/log.h>
42
#include <dns/master.h>
Mark Andrews's avatar
Mark Andrews committed
43
#include <dns/masterdump.h>
44
#include <dns/message.h>
45
#include <dns/name.h>
46
#include <dns/peer.h>
47
#include <dns/rcode.h>
48
#include <dns/rdataclass.h>
49
#include <dns/rdatalist.h>
50
#include <dns/rdataset.h>
Brian Wellington's avatar
Brian Wellington committed
51
#include <dns/rdatastruct.h>
52
#include <dns/rdatatype.h>
Mark Andrews's avatar
Mark Andrews committed
53
#include <dns/request.h>
54 55
#include <dns/resolver.h>
#include <dns/result.h>
56
#include <dns/stats.h>
57
#include <dns/ssu.h>
58
#include <dns/tsig.h>
59
#include <dns/xfrin.h>
60
#include <dns/zone.h>
61

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
#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)))
88

89 90 91
/*
 * Default values.
 */
92 93
#define DNS_DEFAULT_IDLEIN 3600		/* 1 hour */
#define DNS_DEFAULT_IDLEOUT 3600	/* 1 hour */
94
#define MAX_XFER_TIME (2*3600)		/* Documented default is 2 hours */
Mark Andrews's avatar
Mark Andrews committed
95

96 97 98
#ifndef DNS_MAX_EXPIRE
#define DNS_MAX_EXPIRE	14515200	/* 24 weeks */
#endif
Mark Andrews's avatar
Mark Andrews committed
99

100 101 102 103
#ifndef DNS_DUMP_DELAY
#define DNS_DUMP_DELAY 900		/* 15 minutes */
#endif

104 105
typedef struct dns_notify dns_notify_t;
typedef struct dns_stub dns_stub_t;
106
typedef struct dns_load dns_load_t;
107
typedef struct dns_forward dns_forward_t;
108 109
typedef struct dns_io dns_io_t;
typedef ISC_LIST(dns_io_t) dns_iolist_t;
110

111 112 113
#define DNS_ZONE_CHECKLOCK
#ifdef DNS_ZONE_CHECKLOCK
#define LOCK_ZONE(z) \
Mark Andrews's avatar
Mark Andrews committed
114 115 116 117
	 do { LOCK(&(z)->lock); \
	      INSIST((z)->locked == ISC_FALSE); \
	     (z)->locked = ISC_TRUE; \
		} while (0)
118 119
#define UNLOCK_ZONE(z) \
	do { (z)->locked = ISC_FALSE; UNLOCK(&(z)->lock); } while (0)
Mark Andrews's avatar
Mark Andrews committed
120
#define LOCKED_ZONE(z) ((z)->locked)
121 122 123 124 125 126
#else
#define LOCK_ZONE(z) LOCK(&(z)->lock)
#define UNLOCK_ZONE(z) UNLOCK(&(z)->lock)
#define LOCKED_ZONE(z) ISC_TRUE
#endif

127 128 129 130
struct dns_zone {
	/* Unlocked */
	unsigned int		magic;
	isc_mutex_t		lock;
131 132 133
#ifdef DNS_ZONE_CHECKLOCK
	isc_boolean_t		locked;
#endif
134
	isc_mem_t		*mctx;
135
	isc_refcount_t		erefs;
136 137

	/* Locked */
Mark Andrews's avatar
Mark Andrews committed
138
	dns_db_t		*db;
139 140
	dns_zonemgr_t		*zmgr;
	ISC_LINK(dns_zone_t)	link;		/* Used by zmgr. */
141
	isc_timer_t		*timer;
142
	unsigned int		irefs;
143
	dns_name_t		origin;
Mark Andrews's avatar
Mark Andrews committed
144
	char			*masterfile;
145
	char			*journal;
146
	isc_int32_t		journalsize;
147 148 149 150 151
	dns_rdataclass_t	rdclass;
	dns_zonetype_t		type;
	unsigned int		flags;
	unsigned int		options;
	unsigned int		db_argc;
152
	char			**db_argv;
153 154 155
	isc_time_t		expiretime;
	isc_time_t		refreshtime;
	isc_time_t		dumptime;
156
	isc_time_t		loadtime;
157 158 159 160 161
	isc_uint32_t		serial;
	isc_uint32_t		refresh;
	isc_uint32_t		retry;
	isc_uint32_t		expire;
	isc_uint32_t		minimum;
162
	char			*keydirectory;
163 164 165 166 167 168

	isc_uint32_t		maxrefresh;
	isc_uint32_t		minrefresh;
	isc_uint32_t		maxretry;
	isc_uint32_t		minretry;

169
	isc_sockaddr_t		*masters;
David Lawrence's avatar
tabify  
David Lawrence committed
170
	dns_name_t		**masterkeynames;
171 172
	unsigned int		masterscnt;
	unsigned int		curmaster;
Mark Andrews's avatar
Mark Andrews committed
173
	isc_sockaddr_t		masteraddr;
174
	dns_notifytype_t	notifytype;
175
	isc_sockaddr_t		*notify;
176 177
	unsigned int		notifycnt;
	isc_sockaddr_t		notifyfrom;
178
	isc_task_t		*task;
179 180
	isc_sockaddr_t	 	notifysrc4;
	isc_sockaddr_t	 	notifysrc6;
181 182
	isc_sockaddr_t	 	xfrsource4;
	isc_sockaddr_t	 	xfrsource6;
183 184 185
	isc_sockaddr_t	 	altxfrsource4;
	isc_sockaddr_t	 	altxfrsource6;
	isc_sockaddr_t	 	sourceaddr;
Mark Andrews's avatar
Mark Andrews committed
186
	dns_xfrin_ctx_t		*xfr;		/* task locked */
187
	dns_tsigkey_t		*tsigkey;	/* key used for xfr */
188
	/* Access Control Lists */
189
	dns_acl_t		*update_acl;
190
	dns_acl_t		*forward_acl;
191
	dns_acl_t		*notify_acl;
192 193
	dns_acl_t		*query_acl;
	dns_acl_t		*xfr_acl;
194
	isc_boolean_t		update_disabled;
195
	dns_severity_t		check_names;
196
	ISC_LIST(dns_notify_t)	notifies;
Mark Andrews's avatar
Mark Andrews committed
197
	dns_request_t		*request;
198
	dns_loadctx_t		*lctx;
199
	dns_io_t		*readio;
200 201
	dns_dumpctx_t		*dctx;
	dns_io_t		*writeio;
Mark Andrews's avatar
Mark Andrews committed
202 203
	isc_uint32_t		maxxfrin;
	isc_uint32_t		maxxfrout;
204 205
	isc_uint32_t		idlein;
	isc_uint32_t		idleout;
206
	isc_event_t		ctlevent;
207
	dns_ssutable_t		*ssutable;
208
	isc_uint32_t		sigvalidityinterval;
209
	dns_view_t		*view;
210
	dns_acache_t		*acache;
211
	/*
212
	 * Zones in certain states such as "waiting for zone transfer"
213 214 215 216 217
	 * 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.
	 */
218
	ISC_LINK(dns_zone_t)	statelink;
David Lawrence's avatar
tabify  
David Lawrence committed
219
	dns_zonelist_t		*statelist;
220
	/*
221
	 * Optional per-zone statistics counters (NULL if not present).
222
	 */
Brian Wellington's avatar
Brian Wellington committed
223
	isc_uint64_t	    *counters;
224 225
};

226
#define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
227 228 229 230 231 232 233 234
#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)
235
	/* XXX MPA these may need to go back into zone.h */
David Lawrence's avatar
tabify  
David Lawrence committed
236 237
#define DNS_ZONEFLG_REFRESH	0x00000001U	/* refresh check in progress */
#define DNS_ZONEFLG_NEEDDUMP	0x00000002U	/* zone need consolidation */
238
#define DNS_ZONEFLG_USEVC	0x00000004U	/* use tcp for refresh query */
239
#define DNS_ZONEFLG_DUMPING	0x00000008U	/* a dump is in progress */
240
#define DNS_ZONEFLG_HASINCLUDE	0x00000010U	/* $INCLUDE in zone file */
David Lawrence's avatar
tabify  
David Lawrence committed
241 242 243
#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 */
244
#define DNS_ZONEFLG_NEEDREFRESH	0x00000100U	/* refresh check needed */
245
#define DNS_ZONEFLG_UPTODATE	0x00000200U	/* zone contents are
246
						 * uptodate */
247
#define DNS_ZONEFLG_NEEDNOTIFY	0x00000400U	/* need to send out notify
Mark Andrews's avatar
Mark Andrews committed
248
						 * messages */
249
#define DNS_ZONEFLG_DIFFONRELOAD 0x00000800U	/* generate a journal diff on
250
						 * reload */
251
#define DNS_ZONEFLG_NOMASTERS	0x00001000U	/* an attempt to refresh a
252 253
						 * zone with no masters
						 * occured */
254 255 256 257 258
#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) */
259
#define DNS_ZONEFLG_FORCEXFER   0x00008000U     /* Force a zone xfer */
Mark Andrews's avatar
Mark Andrews committed
260 261 262
#define DNS_ZONEFLG_NOREFRESH	0x00010000U
#define DNS_ZONEFLG_DIALNOTIFY	0x00020000U
#define DNS_ZONEFLG_DIALREFRESH	0x00040000U
263
#define DNS_ZONEFLG_SHUTDOWN	0x00080000U
264
#define DNS_ZONEFLAG_NOIXFR	0x00100000U	/* IXFR failed, force AXFR */
265
#define DNS_ZONEFLG_FLUSH	0x00200000U
266
#define DNS_ZONEFLG_NOEDNS	0x00400000U
267
#define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U
268

Mark Andrews's avatar
Mark Andrews committed
269
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
270

271 272 273
/* Flags for zone_load() */
#define DNS_ZONELOADFLAG_NOSTAT	0x00000001U	/* Do not stat() master files */

274
struct dns_zonemgr {
275
	unsigned int		magic;
276
	isc_mem_t *		mctx;
Mark Andrews's avatar
Mark Andrews committed
277
	int			refs;		/* Locked by rwlock */
278 279
	isc_taskmgr_t *		taskmgr;
	isc_timermgr_t *	timermgr;
280
	isc_socketmgr_t *	socketmgr;
281
	isc_taskpool_t *	zonetasks;
282
	isc_task_t *		task;
283
	isc_ratelimiter_t *	rl;
284
	isc_rwlock_t		rwlock;
285 286
	isc_mutex_t		iolock;

287
	/* Locked by rwlock. */
288 289 290
	dns_zonelist_t		zones;
	dns_zonelist_t		waiting_for_xfrin;
	dns_zonelist_t		xfrin_in_progress;
291

292
	/* Configuration data. */
293 294
	isc_uint32_t		transfersin;
	isc_uint32_t		transfersperns;
295
	unsigned int		serialqueryrate;
296 297 298 299 300 301

	/* Locked by iolock */
	isc_uint32_t		iolimit;
	isc_uint32_t		ioactive;
	dns_iolist_t		high;
	dns_iolist_t		low;
302 303
};

Mark Andrews's avatar
Mark Andrews committed
304 305 306
/*
 * Hold notify state.
 */
307
struct dns_notify {
308
	unsigned int		magic;
Mark Andrews's avatar
Mark Andrews committed
309
	unsigned int		flags;
310
	isc_mem_t		*mctx;
Mark Andrews's avatar
Mark Andrews committed
311 312 313 314
	dns_zone_t		*zone;
	dns_adbfind_t		*find;
	dns_request_t		*request;
	dns_name_t		ns;
315
	isc_sockaddr_t		dst;
316 317 318
	ISC_LINK(dns_notify_t)	link;
};

Mark Andrews's avatar
Mark Andrews committed
319 320
#define DNS_NOTIFY_NOSOA	0x0001U

321 322 323 324 325 326 327
/*
 *	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 {
328
	unsigned int		magic;
David Lawrence's avatar
tabify  
David Lawrence committed
329
	isc_mem_t		*mctx;
330 331 332
	dns_zone_t		*zone;
	dns_db_t		*db;
	dns_dbversion_t		*version;
Mark Andrews's avatar
Mark Andrews committed
333 334
};

335 336 337 338
/*
 *	Hold load state.
 */
struct dns_load {
339
	unsigned int		magic;
340 341 342 343 344 345 346
	isc_mem_t		*mctx;
	dns_zone_t		*zone;
	dns_db_t		*db;
	isc_time_t		loadtime;
	dns_rdatacallbacks_t	callbacks;
};

347 348 349 350
/*
 *	Hold forward state.
 */
struct dns_forward {
351
	unsigned int		magic;
352 353 354 355 356 357 358
	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;
Mark Andrews's avatar
Mark Andrews committed
359
	void			*callback_arg;
360 361
};

362 363 364 365
/*
 *	Hold IO request state.
 */
struct dns_io {
366
	unsigned int	magic;
367 368 369 370 371 372 373
	dns_zonemgr_t	*zmgr;
	isc_boolean_t	high;
	isc_task_t	*task;
	ISC_LINK(dns_io_t) link;
	isc_event_t	*event;
};

374 375
#define SEND_BUFFER_SIZE 2048

376
static void zone_settimer(dns_zone_t *, isc_time_t *);
377
static void cancel_refresh(dns_zone_t *);
378
static void zone_debuglog(dns_zone_t *zone, const char *, int debuglevel,
379 380 381
			  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);
382
static void queue_xfrin(dns_zone_t *zone);
Mark Andrews's avatar
Mark Andrews committed
383 384
static void zone_unload(dns_zone_t *zone);
static void zone_expire(dns_zone_t *zone);
385
static void zone_iattach(dns_zone_t *source, dns_zone_t **target);
386
static void zone_idetach(dns_zone_t **zonep);
Mark Andrews's avatar
Mark Andrews committed
387
static isc_result_t zone_replacedb(dns_zone_t *zone, dns_db_t *db,
Brian Wellington's avatar
Brian Wellington committed
388
				   isc_boolean_t dump);
389 390
static inline void zone_attachdb(dns_zone_t *zone, dns_db_t *db);
static inline void zone_detachdb(dns_zone_t *zone);
391
static isc_result_t default_journal(dns_zone_t *zone);
392
static void zone_xfrdone(dns_zone_t *zone, isc_result_t result);
393 394
static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db,
				  isc_time_t loadtime, isc_result_t result);
395
static void zone_needdump(dns_zone_t *zone, unsigned int delay);
396
static void zone_shutdown(isc_task_t *, isc_event_t *);
397 398 399
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);
400 401 402 403 404 405

#if 0
/* ondestroy example */
static void dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event);
#endif

406
static void refresh_callback(isc_task_t *, isc_event_t *);
407
static void stub_callback(isc_task_t *, isc_event_t *);
408 409
static void queue_soa_query(dns_zone_t *zone);
static void soa_query(isc_task_t *, isc_event_t *);
410 411
static void ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset,
		     dns_stub_t *stub);
412 413
static int message_count(dns_message_t *msg, dns_section_t section,
			 dns_rdatatype_t type);
414
static void notify_cancel(dns_zone_t *zone);
415 416
static void notify_find_address(dns_notify_t *notify);
static void notify_send(dns_notify_t *notify);
Mark Andrews's avatar
Mark Andrews committed
417 418 419
static isc_result_t notify_createmessage(dns_zone_t *zone,
					 unsigned int flags,
					 dns_message_t **messagep);
Mark Andrews's avatar
Mark Andrews committed
420
static void notify_done(isc_task_t *task, isc_event_t *event);
421
static void notify_send_toaddr(isc_task_t *task, isc_event_t *event);
422
static isc_result_t zone_dump(dns_zone_t *, isc_boolean_t);
423
static void got_transfer_quota(isc_task_t *task, isc_event_t *event);
David Lawrence's avatar
David Lawrence committed
424 425
static isc_result_t zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr,
					     dns_zone_t *zone);
426
static void zmgr_resume_xfrs(dns_zonemgr_t *zmgr, isc_boolean_t multi);
427
static void zonemgr_free(dns_zonemgr_t *zmgr);
428 429 430 431 432
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);
433

434
static isc_result_t
435
zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount,
436 437
		 unsigned int *soacount, isc_uint32_t *serial,
		 isc_uint32_t *refresh, isc_uint32_t *retry,
438 439
		 isc_uint32_t *expire, isc_uint32_t *minimum,
		 unsigned int *cnames);
440

441
static void zone_freedbargs(dns_zone_t *zone);
442
static void forward_callback(isc_task_t *task, isc_event_t *event);
443 444
static void zone_saveunique(dns_zone_t *zone, const char *path,
			    const char *templat);
445 446
static void zone_maintenance(dns_zone_t *zone);
static void zone_notify(dns_zone_t *zone);
447
static void dump_done(void *arg, isc_result_t result);
448

449
#define ENTER zone_debuglog(zone, me, 1, "enter")
450

451 452
static const unsigned int dbargc_default = 1;
static const char *dbargv_default[] = { "rbt" };
453

454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
#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)

482 483 484 485
/***
 ***	Public functions.
 ***/

486
isc_result_t
487
dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
Andreas Gustafsson's avatar
Andreas Gustafsson committed
488
	isc_result_t result;
489
	dns_zone_t *zone;
490

491 492 493
	REQUIRE(zonep != NULL && *zonep == NULL);
	REQUIRE(mctx != NULL);

Andreas Gustafsson's avatar
Andreas Gustafsson committed
494
	zone = isc_mem_get(mctx, sizeof(*zone));
495
	if (zone == NULL)
496
		return (ISC_R_NOMEMORY);
497

Andreas Gustafsson's avatar
Andreas Gustafsson committed
498 499
	result = isc_mutex_init(&zone->lock);
	if (result != ISC_R_SUCCESS) {
Andreas Gustafsson's avatar
Andreas Gustafsson committed
500
		isc_mem_put(mctx, zone, sizeof(*zone));
501 502
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_mutex_init() failed: %s",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
503
				 isc_result_totext(result));
504
		return (ISC_R_UNEXPECTED);
505 506 507
	}

	/* XXX MPA check that all elements are initialised */
Mark Andrews's avatar
Mark Andrews committed
508
	zone->mctx = NULL;
509 510 511
#ifdef DNS_ZONE_CHECKLOCK
	zone->locked = ISC_FALSE;
#endif
Mark Andrews's avatar
Mark Andrews committed
512 513
	isc_mem_attach(mctx, &zone->mctx);
	zone->db = NULL;
514 515
	zone->zmgr = NULL;
	ISC_LINK_INIT(zone, link);
516
	isc_refcount_init(&zone->erefs, 1);	/* Implicit attach. */
517
	zone->irefs = 0;
518
	dns_name_init(&zone->origin, NULL);
519
	zone->masterfile = NULL;
520
	zone->keydirectory = NULL;
521
	zone->journalsize = -1;
522
	zone->journal = NULL;
523 524 525
	zone->rdclass = dns_rdataclass_none;
	zone->type = dns_zone_none;
	zone->flags = 0;
526
	zone->options = 0;
527 528
	zone->db_argc = 0;
	zone->db_argv = NULL;
529 530 531
	isc_time_settoepoch(&zone->expiretime);
	isc_time_settoepoch(&zone->refreshtime);
	isc_time_settoepoch(&zone->dumptime);
532
	isc_time_settoepoch(&zone->loadtime);
533
	zone->serial = 0;
534 535
	zone->refresh = DNS_ZONE_DEFAULTREFRESH;
	zone->retry = DNS_ZONE_DEFAULTRETRY;
536 537
	zone->expire = 0;
	zone->minimum = 0;
538 539 540 541
	zone->maxrefresh = DNS_ZONE_MAXREFRESH;
	zone->minrefresh = DNS_ZONE_MINREFRESH;
	zone->maxretry = DNS_ZONE_MAXRETRY;
	zone->minretry = DNS_ZONE_MINRETRY;
542
	zone->masters = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
543
	zone->masterkeynames = NULL;
544 545 546
	zone->masterscnt = 0;
	zone->curmaster = 0;
	zone->notify = NULL;
547
	zone->notifytype = dns_notifytype_yes;
548 549 550
	zone->notifycnt = 0;
	zone->task = NULL;
	zone->update_acl = NULL;
551
	zone->forward_acl = NULL;
552
	zone->notify_acl = NULL;
553 554
	zone->query_acl = NULL;
	zone->xfr_acl = NULL;
555
	zone->update_disabled = ISC_FALSE;
556
	zone->check_names = dns_severity_ignore;
Mark Andrews's avatar
Mark Andrews committed
557
	zone->request = NULL;
558
	zone->lctx = NULL;
559
	zone->readio = NULL;
560 561
	zone->dctx = NULL;
	zone->writeio = NULL;
562
	zone->timer = NULL;
563 564
	zone->idlein = DNS_DEFAULT_IDLEIN;
	zone->idleout = DNS_DEFAULT_IDLEOUT;
Mark Andrews's avatar
Mark Andrews committed
565
	ISC_LIST_INIT(zone->notifies);
566 567
	isc_sockaddr_any(&zone->notifysrc4);
	isc_sockaddr_any6(&zone->notifysrc6);
568 569
	isc_sockaddr_any(&zone->xfrsource4);
	isc_sockaddr_any6(&zone->xfrsource6);
570 571
	isc_sockaddr_any(&zone->altxfrsource4);
	isc_sockaddr_any6(&zone->altxfrsource6);
572
	zone->xfr = NULL;
573
	zone->tsigkey = NULL;
Mark Andrews's avatar
Mark Andrews committed
574 575
	zone->maxxfrin = MAX_XFER_TIME;
	zone->maxxfrout = MAX_XFER_TIME;
576
	zone->ssutable = NULL;
577
	zone->sigvalidityinterval = 30 * 24 * 3600;
578
	zone->view = NULL;
579
	zone->acache = NULL;
580 581
	ISC_LINK_INIT(zone, statelink);
	zone->statelist = NULL;
582
	zone->counters = NULL;
583

584
	zone->magic = ZONE_MAGIC;
585 586

	/* Must be after magic is set. */
587
	result = dns_zone_setdbtype(zone, dbargc_default, dbargv_default);
588 589
	if (result != ISC_R_SUCCESS)
		goto free_mutex;
Mark Andrews's avatar
Mark Andrews committed
590

591 592 593
	ISC_EVENT_INIT(&zone->ctlevent, sizeof(zone->ctlevent), 0, NULL,
		       DNS_EVENT_ZONECONTROL, zone_shutdown, zone, zone,
		       NULL, NULL);
594
	*zonep = zone;
595
	return (ISC_R_SUCCESS);
596 597

 free_mutex:
598
	DESTROYLOCK(&zone->lock);
599
	return (ISC_R_NOMEMORY);
600 601
}

602 603 604 605
/*
 * Free a zone.  Because we require that there be no more
 * outstanding events or references, no locking is necessary.
 */
606 607
static void
zone_free(dns_zone_t *zone) {
Mark Andrews's avatar
Mark Andrews committed
608
	isc_mem_t *mctx = NULL;
609

610
	REQUIRE(DNS_ZONE_VALID(zone));
611
	REQUIRE(isc_refcount_current(&zone->erefs) == 0);
612
	REQUIRE(zone->irefs == 0);
613
	REQUIRE(!LOCKED_ZONE(zone));
614
	REQUIRE(zone->timer == NULL);
615

616 617 618
	/*
	 * Managed objects.  Order is important.
	 */
619 620
	if (zone->request != NULL)
		dns_request_destroy(&zone->request); /* XXXMPA */
621
	INSIST(zone->readio == NULL);
622
	INSIST(zone->statelist == NULL);
623
	INSIST(zone->writeio == NULL);
624

625
	if (zone->task != NULL)
626 627 628
		isc_task_detach(&zone->task);
	if (zone->zmgr)
		dns_zonemgr_releasezone(zone->zmgr, zone);
629

630
	/* Unmanaged objects */
631 632 633
	if (zone->masterfile != NULL)
		isc_mem_free(zone->mctx, zone->masterfile);
	zone->masterfile = NULL;
634 635 636
	if (zone->keydirectory != NULL)
		isc_mem_free(zone->mctx, zone->keydirectory);
	zone->keydirectory = NULL;
637
	zone->journalsize = -1;
638 639 640
	if (zone->journal != NULL)
		isc_mem_free(zone->mctx, zone->journal);
	zone->journal = NULL;
641
	if (zone->counters != NULL)
642
		dns_stats_freecounters(zone->mctx, &zone->counters);
Mark Andrews's avatar
Mark Andrews committed
643
	if (zone->db != NULL)
644 645 646
		zone_detachdb(zone);
	if (zone->acache != NULL)
		dns_acache_detach(&zone->acache);
647
	zone_freedbargs(zone);
648 649 650 651
	RUNTIME_CHECK(dns_zone_setmasterswithkeys(zone, NULL, NULL, 0)
		      == ISC_R_SUCCESS);
	RUNTIME_CHECK(dns_zone_setalsonotify(zone, NULL, 0)
		      == ISC_R_SUCCESS);
652
	zone->check_names = dns_severity_ignore;
653
	if (zone->update_acl != NULL)
654
		dns_acl_detach(&zone->update_acl);
655 656
	if (zone->forward_acl != NULL)
		dns_acl_detach(&zone->forward_acl);
657 658
	if (zone->notify_acl != NULL)
		dns_acl_detach(&zone->notify_acl);
659
	if (zone->query_acl != NULL)
660
		dns_acl_detach(&zone->query_acl);
661
	if (zone->xfr_acl != NULL)
662
		dns_acl_detach(&zone->xfr_acl);
663 664
	if (dns_name_dynamic(&zone->origin))
		dns_name_free(&zone->origin, zone->mctx);
665
	if (zone->ssutable != NULL)
666
		dns_ssutable_detach(&zone->ssutable);
667 668

	/* last stuff */
669
	DESTROYLOCK(&zone->lock);
670
	isc_refcount_destroy(&zone->erefs);
671
	zone->magic = 0;
Mark Andrews's avatar
Mark Andrews committed
672
	mctx = zone->mctx;
Andreas Gustafsson's avatar
Andreas Gustafsson committed
673
	isc_mem_put(mctx, zone, sizeof(*zone));
Mark Andrews's avatar
Mark Andrews committed
674
	isc_mem_detach(&mctx);
675 676 677 678 679 680 681
}

/*
 *	Single shot.
 */
void
dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) {
682 683

	REQUIRE(DNS_ZONE_VALID(zone));
684
	REQUIRE(rdclass != dns_rdataclass_none);
685

686 687 688
	/*
	 * Test and set.
	 */
689
	LOCK_ZONE(zone);
690 691 692
	REQUIRE(zone->rdclass == dns_rdataclass_none ||
		zone->rdclass == rdclass);
	zone->rdclass = rdclass;
693
	UNLOCK_ZONE(zone);
694 695
}

696 697 698 699 700 701 702
dns_rdataclass_t
dns_zone_getclass(dns_zone_t *zone){
	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->rdclass);
}

703 704 705 706
void
dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) {
	REQUIRE(DNS_ZONE_VALID(zone));

707
	LOCK_ZONE(zone);
708
	zone->notifytype = notifytype;
709
	UNLOCK_ZONE(zone);
710 711
}

712 713 714 715 716
/*
 *	Single shot.
 */
void
dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type) {
717 718

	REQUIRE(DNS_ZONE_VALID(zone));
719
	REQUIRE(type != dns_zone_none);
720

721 722 723
	/*
	 * Test and set.
	 */
724
	LOCK_ZONE(zone);
725 726
	REQUIRE(zone->type == dns_zone_none || zone->type == type);
	zone->type = type;
727
	UNLOCK_ZONE(zone);
728 729
}

730 731 732 733 734 735 736 737 738
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,
Andreas Gustafsson's avatar
Andreas Gustafsson committed
739
			    zone->db_argc * sizeof(*zone->db_argv));
740 741 742 743 744
	}
	zone->db_argc = 0;
	zone->db_argv = NULL;
}

745
isc_result_t
746
dns_zone_setdbtype(dns_zone_t *zone,
747
		   unsigned int dbargc, const char * const *dbargv) {
748
	isc_result_t result = ISC_R_SUCCESS;
749 750
	char **new = NULL;
	unsigned int i;
751

752
	REQUIRE(DNS_ZONE_VALID(zone));
753 754
	REQUIRE(dbargc >= 1);
	REQUIRE(dbargv != NULL);
755

756
	LOCK_ZONE(zone);
757 758

	/* Set up a new database argument list. */
Andreas Gustafsson's avatar
Andreas Gustafsson committed
759
	new = isc_mem_get(zone->mctx, dbargc * sizeof(*new));
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
	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;
Mark Andrews's avatar
Mark Andrews committed
777

778 779 780 781 782
 nomem:
	if (new != NULL) {
		for (i = 0; i < dbargc; i++) {
			if (zone->db_argv[i] != NULL)
				isc_mem_free(zone->mctx, new[i]);
Mark Andrews's avatar
<