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