controlconf.c revision 186462
1/* 2 * Copyright (C) 2004-2006, 2008 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.40.18.14 2008/07/23 23:33:02 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 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 (void)isc_socket_getpeername(sock, &peeraddr); 601 if (listener->type == isc_sockettype_tcp && 602 !address_ok(&peeraddr, listener->acl)) { 603 char socktext[ISC_SOCKADDR_FORMATSIZE]; 604 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); 605 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 606 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 607 "rejected command channel message from %s", 608 socktext); 609 isc_socket_detach(&sock); 610 goto restart; 611 } 612 613 result = newconnection(listener, sock); 614 if (result != ISC_R_SUCCESS) { 615 char socktext[ISC_SOCKADDR_FORMATSIZE]; 616 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); 617 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 618 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 619 "dropped command channel from %s: %s", 620 socktext, isc_result_totext(result)); 621 isc_socket_detach(&sock); 622 goto restart; 623 } 624 625 restart: 626 control_next(listener); 627 cleanup: 628 isc_event_free(&event); 629} 630 631static void 632controls_shutdown(ns_controls_t *controls) { 633 controllistener_t *listener; 634 controllistener_t *next; 635 636 for (listener = ISC_LIST_HEAD(controls->listeners); 637 listener != NULL; 638 listener = next) 639 { 640 /* 641 * This is asynchronous. As listeners shut down, they will 642 * call their callbacks. 643 */ 644 next = ISC_LIST_NEXT(listener, link); 645 shutdown_listener(listener); 646 } 647} 648 649void 650ns_controls_shutdown(ns_controls_t *controls) { 651 controls_shutdown(controls); 652 controls->shuttingdown = ISC_TRUE; 653} 654 655static isc_result_t 656cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname, 657 const cfg_obj_t **objp) 658{ 659 const cfg_listelt_t *element; 660 const char *str; 661 const cfg_obj_t *obj; 662 663 for (element = cfg_list_first(keylist); 664 element != NULL; 665 element = cfg_list_next(element)) 666 { 667 obj = cfg_listelt_value(element); 668 str = cfg_obj_asstring(cfg_map_getname(obj)); 669 if (strcasecmp(str, keyname) == 0) 670 break; 671 } 672 if (element == NULL) 673 return (ISC_R_NOTFOUND); 674 obj = cfg_listelt_value(element); 675 *objp = obj; 676 return (ISC_R_SUCCESS); 677} 678 679static isc_result_t 680controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx, 681 controlkeylist_t *keyids) 682{ 683 const cfg_listelt_t *element; 684 char *newstr = NULL; 685 const char *str; 686 const cfg_obj_t *obj; 687 controlkey_t *key; 688 689 for (element = cfg_list_first(keylist); 690 element != NULL; 691 element = cfg_list_next(element)) 692 { 693 obj = cfg_listelt_value(element); 694 str = cfg_obj_asstring(obj); 695 newstr = isc_mem_strdup(mctx, str); 696 if (newstr == NULL) 697 goto cleanup; 698 key = isc_mem_get(mctx, sizeof(*key)); 699 if (key == NULL) 700 goto cleanup; 701 key->keyname = newstr; 702 key->secret.base = NULL; 703 key->secret.length = 0; 704 ISC_LINK_INIT(key, link); 705 ISC_LIST_APPEND(*keyids, key, link); 706 newstr = NULL; 707 } 708 return (ISC_R_SUCCESS); 709 710 cleanup: 711 if (newstr != NULL) 712 isc_mem_free(mctx, newstr); 713 free_controlkeylist(keyids, mctx); 714 return (ISC_R_NOMEMORY); 715} 716 717static void 718register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist, 719 controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext) 720{ 721 controlkey_t *keyid, *next; 722 const cfg_obj_t *keydef; 723 char secret[1024]; 724 isc_buffer_t b; 725 isc_result_t result; 726 727 /* 728 * Find the keys corresponding to the keyids used by this listener. 729 */ 730 for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) { 731 next = ISC_LIST_NEXT(keyid, link); 732 733 result = cfgkeylist_find(keylist, keyid->keyname, &keydef); 734 if (result != ISC_R_SUCCESS) { 735 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 736 "couldn't find key '%s' for use with " 737 "command channel %s", 738 keyid->keyname, socktext); 739 ISC_LIST_UNLINK(*keyids, keyid, link); 740 free_controlkey(keyid, mctx); 741 } else { 742 const cfg_obj_t *algobj = NULL; 743 const cfg_obj_t *secretobj = NULL; 744 const char *algstr = NULL; 745 const char *secretstr = NULL; 746 747 (void)cfg_map_get(keydef, "algorithm", &algobj); 748 (void)cfg_map_get(keydef, "secret", &secretobj); 749 INSIST(algobj != NULL && secretobj != NULL); 750 751 algstr = cfg_obj_asstring(algobj); 752 secretstr = cfg_obj_asstring(secretobj); 753 754 if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != 755 ISC_R_SUCCESS) 756 { 757 cfg_obj_log(control, ns_g_lctx, 758 ISC_LOG_WARNING, 759 "unsupported algorithm '%s' in " 760 "key '%s' for use with command " 761 "channel %s", 762 algstr, keyid->keyname, socktext); 763 ISC_LIST_UNLINK(*keyids, keyid, link); 764 free_controlkey(keyid, mctx); 765 continue; 766 } 767 768 isc_buffer_init(&b, secret, sizeof(secret)); 769 result = isc_base64_decodestring(secretstr, &b); 770 771 if (result != ISC_R_SUCCESS) { 772 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, 773 "secret for key '%s' on " 774 "command channel %s: %s", 775 keyid->keyname, socktext, 776 isc_result_totext(result)); 777 ISC_LIST_UNLINK(*keyids, keyid, link); 778 free_controlkey(keyid, mctx); 779 continue; 780 } 781 782 keyid->secret.length = isc_buffer_usedlength(&b); 783 keyid->secret.base = isc_mem_get(mctx, 784 keyid->secret.length); 785 if (keyid->secret.base == NULL) { 786 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, 787 "couldn't register key '%s': " 788 "out of memory", keyid->keyname); 789 ISC_LIST_UNLINK(*keyids, keyid, link); 790 free_controlkey(keyid, mctx); 791 break; 792 } 793 memcpy(keyid->secret.base, isc_buffer_base(&b), 794 keyid->secret.length); 795 } 796 } 797} 798 799#define CHECK(x) \ 800 do { \ 801 result = (x); \ 802 if (result != ISC_R_SUCCESS) \ 803 goto cleanup; \ 804 } while (0) 805 806static isc_result_t 807get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) { 808 isc_result_t result; 809 cfg_parser_t *pctx = NULL; 810 cfg_obj_t *config = NULL; 811 const cfg_obj_t *key = NULL; 812 const cfg_obj_t *algobj = NULL; 813 const cfg_obj_t *secretobj = NULL; 814 const char *algstr = NULL; 815 const char *secretstr = NULL; 816 controlkey_t *keyid = NULL; 817 char secret[1024]; 818 isc_buffer_t b; 819 820 CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx)); 821 CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config)); 822 CHECK(cfg_map_get(config, "key", &key)); 823 824 keyid = isc_mem_get(mctx, sizeof(*keyid)); 825 if (keyid == NULL) 826 CHECK(ISC_R_NOMEMORY); 827 keyid->keyname = isc_mem_strdup(mctx, 828 cfg_obj_asstring(cfg_map_getname(key))); 829 keyid->secret.base = NULL; 830 keyid->secret.length = 0; 831 ISC_LINK_INIT(keyid, link); 832 if (keyid->keyname == NULL) 833 CHECK(ISC_R_NOMEMORY); 834 835 CHECK(bind9_check_key(key, ns_g_lctx)); 836 837 (void)cfg_map_get(key, "algorithm", &algobj); 838 (void)cfg_map_get(key, "secret", &secretobj); 839 INSIST(algobj != NULL && secretobj != NULL); 840 841 algstr = cfg_obj_asstring(algobj); 842 secretstr = cfg_obj_asstring(secretobj); 843 844 if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != ISC_R_SUCCESS) { 845 cfg_obj_log(key, ns_g_lctx, 846 ISC_LOG_WARNING, 847 "unsupported algorithm '%s' in " 848 "key '%s' for use with command " 849 "channel", 850 algstr, keyid->keyname); 851 goto cleanup; 852 } 853 854 isc_buffer_init(&b, secret, sizeof(secret)); 855 result = isc_base64_decodestring(secretstr, &b); 856 857 if (result != ISC_R_SUCCESS) { 858 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 859 "secret for key '%s' on command channel: %s", 860 keyid->keyname, isc_result_totext(result)); 861 CHECK(result); 862 } 863 864 keyid->secret.length = isc_buffer_usedlength(&b); 865 keyid->secret.base = isc_mem_get(mctx, 866 keyid->secret.length); 867 if (keyid->secret.base == NULL) { 868 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 869 "couldn't register key '%s': " 870 "out of memory", keyid->keyname); 871 CHECK(ISC_R_NOMEMORY); 872 } 873 memcpy(keyid->secret.base, isc_buffer_base(&b), 874 keyid->secret.length); 875 ISC_LIST_APPEND(*keyids, keyid, link); 876 keyid = NULL; 877 result = ISC_R_SUCCESS; 878 879 cleanup: 880 if (keyid != NULL) 881 free_controlkey(keyid, mctx); 882 if (config != NULL) 883 cfg_obj_destroy(pctx, &config); 884 if (pctx != NULL) 885 cfg_parser_destroy(&pctx); 886 return (result); 887} 888 889/* 890 * Ensures that both '*global_keylistp' and '*control_keylistp' are 891 * valid or both are NULL. 892 */ 893static void 894get_key_info(const cfg_obj_t *config, const cfg_obj_t *control, 895 const cfg_obj_t **global_keylistp, 896 const cfg_obj_t **control_keylistp) 897{ 898 isc_result_t result; 899 const cfg_obj_t *control_keylist = NULL; 900 const cfg_obj_t *global_keylist = NULL; 901 902 REQUIRE(global_keylistp != NULL && *global_keylistp == NULL); 903 REQUIRE(control_keylistp != NULL && *control_keylistp == NULL); 904 905 control_keylist = cfg_tuple_get(control, "keys"); 906 907 if (!cfg_obj_isvoid(control_keylist) && 908 cfg_list_first(control_keylist) != NULL) { 909 result = cfg_map_get(config, "key", &global_keylist); 910 911 if (result == ISC_R_SUCCESS) { 912 *global_keylistp = global_keylist; 913 *control_keylistp = control_keylist; 914 } 915 } 916} 917 918static void 919update_listener(ns_controls_t *cp, controllistener_t **listenerp, 920 const cfg_obj_t *control, const cfg_obj_t *config, 921 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 922 const char *socktext, isc_sockettype_t type) 923{ 924 controllistener_t *listener; 925 const cfg_obj_t *allow; 926 const cfg_obj_t *global_keylist = NULL; 927 const cfg_obj_t *control_keylist = NULL; 928 dns_acl_t *new_acl = NULL; 929 controlkeylist_t keys; 930 isc_result_t result = ISC_R_SUCCESS; 931 932 for (listener = ISC_LIST_HEAD(cp->listeners); 933 listener != NULL; 934 listener = ISC_LIST_NEXT(listener, link)) 935 if (isc_sockaddr_equal(addr, &listener->address)) 936 break; 937 938 if (listener == NULL) { 939 *listenerp = NULL; 940 return; 941 } 942 943 /* 944 * There is already a listener for this sockaddr. 945 * Update the access list and key information. 946 * 947 * First try to deal with the key situation. There are a few 948 * possibilities: 949 * (a) It had an explicit keylist and still has an explicit keylist. 950 * (b) It had an automagic key and now has an explicit keylist. 951 * (c) It had an explicit keylist and now needs an automagic key. 952 * (d) It has an automagic key and still needs the automagic key. 953 * 954 * (c) and (d) are the annoying ones. The caller needs to know 955 * that it should use the automagic configuration for key information 956 * in place of the named.conf configuration. 957 * 958 * XXXDCL There is one other hazard that has not been dealt with, 959 * the problem that if a key change is being caused by a control 960 * channel reload, then the response will be with the new key 961 * and not able to be decrypted by the client. 962 */ 963 if (control != NULL) 964 get_key_info(config, control, &global_keylist, 965 &control_keylist); 966 967 if (control_keylist != NULL) { 968 INSIST(global_keylist != NULL); 969 970 ISC_LIST_INIT(keys); 971 result = controlkeylist_fromcfg(control_keylist, 972 listener->mctx, &keys); 973 if (result == ISC_R_SUCCESS) { 974 free_controlkeylist(&listener->keys, listener->mctx); 975 listener->keys = keys; 976 register_keys(control, global_keylist, &listener->keys, 977 listener->mctx, socktext); 978 } 979 } else { 980 free_controlkeylist(&listener->keys, listener->mctx); 981 result = get_rndckey(listener->mctx, &listener->keys); 982 } 983 984 if (result != ISC_R_SUCCESS && global_keylist != NULL) { 985 /* 986 * This message might be a little misleading since the 987 * "new keys" might in fact be identical to the old ones, 988 * but tracking whether they are identical just for the 989 * sake of avoiding this message would be too much trouble. 990 */ 991 if (control != NULL) 992 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 993 "couldn't install new keys for " 994 "command channel %s: %s", 995 socktext, isc_result_totext(result)); 996 else 997 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 998 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 999 "couldn't install new keys for " 1000 "command channel %s: %s", 1001 socktext, isc_result_totext(result)); 1002 } 1003 1004 /* 1005 * Now, keep the old access list unless a new one can be made. 1006 */ 1007 if (control != NULL && type == isc_sockettype_tcp) { 1008 allow = cfg_tuple_get(control, "allow"); 1009 result = cfg_acl_fromconfig(allow, config, ns_g_lctx, 1010 aclconfctx, listener->mctx, 1011 &new_acl); 1012 } else { 1013 result = dns_acl_any(listener->mctx, &new_acl); 1014 } 1015 1016 if (result == ISC_R_SUCCESS) { 1017 dns_acl_detach(&listener->acl); 1018 dns_acl_attach(new_acl, &listener->acl); 1019 dns_acl_detach(&new_acl); 1020 /* XXXDCL say the old acl is still used? */ 1021 } else if (control != NULL) 1022 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1023 "couldn't install new acl for " 1024 "command channel %s: %s", 1025 socktext, isc_result_totext(result)); 1026 else 1027 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1028 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 1029 "couldn't install new acl for " 1030 "command channel %s: %s", 1031 socktext, isc_result_totext(result)); 1032 1033 if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { 1034 isc_uint32_t perm, owner, group; 1035 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); 1036 owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); 1037 group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); 1038 result = ISC_R_SUCCESS; 1039 if (listener->perm != perm || listener->owner != owner || 1040 listener->group != group) 1041 result = isc_socket_permunix(&listener->address, perm, 1042 owner, group); 1043 if (result == ISC_R_SUCCESS) { 1044 listener->perm = perm; 1045 listener->owner = owner; 1046 listener->group = group; 1047 } else if (control != NULL) 1048 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1049 "couldn't update ownership/permission for " 1050 "command channel %s", socktext); 1051 } 1052 1053 *listenerp = listener; 1054} 1055 1056static void 1057add_listener(ns_controls_t *cp, controllistener_t **listenerp, 1058 const cfg_obj_t *control, const cfg_obj_t *config, 1059 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 1060 const char *socktext, isc_sockettype_t type) 1061{ 1062 isc_mem_t *mctx = cp->server->mctx; 1063 controllistener_t *listener; 1064 const cfg_obj_t *allow; 1065 const cfg_obj_t *global_keylist = NULL; 1066 const cfg_obj_t *control_keylist = NULL; 1067 dns_acl_t *new_acl = NULL; 1068 isc_result_t result = ISC_R_SUCCESS; 1069 1070 listener = isc_mem_get(mctx, sizeof(*listener)); 1071 if (listener == NULL) 1072 result = ISC_R_NOMEMORY; 1073 1074 if (result == ISC_R_SUCCESS) { 1075 listener->controls = cp; 1076 listener->mctx = mctx; 1077 listener->task = cp->server->task; 1078 listener->address = *addr; 1079 listener->sock = NULL; 1080 listener->listening = ISC_FALSE; 1081 listener->exiting = ISC_FALSE; 1082 listener->acl = NULL; 1083 listener->type = type; 1084 listener->perm = 0; 1085 listener->owner = 0; 1086 listener->group = 0; 1087 ISC_LINK_INIT(listener, link); 1088 ISC_LIST_INIT(listener->keys); 1089 ISC_LIST_INIT(listener->connections); 1090 1091 /* 1092 * Make the acl. 1093 */ 1094 if (control != NULL && type == isc_sockettype_tcp) { 1095 allow = cfg_tuple_get(control, "allow"); 1096 result = cfg_acl_fromconfig(allow, config, ns_g_lctx, 1097 aclconfctx, mctx, &new_acl); 1098 } else { 1099 result = dns_acl_any(mctx, &new_acl); 1100 } 1101 } 1102 1103 if (result == ISC_R_SUCCESS) { 1104 dns_acl_attach(new_acl, &listener->acl); 1105 dns_acl_detach(&new_acl); 1106 1107 if (config != NULL) 1108 get_key_info(config, control, &global_keylist, 1109 &control_keylist); 1110 1111 if (control_keylist != NULL) { 1112 result = controlkeylist_fromcfg(control_keylist, 1113 listener->mctx, 1114 &listener->keys); 1115 if (result == ISC_R_SUCCESS) 1116 register_keys(control, global_keylist, 1117 &listener->keys, 1118 listener->mctx, socktext); 1119 } else 1120 result = get_rndckey(mctx, &listener->keys); 1121 1122 if (result != ISC_R_SUCCESS && control != NULL) 1123 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1124 "couldn't install keys for " 1125 "command channel %s: %s", 1126 socktext, isc_result_totext(result)); 1127 } 1128 1129 if (result == ISC_R_SUCCESS) { 1130 int pf = isc_sockaddr_pf(&listener->address); 1131 if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || 1132#ifdef ISC_PLATFORM_HAVESYSUNH 1133 (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) || 1134#endif 1135 (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) 1136 result = ISC_R_FAMILYNOSUPPORT; 1137 } 1138 1139 if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) 1140 isc_socket_cleanunix(&listener->address, ISC_FALSE); 1141 1142 if (result == ISC_R_SUCCESS) 1143 result = isc_socket_create(ns_g_socketmgr, 1144 isc_sockaddr_pf(&listener->address), 1145 type, &listener->sock); 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