server.c 33.4 KB
Newer Older
1
/*
Bob Halley's avatar
Bob Halley committed
2
 * Copyright (C) 1999, 2000  Internet Software Consortium.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 * 
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

#include <config.h>

20
21
22
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
23
24
25
26
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
Bob Halley's avatar
Bob Halley committed
27
#include <stdarg.h>
28

29
#include <isc/app.h>
30
#include <isc/assertions.h>
31
#include <isc/dir.h>
32
33
34
#include <isc/error.h>
#include <isc/mem.h>
#include <isc/result.h>
35
#include <isc/rwlock.h>
36
#include <isc/socket.h>
37
38
#include <isc/task.h>
#include <isc/thread.h>
39
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
40
#include <isc/util.h>
41

42
#include <dns/acl.h>
43
#include <dns/aclconf.h>
44
#include <dns/cache.h>
45
46
47
#include <dns/confacl.h>
#include <dns/confctx.h>
#include <dns/confip.h>
48
#include <dns/confparser.h>
49
#include <dns/db.h>
Bob Halley's avatar
Bob Halley committed
50
#include <dns/dispatch.h>
51
52
#include <dns/fixedname.h>
#include <dns/journal.h>
53
#include <dns/master.h>
54
55
#include <dns/name.h>
#include <dns/rdata.h>
56
#include <dns/resolver.h>
57
#include <dns/result.h>
58
#include <dns/rootns.h>
59
60
#include <dns/tkeyconf.h>
#include <dns/tsigconf.h>
61
#include <dns/types.h>
62
#include <dns/view.h>
63
#include <dns/zone.h>
64
#include <dns/zoneconf.h>
65

66
#include <named/client.h>
Bob Halley's avatar
Bob Halley committed
67
#include <named/globals.h>
68
69
#include <named/interfacemgr.h>
#include <named/listenlist.h>
70
#include <named/log.h>
71
#include <named/os.h>
Bob Halley's avatar
Bob Halley committed
72
#include <named/server.h>
73
#include <named/types.h>
74

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
 * Check an operation for failure.  Assumes that the function
 * using it has a 'result' variable and a 'cleanup' label.
 */
#define CHECK(op) \
	do { result = (op); 				  	 \
	       if (result != ISC_R_SUCCESS) goto cleanup; 	 \
	} while (0)

#define CHECKM(op, msg) \
	do { result = (op); 				  	  \
	       if (result != ISC_R_SUCCESS) {			  \
			isc_log_write(ns_g_lctx,		  \
				      NS_LOGCATEGORY_GENERAL,	  \
				      NS_LOGMODULE_SERVER,	  \
				      ISC_LOG_ERROR,		  \
				      "%s: %s", msg,		  \
				      isc_result_totext(result)); \
			goto cleanup;				  \
		}						  \
	} while (0)						  \

#define CHECKFATAL(op, msg) \
	do { result = (op); 				  	  \
	       if (result != ISC_R_SUCCESS)			  \
			fatal(msg, result);			  \
	} while (0)						  \

103
104
105
typedef struct {
	isc_mem_t *		mctx;
	dns_viewlist_t		viewlist;
106
	dns_aclconfctx_t	*aclconf;
107
} ns_load_t;
108

109
static void fatal(char *msg, isc_result_t result);
110
static void ns_server_reload(isc_task_t *task, isc_event_t *event);
111

112
113
114
115
116
117
118
119
static isc_result_t
ns_listenelt_fromconfig(dns_c_lstnon_t *celt, dns_c_ctx_t *cctx,
			dns_aclconfctx_t *actx,
			isc_mem_t *mctx, ns_listenelt_t **target);
static isc_result_t
ns_listenlist_fromconfig(dns_c_lstnlist_t *clist, dns_c_ctx_t *cctx,
			 dns_aclconfctx_t *actx,
			 isc_mem_t *mctx, ns_listenlist_t **target);
120

121
122
123
124
125
/*
 * Configure 'view' according to 'cctx'.
 *
 * XXX reconfiguration should preserve cache contents.
 */
126
static isc_result_t
Bob Halley's avatar
Bob Halley committed
127
128
configure_view(dns_view_t *view, dns_c_ctx_t *cctx, isc_mem_t *mctx,
	       dns_dispatch_t *dispatch)
129
{
130
	dns_cache_t *cache;
131
	isc_result_t result;
132
	isc_int32_t cleaning_interval;
Brian Wellington's avatar
Brian Wellington committed
133
	dns_tsig_keyring_t *ring;
134
135
136
137
138
139
	dns_c_forw_t forward;
	dns_c_iplist_t *forwarders;
	dns_fwdpolicy_t fwdpolicy;
	isc_sockaddrlist_t addresses;
	isc_sockaddr_t *sa, *next_sa;
	unsigned int i;
140

141
	REQUIRE(DNS_VIEW_VALID(view));
142

143
144
	ISC_LIST_INIT(addresses);

145
146
	RWLOCK(&view->conflock, isc_rwlocktype_write);
	
147
148
149
	/*
	 * Cache.
	 */
150
	cache = NULL;
151
152
	CHECK(dns_cache_create(mctx, ns_g_taskmgr, ns_g_timermgr,
			       view->rdclass, "rbt", 0, NULL, &cache));
153
	dns_view_setcache(view, cache);
154
155
156
	cleaning_interval = 3600; /* Default is 1 hour. */
	(void) dns_c_ctx_getcleaninterval(cctx, &cleaning_interval);
	dns_cache_setcleaninginterval(cache, cleaning_interval);
157
	dns_cache_detach(&cache);
158

Bob Halley's avatar
Bob Halley committed
159
160
161
162
163
164
165
166
	/*
	 * XXXRTH  Temporary support for loading cache contents.
	 */
	if (ns_g_cachefile != NULL) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_SERVER,
			      ISC_LOG_DEBUG(1), "loading cache '%s'",
			      ns_g_cachefile);
167
		CHECK(dns_db_load(view->cachedb, ns_g_cachefile));
Bob Halley's avatar
Bob Halley committed
168
169
	}

170
171
172
	/*
	 * Resolver.
	 *
Bob Halley's avatar
Bob Halley committed
173
	 * XXXRTH  Hardwired number of tasks.
174
	 */
175
176
	CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31,
				      ns_g_socketmgr, ns_g_timermgr,
Bob Halley's avatar
Bob Halley committed
177
				      0, dispatch, NULL));
178

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
	/*
	 * Set resolver forwarding policy.
	 */
	if (dns_c_ctx_getforwarders(cctx, &forwarders) == ISC_R_SUCCESS) {
		fwdpolicy = dns_fwdpolicy_first;
		/*
		 * Ugh.  Convert between list formats.
		 */
		for (i = 0; i < forwarders->nextidx; i++) {
			sa = isc_mem_get(view->mctx, sizeof *sa);
			if (sa == NULL) {
				result = ISC_R_NOMEMORY;
				goto cleanup;
			}
			*sa = forwarders->ips[i];
			isc_sockaddr_setport(sa, 53);
			ISC_LINK_INIT(sa, link);
			ISC_LIST_APPEND(addresses, sa, link);
		}
		INSIST(!ISC_LIST_EMPTY(addresses));
199
		dns_c_iplist_detach(&forwarders);
200
201
202
203
204
205
206
207
208
209
210
211
212
213
		CHECK(dns_resolver_setforwarders(view->resolver, &addresses));
		/*
		 * XXXRTH  The configuration type 'dns_c_forw_t' should be
		 *         elminated.
		 */
		if (dns_c_ctx_getforward(cctx, &forward) == ISC_R_SUCCESS) {
			INSIST(forward == dns_c_forw_first ||
			       forward == dns_c_forw_only);
			if (forward == dns_c_forw_only)
				fwdpolicy = dns_fwdpolicy_only;
		}
		CHECK(dns_resolver_setfwdpolicy(view->resolver, fwdpolicy));
	}

214
	/*
215
	 * We have default hints for class IN if we need them.
216
	 */
217
	if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
218
		dns_view_sethints(view, ns_g_server->roothints);
219

Brian Wellington's avatar
Brian Wellington committed
220
	/*
221
	 * Configure the view's TSIG keys.
Brian Wellington's avatar
Brian Wellington committed
222
223
	 */
	ring = NULL;
224
	CHECK(dns_tsigkeyring_fromconfig(cctx, view->mctx, &ring));
Brian Wellington's avatar
Brian Wellington committed
225
226
	dns_view_setkeyring(view, ring);

227
228
229
230
231
232
233
234
235
236
237
238
239
240
	/*
	 * Configure the view's peer list.
	 */
	{
		dns_peerlist_t *newpeers = NULL;
		if (cctx->peers != NULL) {
			dns_peerlist_attach(cctx->peers, &newpeers);
		} else {
			CHECK(dns_peerlist_new(mctx, &newpeers));
		}
		dns_peerlist_detach(&view->peers);
		view->peers = newpeers; /* Transfer ownership. */
	}
	
241
 cleanup:
242
	RWUNLOCK(&view->conflock, isc_rwlocktype_write);
243
244
245
246
247
248
249
250

	for (sa = ISC_LIST_HEAD(addresses);
	     sa != NULL;
	     sa = next_sa) {
		next_sa = ISC_LIST_NEXT(sa, link);
		isc_mem_put(view->mctx, sa, sizeof *sa);
	}

251
252
253
	return (result);
}

254
255
256
257
258
259
260
261
/*
 * Create the special view that handles queries for
 * "version.bind. CH".   The version string returned is that
 * configured in 'configctx', or a compiled-in default if
 * there is no "version" configuration option.
 */
static isc_result_t
create_version_view(dns_c_ctx_t *configctx, dns_view_t **viewp) {
262
	isc_result_t result;
263
264
265
266
267
268
269
	dns_db_t *db = NULL;
	dns_zone_t *zone = NULL;
	dns_dbversion_t *dbver = NULL;
	dns_difftuple_t *tuple = NULL;
	dns_diff_t diff;
	dns_view_t *view = NULL;
	char *versiontext;
270
	unsigned char buf[256];
271
272
273
	isc_region_t r;
	size_t len;
	dns_rdata_t rdata;
274
275
	static unsigned char origindata[] = "\007version\004bind";
	dns_name_t origin;
276
277
278
279
280

	REQUIRE(viewp != NULL && *viewp == NULL);

	dns_diff_init(ns_g_mctx, &diff);

281
282
283
284
285
	dns_name_init(&origin, NULL);
	r.base = origindata;
	r.length = sizeof(origindata);
	dns_name_fromregion(&origin, &r);

286
287
288
289
290
291
292
293
294
295
296
297
298
	(void) dns_c_ctx_getversion(configctx, &versiontext);
	if (versiontext == NULL)
		versiontext = ns_g_version;
	len = strlen(versiontext);
	if (len > 255)
		len = 255; /* Silently truncate. */
	buf[0] = len;
	memcpy(buf + 1, versiontext, len);

	r.base = buf;
	r.length = 1 + len;
	dns_rdata_fromregion(&rdata, dns_rdataclass_ch, dns_rdatatype_txt, &r);

299
300
	CHECK(dns_zone_create(&zone, ns_g_mctx));
	CHECK(dns_zone_setorigin(zone, &origin));
301

302
303
304
305
	CHECK(dns_db_create(ns_g_mctx, "rbt", &origin, ISC_FALSE,
			    dns_rdataclass_ch, 0, NULL, &db));
	
	CHECK(dns_db_newversion(db, &dbver));
306

307
308
	CHECK(dns_difftuple_create(ns_g_mctx, DNS_DIFFOP_ADD, &origin,
				   0, &rdata, &tuple));
309
	dns_diff_append(&diff, &tuple);
310
	CHECK(dns_diff_apply(&diff, db, dbver));
311
312
313

	dns_db_closeversion(db, &dbver, ISC_TRUE);

314
315
	CHECK(dns_view_create(ns_g_mctx, dns_rdataclass_ch, "_version",
			      &view));
316

317
	CHECK(dns_zone_replacedb(zone, db, ISC_FALSE));
318

319
	CHECK(dns_view_addzone(view, zone));
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342

	dns_view_freeze(view);

	/* Transfer ownership. */
	*viewp = view;
	view = NULL;

	result = ISC_R_SUCCESS;

 cleanup:
	if (view != NULL)
		dns_view_detach(&view);
	if (zone != NULL)
		dns_zone_detach(&zone);
	if (dbver != NULL)
		dns_db_closeversion(db, &dbver, ISC_FALSE);
	if (db != NULL)
		dns_db_detach(&db);
	dns_diff_clear(&diff);

	return (result);
}

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
static isc_result_t
configure_hints(dns_view_t *view, const char *filename) {
	isc_result_t result;
	dns_db_t *db;

	db = NULL;
	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
	if (result == ISC_R_SUCCESS) {
		dns_view_sethints(view, db);
		dns_db_detach(&db);
	}

	return (result);
}

358
359
360
361
/*
 * Configure or reconfigure a zone.  This callback function
 * is called after parsing each "zone" statement in named.conf.
 */
362
static isc_result_t
363
configure_zone(dns_c_ctx_t *cctx, dns_c_zone_t *czone, dns_c_view_t *cview,
364
365
	  void *uap)
{
366
367
368
369
370
371
372
	ns_load_t *lctx = (ns_load_t *) uap;
	dns_view_t *view = NULL;	/* New view */
	dns_view_t *pview = NULL;	/* Production view */
	dns_zone_t *zone = NULL;	/* New or reused zone */
	dns_zone_t *tzone = NULL;	/* Temporary zone */
	char *viewname;
	
373
	isc_result_t result;
374

375
376
377
378
	char *corigin;	
	isc_buffer_t buffer;
	dns_fixedname_t fixorigin;
	dns_name_t *origin;
379

380
	/*
381
	 * Get the zone origin as a dns_name_t.
382
	 */
383
384
	corigin = NULL;
	/* XXX casting away const */
385
	CHECK(dns_c_zone_getname(czone, (const char **) &corigin));
386
387
	isc_buffer_init(&buffer, corigin, strlen(corigin),
			ISC_BUFFERTYPE_TEXT);
388
389
	isc_buffer_add(&buffer, strlen(corigin));
	dns_fixedname_init(&fixorigin);
390
391
	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
				&buffer, dns_rootname, ISC_FALSE, NULL));
392
393
	origin = dns_fixedname_name(&fixorigin);
	
394
	/*
395
	 * Find or create the view in the new view list.
396
397
	 */
	view = NULL;
398
399
400
401
402
403
404
405
406
407
	if (cview != NULL)
		viewname = cview->name;
	else
		viewname = "_default";
	result = dns_viewlist_find(&lctx->viewlist, viewname,
				   czone->zclass, &view);
	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
		goto cleanup;
	if (view == NULL) {
		dns_view_t *tview = NULL;
408
409
		CHECK(dns_view_create(ns_g_mctx, czone->zclass,
				      viewname, &view));
410
411
412
413
		dns_view_attach(view, &tview);
		ISC_LIST_APPEND(lctx->viewlist, tview, link);
	}

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
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
	/*
	 * Master zones must have 'file' set.
	 */
	if (czone->ztype == dns_c_zone_master &&
	    czone->u.mzone.file == NULL) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
			      "zone '%s': 'file' not specified",
			      corigin);
		result = ISC_R_FAILURE;
		goto cleanup;
	}

	/*
	 * "hints zones" aren't zones.  If we've got one,
	 * configure it and return.
	 */
	if (czone->ztype == dns_c_zone_hint) {
		if (czone->u.hzone.file == NULL) {
			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
				      "zone '%s': 'file' not specified",
				      corigin);
			result = ISC_R_FAILURE;
			goto cleanup;
		}
		if (dns_name_equal(origin, dns_rootname)) {
			result = configure_hints(view, czone->u.hzone.file);
		} else {
			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
				      "ignoring non-root hint zone '%s'",
				      corigin);
			result = ISC_R_SUCCESS;
		}
		goto cleanup;
	}

	/*
	 * "stub zones" aren't zones either.  Eventually we'll
	 * create a "cache freshener" to keep the stub data in the
	 * cache.
	 */
	if (czone->ztype == dns_c_zone_stub) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
	      "stub zone '%s': stub zones are not supported in this release",
			      corigin);
		result = ISC_R_SUCCESS;
		goto cleanup;
	}

	/*
	 * "forward zones" aren't zones either.  Eventually we'll
	 * translate this syntax into the appropriate selective forwarding
	 * configuration.
	 */
	if (czone->ztype == dns_c_zone_forward) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
      "forward zone '%s': forward zones are not supported in this release",
			      corigin);
		result = ISC_R_SUCCESS;
		goto cleanup;
	}

480
481
482
483
484
485
486
487
488
489
	/*
	 * Check for duplicates in the new zone table.
	 */
	result = dns_view_findzone(view, origin, &tzone);
	if (result == ISC_R_SUCCESS) {
		/*
		 * We already have this zone!
		 */
		result = ISC_R_EXISTS;
		goto cleanup;
490
	}
491

492
	/*
493
494
495
496
497
498
499
	 * See if we can reuse an existing zone.  This is
	 * only possible if all of these are true:
	 *   - The zone's view exists
	 *   - A zone with the right name exists in the view
	 *   - The zone is compatible with the config
	 *     options (e.g., an existing master zone cannot 
	 *     be reused if the options specify a slave zone)
500
	 */
Andreas Gustafsson's avatar
Andreas Gustafsson committed
501
502
	result = dns_viewlist_find(&ns_g_server->viewlist,
				   view->name, view->rdclass,
503
504
505
				   &pview);
	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
		goto cleanup;
506
507
508
509
510
511
512
513
	if (pview != NULL)
		result = dns_view_findzone(pview, origin, &zone);
	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
		goto cleanup;
	if (zone != NULL) {
		if (! dns_zone_reusable(zone, czone))
			dns_zone_detach(&zone);
	}
514

515
	/*
516
517
	 * If we cannot reuse an existing zone, we will have to
	 * create a new one.
518
	 */
519
	if (zone == NULL) {
520
521
522
523
		CHECK(dns_zone_create(&zone, lctx->mctx));
		CHECK(dns_zone_setorigin(zone, origin));
		CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
					     zone));
524
525
526
527
528
	}

	/*
	 * Configure the zone.
	 */
529
	CHECK(dns_zone_configure(cctx, lctx->aclconf, czone, zone));
530

531
532
533
534
535
536
	/*
	 * XXX Why was this here?
	 *
	 * if (dns_zone_gettype(zone) == dns_zone_hint)
	 *      INSIST(0);
	 */
537

538
539
540
	/*
	 * Add the zone to its view in the new view list.
	 */
541
	CHECK(dns_view_addzone(view, zone));
542

Bob Halley's avatar
Bob Halley committed
543
 cleanup:
544
545
546
547
548
549
550
551
	if (tzone != NULL)
		dns_zone_detach(&tzone);
	if (zone != NULL)
		dns_zone_detach(&zone);
	if (pview != NULL)
		dns_view_detach(&pview);
	if (view != NULL)
		dns_view_detach(&view);
552
553

	return (result);
554
555
}

556
557
558
559
560
/*
 * Configure a single server ACL at '*aclp'.  Get its configuration by
 * calling 'getacl'.
 */
static isc_result_t
561
562
configure_server_acl(dns_c_ctx_t *cctx, dns_aclconfctx_t *actx, isc_mem_t *mctx,
		     isc_result_t (*getcacl)(dns_c_ctx_t *, dns_c_ipmatchlist_t **),
563
		     dns_acl_t **aclp)
564
{
565
	isc_result_t result = ISC_R_SUCCESS;
566
567
568
569
570
571
	dns_c_ipmatchlist_t *cacl = NULL;
	if (*aclp != NULL)
		dns_acl_detach(aclp);
	(void) (*getcacl)(cctx, &cacl);
	if (cacl != NULL) {
		result = dns_acl_fromconfig(cacl, cctx, actx, mctx, aclp);
572
		dns_c_ipmatchlist_detach(&cacl);
573
	}
574
	return (result);
575
576
}

577
578
579
/*
 * Configure a single server quota.
 */
580
581
582
583
584
585
586
587
588
589
static void
configure_server_quota(dns_c_ctx_t *cctx,
		       isc_result_t (*getquota)(dns_c_ctx_t *, isc_int32_t *),
		       isc_quota_t *quota, int defaultvalue)
{
	isc_int32_t val = defaultvalue;
	(void)(*getquota)(cctx, &val);
	quota->max = val;
}

Bob Halley's avatar
Bob Halley committed
590
591
592
593
594
595
596
597
598
599
600
601
602
static isc_result_t
configure_server_querysource(dns_c_ctx_t *cctx, ns_server_t *server,
			     dns_dispatch_t **dispatchp) {
	isc_result_t result;
	struct in_addr ina;
	isc_sockaddr_t sa, any;
	isc_socket_t *socket;

	ina.s_addr = htonl(INADDR_ANY);
	isc_sockaddr_fromin(&any, &ina, 0);

	*dispatchp = NULL;

603
	if (dns_c_ctx_getquerysource(cctx, &sa) != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
		sa = any;

	/*
	 * XXX  We need to have separate query source options for v4 and v6,
	 *      but right now we only have one option, and the parser allows
	 *      v6 addresses for it.  Until we have a separate v6 option,
	 *      make sure that the query source is v4.
	 */
	if (isc_sockaddr_pf(&sa) != PF_INET)
		return (DNS_R_NOTIMPLEMENTED);

	/*
	 * If we don't support IPv4, we're done!
	 */
	if (isc_net_probeipv4() != ISC_R_SUCCESS)
		return (ISC_R_SUCCESS);

	if (isc_sockaddr_equal(&sa, &any)) {
		/*
		 * The query source is fully wild.  No special dispatcher
		 * work needs to be done.
		 */
		return (ISC_R_SUCCESS);
	}

	/*
	 * If the interface manager has a dispatcher for this address,
	 * use it.
	 */
	if (ns_interfacemgr_findudpdispatcher(server->interfacemgr, &sa,
					      dispatchp) !=
	    ISC_R_SUCCESS) {
		/*
		 * The interface manager doesn't have a matching dispatcher.
		 */
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
		if (server->querysrc_dispatch != NULL) {
			/*
			 * We've already got a custom dispatcher.  If it is
			 * compatible with the new configuration, use it.
			 */
			if (isc_sockaddr_equal(&server->querysrc_address,
					       &sa)) {
				dns_dispatch_attach(server->querysrc_dispatch,
						    dispatchp);
				return (ISC_R_SUCCESS);
			}
			/*
			 * The existing custom dispatcher is not compatible.
			 * We don't need it anymore.
			 */
			dns_dispatch_detach(&server->querysrc_dispatch);
		}
		/*
		 * Create a custom dispatcher.
		 */
		INSIST(server->querysrc_dispatch == NULL);
		server->querysrc_address = sa;
Bob Halley's avatar
Bob Halley committed
661
662
663
664
665
666
667
668
669
670
671
672
673
674
		socket = NULL;
		result = isc_socket_create(ns_g_socketmgr, AF_INET,
					   isc_sockettype_udp,
					   &socket);
		if (result != ISC_R_SUCCESS)
			return (result);
		result = isc_socket_bind(socket, &sa);
		if (result != ISC_R_SUCCESS) {
			isc_socket_detach(&socket);	
			return (result);
		}
		result = dns_dispatch_create(ns_g_mctx, socket,
					     server->task, 4096,
					     1000, 32768, 16411, 16433, NULL,
675
					     &server->querysrc_dispatch);
Bob Halley's avatar
Bob Halley committed
676
677
678
679
680
681
682
		/*
		 * Regardless of whether dns_dispatch_create() succeeded or
		 * failed, we don't need to keep the reference to the socket.
		 */
		isc_socket_detach(&socket);
		if (result != ISC_R_SUCCESS)
			return (result);
683
684
685
686
687
688
689
690
		dns_dispatch_attach(server->querysrc_dispatch, dispatchp);
	} else {
		/*
		 * We're sharing a UDP dispatcher with the interface manager
		 * now.  Any prior custom dispatcher can be discarded.
		 */
		if (server->querysrc_dispatch != NULL)
			dns_dispatch_detach(&server->querysrc_dispatch);
Bob Halley's avatar
Bob Halley committed
691
692
693
694
695
	}

	return (ISC_R_SUCCESS);
}

696
697
698
699
700
701
702
703
/*
 * This function is called as soon as the 'options' statement has been
 * parsed.
 */
static isc_result_t
options_callback(dns_c_ctx_t *cctx, void *uap) {
	isc_result_t result;

Andreas Gustafsson's avatar
Andreas Gustafsson committed
704
	UNUSED(uap);
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725

	/*
	 * Change directory.
	 */
	if (cctx->options != NULL &&
	    cctx->options->directory != NULL) {
		result = isc_dir_chdir(cctx->options->directory);
		if (result != ISC_R_SUCCESS) {
			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
				      NS_LOGMODULE_SERVER,
				      ISC_LOG_ERROR, "change directory "
				      "to '%s' failed: %s",
				      cctx->options->directory,
				      isc_result_totext(result));
			return (result);
		}
	}

	return (ISC_R_SUCCESS);
}

726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747

static void 
scan_interfaces(ns_server_t *server) {
	ns_interfacemgr_scan(server->interfacemgr);
	dns_aclenv_copy(&server->aclenv,
			ns_interfacemgr_getaclenv(server->interfacemgr));
}

/*
 * This event callback is invoked to do periodic network
 * interface scanning.
 */
static void
interface_timer_tick(isc_task_t *task, isc_event_t *event) {
	ns_server_t *server = (ns_server_t *) event->arg;	
	UNUSED(task);
	isc_event_free(&event);
	RWLOCK(&server->conflock, isc_rwlocktype_write);
	scan_interfaces(server);
	RWUNLOCK(&server->conflock, isc_rwlocktype_write);
}

748
static isc_result_t
Bob Halley's avatar
Bob Halley committed
749
750
751
load_configuration(const char *filename, ns_server_t *server,
		   isc_boolean_t first_time)
{
752
753
754
	isc_result_t result;
	ns_load_t lctx;
	dns_c_cbks_t callbacks;
755
	dns_c_ctx_t *configctx;
756
	dns_view_t *view, *view_next;
757
	dns_viewlist_t tmpviewlist;
758
	dns_aclconfctx_t aclconfctx;
Bob Halley's avatar
Bob Halley committed
759
	dns_dispatch_t *dispatch;
Bob Halley's avatar
Bob Halley committed
760
	char *pidfilename;
761
762
	isc_int32_t interface_interval;
	
763
	dns_aclconfctx_init(&aclconfctx);
764

765
766
767
	RWLOCK(&server->conflock, isc_rwlocktype_write);
	dns_zonemgr_lockconf(server->zonemgr, isc_rwlocktype_write);
	
768
	lctx.mctx = ns_g_mctx;
769
	lctx.aclconf = &aclconfctx;
770
	ISC_LIST_INIT(lctx.viewlist);
Bob Halley's avatar
Bob Halley committed
771

772
	callbacks.zonecbk = configure_zone;
773
	callbacks.zonecbkuap = &lctx;
774
	callbacks.optscbk = options_callback;
775
	callbacks.optscbkuap = NULL;
Bob Halley's avatar
Bob Halley committed
776

777
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
Andreas Gustafsson's avatar
Andreas Gustafsson committed
778
779
		      ISC_LOG_INFO, "loading configuration from '%s'",
		      filename);
Bob Halley's avatar
Bob Halley committed
780

781
782
783
	/*
	 * Parse the configuration file creating a parse tree.  Any
	 * 'zone' statements are handled immediately by calling
784
	 * configure_zone() through 'callbacks'.
785
	 */
786
	configctx = NULL;
787
788
789
	CHECK(dns_c_parse_namedconf(filename, ns_g_mctx, &configctx,
				    &callbacks));
	
790
791
792
793
	/*
	 * Configure various server options.
	 */
	(void) dns_c_ctx_getrecursion(configctx, &server->recursion);	
794
	(void) dns_c_ctx_getauthnxdomain(configctx, &server->auth_nxdomain);
Bob Halley's avatar
Bob Halley committed
795
796
	(void) dns_c_ctx_gettransferformat(configctx,
					   &server->transfer_format);
797
	
798
799
800
801
802
803
804
	CHECK(configure_server_acl(configctx, &aclconfctx, ns_g_mctx,
				   dns_c_ctx_getqueryacl, &server->queryacl));
	
	CHECK(configure_server_acl(configctx, &aclconfctx, ns_g_mctx,
				   dns_c_ctx_getrecursionacl,
				   &server->recursionacl));
	
805
	configure_server_quota(configctx, dns_c_ctx_gettransfersout,
806
				     &server->xfroutquota, 10);
807
	configure_server_quota(configctx, dns_c_ctx_gettcpclients,
808
				     &server->tcpquota, 100);
809
	configure_server_quota(configctx, dns_c_ctx_getrecursiveclients,
810
				     &server->recursionquota, 100);
811
812
813
814
815
816
817
818
819
820
821
822
823
824

	/*
	 * Configure the interface manager according to the "listen-on"
	 * statement.
	 */
	{
		dns_c_lstnlist_t *clistenon = NULL;
		ns_listenlist_t *listenon = NULL;

		(void) dns_c_ctx_getlistenlist(configctx, &clistenon);
		if (clistenon != NULL) {
			result = ns_listenlist_fromconfig(clistenon,
							  configctx,
							  &aclconfctx,
Bob Halley's avatar
Bob Halley committed
825
826
							  ns_g_mctx,
							  &listenon);
827
828
		} else {
			/* Not specified, use default. */
829
830
			CHECK(ns_listenlist_default(ns_g_mctx, ns_g_port,
						    &listenon));
831
832
833
834
835
		}
		ns_interfacemgr_setlistenon(server->interfacemgr, listenon);
		ns_listenlist_detach(&listenon);
	}

Bob Halley's avatar
Bob Halley committed
836
837
838
839
840
841
	/*
	 * Rescan the interface list to pick up changes in the
	 * listen-on option.  It's important that we do this before we try
	 * to configure the query source, since the dispatcher we use might
	 * be shared with an interface.
	 */
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
	scan_interfaces(server);

	/*
	 * Arrange for further interface scanning to occur periodically
	 * as specified by the "interface-interval" option.
	 */
	interface_interval = 3600; /* Default is 1 hour. */
	(void) dns_c_ctx_getinterfaceinterval(configctx, &interface_interval);
	if (interface_interval == 0) {
		isc_timer_reset(server->interface_timer, isc_timertype_inactive,
				NULL, NULL, ISC_TRUE);
	} else {
		isc_interval_t interval;
		isc_interval_set(&interval, interface_interval, 0);
		isc_timer_reset(server->interface_timer, isc_timertype_ticker,
				NULL, &interval, ISC_FALSE);
	}
Bob Halley's avatar
Bob Halley committed
859
860
861
862

	dispatch = NULL;
	CHECK(configure_server_querysource(configctx, server, &dispatch));

863
	/*
864
865
	 * If we haven't created any views, create a default view for class
	 * IN.  (We're a caching-only server.)
866
	 */
867
868
	if (ISC_LIST_EMPTY(lctx.viewlist)) {
		view = NULL;
869
870
871
		CHECKM(dns_view_create(ns_g_mctx, dns_rdataclass_in, 
				       "_default", &view),
		       "creating default view");
872
873
		ISC_LIST_APPEND(lctx.viewlist, view, link);
	}
874

875
	/*
876
877
878
	 * Configure and freeze the views.  Their zone tables have
	 * already been filled in at parsing time, but other stuff
	 * like the resolvers are still unconfigured.
879
880
881
882
	 */
	for (view = ISC_LIST_HEAD(lctx.viewlist);
	     view != NULL;
	     view = ISC_LIST_NEXT(view, link))
883
	{
Bob Halley's avatar
Bob Halley committed
884
		CHECK(configure_view(view, configctx, ns_g_mctx, dispatch));
885
		dns_view_freeze(view);
886
	}
Bob Halley's avatar
Bob Halley committed
887
888
889
890
891
892

	/*
	 * We don't need dispatch anymore.
	 */
	if (dispatch != NULL)
		dns_dispatch_detach(&dispatch);
893
	
894
	/*
895
	 * Create (or recreate) the version view.
896
897
	 */
	view = NULL;
898
	CHECK(create_version_view(configctx, &view));
899
	ISC_LIST_APPEND(lctx.viewlist, view, link);
900
	view = NULL;
Michael Graff's avatar
Michael Graff committed
901

902
	/*
903
	 * Swap our new view list with the production one.
904
	 */
905
	tmpviewlist = server->viewlist;
906
	server->viewlist = lctx.viewlist;
907
	lctx.viewlist = tmpviewlist;
908
909

	/*
910
	 * Load the TKEY information from the configuration.
911
	 */
912
913
914
915
916
917
918
919
	{
		dns_tkey_ctx_t *t = NULL;
		CHECKM(dns_tkeyctx_fromconfig(configctx, ns_g_mctx, &t),
		       "configuring TKEY");
		if (server->tkeyctx != NULL)
			dns_tkeyctx_destroy(&server->tkeyctx);
		server->tkeyctx = t;
	}
Bob Halley's avatar
Bob Halley committed
920
921
922
923
924
925

	if (first_time)
		ns_os_changeuser(ns_g_username);

	if (dns_c_ctx_getpidfilename(configctx, &pidfilename) ==
	    ISC_R_NOTFOUND)
Bob Halley's avatar
Bob Halley committed
926
		pidfilename = ns_g_defaultpidfile;
Bob Halley's avatar
Bob Halley committed
927
	ns_os_writepidfile(pidfilename);
928
	
929
	dns_aclconfctx_destroy(&aclconfctx);	
930
931

	dns_c_ctx_delete(&configctx);
932
	
933
 cleanup:
934
935
936
937
938
939
940
941
942
943
944
	/*
	 * This cleans up either the old production view list
	 * or our temporary list depending on whether they
	 * were swapped above or not.
	 */
	for (view = ISC_LIST_HEAD(lctx.viewlist);
	     view != NULL;
	     view = view_next) {
		view_next = ISC_LIST_NEXT(view, link);
		ISC_LIST_UNLINK(lctx.viewlist, view, link);
		dns_view_detach(&view);
945

946
	}
947
948

	dns_zonemgr_unlockconf(server->zonemgr, isc_rwlocktype_write);
949
	RWUNLOCK(&server->conflock, isc_rwlocktype_write);
950
	return (result);
Bob Halley's avatar
Bob Halley committed
951
}
952

953
954
955
956
static isc_result_t
load_zones(ns_server_t *server, isc_boolean_t stop) {
	isc_result_t result;
	dns_view_t *view;
957
958

	dns_zonemgr_lockconf(server->zonemgr, isc_rwlocktype_read);
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
	
	/*
	 * Load zone data from disk.
	 */
	for (view = ISC_LIST_HEAD(server->viewlist);
	     view != NULL;
	     view = ISC_LIST_NEXT(view, link))
	{
		CHECK(dns_view_load(view, stop));
	}

	/*
	 * Force zone maintenance.  Do this after loading
	 * so that we know when we need to force AXFR of
	 * slave zones whose master files are missing.
	 */
	CHECK(dns_zonemgr_forcemaint(server->zonemgr));
 cleanup:
977
	dns_zonemgr_unlockconf(server->zonemgr, isc_rwlocktype_read);	
978
979
980
	return (result);
}

Bob Halley's avatar
Bob Halley committed
981
982
static void
run_server(isc_task_t *task, isc_event_t *event) {
983
	isc_result_t result;
984
	ns_server_t *server = (ns_server_t *) event->arg;
Bob Halley's avatar
Bob Halley committed
985

Andreas Gustafsson's avatar
Andreas Gustafsson committed
986
	UNUSED(task);
987

988
	isc_event_free(&event);
989

990
991
992
	CHECKFATAL(ns_clientmgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
				       &server->clientmgr),
		   "creating client manager");
993
	
994
995
996
997
	CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
					  ns_g_socketmgr, server->clientmgr,
					  &server->interfacemgr),
		   "creating interface manager");
998

999
1000
1001
1002
1003
1004
	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
				    NULL, NULL, server->task,
				    interface_timer_tick,
				    server, &server->interface_timer),
		   "creating interface timer");

Bob Halley's avatar
Bob Halley committed
1005
	CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
1006
		   "loading configuration");
1007

1008
1009
1010
	CHECKFATAL(load_zones(server, ISC_TRUE),
		   "loading zones");

1011
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
Bob Halley's avatar
Bob Halley committed
1012
		      ISC_LOG_INFO, "running");
Bob Halley's avatar
Bob Halley committed
1013
}
Michael Graff's avatar
Michael Graff committed
1014

Bob Halley's avatar
Bob Halley committed
1015
1016
static void
shutdown_server(isc_task_t *task, isc_event_t *event) {
1017
	dns_view_t *view, *view_next;
1018
1019
	ns_server_t *server = (ns_server_t *) event->arg;
		
1020
1021
1022
	UNUSED(task);

	RWLOCK(&server->conflock, isc_rwlocktype_write);
1023

1024
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
Bob Halley's avatar
Bob Halley committed
1025
		      ISC_LOG_INFO, "shutting down");
1026

1027
	for (view = ISC_LIST_HEAD(server->viewlist);
1028
1029
1030
	     view != NULL;
	     view = view_next) {
		view_next = ISC_LIST_NEXT(view, link);
1031
		ISC_LIST_UNLINK(server->viewlist, view, link);
1032
1033
		dns_view_detach(&view);
	}
1034

1035
1036
	if (server->querysrc_dispatch != NULL)
		dns_dispatch_detach(&server->querysrc_dispatch);
1037
	ns_clientmgr_destroy(&server->clientmgr);
1038
	isc_timer_detach(&server->interface_timer);
1039
1040
	ns_interfacemgr_shutdown(server->interfacemgr);
	ns_interfacemgr_detach(&server->interfacemgr);	
1041
1042
	dns_zonemgr_shutdown(server->zonemgr);
	
1043
	isc_task_detach(&server->task);
1044

Bob Halley's avatar
Bob Halley committed
1045
	isc_event_free(&event);
1046
1047

	RWUNLOCK(&server->conflock, isc_rwlocktype_write);
Bob Halley's avatar
Bob Halley committed
1048
}
1049

1050
void
1051
ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
1052
1053
	isc_result_t result;
	
1054
1055
	ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
	if (server == NULL)
1056
1057
		fatal("allocating server object", ISC_R_NOMEMORY);

1058
	server->mctx = mctx;
1059
1060
	server->task = NULL;
	
1061
	CHECKFATAL(isc_rwlock_init(&server->conflock, 1, 1),
1062
1063
		   "initializing server configuration lock");

1064
	/* Initialize configuration data with default values. */
1065
1066
1067
	server->recursion = ISC_TRUE;
	server->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
	server->transfer_format = dns_one_answer;
1068

1069
1070
1071
	server->queryacl = NULL;
	server->recursionacl = NULL;

1072
	result = isc_quota_init(&server->xfroutquota, 10);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
1073
	RUNTIME_CHECK(result == ISC_R_SUCCESS); 
1074
	result = isc_quota_init(&server->tcpquota, 10);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
1075
	RUNTIME_CHECK(result == ISC_R_SUCCESS); 
1076
	result = isc_quota_init(&server->recursionquota, 100);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
1077
	RUNTIME_CHECK(result == ISC_R_SUCCESS); 
1078
1079
1080
1081

	result = dns_aclenv_init(mctx, &server->aclenv);
	RUNTIME_CHECK(result == ISC_R_SUCCESS); 	
		
1082
	/* Initialize server data structures. */
1083
1084
1085
	server->zonemgr = NULL;
	server->clientmgr = NULL;
	server->interfacemgr = NULL;
1086
	ISC_LIST_INIT(server->viewlist);
1087
1088
	server->roothints = NULL;
		
1089
1090
	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
				     &server->roothints),
1091
		   "setting up root hints");
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103

	CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
		   "initializing reload event lock");
	server->reload_event =
		isc_event_allocate(ns_g_mctx, server,
				   NS_EVENT_RELOAD,
				   ns_server_reload,
				   server,
				   sizeof(isc_event_t));
	CHECKFATAL(server->reload_event == NULL ?
		   ISC_R_NOMEMORY : ISC_R_SUCCESS,
		   "allocating reload event");
1104
1105
1106
1107

	server->tkeyctx = NULL;
	CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, &server->tkeyctx),
		   "creating TKEY context");
1108
	server->querysrc_dispatch = NULL;
1109

1110
1111
1112
1113
	/*
	 * Setup the server task, which is responsible for coordinating
	 * startup and shutdown of the server.
	 */
1114
1115
	CHECKFATAL(isc_task_create(ns_g_taskmgr, ns_g_mctx, 0, &server->task),
		   "creating server task");
Bob Halley's avatar
Bob Halley committed
1116
	isc_task_setname(server->task, "server", server);
1117
1118
1119
1120
1121
	CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
		   "isc_task_onshutdown");
	CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
		   "isc_app_onrun");

1122
1123
1124
1125
	server->interface_timer = NULL;
	/*
	 * Create a timer for periodic interface scanning.
	 */
1126
1127
1128
	CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
				      ns_g_socketmgr, &server->zonemgr),
		   "dns_zonemgr_create");
1129

1130
1131
1132
1133
1134
1135
1136
1137
1138
	server->magic = NS_SERVER_MAGIC;
	*serverp = server;
}
	
void
ns_server_destroy(ns_server_t **serverp) {
	ns_server_t *server = *serverp;
	REQUIRE(NS_SERVER_VALID(server));

1139
	REQUIRE(server->querysrc_dispatch == NULL);
1140
1141
1142
	if (server->tkeyctx != NULL)
		dns_tkeyctx_destroy(&server->tkeyctx);

1143
1144
	isc_event_free(&server->reload_event);
	
1145
	INSIST(ISC_LIST_EMPTY(server->viewlist));
1146

1147
1148
	dns_zonemgr_destroy(&server->zonemgr);
	server->zonemgr = NULL;
1149

1150
1151
	dns_db_detach(&server->roothints);
	
1152
1153
1154
1155
	if (server->queryacl != NULL)
		dns_acl_detach(&server->queryacl);
	if (server->recursionacl != NULL)
		dns_acl_detach(&server->recursionacl);
1156

1157
1158
	dns_aclenv_destroy(&server->aclenv);

1159
1160
1161
	isc_quota_destroy(&server->recursionquota);
	isc_quota_destroy(&server->tcpquota);
	isc_quota_destroy(&server->xfroutquota);
1162
	isc_rwlock_destroy(&server->conflock);
Bob Halley's avatar
Bob Halley committed
1163

1164
1165
1166
	server->magic = 0;
	isc_mem_put(server->mctx, server, sizeof(*server));
}
1167

1168
1169
static void
fatal(char *msg, isc_result_t result)
Bob Halley's avatar
Bob Halley committed
1170
{
1171
1172
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
		      ISC_LOG_CRITICAL, "%s: %s", msg, isc_result_totext(result));
Bob Halley's avatar
Bob Halley committed
1173
1174
1175
1176
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
		      ISC_LOG_CRITICAL, "exiting (due to fatal error)");
	exit(1);
}
1177
1178
1179
1180
1181
1182
1183

static void
ns_server_reload(isc_task_t *task, isc_event_t *event) {
	isc_result_t result;
	ns_server_t *server = (ns_server_t *) event->arg;
	UNUSED(task);
	
Bob Halley's avatar
Bob Halley committed
1184
	result = load_configuration(ns_g_conffile, server, ISC_FALSE);
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
	if (result != DNS_R_SUCCESS) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
			      "reloading configuration failed: %s",
			      isc_result_totext(result));
	}
	result = load_zones(server, ISC_FALSE);
	if (result != DNS_R_SUCCESS) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
			      "reloading zones failed: %s",
			      isc_result_totext(result));
	}
	LOCK(&server->reload_event_lock);
	INSIST(server->reload_event == NULL);
	server->reload_event = event;
	UNLOCK(&server->reload_event_lock);
}

void
ns_server_reloadwanted(ns_server_t *server) {
	LOCK(&server->reload_event_lock);
	if (server->reload_event != NULL)
		isc_task_sen