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