00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/base64.h>
00025 #include <isc/buffer.h>
00026 #include <isc/event.h>
00027 #include <isc/file.h>
00028 #include <isc/mem.h>
00029 #include <isc/net.h>
00030 #include <isc/netaddr.h>
00031 #include <isc/random.h>
00032 #include <isc/result.h>
00033 #include <isc/stdtime.h>
00034 #include <isc/string.h>
00035 #include <isc/timer.h>
00036 #include <isc/util.h>
00037
00038 #include <isccfg/namedconf.h>
00039
00040 #include <bind9/check.h>
00041
00042 #include <isccc/alist.h>
00043 #include <isccc/cc.h>
00044 #include <isccc/ccmsg.h>
00045 #include <isccc/events.h>
00046 #include <isccc/result.h>
00047 #include <isccc/sexpr.h>
00048 #include <isccc/symtab.h>
00049 #include <isccc/util.h>
00050
00051 #include <dns/result.h>
00052
00053 #include <named/config.h>
00054 #include <named/control.h>
00055 #include <named/log.h>
00056 #include <named/server.h>
00057
00058
00059
00060
00061
00062
00063
00064 typedef struct controlkey controlkey_t;
00065 typedef ISC_LIST(controlkey_t) controlkeylist_t;
00066
00067 typedef struct controlconnection controlconnection_t;
00068 typedef ISC_LIST(controlconnection_t) controlconnectionlist_t;
00069
00070 typedef struct controllistener controllistener_t;
00071 typedef ISC_LIST(controllistener_t) controllistenerlist_t;
00072
00073 struct controlkey {
00074 char * keyname;
00075 isc_uint32_t algorithm;
00076 isc_region_t secret;
00077 ISC_LINK(controlkey_t) link;
00078 };
00079
00080 struct controlconnection {
00081 isc_socket_t * sock;
00082 isccc_ccmsg_t ccmsg;
00083 isc_boolean_t ccmsg_valid;
00084 isc_boolean_t sending;
00085 isc_timer_t * timer;
00086 isc_buffer_t * buffer;
00087 controllistener_t * listener;
00088 isc_uint32_t nonce;
00089 ISC_LINK(controlconnection_t) link;
00090 };
00091
00092 struct controllistener {
00093 ns_controls_t * controls;
00094 isc_mem_t * mctx;
00095 isc_task_t * task;
00096 isc_sockaddr_t address;
00097 isc_socket_t * sock;
00098 dns_acl_t * acl;
00099 isc_boolean_t listening;
00100 isc_boolean_t exiting;
00101 controlkeylist_t keys;
00102 controlconnectionlist_t connections;
00103 isc_sockettype_t type;
00104 isc_uint32_t perm;
00105 isc_uint32_t owner;
00106 isc_uint32_t group;
00107 ISC_LINK(controllistener_t) link;
00108 };
00109
00110 struct ns_controls {
00111 ns_server_t *server;
00112 controllistenerlist_t listeners;
00113 isc_boolean_t shuttingdown;
00114 isccc_symtab_t *symtab;
00115 };
00116
00117 static void control_newconn(isc_task_t *task, isc_event_t *event);
00118 static void control_recvmessage(isc_task_t *task, isc_event_t *event);
00119
00120 #define CLOCKSKEW 300
00121
00122 static void
00123 free_controlkey(controlkey_t *key, isc_mem_t *mctx) {
00124 if (key->keyname != NULL)
00125 isc_mem_free(mctx, key->keyname);
00126 if (key->secret.base != NULL)
00127 isc_mem_put(mctx, key->secret.base, key->secret.length);
00128 isc_mem_put(mctx, key, sizeof(*key));
00129 }
00130
00131 static void
00132 free_controlkeylist(controlkeylist_t *keylist, isc_mem_t *mctx) {
00133 while (!ISC_LIST_EMPTY(*keylist)) {
00134 controlkey_t *key = ISC_LIST_HEAD(*keylist);
00135 ISC_LIST_UNLINK(*keylist, key, link);
00136 free_controlkey(key, mctx);
00137 }
00138 }
00139
00140 static void
00141 free_listener(controllistener_t *listener) {
00142 INSIST(listener->exiting);
00143 INSIST(!listener->listening);
00144 INSIST(ISC_LIST_EMPTY(listener->connections));
00145
00146 if (listener->sock != NULL)
00147 isc_socket_detach(&listener->sock);
00148
00149 free_controlkeylist(&listener->keys, listener->mctx);
00150
00151 if (listener->acl != NULL)
00152 dns_acl_detach(&listener->acl);
00153
00154 isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
00155 }
00156
00157 static void
00158 maybe_free_listener(controllistener_t *listener) {
00159 if (listener->exiting &&
00160 !listener->listening &&
00161 ISC_LIST_EMPTY(listener->connections))
00162 free_listener(listener);
00163 }
00164
00165 static void
00166 maybe_free_connection(controlconnection_t *conn) {
00167 controllistener_t *listener = conn->listener;
00168
00169 if (conn->buffer != NULL)
00170 isc_buffer_free(&conn->buffer);
00171
00172 if (conn->timer != NULL)
00173 isc_timer_detach(&conn->timer);
00174
00175 if (conn->ccmsg_valid) {
00176 isccc_ccmsg_cancelread(&conn->ccmsg);
00177 return;
00178 }
00179
00180 if (conn->sending) {
00181 isc_socket_cancel(conn->sock, listener->task,
00182 ISC_SOCKCANCEL_SEND);
00183 return;
00184 }
00185
00186 ISC_LIST_UNLINK(listener->connections, conn, link);
00187 isc_mem_put(listener->mctx, conn, sizeof(*conn));
00188 }
00189
00190 static void
00191 shutdown_listener(controllistener_t *listener) {
00192 controlconnection_t *conn;
00193 controlconnection_t *next;
00194
00195 if (!listener->exiting) {
00196 char socktext[ISC_SOCKADDR_FORMATSIZE];
00197
00198 ISC_LIST_UNLINK(listener->controls->listeners, listener, link);
00199
00200 isc_sockaddr_format(&listener->address, socktext,
00201 sizeof(socktext));
00202 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00203 NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
00204 "stopping command channel on %s", socktext);
00205 if (listener->type == isc_sockettype_unix)
00206 isc_socket_cleanunix(&listener->address, ISC_TRUE);
00207 listener->exiting = ISC_TRUE;
00208 }
00209
00210 for (conn = ISC_LIST_HEAD(listener->connections);
00211 conn != NULL;
00212 conn = next)
00213 {
00214 next = ISC_LIST_NEXT(conn, link);
00215 maybe_free_connection(conn);
00216 }
00217
00218 if (listener->listening)
00219 isc_socket_cancel(listener->sock, listener->task,
00220 ISC_SOCKCANCEL_ACCEPT);
00221
00222 maybe_free_listener(listener);
00223 }
00224
00225 static isc_boolean_t
00226 address_ok(isc_sockaddr_t *sockaddr, dns_acl_t *acl) {
00227 isc_netaddr_t netaddr;
00228 isc_result_t result;
00229 int match;
00230
00231 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
00232
00233 result = dns_acl_match(&netaddr, NULL, acl,
00234 &ns_g_server->aclenv, &match, NULL);
00235
00236 if (result != ISC_R_SUCCESS || match <= 0)
00237 return (ISC_FALSE);
00238 else
00239 return (ISC_TRUE);
00240 }
00241
00242 static isc_result_t
00243 control_accept(controllistener_t *listener) {
00244 isc_result_t result;
00245 result = isc_socket_accept(listener->sock,
00246 listener->task,
00247 control_newconn, listener);
00248 if (result != ISC_R_SUCCESS)
00249 UNEXPECTED_ERROR(__FILE__, __LINE__,
00250 "isc_socket_accept() failed: %s",
00251 isc_result_totext(result));
00252 else
00253 listener->listening = ISC_TRUE;
00254 return (result);
00255 }
00256
00257 static isc_result_t
00258 control_listen(controllistener_t *listener) {
00259 isc_result_t result;
00260
00261 result = isc_socket_listen(listener->sock, 0);
00262 if (result != ISC_R_SUCCESS)
00263 UNEXPECTED_ERROR(__FILE__, __LINE__,
00264 "isc_socket_listen() failed: %s",
00265 isc_result_totext(result));
00266 return (result);
00267 }
00268
00269 static void
00270 control_next(controllistener_t *listener) {
00271 (void)control_accept(listener);
00272 }
00273
00274 static void
00275 control_senddone(isc_task_t *task, isc_event_t *event) {
00276 isc_socketevent_t *sevent = (isc_socketevent_t *) event;
00277 controlconnection_t *conn = event->ev_arg;
00278 controllistener_t *listener = conn->listener;
00279 isc_socket_t *sock = (isc_socket_t *)sevent->ev_sender;
00280 isc_result_t result;
00281
00282 REQUIRE(conn->sending);
00283
00284 UNUSED(task);
00285
00286 conn->sending = ISC_FALSE;
00287
00288 if (sevent->result != ISC_R_SUCCESS &&
00289 sevent->result != ISC_R_CANCELED)
00290 {
00291 char socktext[ISC_SOCKADDR_FORMATSIZE];
00292 isc_sockaddr_t peeraddr;
00293
00294 (void)isc_socket_getpeername(sock, &peeraddr);
00295 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
00296 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00297 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
00298 "error sending command response to %s: %s",
00299 socktext, isc_result_totext(sevent->result));
00300 }
00301 isc_event_free(&event);
00302
00303 result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
00304 control_recvmessage, conn);
00305 if (result != ISC_R_SUCCESS) {
00306 isc_socket_detach(&conn->sock);
00307 maybe_free_connection(conn);
00308 maybe_free_listener(listener);
00309 }
00310 }
00311
00312 static inline void
00313 log_invalid(isccc_ccmsg_t *ccmsg, isc_result_t result) {
00314 char socktext[ISC_SOCKADDR_FORMATSIZE];
00315 isc_sockaddr_t peeraddr;
00316
00317 (void)isc_socket_getpeername(ccmsg->sock, &peeraddr);
00318 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
00319 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00320 NS_LOGMODULE_CONTROL, ISC_LOG_ERROR,
00321 "invalid command from %s: %s",
00322 socktext, isc_result_totext(result));
00323 }
00324
00325 static void
00326 control_recvmessage(isc_task_t *task, isc_event_t *event) {
00327 controlconnection_t *conn;
00328 controllistener_t *listener;
00329 controlkey_t *key;
00330 isccc_sexpr_t *request = NULL;
00331 isccc_sexpr_t *response = NULL;
00332 isc_uint32_t algorithm;
00333 isccc_region_t secret;
00334 isc_stdtime_t now;
00335 isc_buffer_t b;
00336 isc_region_t r;
00337 isc_buffer_t *text;
00338 isc_result_t result;
00339 isc_result_t eresult;
00340 isccc_sexpr_t *_ctrl;
00341 isccc_time_t sent;
00342 isccc_time_t exp;
00343 isc_uint32_t nonce;
00344
00345 REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG);
00346
00347 conn = event->ev_arg;
00348 listener = conn->listener;
00349 algorithm = DST_ALG_UNKNOWN;
00350 secret.rstart = NULL;
00351 text = NULL;
00352
00353
00354 if (listener->controls->shuttingdown)
00355 goto cleanup;
00356
00357 if (conn->ccmsg.result != ISC_R_SUCCESS) {
00358 if (conn->ccmsg.result != ISC_R_CANCELED &&
00359 conn->ccmsg.result != ISC_R_EOF)
00360 log_invalid(&conn->ccmsg, conn->ccmsg.result);
00361 goto cleanup;
00362 }
00363
00364 request = NULL;
00365
00366 for (key = ISC_LIST_HEAD(listener->keys);
00367 key != NULL;
00368 key = ISC_LIST_NEXT(key, link))
00369 {
00370 isccc_region_t ccregion;
00371
00372 ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer);
00373 ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer);
00374 secret.rstart = isc_mem_get(listener->mctx, key->secret.length);
00375 if (secret.rstart == NULL)
00376 goto cleanup;
00377 memmove(secret.rstart, key->secret.base, key->secret.length);
00378 secret.rend = secret.rstart + key->secret.length;
00379 algorithm = key->algorithm;
00380 result = isccc_cc_fromwire(&ccregion, &request,
00381 algorithm, &secret);
00382 if (result == ISC_R_SUCCESS)
00383 break;
00384 isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
00385 if (result != ISCCC_R_BADAUTH) {
00386 log_invalid(&conn->ccmsg, result);
00387 goto cleanup;
00388 }
00389 }
00390
00391 if (key == NULL) {
00392 log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
00393 goto cleanup;
00394 }
00395
00396
00397 if (isccc_cc_isreply(request)) {
00398 log_invalid(&conn->ccmsg, ISC_R_FAILURE);
00399 goto cleanup_request;
00400 }
00401
00402 isc_stdtime_get(&now);
00403
00404
00405
00406
00407 _ctrl = isccc_alist_lookup(request, "_ctrl");
00408 if (_ctrl == NULL) {
00409 log_invalid(&conn->ccmsg, ISC_R_FAILURE);
00410 goto cleanup_request;
00411 }
00412
00413 if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) {
00414 if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) {
00415 log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW);
00416 goto cleanup_request;
00417 }
00418 } else {
00419 log_invalid(&conn->ccmsg, ISC_R_FAILURE);
00420 goto cleanup_request;
00421 }
00422
00423
00424
00425
00426 if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS &&
00427 now > exp) {
00428 log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED);
00429 goto cleanup_request;
00430 }
00431
00432
00433
00434
00435 isccc_cc_cleansymtab(listener->controls->symtab, now);
00436 result = isccc_cc_checkdup(listener->controls->symtab, request, now);
00437 if (result != ISC_R_SUCCESS) {
00438 if (result == ISC_R_EXISTS)
00439 result = ISCCC_R_DUPLICATE;
00440 log_invalid(&conn->ccmsg, result);
00441 goto cleanup_request;
00442 }
00443
00444 if (conn->nonce != 0 &&
00445 (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS ||
00446 conn->nonce != nonce)) {
00447 log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
00448 goto cleanup_request;
00449 }
00450
00451 result = isc_buffer_allocate(listener->mctx, &text, 2 * 2048);
00452 if (result != ISC_R_SUCCESS)
00453 goto cleanup_request;
00454
00455
00456
00457
00458 if (conn->nonce == 0) {
00459 while (conn->nonce == 0)
00460 isc_random_get(&conn->nonce);
00461 eresult = ISC_R_SUCCESS;
00462 } else
00463 eresult = ns_control_docommand(request, &text);
00464
00465 result = isccc_cc_createresponse(request, now, now + 60, &response);
00466 if (result != ISC_R_SUCCESS)
00467 goto cleanup_request;
00468 if (eresult != ISC_R_SUCCESS) {
00469 isccc_sexpr_t *data;
00470
00471 data = isccc_alist_lookup(response, "_data");
00472 if (data != NULL) {
00473 const char *estr = isc_result_totext(eresult);
00474 if (isccc_cc_definestring(data, "err", estr) == NULL)
00475 goto cleanup_response;
00476 }
00477 }
00478
00479 if (isc_buffer_usedlength(text) > 0) {
00480 isccc_sexpr_t *data;
00481
00482 data = isccc_alist_lookup(response, "_data");
00483 if (data != NULL) {
00484 char *str = (char *)isc_buffer_base(text);
00485 if (isccc_cc_definestring(data, "text", str) == NULL)
00486 goto cleanup_response;
00487 }
00488 }
00489
00490 _ctrl = isccc_alist_lookup(response, "_ctrl");
00491 if (_ctrl == NULL ||
00492 isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL)
00493 goto cleanup_response;
00494
00495 if (conn->buffer == NULL) {
00496 result = isc_buffer_allocate(listener->mctx,
00497 &conn->buffer, 2 * 2048);
00498 if (result != ISC_R_SUCCESS)
00499 goto cleanup_response;
00500 }
00501
00502 isc_buffer_clear(conn->buffer);
00503
00504 isc_buffer_add(conn->buffer, 4);
00505
00506 result = isccc_cc_towire(response, &conn->buffer, algorithm, &secret);
00507 if (result != ISC_R_SUCCESS)
00508 goto cleanup_response;
00509
00510 isc_buffer_init(&b, conn->buffer->base, 4);
00511 isc_buffer_putuint32(&b, conn->buffer->used - 4);
00512
00513 r.base = conn->buffer->base;
00514 r.length = conn->buffer->used;
00515
00516 result = isc_socket_send(conn->sock, &r, task, control_senddone, conn);
00517 if (result != ISC_R_SUCCESS)
00518 goto cleanup_response;
00519 conn->sending = ISC_TRUE;
00520
00521 isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
00522 isccc_sexpr_free(&request);
00523 isccc_sexpr_free(&response);
00524 isc_buffer_free(&text);
00525 return;
00526
00527 cleanup_response:
00528 isccc_sexpr_free(&response);
00529
00530 cleanup_request:
00531 isccc_sexpr_free(&request);
00532 isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
00533 if (text != NULL)
00534 isc_buffer_free(&text);
00535
00536 cleanup:
00537 isc_socket_detach(&conn->sock);
00538 isccc_ccmsg_invalidate(&conn->ccmsg);
00539 conn->ccmsg_valid = ISC_FALSE;
00540 maybe_free_connection(conn);
00541 maybe_free_listener(listener);
00542 }
00543
00544 static void
00545 control_timeout(isc_task_t *task, isc_event_t *event) {
00546 controlconnection_t *conn = event->ev_arg;
00547
00548 UNUSED(task);
00549
00550 isc_timer_detach(&conn->timer);
00551 maybe_free_connection(conn);
00552
00553 isc_event_free(&event);
00554 }
00555
00556 static isc_result_t
00557 newconnection(controllistener_t *listener, isc_socket_t *sock) {
00558 controlconnection_t *conn;
00559 isc_interval_t interval;
00560 isc_result_t result;
00561
00562 conn = isc_mem_get(listener->mctx, sizeof(*conn));
00563 if (conn == NULL)
00564 return (ISC_R_NOMEMORY);
00565
00566 conn->sock = sock;
00567 isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg);
00568 conn->ccmsg_valid = ISC_TRUE;
00569 conn->sending = ISC_FALSE;
00570 conn->buffer = NULL;
00571 conn->timer = NULL;
00572 isc_interval_set(&interval, 60, 0);
00573 result = isc_timer_create(ns_g_timermgr, isc_timertype_once,
00574 NULL, &interval, listener->task,
00575 control_timeout, conn, &conn->timer);
00576 if (result != ISC_R_SUCCESS)
00577 goto cleanup;
00578
00579 conn->listener = listener;
00580 conn->nonce = 0;
00581 ISC_LINK_INIT(conn, link);
00582
00583 result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
00584 control_recvmessage, conn);
00585 if (result != ISC_R_SUCCESS)
00586 goto cleanup;
00587
00588 ISC_LIST_APPEND(listener->connections, conn, link);
00589 return (ISC_R_SUCCESS);
00590
00591 cleanup:
00592 if (conn->buffer != NULL)
00593 isc_buffer_free(&conn->buffer);
00594 isccc_ccmsg_invalidate(&conn->ccmsg);
00595 if (conn->timer != NULL)
00596 isc_timer_detach(&conn->timer);
00597 isc_mem_put(listener->mctx, conn, sizeof(*conn));
00598 return (result);
00599 }
00600
00601 static void
00602 control_newconn(isc_task_t *task, isc_event_t *event) {
00603 isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
00604 controllistener_t *listener = event->ev_arg;
00605 isc_socket_t *sock;
00606 isc_sockaddr_t peeraddr;
00607 isc_result_t result;
00608
00609 UNUSED(task);
00610
00611 listener->listening = ISC_FALSE;
00612
00613 if (nevent->result != ISC_R_SUCCESS) {
00614 if (nevent->result == ISC_R_CANCELED) {
00615 shutdown_listener(listener);
00616 goto cleanup;
00617 }
00618 goto restart;
00619 }
00620
00621 sock = nevent->newsocket;
00622 isc_socket_setname(sock, "control", NULL);
00623 (void)isc_socket_getpeername(sock, &peeraddr);
00624 if (listener->type == isc_sockettype_tcp &&
00625 !address_ok(&peeraddr, listener->acl)) {
00626 char socktext[ISC_SOCKADDR_FORMATSIZE];
00627 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
00628 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00629 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
00630 "rejected command channel message from %s",
00631 socktext);
00632 isc_socket_detach(&sock);
00633 goto restart;
00634 }
00635
00636 result = newconnection(listener, sock);
00637 if (result != ISC_R_SUCCESS) {
00638 char socktext[ISC_SOCKADDR_FORMATSIZE];
00639 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
00640 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00641 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
00642 "dropped command channel from %s: %s",
00643 socktext, isc_result_totext(result));
00644 isc_socket_detach(&sock);
00645 goto restart;
00646 }
00647
00648 restart:
00649 control_next(listener);
00650 cleanup:
00651 isc_event_free(&event);
00652 }
00653
00654 static void
00655 controls_shutdown(ns_controls_t *controls) {
00656 controllistener_t *listener;
00657 controllistener_t *next;
00658
00659 for (listener = ISC_LIST_HEAD(controls->listeners);
00660 listener != NULL;
00661 listener = next)
00662 {
00663
00664
00665
00666
00667 next = ISC_LIST_NEXT(listener, link);
00668 shutdown_listener(listener);
00669 }
00670 }
00671
00672 void
00673 ns_controls_shutdown(ns_controls_t *controls) {
00674 controls_shutdown(controls);
00675 controls->shuttingdown = ISC_TRUE;
00676 }
00677
00678 static isc_result_t
00679 cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname,
00680 const cfg_obj_t **objp)
00681 {
00682 const cfg_listelt_t *element;
00683 const char *str;
00684 const cfg_obj_t *obj;
00685
00686 for (element = cfg_list_first(keylist);
00687 element != NULL;
00688 element = cfg_list_next(element))
00689 {
00690 obj = cfg_listelt_value(element);
00691 str = cfg_obj_asstring(cfg_map_getname(obj));
00692 if (strcasecmp(str, keyname) == 0)
00693 break;
00694 }
00695 if (element == NULL)
00696 return (ISC_R_NOTFOUND);
00697 obj = cfg_listelt_value(element);
00698 *objp = obj;
00699 return (ISC_R_SUCCESS);
00700 }
00701
00702 static isc_result_t
00703 controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx,
00704 controlkeylist_t *keyids)
00705 {
00706 const cfg_listelt_t *element;
00707 char *newstr = NULL;
00708 const char *str;
00709 const cfg_obj_t *obj;
00710 controlkey_t *key;
00711
00712 for (element = cfg_list_first(keylist);
00713 element != NULL;
00714 element = cfg_list_next(element))
00715 {
00716 obj = cfg_listelt_value(element);
00717 str = cfg_obj_asstring(obj);
00718 newstr = isc_mem_strdup(mctx, str);
00719 if (newstr == NULL)
00720 goto cleanup;
00721 key = isc_mem_get(mctx, sizeof(*key));
00722 if (key == NULL)
00723 goto cleanup;
00724 key->keyname = newstr;
00725 key->algorithm = DST_ALG_UNKNOWN;
00726 key->secret.base = NULL;
00727 key->secret.length = 0;
00728 ISC_LINK_INIT(key, link);
00729 ISC_LIST_APPEND(*keyids, key, link);
00730 newstr = NULL;
00731 }
00732 return (ISC_R_SUCCESS);
00733
00734 cleanup:
00735 if (newstr != NULL)
00736 isc_mem_free(mctx, newstr);
00737 free_controlkeylist(keyids, mctx);
00738 return (ISC_R_NOMEMORY);
00739 }
00740
00741 static void
00742 register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist,
00743 controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext)
00744 {
00745 controlkey_t *keyid, *next;
00746 const cfg_obj_t *keydef;
00747 char secret[1024];
00748 isc_buffer_t b;
00749 isc_result_t result;
00750
00751
00752
00753
00754 for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) {
00755 next = ISC_LIST_NEXT(keyid, link);
00756
00757 result = cfgkeylist_find(keylist, keyid->keyname, &keydef);
00758 if (result != ISC_R_SUCCESS) {
00759 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
00760 "couldn't find key '%s' for use with "
00761 "command channel %s",
00762 keyid->keyname, socktext);
00763 ISC_LIST_UNLINK(*keyids, keyid, link);
00764 free_controlkey(keyid, mctx);
00765 } else {
00766 const cfg_obj_t *algobj = NULL;
00767 const cfg_obj_t *secretobj = NULL;
00768 const char *algstr = NULL;
00769 const char *secretstr = NULL;
00770 unsigned int algtype;
00771
00772 (void)cfg_map_get(keydef, "algorithm", &algobj);
00773 (void)cfg_map_get(keydef, "secret", &secretobj);
00774 INSIST(algobj != NULL && secretobj != NULL);
00775
00776 algstr = cfg_obj_asstring(algobj);
00777 secretstr = cfg_obj_asstring(secretobj);
00778
00779 if (ns_config_getkeyalgorithm2(algstr, NULL,
00780 &algtype, NULL) != ISC_R_SUCCESS)
00781 {
00782 cfg_obj_log(control, ns_g_lctx,
00783 ISC_LOG_WARNING,
00784 "unsupported algorithm '%s' in "
00785 "key '%s' for use with command "
00786 "channel %s",
00787 algstr, keyid->keyname, socktext);
00788 ISC_LIST_UNLINK(*keyids, keyid, link);
00789 free_controlkey(keyid, mctx);
00790 continue;
00791 }
00792
00793 keyid->algorithm = algtype;
00794 isc_buffer_init(&b, secret, sizeof(secret));
00795 result = isc_base64_decodestring(secretstr, &b);
00796
00797 if (result != ISC_R_SUCCESS) {
00798 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
00799 "secret for key '%s' on "
00800 "command channel %s: %s",
00801 keyid->keyname, socktext,
00802 isc_result_totext(result));
00803 ISC_LIST_UNLINK(*keyids, keyid, link);
00804 free_controlkey(keyid, mctx);
00805 continue;
00806 }
00807
00808 keyid->secret.length = isc_buffer_usedlength(&b);
00809 keyid->secret.base = isc_mem_get(mctx,
00810 keyid->secret.length);
00811 if (keyid->secret.base == NULL) {
00812 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
00813 "couldn't register key '%s': "
00814 "out of memory", keyid->keyname);
00815 ISC_LIST_UNLINK(*keyids, keyid, link);
00816 free_controlkey(keyid, mctx);
00817 break;
00818 }
00819 memmove(keyid->secret.base, isc_buffer_base(&b),
00820 keyid->secret.length);
00821 }
00822 }
00823 }
00824
00825 #define CHECK(x) \
00826 do { \
00827 result = (x); \
00828 if (result != ISC_R_SUCCESS) \
00829 goto cleanup; \
00830 } while (0)
00831
00832 static isc_result_t
00833 get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) {
00834 isc_result_t result;
00835 cfg_parser_t *pctx = NULL;
00836 cfg_obj_t *config = NULL;
00837 const cfg_obj_t *key = NULL;
00838 const cfg_obj_t *algobj = NULL;
00839 const cfg_obj_t *secretobj = NULL;
00840 const char *algstr = NULL;
00841 const char *secretstr = NULL;
00842 controlkey_t *keyid = NULL;
00843 char secret[1024];
00844 unsigned int algtype;
00845 isc_buffer_t b;
00846
00847 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00848 NS_LOGMODULE_CONTROL, ISC_LOG_INFO,
00849 "configuring command channel from '%s'",
00850 ns_g_keyfile);
00851 if (! isc_file_exists(ns_g_keyfile))
00852 return (ISC_R_FILENOTFOUND);
00853
00854 CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx));
00855 CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config));
00856 CHECK(cfg_map_get(config, "key", &key));
00857
00858 keyid = isc_mem_get(mctx, sizeof(*keyid));
00859 if (keyid == NULL)
00860 CHECK(ISC_R_NOMEMORY);
00861 keyid->keyname = isc_mem_strdup(mctx,
00862 cfg_obj_asstring(cfg_map_getname(key)));
00863 keyid->secret.base = NULL;
00864 keyid->secret.length = 0;
00865 keyid->algorithm = DST_ALG_UNKNOWN;
00866 ISC_LINK_INIT(keyid, link);
00867 if (keyid->keyname == NULL)
00868 CHECK(ISC_R_NOMEMORY);
00869
00870 CHECK(bind9_check_key(key, ns_g_lctx));
00871
00872 (void)cfg_map_get(key, "algorithm", &algobj);
00873 (void)cfg_map_get(key, "secret", &secretobj);
00874 INSIST(algobj != NULL && secretobj != NULL);
00875
00876 algstr = cfg_obj_asstring(algobj);
00877 secretstr = cfg_obj_asstring(secretobj);
00878
00879 if (ns_config_getkeyalgorithm2(algstr, NULL,
00880 &algtype, NULL) != ISC_R_SUCCESS) {
00881 cfg_obj_log(key, ns_g_lctx,
00882 ISC_LOG_WARNING,
00883 "unsupported algorithm '%s' in "
00884 "key '%s' for use with command "
00885 "channel",
00886 algstr, keyid->keyname);
00887 goto cleanup;
00888 }
00889
00890 keyid->algorithm = algtype;
00891 isc_buffer_init(&b, secret, sizeof(secret));
00892 result = isc_base64_decodestring(secretstr, &b);
00893
00894 if (result != ISC_R_SUCCESS) {
00895 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
00896 "secret for key '%s' on command channel: %s",
00897 keyid->keyname, isc_result_totext(result));
00898 goto cleanup;
00899 }
00900
00901 keyid->secret.length = isc_buffer_usedlength(&b);
00902 keyid->secret.base = isc_mem_get(mctx,
00903 keyid->secret.length);
00904 if (keyid->secret.base == NULL) {
00905 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
00906 "couldn't register key '%s': "
00907 "out of memory", keyid->keyname);
00908 CHECK(ISC_R_NOMEMORY);
00909 }
00910 memmove(keyid->secret.base, isc_buffer_base(&b),
00911 keyid->secret.length);
00912 ISC_LIST_APPEND(*keyids, keyid, link);
00913 keyid = NULL;
00914 result = ISC_R_SUCCESS;
00915
00916 cleanup:
00917 if (keyid != NULL)
00918 free_controlkey(keyid, mctx);
00919 if (config != NULL)
00920 cfg_obj_destroy(pctx, &config);
00921 if (pctx != NULL)
00922 cfg_parser_destroy(&pctx);
00923 return (result);
00924 }
00925
00926
00927
00928
00929
00930 static void
00931 get_key_info(const cfg_obj_t *config, const cfg_obj_t *control,
00932 const cfg_obj_t **global_keylistp,
00933 const cfg_obj_t **control_keylistp)
00934 {
00935 isc_result_t result;
00936 const cfg_obj_t *control_keylist = NULL;
00937 const cfg_obj_t *global_keylist = NULL;
00938
00939 REQUIRE(global_keylistp != NULL && *global_keylistp == NULL);
00940 REQUIRE(control_keylistp != NULL && *control_keylistp == NULL);
00941
00942 control_keylist = cfg_tuple_get(control, "keys");
00943
00944 if (!cfg_obj_isvoid(control_keylist) &&
00945 cfg_list_first(control_keylist) != NULL) {
00946 result = cfg_map_get(config, "key", &global_keylist);
00947
00948 if (result == ISC_R_SUCCESS) {
00949 *global_keylistp = global_keylist;
00950 *control_keylistp = control_keylist;
00951 }
00952 }
00953 }
00954
00955 static void
00956 update_listener(ns_controls_t *cp, controllistener_t **listenerp,
00957 const cfg_obj_t *control, const cfg_obj_t *config,
00958 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
00959 const char *socktext, isc_sockettype_t type)
00960 {
00961 controllistener_t *listener;
00962 const cfg_obj_t *allow;
00963 const cfg_obj_t *global_keylist = NULL;
00964 const cfg_obj_t *control_keylist = NULL;
00965 dns_acl_t *new_acl = NULL;
00966 controlkeylist_t keys;
00967 isc_result_t result = ISC_R_SUCCESS;
00968
00969 for (listener = ISC_LIST_HEAD(cp->listeners);
00970 listener != NULL;
00971 listener = ISC_LIST_NEXT(listener, link))
00972 if (isc_sockaddr_equal(addr, &listener->address))
00973 break;
00974
00975 if (listener == NULL) {
00976 *listenerp = NULL;
00977 return;
00978 }
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000 if (control != NULL)
01001 get_key_info(config, control, &global_keylist,
01002 &control_keylist);
01003
01004 if (control_keylist != NULL) {
01005 INSIST(global_keylist != NULL);
01006
01007 ISC_LIST_INIT(keys);
01008 result = controlkeylist_fromcfg(control_keylist,
01009 listener->mctx, &keys);
01010 if (result == ISC_R_SUCCESS) {
01011 free_controlkeylist(&listener->keys, listener->mctx);
01012 listener->keys = keys;
01013 register_keys(control, global_keylist, &listener->keys,
01014 listener->mctx, socktext);
01015 }
01016 } else {
01017 free_controlkeylist(&listener->keys, listener->mctx);
01018 result = get_rndckey(listener->mctx, &listener->keys);
01019 }
01020
01021 if (result != ISC_R_SUCCESS && global_keylist != NULL) {
01022
01023
01024
01025
01026
01027
01028 if (control != NULL)
01029 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01030 "couldn't install new keys for "
01031 "command channel %s: %s",
01032 socktext, isc_result_totext(result));
01033 else
01034 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01035 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
01036 "couldn't install new keys for "
01037 "command channel %s: %s",
01038 socktext, isc_result_totext(result));
01039 }
01040
01041
01042
01043
01044 if (control != NULL && type == isc_sockettype_tcp) {
01045 allow = cfg_tuple_get(control, "allow");
01046 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
01047 aclconfctx, listener->mctx, 0,
01048 &new_acl);
01049 } else {
01050 result = dns_acl_any(listener->mctx, &new_acl);
01051 }
01052
01053 if (result == ISC_R_SUCCESS) {
01054 dns_acl_detach(&listener->acl);
01055 dns_acl_attach(new_acl, &listener->acl);
01056 dns_acl_detach(&new_acl);
01057
01058 } else if (control != NULL)
01059 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01060 "couldn't install new acl for "
01061 "command channel %s: %s",
01062 socktext, isc_result_totext(result));
01063 else
01064 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01065 NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
01066 "couldn't install new acl for "
01067 "command channel %s: %s",
01068 socktext, isc_result_totext(result));
01069
01070 if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
01071 isc_uint32_t perm, owner, group;
01072 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
01073 owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner"));
01074 group = cfg_obj_asuint32(cfg_tuple_get(control, "group"));
01075 result = ISC_R_SUCCESS;
01076 if (listener->perm != perm || listener->owner != owner ||
01077 listener->group != group)
01078 result = isc_socket_permunix(&listener->address, perm,
01079 owner, group);
01080 if (result == ISC_R_SUCCESS) {
01081 listener->perm = perm;
01082 listener->owner = owner;
01083 listener->group = group;
01084 } else if (control != NULL)
01085 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01086 "couldn't update ownership/permission for "
01087 "command channel %s", socktext);
01088 }
01089
01090 *listenerp = listener;
01091 }
01092
01093 static void
01094 add_listener(ns_controls_t *cp, controllistener_t **listenerp,
01095 const cfg_obj_t *control, const cfg_obj_t *config,
01096 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
01097 const char *socktext, isc_sockettype_t type)
01098 {
01099 isc_mem_t *mctx = cp->server->mctx;
01100 controllistener_t *listener;
01101 const cfg_obj_t *allow;
01102 const cfg_obj_t *global_keylist = NULL;
01103 const cfg_obj_t *control_keylist = NULL;
01104 dns_acl_t *new_acl = NULL;
01105 isc_result_t result = ISC_R_SUCCESS;
01106
01107 listener = isc_mem_get(mctx, sizeof(*listener));
01108 if (listener == NULL)
01109 result = ISC_R_NOMEMORY;
01110
01111 if (result == ISC_R_SUCCESS) {
01112 listener->mctx = NULL;
01113 isc_mem_attach(mctx, &listener->mctx);
01114 listener->controls = cp;
01115 listener->task = cp->server->task;
01116 listener->address = *addr;
01117 listener->sock = NULL;
01118 listener->listening = ISC_FALSE;
01119 listener->exiting = ISC_FALSE;
01120 listener->acl = NULL;
01121 listener->type = type;
01122 listener->perm = 0;
01123 listener->owner = 0;
01124 listener->group = 0;
01125 ISC_LINK_INIT(listener, link);
01126 ISC_LIST_INIT(listener->keys);
01127 ISC_LIST_INIT(listener->connections);
01128
01129
01130
01131
01132 if (control != NULL && type == isc_sockettype_tcp) {
01133 allow = cfg_tuple_get(control, "allow");
01134 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
01135 aclconfctx, mctx, 0,
01136 &new_acl);
01137 } else {
01138 result = dns_acl_any(mctx, &new_acl);
01139 }
01140 }
01141
01142 if (result == ISC_R_SUCCESS) {
01143 dns_acl_attach(new_acl, &listener->acl);
01144 dns_acl_detach(&new_acl);
01145
01146 if (config != NULL)
01147 get_key_info(config, control, &global_keylist,
01148 &control_keylist);
01149
01150 if (control_keylist != NULL) {
01151 result = controlkeylist_fromcfg(control_keylist,
01152 listener->mctx,
01153 &listener->keys);
01154 if (result == ISC_R_SUCCESS)
01155 register_keys(control, global_keylist,
01156 &listener->keys,
01157 listener->mctx, socktext);
01158 } else
01159 result = get_rndckey(mctx, &listener->keys);
01160
01161 if (result != ISC_R_SUCCESS && control != NULL)
01162 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01163 "couldn't install keys for "
01164 "command channel %s: %s",
01165 socktext, isc_result_totext(result));
01166 }
01167
01168 if (result == ISC_R_SUCCESS) {
01169 int pf = isc_sockaddr_pf(&listener->address);
01170 if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
01171 #ifdef ISC_PLATFORM_HAVESYSUNH
01172 (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) ||
01173 #endif
01174 (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
01175 result = ISC_R_FAMILYNOSUPPORT;
01176 }
01177
01178 if (result == ISC_R_SUCCESS && type == isc_sockettype_unix)
01179 isc_socket_cleanunix(&listener->address, ISC_FALSE);
01180
01181 if (result == ISC_R_SUCCESS)
01182 result = isc_socket_create(ns_g_socketmgr,
01183 isc_sockaddr_pf(&listener->address),
01184 type, &listener->sock);
01185 if (result == ISC_R_SUCCESS)
01186 isc_socket_setname(listener->sock, "control", NULL);
01187
01188 #ifndef ISC_ALLOW_MAPPED
01189 if (result == ISC_R_SUCCESS)
01190 isc_socket_ipv6only(listener->sock, ISC_TRUE);
01191 #endif
01192
01193 if (result == ISC_R_SUCCESS)
01194 result = isc_socket_bind(listener->sock, &listener->address,
01195 ISC_SOCKET_REUSEADDRESS);
01196
01197 if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
01198 listener->perm = cfg_obj_asuint32(cfg_tuple_get(control,
01199 "perm"));
01200 listener->owner = cfg_obj_asuint32(cfg_tuple_get(control,
01201 "owner"));
01202 listener->group = cfg_obj_asuint32(cfg_tuple_get(control,
01203 "group"));
01204 result = isc_socket_permunix(&listener->address, listener->perm,
01205 listener->owner, listener->group);
01206 }
01207 if (result == ISC_R_SUCCESS)
01208 result = control_listen(listener);
01209
01210 if (result == ISC_R_SUCCESS)
01211 result = control_accept(listener);
01212
01213 if (result == ISC_R_SUCCESS) {
01214 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01215 NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
01216 "command channel listening on %s", socktext);
01217 *listenerp = listener;
01218
01219 } else {
01220 if (listener != NULL) {
01221 listener->exiting = ISC_TRUE;
01222 free_listener(listener);
01223 }
01224
01225 if (control != NULL)
01226 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01227 "couldn't add command channel %s: %s",
01228 socktext, isc_result_totext(result));
01229 else
01230 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01231 NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
01232 "couldn't add command channel %s: %s",
01233 socktext, isc_result_totext(result));
01234
01235 *listenerp = NULL;
01236 }
01237
01238
01239 }
01240
01241 isc_result_t
01242 ns_controls_configure(ns_controls_t *cp, const cfg_obj_t *config,
01243 cfg_aclconfctx_t *aclconfctx)
01244 {
01245 controllistener_t *listener;
01246 controllistenerlist_t new_listeners;
01247 const cfg_obj_t *controlslist = NULL;
01248 const cfg_listelt_t *element, *element2;
01249 char socktext[ISC_SOCKADDR_FORMATSIZE];
01250
01251 ISC_LIST_INIT(new_listeners);
01252
01253
01254
01255
01256 (void)cfg_map_get(config, "controls", &controlslist);
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266 if (controlslist != NULL) {
01267 for (element = cfg_list_first(controlslist);
01268 element != NULL;
01269 element = cfg_list_next(element)) {
01270 const cfg_obj_t *controls;
01271 const cfg_obj_t *inetcontrols = NULL;
01272
01273 controls = cfg_listelt_value(element);
01274 (void)cfg_map_get(controls, "inet", &inetcontrols);
01275 if (inetcontrols == NULL)
01276 continue;
01277
01278 for (element2 = cfg_list_first(inetcontrols);
01279 element2 != NULL;
01280 element2 = cfg_list_next(element2)) {
01281 const cfg_obj_t *control;
01282 const cfg_obj_t *obj;
01283 isc_sockaddr_t addr;
01284
01285
01286
01287
01288
01289
01290 control = cfg_listelt_value(element2);
01291
01292 obj = cfg_tuple_get(control, "address");
01293 addr = *cfg_obj_assockaddr(obj);
01294 if (isc_sockaddr_getport(&addr) == 0)
01295 isc_sockaddr_setport(&addr,
01296 NS_CONTROL_PORT);
01297
01298 isc_sockaddr_format(&addr, socktext,
01299 sizeof(socktext));
01300
01301 isc_log_write(ns_g_lctx,
01302 NS_LOGCATEGORY_GENERAL,
01303 NS_LOGMODULE_CONTROL,
01304 ISC_LOG_DEBUG(9),
01305 "processing control channel %s",
01306 socktext);
01307
01308 update_listener(cp, &listener, control, config,
01309 &addr, aclconfctx, socktext,
01310 isc_sockettype_tcp);
01311
01312 if (listener != NULL)
01313
01314
01315
01316
01317 ISC_LIST_UNLINK(cp->listeners,
01318 listener, link);
01319 else
01320
01321
01322
01323 add_listener(cp, &listener, control,
01324 config, &addr, aclconfctx,
01325 socktext,
01326 isc_sockettype_tcp);
01327
01328 if (listener != NULL)
01329 ISC_LIST_APPEND(new_listeners,
01330 listener, link);
01331 }
01332 }
01333 for (element = cfg_list_first(controlslist);
01334 element != NULL;
01335 element = cfg_list_next(element)) {
01336 const cfg_obj_t *controls;
01337 const cfg_obj_t *unixcontrols = NULL;
01338
01339 controls = cfg_listelt_value(element);
01340 (void)cfg_map_get(controls, "unix", &unixcontrols);
01341 if (unixcontrols == NULL)
01342 continue;
01343
01344 for (element2 = cfg_list_first(unixcontrols);
01345 element2 != NULL;
01346 element2 = cfg_list_next(element2)) {
01347 const cfg_obj_t *control;
01348 const cfg_obj_t *path;
01349 isc_sockaddr_t addr;
01350 isc_result_t result;
01351
01352
01353
01354
01355
01356
01357 control = cfg_listelt_value(element2);
01358
01359 path = cfg_tuple_get(control, "path");
01360 result = isc_sockaddr_frompath(&addr,
01361 cfg_obj_asstring(path));
01362 if (result != ISC_R_SUCCESS) {
01363 isc_log_write(ns_g_lctx,
01364 NS_LOGCATEGORY_GENERAL,
01365 NS_LOGMODULE_CONTROL,
01366 ISC_LOG_DEBUG(9),
01367 "control channel '%s': %s",
01368 cfg_obj_asstring(path),
01369 isc_result_totext(result));
01370 continue;
01371 }
01372
01373 isc_log_write(ns_g_lctx,
01374 NS_LOGCATEGORY_GENERAL,
01375 NS_LOGMODULE_CONTROL,
01376 ISC_LOG_DEBUG(9),
01377 "processing control channel '%s'",
01378 cfg_obj_asstring(path));
01379
01380 update_listener(cp, &listener, control, config,
01381 &addr, aclconfctx,
01382 cfg_obj_asstring(path),
01383 isc_sockettype_unix);
01384
01385 if (listener != NULL)
01386
01387
01388
01389
01390 ISC_LIST_UNLINK(cp->listeners,
01391 listener, link);
01392 else
01393
01394
01395
01396 add_listener(cp, &listener, control,
01397 config, &addr, aclconfctx,
01398 cfg_obj_asstring(path),
01399 isc_sockettype_unix);
01400
01401 if (listener != NULL)
01402 ISC_LIST_APPEND(new_listeners,
01403 listener, link);
01404 }
01405 }
01406 } else {
01407 int i;
01408
01409 for (i = 0; i < 2; i++) {
01410 isc_sockaddr_t addr;
01411
01412 if (i == 0) {
01413 struct in_addr localhost;
01414
01415 if (isc_net_probeipv4() != ISC_R_SUCCESS)
01416 continue;
01417 localhost.s_addr = htonl(INADDR_LOOPBACK);
01418 isc_sockaddr_fromin(&addr, &localhost, 0);
01419 } else {
01420 if (isc_net_probeipv6() != ISC_R_SUCCESS)
01421 continue;
01422 isc_sockaddr_fromin6(&addr,
01423 &in6addr_loopback, 0);
01424 }
01425 isc_sockaddr_setport(&addr, NS_CONTROL_PORT);
01426
01427 isc_sockaddr_format(&addr, socktext, sizeof(socktext));
01428
01429 update_listener(cp, &listener, NULL, NULL,
01430 &addr, NULL, socktext,
01431 isc_sockettype_tcp);
01432
01433 if (listener != NULL)
01434
01435
01436
01437
01438 ISC_LIST_UNLINK(cp->listeners,
01439 listener, link);
01440 else
01441
01442
01443
01444 add_listener(cp, &listener, NULL, NULL,
01445 &addr, NULL, socktext,
01446 isc_sockettype_tcp);
01447
01448 if (listener != NULL)
01449 ISC_LIST_APPEND(new_listeners,
01450 listener, link);
01451 }
01452 }
01453
01454
01455
01456
01457
01458
01459
01460 controls_shutdown(cp);
01461
01462
01463
01464
01465
01466
01467 ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link);
01468 return (ISC_R_SUCCESS);
01469 }
01470
01471 isc_result_t
01472 ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) {
01473 isc_mem_t *mctx = server->mctx;
01474 isc_result_t result;
01475 ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls));
01476
01477 if (controls == NULL)
01478 return (ISC_R_NOMEMORY);
01479 controls->server = server;
01480 ISC_LIST_INIT(controls->listeners);
01481 controls->shuttingdown = ISC_FALSE;
01482 controls->symtab = NULL;
01483 result = isccc_cc_createsymtab(&controls->symtab);
01484 if (result != ISC_R_SUCCESS) {
01485 isc_mem_put(server->mctx, controls, sizeof(*controls));
01486 return (result);
01487 }
01488 *ctrlsp = controls;
01489 return (ISC_R_SUCCESS);
01490 }
01491
01492 void
01493 ns_controls_destroy(ns_controls_t **ctrlsp) {
01494 ns_controls_t *controls = *ctrlsp;
01495
01496 REQUIRE(ISC_LIST_EMPTY(controls->listeners));
01497
01498 isccc_symtab_destroy(&controls->symtab);
01499 isc_mem_put(controls->server->mctx, controls, sizeof(*controls));
01500 *ctrlsp = NULL;
01501 }