1 /* $NetBSD: controlconf.c,v 1.10 2014/12/10 04:37:51 christos Exp $ */
4 * Copyright (C) 2004-2008, 2011-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2001-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: controlconf.c,v 1.63 2011/12/22 08:07:48 marka Exp */
26 #include <isc/base64.h>
27 #include <isc/buffer.h>
28 #include <isc/event.h>
32 #include <isc/netaddr.h>
33 #include <isc/random.h>
34 #include <isc/result.h>
35 #include <isc/stdtime.h>
36 #include <isc/string.h>
37 #include <isc/timer.h>
40 #include <isccfg/namedconf.h>
42 #include <bind9/check.h>
44 #include <isccc/alist.h>
46 #include <isccc/ccmsg.h>
47 #include <isccc/events.h>
48 #include <isccc/result.h>
49 #include <isccc/sexpr.h>
50 #include <isccc/symtab.h>
51 #include <isccc/util.h>
53 #include <dns/result.h>
55 #include <named/config.h>
56 #include <named/control.h>
57 #include <named/log.h>
58 #include <named/server.h>
61 * Note: Listeners and connections are not locked. All event handlers are
62 * executed by the server task, and all callers of exported routines must
63 * be running under the server task.
66 typedef struct controlkey controlkey_t
;
67 typedef ISC_LIST(controlkey_t
) controlkeylist_t
;
69 typedef struct controlconnection controlconnection_t
;
70 typedef ISC_LIST(controlconnection_t
) controlconnectionlist_t
;
72 typedef struct controllistener controllistener_t
;
73 typedef ISC_LIST(controllistener_t
) controllistenerlist_t
;
77 isc_uint32_t algorithm
;
79 ISC_LINK(controlkey_t
) link
;
82 struct controlconnection
{
85 isc_boolean_t ccmsg_valid
;
86 isc_boolean_t sending
;
88 unsigned char buffer
[2048];
89 controllistener_t
* listener
;
91 ISC_LINK(controlconnection_t
) link
;
94 struct controllistener
{
95 ns_controls_t
* controls
;
98 isc_sockaddr_t address
;
101 isc_boolean_t listening
;
102 isc_boolean_t exiting
;
103 controlkeylist_t keys
;
104 controlconnectionlist_t connections
;
105 isc_sockettype_t type
;
109 ISC_LINK(controllistener_t
) link
;
114 controllistenerlist_t listeners
;
115 isc_boolean_t shuttingdown
;
116 isccc_symtab_t
*symtab
;
119 static void control_newconn(isc_task_t
*task
, isc_event_t
*event
);
120 static void control_recvmessage(isc_task_t
*task
, isc_event_t
*event
);
122 #define CLOCKSKEW 300
125 free_controlkey(controlkey_t
*key
, isc_mem_t
*mctx
) {
126 if (key
->keyname
!= NULL
)
127 isc_mem_free(mctx
, key
->keyname
);
128 if (key
->secret
.base
!= NULL
)
129 isc_mem_put(mctx
, key
->secret
.base
, key
->secret
.length
);
130 isc_mem_put(mctx
, key
, sizeof(*key
));
134 free_controlkeylist(controlkeylist_t
*keylist
, isc_mem_t
*mctx
) {
135 while (!ISC_LIST_EMPTY(*keylist
)) {
136 controlkey_t
*key
= ISC_LIST_HEAD(*keylist
);
137 ISC_LIST_UNLINK(*keylist
, key
, link
);
138 free_controlkey(key
, mctx
);
143 free_listener(controllistener_t
*listener
) {
144 INSIST(listener
->exiting
);
145 INSIST(!listener
->listening
);
146 INSIST(ISC_LIST_EMPTY(listener
->connections
));
148 if (listener
->sock
!= NULL
)
149 isc_socket_detach(&listener
->sock
);
151 free_controlkeylist(&listener
->keys
, listener
->mctx
);
153 if (listener
->acl
!= NULL
)
154 dns_acl_detach(&listener
->acl
);
156 isc_mem_putanddetach(&listener
->mctx
, listener
, sizeof(*listener
));
160 maybe_free_listener(controllistener_t
*listener
) {
161 if (listener
->exiting
&&
162 !listener
->listening
&&
163 ISC_LIST_EMPTY(listener
->connections
))
164 free_listener(listener
);
168 maybe_free_connection(controlconnection_t
*conn
) {
169 controllistener_t
*listener
= conn
->listener
;
171 if (conn
->timer
!= NULL
)
172 isc_timer_detach(&conn
->timer
);
174 if (conn
->ccmsg_valid
) {
175 isccc_ccmsg_cancelread(&conn
->ccmsg
);
180 isc_socket_cancel(conn
->sock
, listener
->task
,
181 ISC_SOCKCANCEL_SEND
);
185 ISC_LIST_UNLINK(listener
->connections
, conn
, link
);
186 isc_mem_put(listener
->mctx
, conn
, sizeof(*conn
));
190 shutdown_listener(controllistener_t
*listener
) {
191 controlconnection_t
*conn
;
192 controlconnection_t
*next
;
194 if (!listener
->exiting
) {
195 char socktext
[ISC_SOCKADDR_FORMATSIZE
];
197 ISC_LIST_UNLINK(listener
->controls
->listeners
, listener
, link
);
199 isc_sockaddr_format(&listener
->address
, socktext
,
201 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
202 NS_LOGMODULE_CONTROL
, ISC_LOG_NOTICE
,
203 "stopping command channel on %s", socktext
);
204 if (listener
->type
== isc_sockettype_unix
)
205 isc_socket_cleanunix(&listener
->address
, ISC_TRUE
);
206 listener
->exiting
= ISC_TRUE
;
209 for (conn
= ISC_LIST_HEAD(listener
->connections
);
213 next
= ISC_LIST_NEXT(conn
, link
);
214 maybe_free_connection(conn
);
217 if (listener
->listening
)
218 isc_socket_cancel(listener
->sock
, listener
->task
,
219 ISC_SOCKCANCEL_ACCEPT
);
221 maybe_free_listener(listener
);
225 address_ok(isc_sockaddr_t
*sockaddr
, dns_acl_t
*acl
) {
226 isc_netaddr_t netaddr
;
230 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
232 result
= dns_acl_match(&netaddr
, NULL
, acl
,
233 &ns_g_server
->aclenv
, &match
, NULL
);
235 if (result
!= ISC_R_SUCCESS
|| match
<= 0)
242 control_accept(controllistener_t
*listener
) {
244 result
= isc_socket_accept(listener
->sock
,
246 control_newconn
, listener
);
247 if (result
!= ISC_R_SUCCESS
)
248 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
249 "isc_socket_accept() failed: %s",
250 isc_result_totext(result
));
252 listener
->listening
= ISC_TRUE
;
257 control_listen(controllistener_t
*listener
) {
260 result
= isc_socket_listen(listener
->sock
, 0);
261 if (result
!= ISC_R_SUCCESS
)
262 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
263 "isc_socket_listen() failed: %s",
264 isc_result_totext(result
));
269 control_next(controllistener_t
*listener
) {
270 (void)control_accept(listener
);
274 control_senddone(isc_task_t
*task
, isc_event_t
*event
) {
275 isc_socketevent_t
*sevent
= (isc_socketevent_t
*) event
;
276 controlconnection_t
*conn
= event
->ev_arg
;
277 controllistener_t
*listener
= conn
->listener
;
278 isc_socket_t
*sock
= (isc_socket_t
*)sevent
->ev_sender
;
281 REQUIRE(conn
->sending
);
285 conn
->sending
= ISC_FALSE
;
287 if (sevent
->result
!= ISC_R_SUCCESS
&&
288 sevent
->result
!= ISC_R_CANCELED
)
290 char socktext
[ISC_SOCKADDR_FORMATSIZE
];
291 isc_sockaddr_t peeraddr
;
293 (void)isc_socket_getpeername(sock
, &peeraddr
);
294 isc_sockaddr_format(&peeraddr
, socktext
, sizeof(socktext
));
295 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
296 NS_LOGMODULE_CONTROL
, ISC_LOG_WARNING
,
297 "error sending command response to %s: %s",
298 socktext
, isc_result_totext(sevent
->result
));
300 isc_event_free(&event
);
302 result
= isccc_ccmsg_readmessage(&conn
->ccmsg
, listener
->task
,
303 control_recvmessage
, conn
);
304 if (result
!= ISC_R_SUCCESS
) {
305 isc_socket_detach(&conn
->sock
);
306 maybe_free_connection(conn
);
307 maybe_free_listener(listener
);
312 log_invalid(isccc_ccmsg_t
*ccmsg
, isc_result_t result
) {
313 char socktext
[ISC_SOCKADDR_FORMATSIZE
];
314 isc_sockaddr_t peeraddr
;
316 (void)isc_socket_getpeername(ccmsg
->sock
, &peeraddr
);
317 isc_sockaddr_format(&peeraddr
, socktext
, sizeof(socktext
));
318 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
319 NS_LOGMODULE_CONTROL
, ISC_LOG_ERROR
,
320 "invalid command from %s: %s",
321 socktext
, isc_result_totext(result
));
325 control_recvmessage(isc_task_t
*task
, isc_event_t
*event
) {
326 controlconnection_t
*conn
;
327 controllistener_t
*listener
;
329 isccc_sexpr_t
*request
= NULL
;
330 isccc_sexpr_t
*response
= NULL
;
331 isccc_region_t ccregion
;
332 isc_uint32_t algorithm
;
333 isccc_region_t secret
;
339 char textarray
[2*1024];
341 isc_result_t eresult
;
342 isccc_sexpr_t
*_ctrl
;
347 REQUIRE(event
->ev_type
== ISCCC_EVENT_CCMSG
);
349 conn
= event
->ev_arg
;
350 listener
= conn
->listener
;
351 algorithm
= DST_ALG_UNKNOWN
;
352 secret
.rstart
= NULL
;
354 /* Is the server shutting down? */
355 if (listener
->controls
->shuttingdown
)
358 if (conn
->ccmsg
.result
!= ISC_R_SUCCESS
) {
359 if (conn
->ccmsg
.result
!= ISC_R_CANCELED
&&
360 conn
->ccmsg
.result
!= ISC_R_EOF
)
361 log_invalid(&conn
->ccmsg
, conn
->ccmsg
.result
);
367 for (key
= ISC_LIST_HEAD(listener
->keys
);
369 key
= ISC_LIST_NEXT(key
, link
))
371 ccregion
.rstart
= isc_buffer_base(&conn
->ccmsg
.buffer
);
372 ccregion
.rend
= isc_buffer_used(&conn
->ccmsg
.buffer
);
373 secret
.rstart
= isc_mem_get(listener
->mctx
, key
->secret
.length
);
374 if (secret
.rstart
== NULL
)
376 memmove(secret
.rstart
, key
->secret
.base
, key
->secret
.length
);
377 secret
.rend
= secret
.rstart
+ key
->secret
.length
;
378 algorithm
= key
->algorithm
;
379 result
= isccc_cc_fromwire(&ccregion
, &request
,
381 if (result
== ISC_R_SUCCESS
)
383 isc_mem_put(listener
->mctx
, secret
.rstart
, REGION_SIZE(secret
));
384 if (result
!= ISCCC_R_BADAUTH
) {
385 log_invalid(&conn
->ccmsg
, result
);
391 log_invalid(&conn
->ccmsg
, ISCCC_R_BADAUTH
);
395 /* We shouldn't be getting a reply. */
396 if (isccc_cc_isreply(request
)) {
397 log_invalid(&conn
->ccmsg
, ISC_R_FAILURE
);
398 goto cleanup_request
;
401 isc_stdtime_get(&now
);
404 * Limit exposure to replay attacks.
406 _ctrl
= isccc_alist_lookup(request
, "_ctrl");
408 log_invalid(&conn
->ccmsg
, ISC_R_FAILURE
);
409 goto cleanup_request
;
412 if (isccc_cc_lookupuint32(_ctrl
, "_tim", &sent
) == ISC_R_SUCCESS
) {
413 if ((sent
+ CLOCKSKEW
) < now
|| (sent
- CLOCKSKEW
) > now
) {
414 log_invalid(&conn
->ccmsg
, ISCCC_R_CLOCKSKEW
);
415 goto cleanup_request
;
418 log_invalid(&conn
->ccmsg
, ISC_R_FAILURE
);
419 goto cleanup_request
;
423 * Expire messages that are too old.
425 if (isccc_cc_lookupuint32(_ctrl
, "_exp", &exp
) == ISC_R_SUCCESS
&&
427 log_invalid(&conn
->ccmsg
, ISCCC_R_EXPIRED
);
428 goto cleanup_request
;
432 * Duplicate suppression (required for UDP).
434 isccc_cc_cleansymtab(listener
->controls
->symtab
, now
);
435 result
= isccc_cc_checkdup(listener
->controls
->symtab
, request
, now
);
436 if (result
!= ISC_R_SUCCESS
) {
437 if (result
== ISC_R_EXISTS
)
438 result
= ISCCC_R_DUPLICATE
;
439 log_invalid(&conn
->ccmsg
, result
);
440 goto cleanup_request
;
443 if (conn
->nonce
!= 0 &&
444 (isccc_cc_lookupuint32(_ctrl
, "_nonce", &nonce
) != ISC_R_SUCCESS
||
445 conn
->nonce
!= nonce
)) {
446 log_invalid(&conn
->ccmsg
, ISCCC_R_BADAUTH
);
447 goto cleanup_request
;
450 isc_buffer_init(&text
, textarray
, sizeof(textarray
));
455 if (conn
->nonce
== 0) {
456 while (conn
->nonce
== 0)
457 isc_random_get(&conn
->nonce
);
458 eresult
= ISC_R_SUCCESS
;
460 eresult
= ns_control_docommand(request
, &text
);
462 result
= isccc_cc_createresponse(request
, now
, now
+ 60, &response
);
463 if (result
!= ISC_R_SUCCESS
)
464 goto cleanup_request
;
465 if (eresult
!= ISC_R_SUCCESS
) {
468 data
= isccc_alist_lookup(response
, "_data");
470 const char *estr
= isc_result_totext(eresult
);
471 if (isccc_cc_definestring(data
, "err", estr
) == NULL
)
472 goto cleanup_response
;
476 if (isc_buffer_usedlength(&text
) > 0) {
479 data
= isccc_alist_lookup(response
, "_data");
481 char *str
= (char *)isc_buffer_base(&text
);
482 if (isccc_cc_definestring(data
, "text", str
) == NULL
)
483 goto cleanup_response
;
487 _ctrl
= isccc_alist_lookup(response
, "_ctrl");
489 isccc_cc_defineuint32(_ctrl
, "_nonce", conn
->nonce
) == NULL
)
490 goto cleanup_response
;
492 ccregion
.rstart
= conn
->buffer
+ 4;
493 ccregion
.rend
= conn
->buffer
+ sizeof(conn
->buffer
);
494 result
= isccc_cc_towire(response
, &ccregion
, algorithm
, &secret
);
495 if (result
!= ISC_R_SUCCESS
)
496 goto cleanup_response
;
497 isc_buffer_init(&b
, conn
->buffer
, 4);
498 len
= sizeof(conn
->buffer
) - REGION_SIZE(ccregion
);
499 isc_buffer_putuint32(&b
, len
- 4);
500 r
.base
= conn
->buffer
;
503 result
= isc_socket_send(conn
->sock
, &r
, task
, control_senddone
, conn
);
504 if (result
!= ISC_R_SUCCESS
)
505 goto cleanup_response
;
506 conn
->sending
= ISC_TRUE
;
508 isc_mem_put(listener
->mctx
, secret
.rstart
, REGION_SIZE(secret
));
509 isccc_sexpr_free(&request
);
510 isccc_sexpr_free(&response
);
514 isccc_sexpr_free(&response
);
517 isccc_sexpr_free(&request
);
518 isc_mem_put(listener
->mctx
, secret
.rstart
, REGION_SIZE(secret
));
521 isc_socket_detach(&conn
->sock
);
522 isccc_ccmsg_invalidate(&conn
->ccmsg
);
523 conn
->ccmsg_valid
= ISC_FALSE
;
524 maybe_free_connection(conn
);
525 maybe_free_listener(listener
);
529 control_timeout(isc_task_t
*task
, isc_event_t
*event
) {
530 controlconnection_t
*conn
= event
->ev_arg
;
534 isc_timer_detach(&conn
->timer
);
535 maybe_free_connection(conn
);
537 isc_event_free(&event
);
541 newconnection(controllistener_t
*listener
, isc_socket_t
*sock
) {
542 controlconnection_t
*conn
;
543 isc_interval_t interval
;
546 conn
= isc_mem_get(listener
->mctx
, sizeof(*conn
));
548 return (ISC_R_NOMEMORY
);
551 isccc_ccmsg_init(listener
->mctx
, sock
, &conn
->ccmsg
);
552 conn
->ccmsg_valid
= ISC_TRUE
;
553 conn
->sending
= ISC_FALSE
;
555 isc_interval_set(&interval
, 60, 0);
556 result
= isc_timer_create(ns_g_timermgr
, isc_timertype_once
,
557 NULL
, &interval
, listener
->task
,
558 control_timeout
, conn
, &conn
->timer
);
559 if (result
!= ISC_R_SUCCESS
)
562 conn
->listener
= listener
;
564 ISC_LINK_INIT(conn
, link
);
566 result
= isccc_ccmsg_readmessage(&conn
->ccmsg
, listener
->task
,
567 control_recvmessage
, conn
);
568 if (result
!= ISC_R_SUCCESS
)
570 isccc_ccmsg_setmaxsize(&conn
->ccmsg
, 2048);
572 ISC_LIST_APPEND(listener
->connections
, conn
, link
);
573 return (ISC_R_SUCCESS
);
576 isccc_ccmsg_invalidate(&conn
->ccmsg
);
577 if (conn
->timer
!= NULL
)
578 isc_timer_detach(&conn
->timer
);
579 isc_mem_put(listener
->mctx
, conn
, sizeof(*conn
));
584 control_newconn(isc_task_t
*task
, isc_event_t
*event
) {
585 isc_socket_newconnev_t
*nevent
= (isc_socket_newconnev_t
*)event
;
586 controllistener_t
*listener
= event
->ev_arg
;
588 isc_sockaddr_t peeraddr
;
593 listener
->listening
= ISC_FALSE
;
595 if (nevent
->result
!= ISC_R_SUCCESS
) {
596 if (nevent
->result
== ISC_R_CANCELED
) {
597 shutdown_listener(listener
);
603 sock
= nevent
->newsocket
;
604 isc_socket_setname(sock
, "control", NULL
);
605 (void)isc_socket_getpeername(sock
, &peeraddr
);
606 if (listener
->type
== isc_sockettype_tcp
&&
607 !address_ok(&peeraddr
, listener
->acl
)) {
608 char socktext
[ISC_SOCKADDR_FORMATSIZE
];
609 isc_sockaddr_format(&peeraddr
, socktext
, sizeof(socktext
));
610 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
611 NS_LOGMODULE_CONTROL
, ISC_LOG_WARNING
,
612 "rejected command channel message from %s",
614 isc_socket_detach(&sock
);
618 result
= newconnection(listener
, sock
);
619 if (result
!= ISC_R_SUCCESS
) {
620 char socktext
[ISC_SOCKADDR_FORMATSIZE
];
621 isc_sockaddr_format(&peeraddr
, socktext
, sizeof(socktext
));
622 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
623 NS_LOGMODULE_CONTROL
, ISC_LOG_WARNING
,
624 "dropped command channel from %s: %s",
625 socktext
, isc_result_totext(result
));
626 isc_socket_detach(&sock
);
631 control_next(listener
);
633 isc_event_free(&event
);
637 controls_shutdown(ns_controls_t
*controls
) {
638 controllistener_t
*listener
;
639 controllistener_t
*next
;
641 for (listener
= ISC_LIST_HEAD(controls
->listeners
);
646 * This is asynchronous. As listeners shut down, they will
647 * call their callbacks.
649 next
= ISC_LIST_NEXT(listener
, link
);
650 shutdown_listener(listener
);
655 ns_controls_shutdown(ns_controls_t
*controls
) {
656 controls_shutdown(controls
);
657 controls
->shuttingdown
= ISC_TRUE
;
661 cfgkeylist_find(const cfg_obj_t
*keylist
, const char *keyname
,
662 const cfg_obj_t
**objp
)
664 const cfg_listelt_t
*element
;
666 const cfg_obj_t
*obj
;
668 for (element
= cfg_list_first(keylist
);
670 element
= cfg_list_next(element
))
672 obj
= cfg_listelt_value(element
);
673 str
= cfg_obj_asstring(cfg_map_getname(obj
));
674 if (strcasecmp(str
, keyname
) == 0)
678 return (ISC_R_NOTFOUND
);
679 obj
= cfg_listelt_value(element
);
681 return (ISC_R_SUCCESS
);
685 controlkeylist_fromcfg(const cfg_obj_t
*keylist
, isc_mem_t
*mctx
,
686 controlkeylist_t
*keyids
)
688 const cfg_listelt_t
*element
;
691 const cfg_obj_t
*obj
;
694 for (element
= cfg_list_first(keylist
);
696 element
= cfg_list_next(element
))
698 obj
= cfg_listelt_value(element
);
699 str
= cfg_obj_asstring(obj
);
700 newstr
= isc_mem_strdup(mctx
, str
);
703 key
= isc_mem_get(mctx
, sizeof(*key
));
706 key
->keyname
= newstr
;
707 key
->algorithm
= DST_ALG_UNKNOWN
;
708 key
->secret
.base
= NULL
;
709 key
->secret
.length
= 0;
710 ISC_LINK_INIT(key
, link
);
711 ISC_LIST_APPEND(*keyids
, key
, link
);
714 return (ISC_R_SUCCESS
);
718 isc_mem_free(mctx
, newstr
);
719 free_controlkeylist(keyids
, mctx
);
720 return (ISC_R_NOMEMORY
);
724 register_keys(const cfg_obj_t
*control
, const cfg_obj_t
*keylist
,
725 controlkeylist_t
*keyids
, isc_mem_t
*mctx
, const char *socktext
)
727 controlkey_t
*keyid
, *next
;
728 const cfg_obj_t
*keydef
;
734 * Find the keys corresponding to the keyids used by this listener.
736 for (keyid
= ISC_LIST_HEAD(*keyids
); keyid
!= NULL
; keyid
= next
) {
737 next
= ISC_LIST_NEXT(keyid
, link
);
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
);
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 unsigned int algtype
;
754 (void)cfg_map_get(keydef
, "algorithm", &algobj
);
755 (void)cfg_map_get(keydef
, "secret", &secretobj
);
756 INSIST(algobj
!= NULL
&& secretobj
!= NULL
);
758 algstr
= cfg_obj_asstring(algobj
);
759 secretstr
= cfg_obj_asstring(secretobj
);
761 if (ns_config_getkeyalgorithm2(algstr
, NULL
,
762 &algtype
, NULL
) != ISC_R_SUCCESS
)
764 cfg_obj_log(control
, ns_g_lctx
,
766 "unsupported algorithm '%s' in "
767 "key '%s' for use with command "
769 algstr
, keyid
->keyname
, socktext
);
770 ISC_LIST_UNLINK(*keyids
, keyid
, link
);
771 free_controlkey(keyid
, mctx
);
775 keyid
->algorithm
= algtype
;
776 isc_buffer_init(&b
, secret
, sizeof(secret
));
777 result
= isc_base64_decodestring(secretstr
, &b
);
779 if (result
!= ISC_R_SUCCESS
) {
780 cfg_obj_log(keydef
, ns_g_lctx
, ISC_LOG_WARNING
,
781 "secret for key '%s' on "
782 "command channel %s: %s",
783 keyid
->keyname
, socktext
,
784 isc_result_totext(result
));
785 ISC_LIST_UNLINK(*keyids
, keyid
, link
);
786 free_controlkey(keyid
, mctx
);
790 keyid
->secret
.length
= isc_buffer_usedlength(&b
);
791 keyid
->secret
.base
= isc_mem_get(mctx
,
792 keyid
->secret
.length
);
793 if (keyid
->secret
.base
== NULL
) {
794 cfg_obj_log(keydef
, ns_g_lctx
, ISC_LOG_WARNING
,
795 "couldn't register key '%s': "
796 "out of memory", keyid
->keyname
);
797 ISC_LIST_UNLINK(*keyids
, keyid
, link
);
798 free_controlkey(keyid
, mctx
);
801 memmove(keyid
->secret
.base
, isc_buffer_base(&b
),
802 keyid
->secret
.length
);
810 if (result != ISC_R_SUCCESS) \
812 } while (/*CONSTCOND*/0)
815 get_rndckey(isc_mem_t
*mctx
, controlkeylist_t
*keyids
) {
817 cfg_parser_t
*pctx
= NULL
;
818 cfg_obj_t
*config
= NULL
;
819 const cfg_obj_t
*key
= NULL
;
820 const cfg_obj_t
*algobj
= NULL
;
821 const cfg_obj_t
*secretobj
= NULL
;
822 const char *algstr
= NULL
;
823 const char *secretstr
= NULL
;
824 controlkey_t
*keyid
= NULL
;
826 unsigned int algtype
;
829 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
830 NS_LOGMODULE_CONTROL
, ISC_LOG_INFO
,
831 "configuring command channel from '%s'",
833 if (! isc_file_exists(ns_g_keyfile
))
834 return (ISC_R_FILENOTFOUND
);
836 CHECK(cfg_parser_create(mctx
, ns_g_lctx
, &pctx
));
837 CHECK(cfg_parse_file(pctx
, ns_g_keyfile
, &cfg_type_rndckey
, &config
));
838 CHECK(cfg_map_get(config
, "key", &key
));
840 keyid
= isc_mem_get(mctx
, sizeof(*keyid
));
842 CHECK(ISC_R_NOMEMORY
);
843 keyid
->keyname
= isc_mem_strdup(mctx
,
844 cfg_obj_asstring(cfg_map_getname(key
)));
845 keyid
->secret
.base
= NULL
;
846 keyid
->secret
.length
= 0;
847 keyid
->algorithm
= DST_ALG_UNKNOWN
;
848 ISC_LINK_INIT(keyid
, link
);
849 if (keyid
->keyname
== NULL
)
850 CHECK(ISC_R_NOMEMORY
);
852 CHECK(bind9_check_key(key
, ns_g_lctx
));
854 (void)cfg_map_get(key
, "algorithm", &algobj
);
855 (void)cfg_map_get(key
, "secret", &secretobj
);
856 INSIST(algobj
!= NULL
&& secretobj
!= NULL
);
858 algstr
= cfg_obj_asstring(algobj
);
859 secretstr
= cfg_obj_asstring(secretobj
);
861 if (ns_config_getkeyalgorithm2(algstr
, NULL
,
862 &algtype
, NULL
) != ISC_R_SUCCESS
) {
863 cfg_obj_log(key
, ns_g_lctx
,
865 "unsupported algorithm '%s' in "
866 "key '%s' for use with command "
868 algstr
, keyid
->keyname
);
872 keyid
->algorithm
= algtype
;
873 isc_buffer_init(&b
, secret
, sizeof(secret
));
874 result
= isc_base64_decodestring(secretstr
, &b
);
876 if (result
!= ISC_R_SUCCESS
) {
877 cfg_obj_log(key
, ns_g_lctx
, ISC_LOG_WARNING
,
878 "secret for key '%s' on command channel: %s",
879 keyid
->keyname
, isc_result_totext(result
));
883 keyid
->secret
.length
= isc_buffer_usedlength(&b
);
884 keyid
->secret
.base
= isc_mem_get(mctx
,
885 keyid
->secret
.length
);
886 if (keyid
->secret
.base
== NULL
) {
887 cfg_obj_log(key
, ns_g_lctx
, ISC_LOG_WARNING
,
888 "couldn't register key '%s': "
889 "out of memory", keyid
->keyname
);
890 CHECK(ISC_R_NOMEMORY
);
892 memmove(keyid
->secret
.base
, isc_buffer_base(&b
),
893 keyid
->secret
.length
);
894 ISC_LIST_APPEND(*keyids
, keyid
, link
);
896 result
= ISC_R_SUCCESS
;
900 free_controlkey(keyid
, mctx
);
902 cfg_obj_destroy(pctx
, &config
);
904 cfg_parser_destroy(&pctx
);
909 * Ensures that both '*global_keylistp' and '*control_keylistp' are
910 * valid or both are NULL.
913 get_key_info(const cfg_obj_t
*config
, const cfg_obj_t
*control
,
914 const cfg_obj_t
**global_keylistp
,
915 const cfg_obj_t
**control_keylistp
)
918 const cfg_obj_t
*control_keylist
= NULL
;
919 const cfg_obj_t
*global_keylist
= NULL
;
921 REQUIRE(global_keylistp
!= NULL
&& *global_keylistp
== NULL
);
922 REQUIRE(control_keylistp
!= NULL
&& *control_keylistp
== NULL
);
924 control_keylist
= cfg_tuple_get(control
, "keys");
926 if (!cfg_obj_isvoid(control_keylist
) &&
927 cfg_list_first(control_keylist
) != NULL
) {
928 result
= cfg_map_get(config
, "key", &global_keylist
);
930 if (result
== ISC_R_SUCCESS
) {
931 *global_keylistp
= global_keylist
;
932 *control_keylistp
= control_keylist
;
938 update_listener(ns_controls_t
*cp
, controllistener_t
**listenerp
,
939 const cfg_obj_t
*control
, const cfg_obj_t
*config
,
940 isc_sockaddr_t
*addr
, cfg_aclconfctx_t
*aclconfctx
,
941 const char *socktext
, isc_sockettype_t type
)
943 controllistener_t
*listener
;
944 const cfg_obj_t
*allow
;
945 const cfg_obj_t
*global_keylist
= NULL
;
946 const cfg_obj_t
*control_keylist
= NULL
;
947 dns_acl_t
*new_acl
= NULL
;
948 controlkeylist_t keys
;
949 isc_result_t result
= ISC_R_SUCCESS
;
951 for (listener
= ISC_LIST_HEAD(cp
->listeners
);
953 listener
= ISC_LIST_NEXT(listener
, link
))
954 if (isc_sockaddr_equal(addr
, &listener
->address
))
957 if (listener
== NULL
) {
963 * There is already a listener for this sockaddr.
964 * Update the access list and key information.
966 * First try to deal with the key situation. There are a few
968 * (a) It had an explicit keylist and still has an explicit keylist.
969 * (b) It had an automagic key and now has an explicit keylist.
970 * (c) It had an explicit keylist and now needs an automagic key.
971 * (d) It has an automagic key and still needs the automagic key.
973 * (c) and (d) are the annoying ones. The caller needs to know
974 * that it should use the automagic configuration for key information
975 * in place of the named.conf configuration.
977 * XXXDCL There is one other hazard that has not been dealt with,
978 * the problem that if a key change is being caused by a control
979 * channel reload, then the response will be with the new key
980 * and not able to be decrypted by the client.
983 get_key_info(config
, control
, &global_keylist
,
986 if (control_keylist
!= NULL
) {
987 INSIST(global_keylist
!= NULL
);
990 result
= controlkeylist_fromcfg(control_keylist
,
991 listener
->mctx
, &keys
);
992 if (result
== ISC_R_SUCCESS
) {
993 free_controlkeylist(&listener
->keys
, listener
->mctx
);
994 listener
->keys
= keys
;
995 register_keys(control
, global_keylist
, &listener
->keys
,
996 listener
->mctx
, socktext
);
999 free_controlkeylist(&listener
->keys
, listener
->mctx
);
1000 result
= get_rndckey(listener
->mctx
, &listener
->keys
);
1003 if (result
!= ISC_R_SUCCESS
&& global_keylist
!= NULL
) {
1005 * This message might be a little misleading since the
1006 * "new keys" might in fact be identical to the old ones,
1007 * but tracking whether they are identical just for the
1008 * sake of avoiding this message would be too much trouble.
1010 if (control
!= NULL
)
1011 cfg_obj_log(control
, ns_g_lctx
, ISC_LOG_WARNING
,
1012 "couldn't install new keys for "
1013 "command channel %s: %s",
1014 socktext
, isc_result_totext(result
));
1016 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
1017 NS_LOGMODULE_CONTROL
, ISC_LOG_WARNING
,
1018 "couldn't install new keys for "
1019 "command channel %s: %s",
1020 socktext
, isc_result_totext(result
));
1024 * Now, keep the old access list unless a new one can be made.
1026 if (control
!= NULL
&& type
== isc_sockettype_tcp
) {
1027 allow
= cfg_tuple_get(control
, "allow");
1028 result
= cfg_acl_fromconfig(allow
, config
, ns_g_lctx
,
1029 aclconfctx
, listener
->mctx
, 0,
1032 result
= dns_acl_any(listener
->mctx
, &new_acl
);
1035 if (result
== ISC_R_SUCCESS
) {
1036 dns_acl_detach(&listener
->acl
);
1037 dns_acl_attach(new_acl
, &listener
->acl
);
1038 dns_acl_detach(&new_acl
);
1039 /* XXXDCL say the old acl is still used? */
1040 } else if (control
!= NULL
)
1041 cfg_obj_log(control
, ns_g_lctx
, ISC_LOG_WARNING
,
1042 "couldn't install new acl for "
1043 "command channel %s: %s",
1044 socktext
, isc_result_totext(result
));
1046 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
1047 NS_LOGMODULE_CONTROL
, ISC_LOG_WARNING
,
1048 "couldn't install new acl for "
1049 "command channel %s: %s",
1050 socktext
, isc_result_totext(result
));
1052 if (result
== ISC_R_SUCCESS
&& type
== isc_sockettype_unix
) {
1053 isc_uint32_t perm
, owner
, group
;
1054 perm
= cfg_obj_asuint32(cfg_tuple_get(control
, "perm"));
1055 owner
= cfg_obj_asuint32(cfg_tuple_get(control
, "owner"));
1056 group
= cfg_obj_asuint32(cfg_tuple_get(control
, "group"));
1057 result
= ISC_R_SUCCESS
;
1058 if (listener
->perm
!= perm
|| listener
->owner
!= owner
||
1059 listener
->group
!= group
)
1060 result
= isc_socket_permunix(&listener
->address
, perm
,
1062 if (result
== ISC_R_SUCCESS
) {
1063 listener
->perm
= perm
;
1064 listener
->owner
= owner
;
1065 listener
->group
= group
;
1066 } else if (control
!= NULL
)
1067 cfg_obj_log(control
, ns_g_lctx
, ISC_LOG_WARNING
,
1068 "couldn't update ownership/permission for "
1069 "command channel %s", socktext
);
1072 *listenerp
= listener
;
1076 add_listener(ns_controls_t
*cp
, controllistener_t
**listenerp
,
1077 const cfg_obj_t
*control
, const cfg_obj_t
*config
,
1078 isc_sockaddr_t
*addr
, cfg_aclconfctx_t
*aclconfctx
,
1079 const char *socktext
, isc_sockettype_t type
)
1081 isc_mem_t
*mctx
= cp
->server
->mctx
;
1082 controllistener_t
*listener
;
1083 const cfg_obj_t
*allow
;
1084 const cfg_obj_t
*global_keylist
= NULL
;
1085 const cfg_obj_t
*control_keylist
= NULL
;
1086 dns_acl_t
*new_acl
= NULL
;
1087 isc_result_t result
= ISC_R_SUCCESS
;
1089 listener
= isc_mem_get(mctx
, sizeof(*listener
));
1090 if (listener
== NULL
)
1091 result
= ISC_R_NOMEMORY
;
1093 if (result
== ISC_R_SUCCESS
) {
1094 listener
->mctx
= NULL
;
1095 isc_mem_attach(mctx
, &listener
->mctx
);
1096 listener
->controls
= cp
;
1097 listener
->task
= cp
->server
->task
;
1098 listener
->address
= *addr
;
1099 listener
->sock
= NULL
;
1100 listener
->listening
= ISC_FALSE
;
1101 listener
->exiting
= ISC_FALSE
;
1102 listener
->acl
= NULL
;
1103 listener
->type
= type
;
1105 listener
->owner
= 0;
1106 listener
->group
= 0;
1107 ISC_LINK_INIT(listener
, link
);
1108 ISC_LIST_INIT(listener
->keys
);
1109 ISC_LIST_INIT(listener
->connections
);
1114 if (control
!= NULL
&& type
== isc_sockettype_tcp
) {
1115 allow
= cfg_tuple_get(control
, "allow");
1116 result
= cfg_acl_fromconfig(allow
, config
, ns_g_lctx
,
1117 aclconfctx
, mctx
, 0,
1120 result
= dns_acl_any(mctx
, &new_acl
);
1124 if (result
== ISC_R_SUCCESS
) {
1125 dns_acl_attach(new_acl
, &listener
->acl
);
1126 dns_acl_detach(&new_acl
);
1129 get_key_info(config
, control
, &global_keylist
,
1132 if (control_keylist
!= NULL
) {
1133 result
= controlkeylist_fromcfg(control_keylist
,
1136 if (result
== ISC_R_SUCCESS
)
1137 register_keys(control
, global_keylist
,
1139 listener
->mctx
, socktext
);
1141 result
= get_rndckey(mctx
, &listener
->keys
);
1143 if (result
!= ISC_R_SUCCESS
&& control
!= NULL
)
1144 cfg_obj_log(control
, ns_g_lctx
, ISC_LOG_WARNING
,
1145 "couldn't install keys for "
1146 "command channel %s: %s",
1147 socktext
, isc_result_totext(result
));
1150 if (result
== ISC_R_SUCCESS
) {
1151 int pf
= isc_sockaddr_pf(&listener
->address
);
1152 if ((pf
== AF_INET
&& isc_net_probeipv4() != ISC_R_SUCCESS
) ||
1153 #ifdef ISC_PLATFORM_HAVESYSUNH
1154 (pf
== AF_UNIX
&& isc_net_probeunix() != ISC_R_SUCCESS
) ||
1156 (pf
== AF_INET6
&& isc_net_probeipv6() != ISC_R_SUCCESS
))
1157 result
= ISC_R_FAMILYNOSUPPORT
;
1160 if (result
== ISC_R_SUCCESS
&& type
== isc_sockettype_unix
)
1161 isc_socket_cleanunix(&listener
->address
, ISC_FALSE
);
1163 if (result
== ISC_R_SUCCESS
)
1164 result
= isc_socket_create(ns_g_socketmgr
,
1165 isc_sockaddr_pf(&listener
->address
),
1166 type
, &listener
->sock
);
1167 if (result
== ISC_R_SUCCESS
)
1168 isc_socket_setname(listener
->sock
, "control", NULL
);
1170 #ifndef ISC_ALLOW_MAPPED
1171 if (result
== ISC_R_SUCCESS
)
1172 isc_socket_ipv6only(listener
->sock
, ISC_TRUE
);
1175 if (result
== ISC_R_SUCCESS
)
1176 result
= isc_socket_bind(listener
->sock
, &listener
->address
,
1177 ISC_SOCKET_REUSEADDRESS
);
1179 if (result
== ISC_R_SUCCESS
&& type
== isc_sockettype_unix
) {
1180 listener
->perm
= cfg_obj_asuint32(cfg_tuple_get(control
,
1182 listener
->owner
= cfg_obj_asuint32(cfg_tuple_get(control
,
1184 listener
->group
= cfg_obj_asuint32(cfg_tuple_get(control
,
1186 result
= isc_socket_permunix(&listener
->address
, listener
->perm
,
1187 listener
->owner
, listener
->group
);
1189 if (result
== ISC_R_SUCCESS
)
1190 result
= control_listen(listener
);
1192 if (result
== ISC_R_SUCCESS
)
1193 result
= control_accept(listener
);
1195 if (result
== ISC_R_SUCCESS
) {
1196 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
1197 NS_LOGMODULE_CONTROL
, ISC_LOG_NOTICE
,
1198 "command channel listening on %s", socktext
);
1199 *listenerp
= listener
;
1202 if (listener
!= NULL
) {
1203 listener
->exiting
= ISC_TRUE
;
1204 free_listener(listener
);
1207 if (control
!= NULL
)
1208 cfg_obj_log(control
, ns_g_lctx
, ISC_LOG_WARNING
,
1209 "couldn't add command channel %s: %s",
1210 socktext
, isc_result_totext(result
));
1212 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
1213 NS_LOGMODULE_CONTROL
, ISC_LOG_NOTICE
,
1214 "couldn't add command channel %s: %s",
1215 socktext
, isc_result_totext(result
));
1220 /* XXXDCL return error results? fail hard? */
1224 ns_controls_configure(ns_controls_t
*cp
, const cfg_obj_t
*config
,
1225 cfg_aclconfctx_t
*aclconfctx
)
1227 controllistener_t
*listener
;
1228 controllistenerlist_t new_listeners
;
1229 const cfg_obj_t
*controlslist
= NULL
;
1230 const cfg_listelt_t
*element
, *element2
;
1231 char socktext
[ISC_SOCKADDR_FORMATSIZE
];
1233 ISC_LIST_INIT(new_listeners
);
1236 * Get the list of named.conf 'controls' statements.
1238 (void)cfg_map_get(config
, "controls", &controlslist
);
1241 * Run through the new control channel list, noting sockets that
1242 * are already being listened on and moving them to the new list.
1244 * Identifying duplicate addr/port combinations is left to either
1245 * the underlying config code, or to the bind attempt getting an
1246 * address-in-use error.
1248 if (controlslist
!= NULL
) {
1249 for (element
= cfg_list_first(controlslist
);
1251 element
= cfg_list_next(element
)) {
1252 const cfg_obj_t
*controls
;
1253 const cfg_obj_t
*inetcontrols
= NULL
;
1255 controls
= cfg_listelt_value(element
);
1256 (void)cfg_map_get(controls
, "inet", &inetcontrols
);
1257 if (inetcontrols
== NULL
)
1260 for (element2
= cfg_list_first(inetcontrols
);
1262 element2
= cfg_list_next(element2
)) {
1263 const cfg_obj_t
*control
;
1264 const cfg_obj_t
*obj
;
1265 isc_sockaddr_t addr
;
1268 * The parser handles BIND 8 configuration file
1269 * syntax, so it allows unix phrases as well
1270 * inet phrases with no keys{} clause.
1272 control
= cfg_listelt_value(element2
);
1274 obj
= cfg_tuple_get(control
, "address");
1275 addr
= *cfg_obj_assockaddr(obj
);
1276 if (isc_sockaddr_getport(&addr
) == 0)
1277 isc_sockaddr_setport(&addr
,
1280 isc_sockaddr_format(&addr
, socktext
,
1283 isc_log_write(ns_g_lctx
,
1284 NS_LOGCATEGORY_GENERAL
,
1285 NS_LOGMODULE_CONTROL
,
1287 "processing control channel %s",
1290 update_listener(cp
, &listener
, control
, config
,
1291 &addr
, aclconfctx
, socktext
,
1292 isc_sockettype_tcp
);
1294 if (listener
!= NULL
)
1296 * Remove the listener from the old
1297 * list, so it won't be shut down.
1299 ISC_LIST_UNLINK(cp
->listeners
,
1303 * This is a new listener.
1305 add_listener(cp
, &listener
, control
,
1306 config
, &addr
, aclconfctx
,
1308 isc_sockettype_tcp
);
1310 if (listener
!= NULL
)
1311 ISC_LIST_APPEND(new_listeners
,
1315 for (element
= cfg_list_first(controlslist
);
1317 element
= cfg_list_next(element
)) {
1318 const cfg_obj_t
*controls
;
1319 const cfg_obj_t
*unixcontrols
= NULL
;
1321 controls
= cfg_listelt_value(element
);
1322 (void)cfg_map_get(controls
, "unix", &unixcontrols
);
1323 if (unixcontrols
== NULL
)
1326 for (element2
= cfg_list_first(unixcontrols
);
1328 element2
= cfg_list_next(element2
)) {
1329 const cfg_obj_t
*control
;
1330 const cfg_obj_t
*path
;
1331 isc_sockaddr_t addr
;
1332 isc_result_t result
;
1335 * The parser handles BIND 8 configuration file
1336 * syntax, so it allows unix phrases as well
1337 * inet phrases with no keys{} clause.
1339 control
= cfg_listelt_value(element2
);
1341 path
= cfg_tuple_get(control
, "path");
1342 result
= isc_sockaddr_frompath(&addr
,
1343 cfg_obj_asstring(path
));
1344 if (result
!= ISC_R_SUCCESS
) {
1345 isc_log_write(ns_g_lctx
,
1346 NS_LOGCATEGORY_GENERAL
,
1347 NS_LOGMODULE_CONTROL
,
1349 "control channel '%s': %s",
1350 cfg_obj_asstring(path
),
1351 isc_result_totext(result
));
1355 isc_log_write(ns_g_lctx
,
1356 NS_LOGCATEGORY_GENERAL
,
1357 NS_LOGMODULE_CONTROL
,
1359 "processing control channel '%s'",
1360 cfg_obj_asstring(path
));
1362 update_listener(cp
, &listener
, control
, config
,
1364 cfg_obj_asstring(path
),
1365 isc_sockettype_unix
);
1367 if (listener
!= NULL
)
1369 * Remove the listener from the old
1370 * list, so it won't be shut down.
1372 ISC_LIST_UNLINK(cp
->listeners
,
1376 * This is a new listener.
1378 add_listener(cp
, &listener
, control
,
1379 config
, &addr
, aclconfctx
,
1380 cfg_obj_asstring(path
),
1381 isc_sockettype_unix
);
1383 if (listener
!= NULL
)
1384 ISC_LIST_APPEND(new_listeners
,
1391 for (i
= 0; i
< 2; i
++) {
1392 isc_sockaddr_t addr
;
1395 struct in_addr localhost
;
1397 if (isc_net_probeipv4() != ISC_R_SUCCESS
)
1399 localhost
.s_addr
= htonl(INADDR_LOOPBACK
);
1400 isc_sockaddr_fromin(&addr
, &localhost
, 0);
1402 if (isc_net_probeipv6() != ISC_R_SUCCESS
)
1404 isc_sockaddr_fromin6(&addr
,
1405 &in6addr_loopback
, 0);
1407 isc_sockaddr_setport(&addr
, NS_CONTROL_PORT
);
1409 isc_sockaddr_format(&addr
, socktext
, sizeof(socktext
));
1411 update_listener(cp
, &listener
, NULL
, NULL
,
1412 &addr
, NULL
, socktext
,
1413 isc_sockettype_tcp
);
1415 if (listener
!= NULL
)
1417 * Remove the listener from the old
1418 * list, so it won't be shut down.
1420 ISC_LIST_UNLINK(cp
->listeners
,
1424 * This is a new listener.
1426 add_listener(cp
, &listener
, NULL
, NULL
,
1427 &addr
, NULL
, socktext
,
1428 isc_sockettype_tcp
);
1430 if (listener
!= NULL
)
1431 ISC_LIST_APPEND(new_listeners
,
1437 * ns_control_shutdown() will stop whatever is on the global
1438 * listeners list, which currently only has whatever sockaddrs
1439 * were in the previous configuration (if any) that do not
1440 * remain in the current configuration.
1442 controls_shutdown(cp
);
1445 * Put all of the valid listeners on the listeners list.
1446 * Anything already on listeners in the process of shutting
1447 * down will be taken care of by listen_done().
1449 ISC_LIST_APPENDLIST(cp
->listeners
, new_listeners
, link
);
1450 return (ISC_R_SUCCESS
);
1454 ns_controls_create(ns_server_t
*server
, ns_controls_t
**ctrlsp
) {
1455 isc_mem_t
*mctx
= server
->mctx
;
1456 isc_result_t result
;
1457 ns_controls_t
*controls
= isc_mem_get(mctx
, sizeof(*controls
));
1459 if (controls
== NULL
)
1460 return (ISC_R_NOMEMORY
);
1461 controls
->server
= server
;
1462 ISC_LIST_INIT(controls
->listeners
);
1463 controls
->shuttingdown
= ISC_FALSE
;
1464 controls
->symtab
= NULL
;
1465 result
= isccc_cc_createsymtab(&controls
->symtab
);
1466 if (result
!= ISC_R_SUCCESS
) {
1467 isc_mem_put(server
->mctx
, controls
, sizeof(*controls
));
1471 return (ISC_R_SUCCESS
);
1475 ns_controls_destroy(ns_controls_t
**ctrlsp
) {
1476 ns_controls_t
*controls
= *ctrlsp
;
1478 REQUIRE(ISC_LIST_EMPTY(controls
->listeners
));
1480 isccc_symtab_destroy(&controls
->symtab
);
1481 isc_mem_put(controls
->server
->mctx
, controls
, sizeof(*controls
));