xref: /netbsd-src/external/mpl/bind/dist/bin/named/controlconf.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: controlconf.c,v 1.13 2025/01/26 16:24:33 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 #include <inttypes.h>
19 #include <stdbool.h>
20 
21 #include <isc/async.h>
22 #include <isc/base64.h>
23 #include <isc/buffer.h>
24 #include <isc/file.h>
25 #include <isc/mem.h>
26 #include <isc/mutex.h>
27 #include <isc/net.h>
28 #include <isc/netaddr.h>
29 #include <isc/netmgr.h>
30 #include <isc/nonce.h>
31 #include <isc/random.h>
32 #include <isc/refcount.h>
33 #include <isc/result.h>
34 #include <isc/stdtime.h>
35 #include <isc/string.h>
36 #include <isc/util.h>
37 
38 #include <isccc/alist.h>
39 #include <isccc/cc.h>
40 #include <isccc/ccmsg.h>
41 #include <isccc/sexpr.h>
42 #include <isccc/symtab.h>
43 #include <isccc/util.h>
44 
45 #include <isccfg/check.h>
46 #include <isccfg/namedconf.h>
47 
48 #include <named/config.h>
49 #include <named/control.h>
50 #include <named/log.h>
51 #include <named/main.h>
52 #include <named/server.h>
53 
54 /* Add -DNAMED_CONTROLCONF_TRACE=1 to CFLAGS for detailed reference tracing */
55 
56 typedef struct controlkey controlkey_t;
57 typedef ISC_LIST(controlkey_t) controlkeylist_t;
58 
59 typedef struct controlconnection controlconnection_t;
60 typedef ISC_LIST(controlconnection_t) controlconnectionlist_t;
61 
62 typedef struct controllistener controllistener_t;
63 typedef ISC_LIST(controllistener_t) controllistenerlist_t;
64 
65 struct controlkey {
66 	char *keyname;
67 	uint32_t algorithm;
68 	isc_region_t secret;
69 	ISC_LINK(controlkey_t) link;
70 };
71 
72 struct controlconnection {
73 	isc_refcount_t references;
74 	isccc_ccmsg_t ccmsg;
75 	controllistener_t *listener;
76 	isccc_sexpr_t *ctrl;
77 	isc_buffer_t *buffer;
78 	isc_buffer_t *text;
79 	isccc_sexpr_t *request;
80 	isccc_sexpr_t *response;
81 	uint32_t alg;
82 	isccc_region_t secret;
83 	uint32_t nonce;
84 	isc_stdtime_t now;
85 	isc_result_t result;
86 	ISC_LINK(controlconnection_t) link;
87 	bool shuttingdown;
88 };
89 
90 struct controllistener {
91 	named_controls_t *controls;
92 	isc_mem_t *mctx;
93 	isc_sockaddr_t address;
94 	isc_nmsocket_t *sock;
95 	dns_acl_t *acl;
96 	bool shuttingdown;
97 	isc_refcount_t references;
98 	controlkeylist_t keys;
99 	controlconnectionlist_t connections;
100 	isc_socktype_t type;
101 	uint32_t perm;
102 	uint32_t owner;
103 	uint32_t group;
104 	bool readonly;
105 	ISC_LINK(controllistener_t) link;
106 };
107 
108 struct named_controls {
109 	named_server_t *server;
110 	controllistenerlist_t listeners;
111 	bool shuttingdown;
112 	isc_mutex_t symtab_lock;
113 	isccc_symtab_t *symtab;
114 };
115 
116 static isc_result_t
117 control_newconn(isc_nmhandle_t *handle, isc_result_t result, void *arg);
118 static void
119 control_recvmessage(isc_nmhandle_t *handle, isc_result_t result, void *arg);
120 static void
121 conn_cleanup(controlconnection_t *conn);
122 static void
123 conn_free(controlconnection_t *conn);
124 static void
125 conn_shutdown(controlconnection_t *conn);
126 
127 #if NAMED_CONTROLCONF_TRACE
128 #define controllistener_ref(ptr) \
129 	controllistener__ref(ptr, __func__, __FILE__, __LINE__)
130 #define controllistener_unref(ptr) \
131 	controllistener__unref(ptr, __func__, __FILE__, __LINE__)
132 #define controllistener_attach(ptr, ptrp) \
133 	controllistener__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
134 #define controllistener_detach(ptrp) \
135 	controllistener__detach(ptrp, __func__, __FILE__, __LINE__)
136 ISC_REFCOUNT_TRACE_DECL(controllistener);
137 
138 #define controlconnection_ref(ptr) \
139 	controlconnection__ref(ptr, __func__, __FILE__, __LINE__)
140 #define controlconnection_unref(ptr) \
141 	controlconnection__unref(ptr, __func__, __FILE__, __LINE__)
142 #define controlconnection_attach(ptr, ptrp) \
143 	controlconnection__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
144 #define controlconnection_detach(ptrp) \
145 	controlconnection__detach(ptrp, __func__, __FILE__, __LINE__)
146 ISC_REFCOUNT_TRACE_DECL(controlconnection);
147 #else
148 ISC_REFCOUNT_DECL(controllistener);
149 ISC_REFCOUNT_DECL(controlconnection);
150 #endif
151 
152 #define CLOCKSKEW 300
153 
154 #define CHECK(x)                               \
155 	{                                      \
156 		result = (x);                  \
157 		if (result != ISC_R_SUCCESS) { \
158 			goto cleanup;          \
159 		}                              \
160 	}
161 
162 static void
163 free_controlkey(controlkey_t *key, isc_mem_t *mctx) {
164 	if (key->keyname != NULL) {
165 		isc_mem_free(mctx, key->keyname);
166 	}
167 	if (key->secret.base != NULL) {
168 		isc_mem_put(mctx, key->secret.base, key->secret.length);
169 	}
170 	isc_mem_put(mctx, key, sizeof(*key));
171 }
172 
173 static void
174 free_controlkeylist(controlkeylist_t *keylist, isc_mem_t *mctx) {
175 	while (!ISC_LIST_EMPTY(*keylist)) {
176 		controlkey_t *key = ISC_LIST_HEAD(*keylist);
177 		ISC_LIST_UNLINK(*keylist, key, link);
178 		free_controlkey(key, mctx);
179 	}
180 }
181 
182 static void
183 free_listener(controllistener_t *listener) {
184 	REQUIRE(listener->shuttingdown);
185 	REQUIRE(ISC_LIST_EMPTY(listener->connections));
186 	REQUIRE(listener->sock == NULL);
187 
188 	free_controlkeylist(&listener->keys, listener->mctx);
189 
190 	if (listener->acl != NULL) {
191 		dns_acl_detach(&listener->acl);
192 	}
193 
194 	isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
195 }
196 
197 #if NAMED_CONTROLCONF_TRACE
198 ISC_REFCOUNT_TRACE_IMPL(controllistener, free_listener);
199 ISC_REFCOUNT_TRACE_IMPL(controlconnection, conn_free);
200 #else
201 ISC_REFCOUNT_IMPL(controllistener, free_listener);
202 ISC_REFCOUNT_IMPL(controlconnection, conn_free);
203 #endif
204 
205 static void
206 shutdown_listener(controllistener_t *listener) {
207 	controlconnection_t *conn = NULL;
208 	controlconnection_t *next = NULL;
209 
210 	/* Don't shutdown the same listener twice */
211 	if (listener->shuttingdown) {
212 		return;
213 	}
214 	listener->shuttingdown = true;
215 
216 	for (conn = ISC_LIST_HEAD(listener->connections); conn != NULL;
217 	     conn = next)
218 	{
219 		/*
220 		 * 'conn' is likely to be freed by the conn_shutdown() call.
221 		 */
222 		next = ISC_LIST_NEXT(conn, link);
223 		conn_shutdown(conn);
224 	}
225 
226 	ISC_LIST_UNLINK(listener->controls->listeners, listener, link);
227 
228 	char socktext[ISC_SOCKADDR_FORMATSIZE];
229 	isc_sockaddr_format(&listener->address, socktext, sizeof(socktext));
230 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
231 		      NAMED_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
232 		      "stopping command channel on %s", socktext);
233 
234 	isc_nm_stoplistening(listener->sock);
235 	isc_nmsocket_close(&listener->sock);
236 	controllistener_detach(&listener);
237 }
238 
239 static bool
240 address_ok(isc_sockaddr_t *sockaddr, controllistener_t *listener) {
241 	dns_aclenv_t *env =
242 		ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
243 	isc_netaddr_t netaddr;
244 	isc_result_t result;
245 	int match;
246 
247 	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
248 
249 	result = dns_acl_match(&netaddr, NULL, listener->acl, env, &match,
250 			       NULL);
251 	return result == ISC_R_SUCCESS && match > 0;
252 }
253 
254 static void
255 control_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
256 	controlconnection_t *conn = (controlconnection_t *)arg;
257 
258 	if (conn->shuttingdown) {
259 		/* The connection is shuttingdown */
260 		result = ISC_R_SHUTTINGDOWN;
261 	}
262 
263 	if (result == ISC_R_SUCCESS) {
264 		/* Everything is peachy, continue reading from the socket */
265 		isccc_ccmsg_readmessage(&conn->ccmsg, control_recvmessage,
266 					conn);
267 		/* Detach the sending reference */
268 		controlconnection_detach(&conn);
269 		return;
270 	}
271 
272 	if (result != ISC_R_SHUTTINGDOWN) {
273 		char socktext[ISC_SOCKADDR_FORMATSIZE];
274 		isc_sockaddr_t peeraddr = isc_nmhandle_peeraddr(handle);
275 
276 		isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
277 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
278 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING,
279 			      "error sending command response to %s: %s",
280 			      socktext, isc_result_totext(result));
281 	}
282 
283 	/* Shutdown the reading */
284 	conn_shutdown(conn);
285 
286 	/* Detach the sending reference */
287 	controlconnection_detach(&conn);
288 }
289 
290 static void
291 log_invalid(isccc_ccmsg_t *ccmsg, isc_result_t result) {
292 	char socktext[ISC_SOCKADDR_FORMATSIZE];
293 	isc_sockaddr_t peeraddr = isc_nmhandle_peeraddr(ccmsg->handle);
294 
295 	isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
296 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
297 		      NAMED_LOGMODULE_CONTROL, ISC_LOG_ERROR,
298 		      "invalid command from %s: %s", socktext,
299 		      isc_result_totext(result));
300 }
301 
302 static void
303 conn_cleanup(controlconnection_t *conn) {
304 	controllistener_t *listener = conn->listener;
305 
306 	if (conn->response != NULL) {
307 		isccc_sexpr_free(&conn->response);
308 	}
309 	if (conn->request != NULL) {
310 		isccc_sexpr_free(&conn->request);
311 	}
312 	if (conn->secret.rstart != NULL) {
313 		isc_mem_put(listener->mctx, conn->secret.rstart,
314 			    REGION_SIZE(conn->secret));
315 	}
316 	if (conn->text != NULL) {
317 		isc_buffer_free(&conn->text);
318 	}
319 }
320 
321 static void
322 control_respond(controlconnection_t *conn) {
323 	controllistener_t *listener = conn->listener;
324 	isccc_sexpr_t *data = NULL;
325 	isc_buffer_t b;
326 	isc_region_t r;
327 	isc_result_t result;
328 
329 	result = isccc_cc_createresponse(conn->request, conn->now,
330 					 conn->now + 60, &conn->response);
331 	if (result != ISC_R_SUCCESS) {
332 		goto cleanup;
333 	}
334 
335 	if (conn->result == ISC_R_SHUTTINGDOWN) {
336 		result = ISC_R_SUCCESS;
337 	} else {
338 		result = conn->result;
339 	}
340 
341 	data = isccc_alist_lookup(conn->response, "_data");
342 	if (data != NULL) {
343 		if (isccc_cc_defineuint32(data, "result", result) == NULL) {
344 			goto cleanup;
345 		}
346 	}
347 
348 	if (result != ISC_R_SUCCESS) {
349 		if (data != NULL) {
350 			const char *estr = isc_result_totext(result);
351 			if (isccc_cc_definestring(data, "err", estr) == NULL) {
352 				goto cleanup;
353 			}
354 		}
355 	}
356 
357 	if (isc_buffer_usedlength(conn->text) > 0) {
358 		if (data != NULL) {
359 			char *str = (char *)isc_buffer_base(conn->text);
360 			if (isccc_cc_definestring(data, "text", str) == NULL) {
361 				goto cleanup;
362 			}
363 		}
364 	}
365 
366 	conn->ctrl = isccc_alist_lookup(conn->response, "_ctrl");
367 	if (conn->ctrl == NULL ||
368 	    isccc_cc_defineuint32(conn->ctrl, "_nonce", conn->nonce) == NULL)
369 	{
370 		goto cleanup;
371 	}
372 
373 	if (conn->buffer == NULL) {
374 		isc_buffer_allocate(listener->mctx, &conn->buffer, 2 * 2048);
375 	}
376 
377 	isc_buffer_clear(conn->buffer);
378 	/* Skip the length field (4 bytes) */
379 	isc_buffer_add(conn->buffer, 4);
380 
381 	result = isccc_cc_towire(conn->response, &conn->buffer, conn->alg,
382 				 &conn->secret);
383 	if (result != ISC_R_SUCCESS) {
384 		return;
385 	}
386 
387 	isc_buffer_init(&b, conn->buffer->base, 4);
388 	isc_buffer_putuint32(&b, conn->buffer->used - 4);
389 
390 	r.base = conn->buffer->base;
391 	r.length = conn->buffer->used;
392 
393 	/* Attach the sending reference */
394 	controlconnection_ref(conn);
395 	isccc_ccmsg_sendmessage(&conn->ccmsg, &r, control_senddone, conn);
396 
397 cleanup:
398 	conn_cleanup(conn);
399 }
400 
401 static void
402 control_command(void *arg) {
403 	controlconnection_t *conn = (controlconnection_t *)arg;
404 
405 	/* Don't run the command if we already started the shutdown */
406 	if (!conn->shuttingdown) {
407 		conn->result = named_control_docommand(
408 			conn->request, conn->listener->readonly, &conn->text);
409 		control_respond(conn);
410 	}
411 
412 	/* Detach the control command reference */
413 	controlconnection_detach(&conn);
414 }
415 
416 static void
417 conn_shutdown(controlconnection_t *conn) {
418 	/* Don't shutdown the same controlconnection twice */
419 	if (conn->shuttingdown) {
420 		return;
421 	}
422 	conn->shuttingdown = true;
423 
424 	/*
425 	 * Close the TCP connection to make sure that no read callback will be
426 	 * called for it ever again.
427 	 */
428 	isccc_ccmsg_disconnect(&conn->ccmsg);
429 
430 	/* Detach the reading reference */
431 	controlconnection_detach(&conn);
432 }
433 
434 static void
435 control_recvmessage(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
436 		    void *arg) {
437 	controlconnection_t *conn = (controlconnection_t *)arg;
438 	controllistener_t *listener = conn->listener;
439 	controlkey_t *key = NULL;
440 	isccc_time_t sent;
441 	isccc_time_t exp;
442 	uint32_t nonce;
443 
444 	if (result != ISC_R_SUCCESS) {
445 		goto cleanup;
446 	}
447 
448 	for (key = ISC_LIST_HEAD(listener->keys); key != NULL;
449 	     key = ISC_LIST_NEXT(key, link))
450 	{
451 		isccc_region_t ccregion;
452 
453 		isccc_ccmsg_toregion(&conn->ccmsg, &ccregion);
454 		conn->secret.rstart = isc_mem_get(listener->mctx,
455 						  key->secret.length);
456 		memmove(conn->secret.rstart, key->secret.base,
457 			key->secret.length);
458 		conn->secret.rend = conn->secret.rstart + key->secret.length;
459 		conn->alg = key->algorithm;
460 		result = isccc_cc_fromwire(&ccregion, &conn->request, conn->alg,
461 					   &conn->secret);
462 		if (result == ISC_R_SUCCESS) {
463 			break;
464 		}
465 		isc_mem_put(listener->mctx, conn->secret.rstart,
466 			    REGION_SIZE(conn->secret));
467 	}
468 
469 	if (key == NULL) {
470 		result = ISCCC_R_BADAUTH;
471 		goto cleanup;
472 	}
473 
474 	/* We shouldn't be getting a reply. */
475 	if (isccc_cc_isreply(conn->request)) {
476 		result = ISC_R_FAILURE;
477 		goto cleanup;
478 	}
479 
480 	conn->now = isc_stdtime_now();
481 
482 	/*
483 	 * Limit exposure to replay attacks.
484 	 */
485 	conn->ctrl = isccc_alist_lookup(conn->request, "_ctrl");
486 	if (!isccc_alist_alistp(conn->ctrl)) {
487 		result = ISC_R_FAILURE;
488 		goto cleanup;
489 	}
490 
491 	if (isccc_cc_lookupuint32(conn->ctrl, "_tim", &sent) == ISC_R_SUCCESS) {
492 		if ((sent + CLOCKSKEW) < conn->now ||
493 		    (sent - CLOCKSKEW) > conn->now)
494 		{
495 			result = ISCCC_R_CLOCKSKEW;
496 			goto cleanup;
497 		}
498 	} else {
499 		result = ISC_R_FAILURE;
500 		goto cleanup;
501 	}
502 
503 	/*
504 	 * Expire messages that are too old.
505 	 */
506 	if (isccc_cc_lookupuint32(conn->ctrl, "_exp", &exp) == ISC_R_SUCCESS &&
507 	    conn->now > exp)
508 	{
509 		result = ISCCC_R_EXPIRED;
510 		goto cleanup;
511 	}
512 
513 	/*
514 	 * Duplicate suppression (required for UDP).
515 	 */
516 	LOCK(&listener->controls->symtab_lock);
517 	isccc_cc_cleansymtab(listener->controls->symtab, conn->now);
518 	result = isccc_cc_checkdup(listener->controls->symtab, conn->request,
519 				   conn->now);
520 	UNLOCK(&listener->controls->symtab_lock);
521 	if (result != ISC_R_SUCCESS) {
522 		if (result == ISC_R_EXISTS) {
523 			result = ISCCC_R_DUPLICATE;
524 		}
525 		goto cleanup;
526 	}
527 
528 	if (conn->nonce != 0 &&
529 	    (isccc_cc_lookupuint32(conn->ctrl, "_nonce", &nonce) !=
530 		     ISC_R_SUCCESS ||
531 	     conn->nonce != nonce))
532 	{
533 		result = ISCCC_R_BADAUTH;
534 		goto cleanup;
535 	}
536 
537 	isc_buffer_allocate(listener->mctx, &conn->text, 2 * 2048);
538 
539 	if (conn->nonce == 0) {
540 		/*
541 		 * Establish nonce.
542 		 */
543 		while (conn->nonce == 0) {
544 			isc_nonce_buf(&conn->nonce, sizeof(conn->nonce));
545 		}
546 		conn->result = ISC_R_SUCCESS;
547 		control_respond(conn);
548 		return;
549 	}
550 
551 	/* Attach the command reference */
552 	controlconnection_ref(conn);
553 
554 	/* Trigger the command asynchronously. */
555 	isc_async_run(named_g_mainloop, control_command, conn);
556 
557 	return;
558 
559 cleanup:
560 	switch (result) {
561 	case ISC_R_SHUTTINGDOWN:
562 	case ISC_R_EOF:
563 		break;
564 	default:
565 		log_invalid(&conn->ccmsg, result);
566 	}
567 
568 	conn_shutdown(conn);
569 }
570 
571 static void
572 conn_free(controlconnection_t *conn) {
573 	/* Make sure that the connection was shutdown first */
574 	REQUIRE(conn->shuttingdown);
575 
576 	controllistener_t *listener = conn->listener;
577 
578 	isccc_ccmsg_invalidate(&conn->ccmsg);
579 
580 	conn_cleanup(conn);
581 
582 	if (conn->buffer != NULL) {
583 		isc_buffer_free(&conn->buffer);
584 	}
585 
586 	ISC_LIST_UNLINK(listener->connections, conn, link);
587 #ifdef ENABLE_AFL
588 	if (named_g_fuzz_type == isc_fuzz_rndc) {
589 		named_fuzz_notify();
590 	}
591 #endif /* ifdef ENABLE_AFL */
592 
593 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
594 		      NAMED_LOGMODULE_CONTROL, ISC_LOG_DEBUG(3),
595 		      "freeing control connection");
596 
597 	isc_mem_put(listener->mctx, conn, sizeof(*conn));
598 
599 	controllistener_detach(&listener);
600 }
601 
602 static void
603 newconnection(controllistener_t *listener, isc_nmhandle_t *handle) {
604 	/* Don't create new connection if we are shutting down */
605 	if (listener->shuttingdown) {
606 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
607 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_DEBUG(3),
608 			      "rejected new control connection: %s",
609 			      isc_result_totext(ISC_R_SHUTTINGDOWN));
610 		return;
611 	}
612 
613 	controlconnection_t *conn = isc_mem_get(listener->mctx, sizeof(*conn));
614 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
615 		      NAMED_LOGMODULE_CONTROL, ISC_LOG_DEBUG(3),
616 		      "allocate new control connection");
617 
618 	*conn = (controlconnection_t){
619 		.alg = DST_ALG_UNKNOWN,
620 		.references = ISC_REFCOUNT_INITIALIZER(1),
621 		.listener = controllistener_ref(listener),
622 		.link = ISC_LINK_INITIALIZER,
623 	};
624 
625 	/* isccc_ccmsg_init() attaches to the handle */
626 	isccc_ccmsg_init(listener->mctx, handle, &conn->ccmsg);
627 
628 	/* Set a 32 KiB upper limit on incoming message. */
629 	isccc_ccmsg_setmaxsize(&conn->ccmsg, 32768);
630 
631 	ISC_LIST_APPEND(listener->connections, conn, link);
632 
633 	/* The reading reference has been initialized in the initializer */
634 	isccc_ccmsg_readmessage(&conn->ccmsg, control_recvmessage, conn);
635 }
636 
637 static isc_result_t
638 control_newconn(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
639 	controllistener_t *listener = arg;
640 	isc_sockaddr_t peeraddr;
641 
642 	if (result != ISC_R_SUCCESS) {
643 		if (result == ISC_R_SHUTTINGDOWN) {
644 			shutdown_listener(listener);
645 		}
646 		return result;
647 	}
648 
649 	peeraddr = isc_nmhandle_peeraddr(handle);
650 	if (!address_ok(&peeraddr, listener)) {
651 		char socktext[ISC_SOCKADDR_FORMATSIZE];
652 		isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
653 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
654 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING,
655 			      "rejected command channel message from %s",
656 			      socktext);
657 		return ISC_R_FAILURE;
658 	}
659 
660 	newconnection(listener, handle);
661 	return ISC_R_SUCCESS;
662 }
663 
664 static void
665 controls_shutdown(named_controls_t *controls) {
666 	controllistener_t *listener = NULL;
667 	controllistener_t *next = NULL;
668 
669 	for (listener = ISC_LIST_HEAD(controls->listeners); listener != NULL;
670 	     listener = next)
671 	{
672 		/*
673 		 * As listeners shut down, they will call their callbacks.
674 		 */
675 		next = ISC_LIST_NEXT(listener, link);
676 		shutdown_listener(listener);
677 	}
678 }
679 
680 void
681 named_controls_shutdown(named_controls_t *controls) {
682 	/*
683 	 * Don't ever shutdown the controls twice.
684 	 *
685 	 * NOTE: This functions is called when the server is shutting down, but
686 	 * controls_shutdown() can and will be called multiple times - on each
687 	 * reconfiguration, the listeners will be torn down and recreated again,
688 	 * see named_controls_configure() for details.
689 	 */
690 	if (controls->shuttingdown) {
691 		return;
692 	}
693 	controls->shuttingdown = true;
694 
695 	controls_shutdown(controls);
696 }
697 
698 static isc_result_t
699 cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname,
700 		const cfg_obj_t **objp) {
701 	const cfg_listelt_t *element = NULL;
702 	const char *str = NULL;
703 	const cfg_obj_t *obj = NULL;
704 
705 	for (element = cfg_list_first(keylist); element != NULL;
706 	     element = cfg_list_next(element))
707 	{
708 		obj = cfg_listelt_value(element);
709 		str = cfg_obj_asstring(cfg_map_getname(obj));
710 		if (strcasecmp(str, keyname) == 0) {
711 			break;
712 		}
713 	}
714 	if (element == NULL) {
715 		return ISC_R_NOTFOUND;
716 	}
717 	obj = cfg_listelt_value(element);
718 	*objp = obj;
719 	return ISC_R_SUCCESS;
720 }
721 
722 static void
723 controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx,
724 		       controlkeylist_t *keyids) {
725 	const cfg_listelt_t *element = NULL;
726 	char *newstr = NULL;
727 	const char *str = NULL;
728 	const cfg_obj_t *obj = NULL;
729 	controlkey_t *key = NULL;
730 
731 	for (element = cfg_list_first(keylist); element != NULL;
732 	     element = cfg_list_next(element))
733 	{
734 		obj = cfg_listelt_value(element);
735 		str = cfg_obj_asstring(obj);
736 		newstr = isc_mem_strdup(mctx, str);
737 		key = isc_mem_get(mctx, sizeof(*key));
738 		key->keyname = newstr;
739 		key->algorithm = DST_ALG_UNKNOWN;
740 		key->secret.base = NULL;
741 		key->secret.length = 0;
742 		ISC_LINK_INIT(key, link);
743 		ISC_LIST_APPEND(*keyids, key, link);
744 		newstr = NULL;
745 	}
746 }
747 
748 static void
749 register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist,
750 	      controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext) {
751 	controlkey_t *keyid = NULL, *next = NULL;
752 	const cfg_obj_t *keydef = NULL;
753 	char secret[1024];
754 	isc_buffer_t b;
755 	isc_result_t result;
756 
757 	/*
758 	 * Find the keys corresponding to the keyids used by this listener.
759 	 */
760 	for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) {
761 		next = ISC_LIST_NEXT(keyid, link);
762 
763 		result = cfgkeylist_find(keylist, keyid->keyname, &keydef);
764 		if (result != ISC_R_SUCCESS) {
765 			cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING,
766 				    "couldn't find key '%s' for use with "
767 				    "command channel %s",
768 				    keyid->keyname, socktext);
769 			ISC_LIST_UNLINK(*keyids, keyid, link);
770 			free_controlkey(keyid, mctx);
771 		} else {
772 			const cfg_obj_t *algobj = NULL;
773 			const cfg_obj_t *secretobj = NULL;
774 			const char *algstr = NULL;
775 			const char *secretstr = NULL;
776 			unsigned int algtype;
777 
778 			(void)cfg_map_get(keydef, "algorithm", &algobj);
779 			(void)cfg_map_get(keydef, "secret", &secretobj);
780 			INSIST(algobj != NULL && secretobj != NULL);
781 
782 			algstr = cfg_obj_asstring(algobj);
783 			secretstr = cfg_obj_asstring(secretobj);
784 
785 			result = named_config_getkeyalgorithm(algstr, &algtype,
786 							      NULL);
787 			if (result != ISC_R_SUCCESS) {
788 				cfg_obj_log(control, named_g_lctx,
789 					    ISC_LOG_WARNING,
790 					    "unsupported algorithm '%s' in "
791 					    "key '%s' for use with command "
792 					    "channel %s",
793 					    algstr, keyid->keyname, socktext);
794 				ISC_LIST_UNLINK(*keyids, keyid, link);
795 				free_controlkey(keyid, mctx);
796 				continue;
797 			}
798 
799 			keyid->algorithm = algtype;
800 			isc_buffer_init(&b, secret, sizeof(secret));
801 			result = isc_base64_decodestring(secretstr, &b);
802 
803 			if (result != ISC_R_SUCCESS) {
804 				cfg_obj_log(keydef, named_g_lctx,
805 					    ISC_LOG_WARNING,
806 					    "secret for key '%s' on "
807 					    "command channel %s: %s",
808 					    keyid->keyname, socktext,
809 					    isc_result_totext(result));
810 				ISC_LIST_UNLINK(*keyids, keyid, link);
811 				free_controlkey(keyid, mctx);
812 				continue;
813 			}
814 
815 			keyid->secret.length = isc_buffer_usedlength(&b);
816 			keyid->secret.base = isc_mem_get(mctx,
817 							 keyid->secret.length);
818 			memmove(keyid->secret.base, isc_buffer_base(&b),
819 				keyid->secret.length);
820 		}
821 	}
822 }
823 
824 static isc_result_t
825 get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) {
826 	isc_result_t result;
827 	cfg_parser_t *pctx = NULL;
828 	cfg_obj_t *config = NULL;
829 	const cfg_obj_t *key = NULL;
830 	const cfg_obj_t *algobj = NULL;
831 	const cfg_obj_t *secretobj = NULL;
832 	const char *algstr = NULL;
833 	const char *secretstr = NULL;
834 	controlkey_t *keyid = NULL;
835 	char secret[1024];
836 	unsigned int algtype;
837 	isc_buffer_t b;
838 
839 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
840 		      NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
841 		      "configuring command channel from '%s'", named_g_keyfile);
842 	if (!isc_file_exists(named_g_keyfile)) {
843 		return ISC_R_FILENOTFOUND;
844 	}
845 
846 	CHECK(cfg_parser_create(mctx, named_g_lctx, &pctx));
847 	CHECK(cfg_parse_file(pctx, named_g_keyfile, &cfg_type_rndckey,
848 			     &config));
849 	CHECK(cfg_map_get(config, "key", &key));
850 
851 	keyid = isc_mem_get(mctx, sizeof(*keyid));
852 	keyid->keyname = isc_mem_strdup(mctx,
853 					cfg_obj_asstring(cfg_map_getname(key)));
854 	keyid->secret.base = NULL;
855 	keyid->secret.length = 0;
856 	keyid->algorithm = DST_ALG_UNKNOWN;
857 	ISC_LINK_INIT(keyid, link);
858 	if (keyid->keyname == NULL) {
859 		CHECK(ISC_R_NOMEMORY);
860 	}
861 
862 	CHECK(isccfg_check_key(key, named_g_lctx));
863 
864 	(void)cfg_map_get(key, "algorithm", &algobj);
865 	(void)cfg_map_get(key, "secret", &secretobj);
866 	INSIST(algobj != NULL && secretobj != NULL);
867 
868 	algstr = cfg_obj_asstring(algobj);
869 	secretstr = cfg_obj_asstring(secretobj);
870 
871 	result = named_config_getkeyalgorithm(algstr, &algtype, NULL);
872 	if (result != ISC_R_SUCCESS) {
873 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
874 			    "unsupported algorithm '%s' in "
875 			    "key '%s' for use with command "
876 			    "channel",
877 			    algstr, keyid->keyname);
878 		goto cleanup;
879 	}
880 
881 	keyid->algorithm = algtype;
882 	isc_buffer_init(&b, secret, sizeof(secret));
883 	result = isc_base64_decodestring(secretstr, &b);
884 
885 	if (result != ISC_R_SUCCESS) {
886 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
887 			    "secret for key '%s' on command channel: %s",
888 			    keyid->keyname, isc_result_totext(result));
889 		goto cleanup;
890 	}
891 
892 	keyid->secret.length = isc_buffer_usedlength(&b);
893 	keyid->secret.base = isc_mem_get(mctx, keyid->secret.length);
894 	memmove(keyid->secret.base, isc_buffer_base(&b), keyid->secret.length);
895 	ISC_LIST_APPEND(*keyids, keyid, link);
896 	keyid = NULL;
897 	result = ISC_R_SUCCESS;
898 
899 cleanup:
900 	if (keyid != NULL) {
901 		free_controlkey(keyid, mctx);
902 	}
903 	if (config != NULL) {
904 		cfg_obj_destroy(pctx, &config);
905 	}
906 	if (pctx != NULL) {
907 		cfg_parser_destroy(&pctx);
908 	}
909 	return result;
910 }
911 
912 /*
913  * Ensures that both '*global_keylistp' and '*control_keylistp' are
914  * valid or both are NULL.
915  */
916 static void
917 get_key_info(const cfg_obj_t *config, const cfg_obj_t *control,
918 	     const cfg_obj_t **global_keylistp,
919 	     const cfg_obj_t **control_keylistp) {
920 	isc_result_t result;
921 	const cfg_obj_t *control_keylist = NULL;
922 	const cfg_obj_t *global_keylist = NULL;
923 
924 	REQUIRE(global_keylistp != NULL && *global_keylistp == NULL);
925 	REQUIRE(control_keylistp != NULL && *control_keylistp == NULL);
926 
927 	control_keylist = cfg_tuple_get(control, "keys");
928 
929 	if (!cfg_obj_isvoid(control_keylist) &&
930 	    cfg_list_first(control_keylist) != NULL)
931 	{
932 		result = cfg_map_get(config, "key", &global_keylist);
933 
934 		if (result == ISC_R_SUCCESS) {
935 			*global_keylistp = global_keylist;
936 			*control_keylistp = control_keylist;
937 		}
938 	}
939 }
940 
941 static void
942 update_listener(named_controls_t *cp, controllistener_t **listenerp,
943 		const cfg_obj_t *control, const cfg_obj_t *config,
944 		isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
945 		const char *socktext, isc_socktype_t type) {
946 	controllistener_t *listener = NULL;
947 	const cfg_obj_t *allow = NULL;
948 	const cfg_obj_t *global_keylist = NULL;
949 	const cfg_obj_t *control_keylist = NULL;
950 	dns_acl_t *new_acl = NULL;
951 	controlkeylist_t keys;
952 	isc_result_t result = ISC_R_SUCCESS;
953 
954 	for (listener = ISC_LIST_HEAD(cp->listeners); listener != NULL;
955 	     listener = ISC_LIST_NEXT(listener, link))
956 	{
957 		if (isc_sockaddr_equal(addr, &listener->address)) {
958 			break;
959 		}
960 	}
961 
962 	if (listener == NULL) {
963 		*listenerp = NULL;
964 		return;
965 	}
966 
967 	/*
968 	 * There is already a listener for this sockaddr.
969 	 * Update the access list and key information.
970 	 *
971 	 * First try to deal with the key situation.  There are a few
972 	 * possibilities:
973 	 *  (a)	It had an explicit keylist and still has an explicit keylist.
974 	 *  (b)	It had an automagic key and now has an explicit keylist.
975 	 *  (c)	It had an explicit keylist and now needs an automagic key.
976 	 *  (d) It has an automagic key and still needs the automagic key.
977 	 *
978 	 * (c) and (d) are the annoying ones.  The caller needs to know
979 	 * that it should use the automagic configuration for key information
980 	 * in place of the named.conf configuration.
981 	 *
982 	 * XXXDCL There is one other hazard that has not been dealt with,
983 	 * the problem that if a key change is being caused by a control
984 	 * channel reload, then the response will be with the new key
985 	 * and not able to be decrypted by the client.
986 	 */
987 	if (control != NULL) {
988 		get_key_info(config, control, &global_keylist,
989 			     &control_keylist);
990 	}
991 
992 	if (control_keylist != NULL) {
993 		INSIST(global_keylist != NULL);
994 
995 		ISC_LIST_INIT(keys);
996 		controlkeylist_fromcfg(control_keylist, listener->mctx, &keys);
997 		free_controlkeylist(&listener->keys, listener->mctx);
998 		listener->keys = keys;
999 		register_keys(control, global_keylist, &listener->keys,
1000 			      listener->mctx, socktext);
1001 	} else {
1002 		free_controlkeylist(&listener->keys, listener->mctx);
1003 		result = get_rndckey(listener->mctx, &listener->keys);
1004 	}
1005 
1006 	if (result != ISC_R_SUCCESS && global_keylist != NULL) {
1007 		/*
1008 		 * This message might be a little misleading since the
1009 		 * "new keys" might in fact be identical to the old ones,
1010 		 * but tracking whether they are identical just for the
1011 		 * sake of avoiding this message would be too much trouble.
1012 		 */
1013 		if (control != NULL) {
1014 			cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING,
1015 				    "couldn't install new keys for "
1016 				    "command channel %s: %s",
1017 				    socktext, isc_result_totext(result));
1018 		} else {
1019 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1020 				      NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING,
1021 				      "couldn't install new keys for "
1022 				      "command channel %s: %s",
1023 				      socktext, isc_result_totext(result));
1024 		}
1025 	}
1026 
1027 	/*
1028 	 * Now, keep the old access list unless a new one can be made.
1029 	 */
1030 	if (control != NULL && type == isc_socktype_tcp) {
1031 		allow = cfg_tuple_get(control, "allow");
1032 		result = cfg_acl_fromconfig(allow, config, named_g_lctx,
1033 					    aclconfctx, listener->mctx, 0,
1034 					    &new_acl);
1035 	} else {
1036 		result = dns_acl_any(listener->mctx, &new_acl);
1037 	}
1038 
1039 	if (control != NULL) {
1040 		const cfg_obj_t *readonly = NULL;
1041 
1042 		readonly = cfg_tuple_get(control, "read-only");
1043 		if (!cfg_obj_isvoid(readonly)) {
1044 			listener->readonly = cfg_obj_asboolean(readonly);
1045 		}
1046 	}
1047 
1048 	if (result == ISC_R_SUCCESS) {
1049 		dns_acl_detach(&listener->acl);
1050 		dns_acl_attach(new_acl, &listener->acl);
1051 		dns_acl_detach(&new_acl);
1052 		/* XXXDCL say the old acl is still used? */
1053 	} else if (control != NULL) {
1054 		cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING,
1055 			    "couldn't install new acl for "
1056 			    "command channel %s: %s",
1057 			    socktext, isc_result_totext(result));
1058 	} else {
1059 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1060 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING,
1061 			      "couldn't install new acl for "
1062 			      "command channel %s: %s",
1063 			      socktext, isc_result_totext(result));
1064 	}
1065 
1066 	*listenerp = listener;
1067 }
1068 
1069 static void
1070 add_listener(named_controls_t *cp, controllistener_t **listenerp,
1071 	     const cfg_obj_t *control, const cfg_obj_t *config,
1072 	     isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
1073 	     const char *socktext, isc_socktype_t type) {
1074 	isc_mem_t *mctx = cp->server->mctx;
1075 	controllistener_t *listener = NULL;
1076 	const cfg_obj_t *allow = NULL;
1077 	const cfg_obj_t *global_keylist = NULL;
1078 	const cfg_obj_t *control_keylist = NULL;
1079 	dns_acl_t *new_acl = NULL;
1080 	isc_result_t result = ISC_R_SUCCESS;
1081 	int pf;
1082 
1083 	/* Don't create new listener if we are shutting down */
1084 	if (cp->shuttingdown) {
1085 		result = ISC_R_SHUTTINGDOWN;
1086 		goto shuttingdown;
1087 	}
1088 
1089 	listener = isc_mem_get(mctx, sizeof(*listener));
1090 	*listener = (controllistener_t){ .controls = cp,
1091 					 .address = *addr,
1092 					 .type = type };
1093 	isc_mem_attach(mctx, &listener->mctx);
1094 	ISC_LINK_INIT(listener, link);
1095 	ISC_LIST_INIT(listener->keys);
1096 	ISC_LIST_INIT(listener->connections);
1097 	isc_refcount_init(&listener->references, 1);
1098 
1099 	/*
1100 	 * Make the ACL.
1101 	 */
1102 	if (control != NULL && type == isc_socktype_tcp) {
1103 		const cfg_obj_t *readonly = NULL;
1104 
1105 		allow = cfg_tuple_get(control, "allow");
1106 		CHECK(cfg_acl_fromconfig(allow, config, named_g_lctx,
1107 					 aclconfctx, mctx, 0, &new_acl));
1108 
1109 		readonly = cfg_tuple_get(control, "read-only");
1110 		if (!cfg_obj_isvoid(readonly)) {
1111 			listener->readonly = cfg_obj_asboolean(readonly);
1112 		}
1113 	} else {
1114 		CHECK(dns_acl_any(mctx, &new_acl));
1115 	}
1116 
1117 	dns_acl_attach(new_acl, &listener->acl);
1118 	dns_acl_detach(&new_acl);
1119 
1120 	if (config != NULL) {
1121 		get_key_info(config, control, &global_keylist,
1122 			     &control_keylist);
1123 	}
1124 
1125 	if (control_keylist != NULL) {
1126 		controlkeylist_fromcfg(control_keylist, listener->mctx,
1127 				       &listener->keys);
1128 		register_keys(control, global_keylist, &listener->keys,
1129 			      listener->mctx, socktext);
1130 	} else {
1131 		result = get_rndckey(mctx, &listener->keys);
1132 		if (result != ISC_R_SUCCESS && control != NULL) {
1133 			cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING,
1134 				    "couldn't install keys for "
1135 				    "command channel %s: %s",
1136 				    socktext, isc_result_totext(result));
1137 		}
1138 	}
1139 
1140 	pf = isc_sockaddr_pf(&listener->address);
1141 	if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
1142 	    (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
1143 	{
1144 		CHECK(ISC_R_FAMILYNOSUPPORT);
1145 	}
1146 
1147 	CHECK(isc_nm_listentcp(named_g_netmgr, ISC_NM_LISTEN_ONE,
1148 			       &listener->address, control_newconn, listener, 5,
1149 			       NULL, &listener->sock));
1150 
1151 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1152 		      NAMED_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
1153 		      "command channel listening on %s", socktext);
1154 	*listenerp = listener;
1155 	return;
1156 
1157 cleanup:
1158 	isc_refcount_decrement(&listener->references);
1159 	listener->shuttingdown = true;
1160 	free_listener(listener);
1161 
1162 shuttingdown:
1163 	if (control != NULL) {
1164 		cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING,
1165 			    "couldn't add command channel %s: %s", socktext,
1166 			    isc_result_totext(result));
1167 	} else {
1168 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1169 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
1170 			      "couldn't add command channel %s: %s", socktext,
1171 			      isc_result_totext(result));
1172 	}
1173 
1174 	*listenerp = NULL;
1175 }
1176 
1177 isc_result_t
1178 named_controls_configure(named_controls_t *cp, const cfg_obj_t *config,
1179 			 cfg_aclconfctx_t *aclconfctx) {
1180 	controllistener_t *listener = NULL;
1181 	controllistenerlist_t new_listeners;
1182 	const cfg_obj_t *controlslist = NULL;
1183 	const cfg_listelt_t *element, *element2;
1184 	char socktext[ISC_SOCKADDR_FORMATSIZE];
1185 
1186 	ISC_LIST_INIT(new_listeners);
1187 
1188 	/*
1189 	 * Get the list of named.conf 'controls' statements.
1190 	 */
1191 	(void)cfg_map_get(config, "controls", &controlslist);
1192 
1193 	/*
1194 	 * Run through the new control channel list, noting sockets that
1195 	 * are already being listened on and moving them to the new list.
1196 	 *
1197 	 * Identifying duplicate addr/port combinations is left to either
1198 	 * the underlying config code, or to the bind attempt getting an
1199 	 * address-in-use error.
1200 	 */
1201 	if (controlslist != NULL) {
1202 		for (element = cfg_list_first(controlslist); element != NULL;
1203 		     element = cfg_list_next(element))
1204 		{
1205 			const cfg_obj_t *controls = NULL;
1206 			const cfg_obj_t *inetcontrols = NULL;
1207 			const cfg_obj_t *unixcontrols = NULL;
1208 
1209 			controls = cfg_listelt_value(element);
1210 
1211 			(void)cfg_map_get(controls, "unix", &unixcontrols);
1212 			if (unixcontrols != NULL) {
1213 				cfg_obj_log(controls, named_g_lctx,
1214 					    ISC_LOG_ERROR,
1215 					    "UNIX domain sockets are not "
1216 					    "supported");
1217 				return ISC_R_FAILURE;
1218 			}
1219 
1220 			(void)cfg_map_get(controls, "inet", &inetcontrols);
1221 			if (inetcontrols == NULL) {
1222 				continue;
1223 			}
1224 
1225 			for (element2 = cfg_list_first(inetcontrols);
1226 			     element2 != NULL;
1227 			     element2 = cfg_list_next(element2))
1228 			{
1229 				const cfg_obj_t *control = NULL;
1230 				const cfg_obj_t *obj = NULL;
1231 				isc_sockaddr_t addr;
1232 
1233 				/*
1234 				 * The parser handles BIND 8 configuration file
1235 				 * syntax, so it allows inet phrases with no
1236 				 * keys{} clause.
1237 				 */
1238 				control = cfg_listelt_value(element2);
1239 
1240 				obj = cfg_tuple_get(control, "address");
1241 				addr = *cfg_obj_assockaddr(obj);
1242 				if (isc_sockaddr_getport(&addr) == 0) {
1243 					isc_sockaddr_setport(
1244 						&addr, NAMED_CONTROL_PORT);
1245 				}
1246 
1247 				isc_sockaddr_format(&addr, socktext,
1248 						    sizeof(socktext));
1249 
1250 				isc_log_write(named_g_lctx,
1251 					      NAMED_LOGCATEGORY_GENERAL,
1252 					      NAMED_LOGMODULE_CONTROL,
1253 					      ISC_LOG_DEBUG(9),
1254 					      "processing control channel %s",
1255 					      socktext);
1256 
1257 				update_listener(cp, &listener, control, config,
1258 						&addr, aclconfctx, socktext,
1259 						isc_socktype_tcp);
1260 
1261 				if (listener != NULL) {
1262 					/*
1263 					 * Remove the listener from the old
1264 					 * list, so it won't be shut down.
1265 					 */
1266 					ISC_LIST_UNLINK(cp->listeners, listener,
1267 							link);
1268 				} else {
1269 					/*
1270 					 * This is a new listener.
1271 					 */
1272 					add_listener(cp, &listener, control,
1273 						     config, &addr, aclconfctx,
1274 						     socktext,
1275 						     isc_socktype_tcp);
1276 				}
1277 
1278 				if (listener != NULL) {
1279 					ISC_LIST_APPEND(new_listeners, listener,
1280 							link);
1281 				}
1282 			}
1283 		}
1284 	} else {
1285 		int i;
1286 
1287 		for (i = 0; i < 2; i++) {
1288 			isc_sockaddr_t addr;
1289 
1290 			if (i == 0) {
1291 				struct in_addr localhost;
1292 
1293 				if (isc_net_probeipv4() != ISC_R_SUCCESS) {
1294 					continue;
1295 				}
1296 				localhost.s_addr = htonl(INADDR_LOOPBACK);
1297 				isc_sockaddr_fromin(&addr, &localhost, 0);
1298 			} else {
1299 				if (isc_net_probeipv6() != ISC_R_SUCCESS) {
1300 					continue;
1301 				}
1302 				isc_sockaddr_fromin6(&addr, &in6addr_loopback,
1303 						     0);
1304 			}
1305 			isc_sockaddr_setport(&addr, NAMED_CONTROL_PORT);
1306 
1307 			isc_sockaddr_format(&addr, socktext, sizeof(socktext));
1308 
1309 			update_listener(cp, &listener, NULL, NULL, &addr, NULL,
1310 					socktext, isc_socktype_tcp);
1311 
1312 			if (listener != NULL) {
1313 				/*
1314 				 * Remove the listener from the old
1315 				 * list, so it won't be shut down.
1316 				 */
1317 				ISC_LIST_UNLINK(cp->listeners, listener, link);
1318 			} else {
1319 				/*
1320 				 * This is a new listener.
1321 				 */
1322 				add_listener(cp, &listener, NULL, NULL, &addr,
1323 					     NULL, socktext, isc_socktype_tcp);
1324 			}
1325 
1326 			if (listener != NULL) {
1327 				ISC_LIST_APPEND(new_listeners, listener, link);
1328 			}
1329 		}
1330 	}
1331 
1332 	/*
1333 	 * named_control_shutdown() will stop whatever is on the global
1334 	 * listeners list, which currently only has whatever sockaddrs
1335 	 * were in the previous configuration (if any) that do not
1336 	 * remain in the current configuration.
1337 	 */
1338 	controls_shutdown(cp);
1339 
1340 	/*
1341 	 * Put all of the valid listeners on the listeners list.
1342 	 * Anything already on listeners in the process of shutting
1343 	 * down will be taken care of by listen_done().
1344 	 */
1345 	ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link);
1346 	return ISC_R_SUCCESS;
1347 }
1348 
1349 isc_result_t
1350 named_controls_create(named_server_t *server, named_controls_t **ctrlsp) {
1351 	isc_mem_t *mctx = server->mctx;
1352 	isc_result_t result;
1353 	named_controls_t *controls = isc_mem_get(mctx, sizeof(*controls));
1354 
1355 	*controls = (named_controls_t){
1356 		.server = server,
1357 	};
1358 
1359 	ISC_LIST_INIT(controls->listeners);
1360 
1361 	isc_mutex_init(&controls->symtab_lock);
1362 	LOCK(&controls->symtab_lock);
1363 	result = isccc_cc_createsymtab(&controls->symtab);
1364 	UNLOCK(&controls->symtab_lock);
1365 
1366 	if (result != ISC_R_SUCCESS) {
1367 		isc_mutex_destroy(&controls->symtab_lock);
1368 		isc_mem_put(server->mctx, controls, sizeof(*controls));
1369 		return result;
1370 	}
1371 	*ctrlsp = controls;
1372 	return ISC_R_SUCCESS;
1373 }
1374 
1375 void
1376 named_controls_destroy(named_controls_t **ctrlsp) {
1377 	named_controls_t *controls = *ctrlsp;
1378 	*ctrlsp = NULL;
1379 
1380 	REQUIRE(controls->shuttingdown);
1381 	REQUIRE(ISC_LIST_EMPTY(controls->listeners));
1382 
1383 	LOCK(&controls->symtab_lock);
1384 	isccc_symtab_destroy(&controls->symtab);
1385 	UNLOCK(&controls->symtab_lock);
1386 	isc_mutex_destroy(&controls->symtab_lock);
1387 	isc_mem_put(controls->server->mctx, controls, sizeof(*controls));
1388 }
1389