controlconf.c revision 225736
1/* 2 * Copyright (C) 2004-2008, 2011 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.2 2011-03-12 04:59:14 tbox 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 if (result == ISCCC_R_BADAUTH) { 377 /* 378 * For some reason, request is non-NULL when 379 * isccc_cc_fromwire returns ISCCC_R_BADAUTH. 380 */ 381 if (request != NULL) 382 isccc_sexpr_free(&request); 383 } else { 384 log_invalid(&conn->ccmsg, result); 385 goto cleanup; 386 } 387 } 388 389 if (key == NULL) { 390 log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); 391 goto cleanup; 392 } 393 394 /* We shouldn't be getting a reply. */ 395 if (isccc_cc_isreply(request)) { 396 log_invalid(&conn->ccmsg, ISC_R_FAILURE); 397 goto cleanup_request; 398 } 399 400 isc_stdtime_get(&now); 401 402 /* 403 * Limit exposure to replay attacks. 404 */ 405 _ctrl = isccc_alist_lookup(request, "_ctrl"); 406 if (_ctrl == NULL) { 407 log_invalid(&conn->ccmsg, ISC_R_FAILURE); 408 goto cleanup_request; 409 } 410 411 if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) { 412 if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) { 413 log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW); 414 goto cleanup_request; 415 } 416 } else { 417 log_invalid(&conn->ccmsg, ISC_R_FAILURE); 418 goto cleanup_request; 419 } 420 421 /* 422 * Expire messages that are too old. 423 */ 424 if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS && 425 now > exp) { 426 log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED); 427 goto cleanup_request; 428 } 429 430 /* 431 * Duplicate suppression (required for UDP). 432 */ 433 isccc_cc_cleansymtab(listener->controls->symtab, now); 434 result = isccc_cc_checkdup(listener->controls->symtab, request, now); 435 if (result != ISC_R_SUCCESS) { 436 if (result == ISC_R_EXISTS) 437 result = ISCCC_R_DUPLICATE; 438 log_invalid(&conn->ccmsg, result); 439 goto cleanup_request; 440 } 441 442 if (conn->nonce != 0 && 443 (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS || 444 conn->nonce != nonce)) { 445 log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); 446 goto cleanup_request; 447 } 448 449 /* 450 * Establish nonce. 451 */ 452 while (conn->nonce == 0) 453 isc_random_get(&conn->nonce); 454 455 isc_buffer_init(&text, textarray, sizeof(textarray)); 456 eresult = ns_control_docommand(request, &text); 457 458 result = isccc_cc_createresponse(request, now, now + 60, &response); 459 if (result != ISC_R_SUCCESS) 460 goto cleanup_request; 461 if (eresult != ISC_R_SUCCESS) { 462 isccc_sexpr_t *data; 463 464 data = isccc_alist_lookup(response, "_data"); 465 if (data != NULL) { 466 const char *estr = isc_result_totext(eresult); 467 if (isccc_cc_definestring(data, "err", estr) == NULL) 468 goto cleanup_response; 469 } 470 } 471 472 if (isc_buffer_usedlength(&text) > 0) { 473 isccc_sexpr_t *data; 474 475 data = isccc_alist_lookup(response, "_data"); 476 if (data != NULL) { 477 char *str = (char *)isc_buffer_base(&text); 478 if (isccc_cc_definestring(data, "text", str) == NULL) 479 goto cleanup_response; 480 } 481 } 482 483 _ctrl = isccc_alist_lookup(response, "_ctrl"); 484 if (_ctrl == NULL || 485 isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL) 486 goto cleanup_response; 487 488 ccregion.rstart = conn->buffer + 4; 489 ccregion.rend = conn->buffer + sizeof(conn->buffer); 490 result = isccc_cc_towire(response, &ccregion, &secret); 491 if (result != ISC_R_SUCCESS) 492 goto cleanup_response; 493 isc_buffer_init(&b, conn->buffer, 4); 494 len = sizeof(conn->buffer) - REGION_SIZE(ccregion); 495 isc_buffer_putuint32(&b, len - 4); 496 r.base = conn->buffer; 497 r.length = len; 498 499 result = isc_socket_send(conn->sock, &r, task, control_senddone, conn); 500 if (result != ISC_R_SUCCESS) 501 goto cleanup_response; 502 conn->sending = ISC_TRUE; 503 504 isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); 505 isccc_sexpr_free(&request); 506 isccc_sexpr_free(&response); 507 return; 508 509 cleanup_response: 510 isccc_sexpr_free(&response); 511 512 cleanup_request: 513 isccc_sexpr_free(&request); 514 isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); 515 516 cleanup: 517 isc_socket_detach(&conn->sock); 518 isccc_ccmsg_invalidate(&conn->ccmsg); 519 conn->ccmsg_valid = ISC_FALSE; 520 maybe_free_connection(conn); 521 maybe_free_listener(listener); 522} 523 524static void 525control_timeout(isc_task_t *task, isc_event_t *event) { 526 controlconnection_t *conn = event->ev_arg; 527 528 UNUSED(task); 529 530 isc_timer_detach(&conn->timer); 531 maybe_free_connection(conn); 532 533 isc_event_free(&event); 534} 535 536static isc_result_t 537newconnection(controllistener_t *listener, isc_socket_t *sock) { 538 controlconnection_t *conn; 539 isc_interval_t interval; 540 isc_result_t result; 541 542 conn = isc_mem_get(listener->mctx, sizeof(*conn)); 543 if (conn == NULL) 544 return (ISC_R_NOMEMORY); 545 546 conn->sock = sock; 547 isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg); 548 conn->ccmsg_valid = ISC_TRUE; 549 conn->sending = ISC_FALSE; 550 conn->timer = NULL; 551 isc_interval_set(&interval, 60, 0); 552 result = isc_timer_create(ns_g_timermgr, isc_timertype_once, 553 NULL, &interval, listener->task, 554 control_timeout, conn, &conn->timer); 555 if (result != ISC_R_SUCCESS) 556 goto cleanup; 557 558 conn->listener = listener; 559 conn->nonce = 0; 560 ISC_LINK_INIT(conn, link); 561 562 result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task, 563 control_recvmessage, conn); 564 if (result != ISC_R_SUCCESS) 565 goto cleanup; 566 isccc_ccmsg_setmaxsize(&conn->ccmsg, 2048); 567 568 ISC_LIST_APPEND(listener->connections, conn, link); 569 return (ISC_R_SUCCESS); 570 571 cleanup: 572 isccc_ccmsg_invalidate(&conn->ccmsg); 573 if (conn->timer != NULL) 574 isc_timer_detach(&conn->timer); 575 isc_mem_put(listener->mctx, conn, sizeof(*conn)); 576 return (result); 577} 578 579static void 580control_newconn(isc_task_t *task, isc_event_t *event) { 581 isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; 582 controllistener_t *listener = event->ev_arg; 583 isc_socket_t *sock; 584 isc_sockaddr_t peeraddr; 585 isc_result_t result; 586 587 UNUSED(task); 588 589 listener->listening = ISC_FALSE; 590 591 if (nevent->result != ISC_R_SUCCESS) { 592 if (nevent->result == ISC_R_CANCELED) { 593 shutdown_listener(listener); 594 goto cleanup; 595 } 596 goto restart; 597 } 598 599 sock = nevent->newsocket; 600 isc_socket_setname(sock, "control", NULL); 601 (void)isc_socket_getpeername(sock, &peeraddr); 602 if (listener->type == isc_sockettype_tcp && 603 !address_ok(&peeraddr, listener->acl)) { 604 char socktext[ISC_SOCKADDR_FORMATSIZE]; 605 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); 606 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 607 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 608 "rejected command channel message from %s", 609 socktext); 610 isc_socket_detach(&sock); 611 goto restart; 612 } 613 614 result = newconnection(listener, sock); 615 if (result != ISC_R_SUCCESS) { 616 char socktext[ISC_SOCKADDR_FORMATSIZE]; 617 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); 618 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 619 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 620 "dropped command channel from %s: %s", 621 socktext, isc_result_totext(result)); 622 isc_socket_detach(&sock); 623 goto restart; 624 } 625 626 restart: 627 control_next(listener); 628 cleanup: 629 isc_event_free(&event); 630} 631 632static void 633controls_shutdown(ns_controls_t *controls) { 634 controllistener_t *listener; 635 controllistener_t *next; 636 637 for (listener = ISC_LIST_HEAD(controls->listeners); 638 listener != NULL; 639 listener = next) 640 { 641 /* 642 * This is asynchronous. As listeners shut down, they will 643 * call their callbacks. 644 */ 645 next = ISC_LIST_NEXT(listener, link); 646 shutdown_listener(listener); 647 } 648} 649 650void 651ns_controls_shutdown(ns_controls_t *controls) { 652 controls_shutdown(controls); 653 controls->shuttingdown = ISC_TRUE; 654} 655 656static isc_result_t 657cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname, 658 const cfg_obj_t **objp) 659{ 660 const cfg_listelt_t *element; 661 const char *str; 662 const cfg_obj_t *obj; 663 664 for (element = cfg_list_first(keylist); 665 element != NULL; 666 element = cfg_list_next(element)) 667 { 668 obj = cfg_listelt_value(element); 669 str = cfg_obj_asstring(cfg_map_getname(obj)); 670 if (strcasecmp(str, keyname) == 0) 671 break; 672 } 673 if (element == NULL) 674 return (ISC_R_NOTFOUND); 675 obj = cfg_listelt_value(element); 676 *objp = obj; 677 return (ISC_R_SUCCESS); 678} 679 680static isc_result_t 681controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx, 682 controlkeylist_t *keyids) 683{ 684 const cfg_listelt_t *element; 685 char *newstr = NULL; 686 const char *str; 687 const cfg_obj_t *obj; 688 controlkey_t *key; 689 690 for (element = cfg_list_first(keylist); 691 element != NULL; 692 element = cfg_list_next(element)) 693 { 694 obj = cfg_listelt_value(element); 695 str = cfg_obj_asstring(obj); 696 newstr = isc_mem_strdup(mctx, str); 697 if (newstr == NULL) 698 goto cleanup; 699 key = isc_mem_get(mctx, sizeof(*key)); 700 if (key == NULL) 701 goto cleanup; 702 key->keyname = newstr; 703 key->secret.base = NULL; 704 key->secret.length = 0; 705 ISC_LINK_INIT(key, link); 706 ISC_LIST_APPEND(*keyids, key, link); 707 newstr = NULL; 708 } 709 return (ISC_R_SUCCESS); 710 711 cleanup: 712 if (newstr != NULL) 713 isc_mem_free(mctx, newstr); 714 free_controlkeylist(keyids, mctx); 715 return (ISC_R_NOMEMORY); 716} 717 718static void 719register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist, 720 controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext) 721{ 722 controlkey_t *keyid, *next; 723 const cfg_obj_t *keydef; 724 char secret[1024]; 725 isc_buffer_t b; 726 isc_result_t result; 727 728 /* 729 * Find the keys corresponding to the keyids used by this listener. 730 */ 731 for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) { 732 next = ISC_LIST_NEXT(keyid, link); 733 734 result = cfgkeylist_find(keylist, keyid->keyname, &keydef); 735 if (result != ISC_R_SUCCESS) { 736 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 737 "couldn't find key '%s' for use with " 738 "command channel %s", 739 keyid->keyname, socktext); 740 ISC_LIST_UNLINK(*keyids, keyid, link); 741 free_controlkey(keyid, mctx); 742 } else { 743 const cfg_obj_t *algobj = NULL; 744 const cfg_obj_t *secretobj = NULL; 745 const char *algstr = NULL; 746 const char *secretstr = NULL; 747 748 (void)cfg_map_get(keydef, "algorithm", &algobj); 749 (void)cfg_map_get(keydef, "secret", &secretobj); 750 INSIST(algobj != NULL && secretobj != NULL); 751 752 algstr = cfg_obj_asstring(algobj); 753 secretstr = cfg_obj_asstring(secretobj); 754 755 if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != 756 ISC_R_SUCCESS) 757 { 758 cfg_obj_log(control, ns_g_lctx, 759 ISC_LOG_WARNING, 760 "unsupported algorithm '%s' in " 761 "key '%s' for use with command " 762 "channel %s", 763 algstr, keyid->keyname, socktext); 764 ISC_LIST_UNLINK(*keyids, keyid, link); 765 free_controlkey(keyid, mctx); 766 continue; 767 } 768 769 isc_buffer_init(&b, secret, sizeof(secret)); 770 result = isc_base64_decodestring(secretstr, &b); 771 772 if (result != ISC_R_SUCCESS) { 773 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, 774 "secret for key '%s' on " 775 "command channel %s: %s", 776 keyid->keyname, socktext, 777 isc_result_totext(result)); 778 ISC_LIST_UNLINK(*keyids, keyid, link); 779 free_controlkey(keyid, mctx); 780 continue; 781 } 782 783 keyid->secret.length = isc_buffer_usedlength(&b); 784 keyid->secret.base = isc_mem_get(mctx, 785 keyid->secret.length); 786 if (keyid->secret.base == NULL) { 787 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, 788 "couldn't register key '%s': " 789 "out of memory", keyid->keyname); 790 ISC_LIST_UNLINK(*keyids, keyid, link); 791 free_controlkey(keyid, mctx); 792 break; 793 } 794 memcpy(keyid->secret.base, isc_buffer_base(&b), 795 keyid->secret.length); 796 } 797 } 798} 799 800#define CHECK(x) \ 801 do { \ 802 result = (x); \ 803 if (result != ISC_R_SUCCESS) \ 804 goto cleanup; \ 805 } while (0) 806 807static isc_result_t 808get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) { 809 isc_result_t result; 810 cfg_parser_t *pctx = NULL; 811 cfg_obj_t *config = NULL; 812 const cfg_obj_t *key = NULL; 813 const cfg_obj_t *algobj = NULL; 814 const cfg_obj_t *secretobj = NULL; 815 const char *algstr = NULL; 816 const char *secretstr = NULL; 817 controlkey_t *keyid = NULL; 818 char secret[1024]; 819 isc_buffer_t b; 820 821 CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx)); 822 CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config)); 823 CHECK(cfg_map_get(config, "key", &key)); 824 825 keyid = isc_mem_get(mctx, sizeof(*keyid)); 826 if (keyid == NULL) 827 CHECK(ISC_R_NOMEMORY); 828 keyid->keyname = isc_mem_strdup(mctx, 829 cfg_obj_asstring(cfg_map_getname(key))); 830 keyid->secret.base = NULL; 831 keyid->secret.length = 0; 832 ISC_LINK_INIT(keyid, link); 833 if (keyid->keyname == NULL) 834 CHECK(ISC_R_NOMEMORY); 835 836 CHECK(bind9_check_key(key, ns_g_lctx)); 837 838 (void)cfg_map_get(key, "algorithm", &algobj); 839 (void)cfg_map_get(key, "secret", &secretobj); 840 INSIST(algobj != NULL && secretobj != NULL); 841 842 algstr = cfg_obj_asstring(algobj); 843 secretstr = cfg_obj_asstring(secretobj); 844 845 if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != ISC_R_SUCCESS) { 846 cfg_obj_log(key, ns_g_lctx, 847 ISC_LOG_WARNING, 848 "unsupported algorithm '%s' in " 849 "key '%s' for use with command " 850 "channel", 851 algstr, keyid->keyname); 852 goto cleanup; 853 } 854 855 isc_buffer_init(&b, secret, sizeof(secret)); 856 result = isc_base64_decodestring(secretstr, &b); 857 858 if (result != ISC_R_SUCCESS) { 859 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 860 "secret for key '%s' on command channel: %s", 861 keyid->keyname, isc_result_totext(result)); 862 goto cleanup; 863 } 864 865 keyid->secret.length = isc_buffer_usedlength(&b); 866 keyid->secret.base = isc_mem_get(mctx, 867 keyid->secret.length); 868 if (keyid->secret.base == NULL) { 869 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 870 "couldn't register key '%s': " 871 "out of memory", keyid->keyname); 872 CHECK(ISC_R_NOMEMORY); 873 } 874 memcpy(keyid->secret.base, isc_buffer_base(&b), 875 keyid->secret.length); 876 ISC_LIST_APPEND(*keyids, keyid, link); 877 keyid = NULL; 878 result = ISC_R_SUCCESS; 879 880 cleanup: 881 if (keyid != NULL) 882 free_controlkey(keyid, mctx); 883 if (config != NULL) 884 cfg_obj_destroy(pctx, &config); 885 if (pctx != NULL) 886 cfg_parser_destroy(&pctx); 887 return (result); 888} 889 890/* 891 * Ensures that both '*global_keylistp' and '*control_keylistp' are 892 * valid or both are NULL. 893 */ 894static void 895get_key_info(const cfg_obj_t *config, const cfg_obj_t *control, 896 const cfg_obj_t **global_keylistp, 897 const cfg_obj_t **control_keylistp) 898{ 899 isc_result_t result; 900 const cfg_obj_t *control_keylist = NULL; 901 const cfg_obj_t *global_keylist = NULL; 902 903 REQUIRE(global_keylistp != NULL && *global_keylistp == NULL); 904 REQUIRE(control_keylistp != NULL && *control_keylistp == NULL); 905 906 control_keylist = cfg_tuple_get(control, "keys"); 907 908 if (!cfg_obj_isvoid(control_keylist) && 909 cfg_list_first(control_keylist) != NULL) { 910 result = cfg_map_get(config, "key", &global_keylist); 911 912 if (result == ISC_R_SUCCESS) { 913 *global_keylistp = global_keylist; 914 *control_keylistp = control_keylist; 915 } 916 } 917} 918 919static void 920update_listener(ns_controls_t *cp, controllistener_t **listenerp, 921 const cfg_obj_t *control, const cfg_obj_t *config, 922 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 923 const char *socktext, isc_sockettype_t type) 924{ 925 controllistener_t *listener; 926 const cfg_obj_t *allow; 927 const cfg_obj_t *global_keylist = NULL; 928 const cfg_obj_t *control_keylist = NULL; 929 dns_acl_t *new_acl = NULL; 930 controlkeylist_t keys; 931 isc_result_t result = ISC_R_SUCCESS; 932 933 for (listener = ISC_LIST_HEAD(cp->listeners); 934 listener != NULL; 935 listener = ISC_LIST_NEXT(listener, link)) 936 if (isc_sockaddr_equal(addr, &listener->address)) 937 break; 938 939 if (listener == NULL) { 940 *listenerp = NULL; 941 return; 942 } 943 944 /* 945 * There is already a listener for this sockaddr. 946 * Update the access list and key information. 947 * 948 * First try to deal with the key situation. There are a few 949 * possibilities: 950 * (a) It had an explicit keylist and still has an explicit keylist. 951 * (b) It had an automagic key and now has an explicit keylist. 952 * (c) It had an explicit keylist and now needs an automagic key. 953 * (d) It has an automagic key and still needs the automagic key. 954 * 955 * (c) and (d) are the annoying ones. The caller needs to know 956 * that it should use the automagic configuration for key information 957 * in place of the named.conf configuration. 958 * 959 * XXXDCL There is one other hazard that has not been dealt with, 960 * the problem that if a key change is being caused by a control 961 * channel reload, then the response will be with the new key 962 * and not able to be decrypted by the client. 963 */ 964 if (control != NULL) 965 get_key_info(config, control, &global_keylist, 966 &control_keylist); 967 968 if (control_keylist != NULL) { 969 INSIST(global_keylist != NULL); 970 971 ISC_LIST_INIT(keys); 972 result = controlkeylist_fromcfg(control_keylist, 973 listener->mctx, &keys); 974 if (result == ISC_R_SUCCESS) { 975 free_controlkeylist(&listener->keys, listener->mctx); 976 listener->keys = keys; 977 register_keys(control, global_keylist, &listener->keys, 978 listener->mctx, socktext); 979 } 980 } else { 981 free_controlkeylist(&listener->keys, listener->mctx); 982 result = get_rndckey(listener->mctx, &listener->keys); 983 } 984 985 if (result != ISC_R_SUCCESS && global_keylist != NULL) { 986 /* 987 * This message might be a little misleading since the 988 * "new keys" might in fact be identical to the old ones, 989 * but tracking whether they are identical just for the 990 * sake of avoiding this message would be too much trouble. 991 */ 992 if (control != NULL) 993 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 994 "couldn't install new keys for " 995 "command channel %s: %s", 996 socktext, isc_result_totext(result)); 997 else 998 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 999 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 1000 "couldn't install new keys for " 1001 "command channel %s: %s", 1002 socktext, isc_result_totext(result)); 1003 } 1004 1005 /* 1006 * Now, keep the old access list unless a new one can be made. 1007 */ 1008 if (control != NULL && type == isc_sockettype_tcp) { 1009 allow = cfg_tuple_get(control, "allow"); 1010 result = cfg_acl_fromconfig(allow, config, ns_g_lctx, 1011 aclconfctx, listener->mctx, 0, 1012 &new_acl); 1013 } else { 1014 result = dns_acl_any(listener->mctx, &new_acl); 1015 } 1016 1017 if (result == ISC_R_SUCCESS) { 1018 dns_acl_detach(&listener->acl); 1019 dns_acl_attach(new_acl, &listener->acl); 1020 dns_acl_detach(&new_acl); 1021 /* XXXDCL say the old acl is still used? */ 1022 } else if (control != NULL) 1023 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1024 "couldn't install new acl for " 1025 "command channel %s: %s", 1026 socktext, isc_result_totext(result)); 1027 else 1028 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1029 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 1030 "couldn't install new acl for " 1031 "command channel %s: %s", 1032 socktext, isc_result_totext(result)); 1033 1034 if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { 1035 isc_uint32_t perm, owner, group; 1036 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); 1037 owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); 1038 group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); 1039 result = ISC_R_SUCCESS; 1040 if (listener->perm != perm || listener->owner != owner || 1041 listener->group != group) 1042 result = isc_socket_permunix(&listener->address, perm, 1043 owner, group); 1044 if (result == ISC_R_SUCCESS) { 1045 listener->perm = perm; 1046 listener->owner = owner; 1047 listener->group = group; 1048 } else if (control != NULL) 1049 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1050 "couldn't update ownership/permission for " 1051 "command channel %s", socktext); 1052 } 1053 1054 *listenerp = listener; 1055} 1056 1057static void 1058add_listener(ns_controls_t *cp, controllistener_t **listenerp, 1059 const cfg_obj_t *control, const cfg_obj_t *config, 1060 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 1061 const char *socktext, isc_sockettype_t type) 1062{ 1063 isc_mem_t *mctx = cp->server->mctx; 1064 controllistener_t *listener; 1065 const cfg_obj_t *allow; 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 1071 listener = isc_mem_get(mctx, sizeof(*listener)); 1072 if (listener == NULL) 1073 result = ISC_R_NOMEMORY; 1074 1075 if (result == ISC_R_SUCCESS) { 1076 listener->controls = cp; 1077 listener->mctx = mctx; 1078 listener->task = cp->server->task; 1079 listener->address = *addr; 1080 listener->sock = NULL; 1081 listener->listening = ISC_FALSE; 1082 listener->exiting = ISC_FALSE; 1083 listener->acl = NULL; 1084 listener->type = type; 1085 listener->perm = 0; 1086 listener->owner = 0; 1087 listener->group = 0; 1088 ISC_LINK_INIT(listener, link); 1089 ISC_LIST_INIT(listener->keys); 1090 ISC_LIST_INIT(listener->connections); 1091 1092 /* 1093 * Make the acl. 1094 */ 1095 if (control != NULL && type == isc_sockettype_tcp) { 1096 allow = cfg_tuple_get(control, "allow"); 1097 result = cfg_acl_fromconfig(allow, config, ns_g_lctx, 1098 aclconfctx, mctx, 0, 1099 &new_acl); 1100 } else { 1101 result = dns_acl_any(mctx, &new_acl); 1102 } 1103 } 1104 1105 if (result == ISC_R_SUCCESS) { 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 if (control_keylist != NULL) { 1114 result = controlkeylist_fromcfg(control_keylist, 1115 listener->mctx, 1116 &listener->keys); 1117 if (result == ISC_R_SUCCESS) 1118 register_keys(control, global_keylist, 1119 &listener->keys, 1120 listener->mctx, socktext); 1121 } else 1122 result = get_rndckey(mctx, &listener->keys); 1123 1124 if (result != ISC_R_SUCCESS && control != NULL) 1125 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1126 "couldn't install keys for " 1127 "command channel %s: %s", 1128 socktext, isc_result_totext(result)); 1129 } 1130 1131 if (result == ISC_R_SUCCESS) { 1132 int pf = isc_sockaddr_pf(&listener->address); 1133 if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || 1134#ifdef ISC_PLATFORM_HAVESYSUNH 1135 (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) || 1136#endif 1137 (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) 1138 result = ISC_R_FAMILYNOSUPPORT; 1139 } 1140 1141 if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) 1142 isc_socket_cleanunix(&listener->address, ISC_FALSE); 1143 1144 if (result == ISC_R_SUCCESS) 1145 result = isc_socket_create(ns_g_socketmgr, 1146 isc_sockaddr_pf(&listener->address), 1147 type, &listener->sock); 1148 if (result == ISC_R_SUCCESS) 1149 isc_socket_setname(listener->sock, "control", NULL); 1150 1151 if (result == ISC_R_SUCCESS) 1152 result = isc_socket_bind(listener->sock, &listener->address, 1153 ISC_SOCKET_REUSEADDRESS); 1154 1155 if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { 1156 listener->perm = cfg_obj_asuint32(cfg_tuple_get(control, 1157 "perm")); 1158 listener->owner = cfg_obj_asuint32(cfg_tuple_get(control, 1159 "owner")); 1160 listener->group = cfg_obj_asuint32(cfg_tuple_get(control, 1161 "group")); 1162 result = isc_socket_permunix(&listener->address, listener->perm, 1163 listener->owner, listener->group); 1164 } 1165 if (result == ISC_R_SUCCESS) 1166 result = control_listen(listener); 1167 1168 if (result == ISC_R_SUCCESS) 1169 result = control_accept(listener); 1170 1171 if (result == ISC_R_SUCCESS) { 1172 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1173 NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, 1174 "command channel listening on %s", socktext); 1175 *listenerp = listener; 1176 1177 } else { 1178 if (listener != NULL) { 1179 listener->exiting = ISC_TRUE; 1180 free_listener(listener); 1181 } 1182 1183 if (control != NULL) 1184 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1185 "couldn't add command channel %s: %s", 1186 socktext, isc_result_totext(result)); 1187 else 1188 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1189 NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, 1190 "couldn't add command channel %s: %s", 1191 socktext, isc_result_totext(result)); 1192 1193 *listenerp = NULL; 1194 } 1195 1196 /* XXXDCL return error results? fail hard? */ 1197} 1198 1199isc_result_t 1200ns_controls_configure(ns_controls_t *cp, const cfg_obj_t *config, 1201 cfg_aclconfctx_t *aclconfctx) 1202{ 1203 controllistener_t *listener; 1204 controllistenerlist_t new_listeners; 1205 const cfg_obj_t *controlslist = NULL; 1206 const cfg_listelt_t *element, *element2; 1207 char socktext[ISC_SOCKADDR_FORMATSIZE]; 1208 1209 ISC_LIST_INIT(new_listeners); 1210 1211 /* 1212 * Get the list of named.conf 'controls' statements. 1213 */ 1214 (void)cfg_map_get(config, "controls", &controlslist); 1215 1216 /* 1217 * Run through the new control channel list, noting sockets that 1218 * are already being listened on and moving them to the new list. 1219 * 1220 * Identifying duplicate addr/port combinations is left to either 1221 * the underlying config code, or to the bind attempt getting an 1222 * address-in-use error. 1223 */ 1224 if (controlslist != NULL) { 1225 for (element = cfg_list_first(controlslist); 1226 element != NULL; 1227 element = cfg_list_next(element)) { 1228 const cfg_obj_t *controls; 1229 const cfg_obj_t *inetcontrols = NULL; 1230 1231 controls = cfg_listelt_value(element); 1232 (void)cfg_map_get(controls, "inet", &inetcontrols); 1233 if (inetcontrols == NULL) 1234 continue; 1235 1236 for (element2 = cfg_list_first(inetcontrols); 1237 element2 != NULL; 1238 element2 = cfg_list_next(element2)) { 1239 const cfg_obj_t *control; 1240 const cfg_obj_t *obj; 1241 isc_sockaddr_t addr; 1242 1243 /* 1244 * The parser handles BIND 8 configuration file 1245 * syntax, so it allows unix phrases as well 1246 * inet phrases with no keys{} clause. 1247 */ 1248 control = cfg_listelt_value(element2); 1249 1250 obj = cfg_tuple_get(control, "address"); 1251 addr = *cfg_obj_assockaddr(obj); 1252 if (isc_sockaddr_getport(&addr) == 0) 1253 isc_sockaddr_setport(&addr, 1254 NS_CONTROL_PORT); 1255 1256 isc_sockaddr_format(&addr, socktext, 1257 sizeof(socktext)); 1258 1259 isc_log_write(ns_g_lctx, 1260 NS_LOGCATEGORY_GENERAL, 1261 NS_LOGMODULE_CONTROL, 1262 ISC_LOG_DEBUG(9), 1263 "processing control channel %s", 1264 socktext); 1265 1266 update_listener(cp, &listener, control, config, 1267 &addr, aclconfctx, socktext, 1268 isc_sockettype_tcp); 1269 1270 if (listener != NULL) 1271 /* 1272 * Remove the listener from the old 1273 * list, so it won't be shut down. 1274 */ 1275 ISC_LIST_UNLINK(cp->listeners, 1276 listener, link); 1277 else 1278 /* 1279 * This is a new listener. 1280 */ 1281 add_listener(cp, &listener, control, 1282 config, &addr, aclconfctx, 1283 socktext, 1284 isc_sockettype_tcp); 1285 1286 if (listener != NULL) 1287 ISC_LIST_APPEND(new_listeners, 1288 listener, link); 1289 } 1290 } 1291 for (element = cfg_list_first(controlslist); 1292 element != NULL; 1293 element = cfg_list_next(element)) { 1294 const cfg_obj_t *controls; 1295 const cfg_obj_t *unixcontrols = NULL; 1296 1297 controls = cfg_listelt_value(element); 1298 (void)cfg_map_get(controls, "unix", &unixcontrols); 1299 if (unixcontrols == NULL) 1300 continue; 1301 1302 for (element2 = cfg_list_first(unixcontrols); 1303 element2 != NULL; 1304 element2 = cfg_list_next(element2)) { 1305 const cfg_obj_t *control; 1306 const cfg_obj_t *path; 1307 isc_sockaddr_t addr; 1308 isc_result_t result; 1309 1310 /* 1311 * The parser handles BIND 8 configuration file 1312 * syntax, so it allows unix phrases as well 1313 * inet phrases with no keys{} clause. 1314 */ 1315 control = cfg_listelt_value(element2); 1316 1317 path = cfg_tuple_get(control, "path"); 1318 result = isc_sockaddr_frompath(&addr, 1319 cfg_obj_asstring(path)); 1320 if (result != ISC_R_SUCCESS) { 1321 isc_log_write(ns_g_lctx, 1322 NS_LOGCATEGORY_GENERAL, 1323 NS_LOGMODULE_CONTROL, 1324 ISC_LOG_DEBUG(9), 1325 "control channel '%s': %s", 1326 cfg_obj_asstring(path), 1327 isc_result_totext(result)); 1328 continue; 1329 } 1330 1331 isc_log_write(ns_g_lctx, 1332 NS_LOGCATEGORY_GENERAL, 1333 NS_LOGMODULE_CONTROL, 1334 ISC_LOG_DEBUG(9), 1335 "processing control channel '%s'", 1336 cfg_obj_asstring(path)); 1337 1338 update_listener(cp, &listener, control, config, 1339 &addr, aclconfctx, 1340 cfg_obj_asstring(path), 1341 isc_sockettype_unix); 1342 1343 if (listener != NULL) 1344 /* 1345 * Remove the listener from the old 1346 * list, so it won't be shut down. 1347 */ 1348 ISC_LIST_UNLINK(cp->listeners, 1349 listener, link); 1350 else 1351 /* 1352 * This is a new listener. 1353 */ 1354 add_listener(cp, &listener, control, 1355 config, &addr, aclconfctx, 1356 cfg_obj_asstring(path), 1357 isc_sockettype_unix); 1358 1359 if (listener != NULL) 1360 ISC_LIST_APPEND(new_listeners, 1361 listener, link); 1362 } 1363 } 1364 } else { 1365 int i; 1366 1367 for (i = 0; i < 2; i++) { 1368 isc_sockaddr_t addr; 1369 1370 if (i == 0) { 1371 struct in_addr localhost; 1372 1373 if (isc_net_probeipv4() != ISC_R_SUCCESS) 1374 continue; 1375 localhost.s_addr = htonl(INADDR_LOOPBACK); 1376 isc_sockaddr_fromin(&addr, &localhost, 0); 1377 } else { 1378 if (isc_net_probeipv6() != ISC_R_SUCCESS) 1379 continue; 1380 isc_sockaddr_fromin6(&addr, 1381 &in6addr_loopback, 0); 1382 } 1383 isc_sockaddr_setport(&addr, NS_CONTROL_PORT); 1384 1385 isc_sockaddr_format(&addr, socktext, sizeof(socktext)); 1386 1387 update_listener(cp, &listener, NULL, NULL, 1388 &addr, NULL, socktext, 1389 isc_sockettype_tcp); 1390 1391 if (listener != NULL) 1392 /* 1393 * Remove the listener from the old 1394 * list, so it won't be shut down. 1395 */ 1396 ISC_LIST_UNLINK(cp->listeners, 1397 listener, link); 1398 else 1399 /* 1400 * This is a new listener. 1401 */ 1402 add_listener(cp, &listener, NULL, NULL, 1403 &addr, NULL, socktext, 1404 isc_sockettype_tcp); 1405 1406 if (listener != NULL) 1407 ISC_LIST_APPEND(new_listeners, 1408 listener, link); 1409 } 1410 } 1411 1412 /* 1413 * ns_control_shutdown() will stop whatever is on the global 1414 * listeners list, which currently only has whatever sockaddrs 1415 * were in the previous configuration (if any) that do not 1416 * remain in the current configuration. 1417 */ 1418 controls_shutdown(cp); 1419 1420 /* 1421 * Put all of the valid listeners on the listeners list. 1422 * Anything already on listeners in the process of shutting 1423 * down will be taken care of by listen_done(). 1424 */ 1425 ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link); 1426 return (ISC_R_SUCCESS); 1427} 1428 1429isc_result_t 1430ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) { 1431 isc_mem_t *mctx = server->mctx; 1432 isc_result_t result; 1433 ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls)); 1434 1435 if (controls == NULL) 1436 return (ISC_R_NOMEMORY); 1437 controls->server = server; 1438 ISC_LIST_INIT(controls->listeners); 1439 controls->shuttingdown = ISC_FALSE; 1440 controls->symtab = NULL; 1441 result = isccc_cc_createsymtab(&controls->symtab); 1442 if (result != ISC_R_SUCCESS) { 1443 isc_mem_put(server->mctx, controls, sizeof(*controls)); 1444 return (result); 1445 } 1446 *ctrlsp = controls; 1447 return (ISC_R_SUCCESS); 1448} 1449 1450void 1451ns_controls_destroy(ns_controls_t **ctrlsp) { 1452 ns_controls_t *controls = *ctrlsp; 1453 1454 REQUIRE(ISC_LIST_EMPTY(controls->listeners)); 1455 1456 isccc_symtab_destroy(&controls->symtab); 1457 isc_mem_put(controls->server->mctx, controls, sizeof(*controls)); 1458 *ctrlsp = NULL; 1459} 1460