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