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