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