1*00b67f09SDavid van Moolenbroek /* $NetBSD: controlconf.c,v 1.10 2014/12/10 04:37:51 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004-2008, 2011-2014 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 2001-2003 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: controlconf.c,v 1.63 2011/12/22 08:07:48 marka Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek
26*00b67f09SDavid van Moolenbroek #include <isc/base64.h>
27*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
28*00b67f09SDavid van Moolenbroek #include <isc/event.h>
29*00b67f09SDavid van Moolenbroek #include <isc/file.h>
30*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
31*00b67f09SDavid van Moolenbroek #include <isc/net.h>
32*00b67f09SDavid van Moolenbroek #include <isc/netaddr.h>
33*00b67f09SDavid van Moolenbroek #include <isc/random.h>
34*00b67f09SDavid van Moolenbroek #include <isc/result.h>
35*00b67f09SDavid van Moolenbroek #include <isc/stdtime.h>
36*00b67f09SDavid van Moolenbroek #include <isc/string.h>
37*00b67f09SDavid van Moolenbroek #include <isc/timer.h>
38*00b67f09SDavid van Moolenbroek #include <isc/util.h>
39*00b67f09SDavid van Moolenbroek
40*00b67f09SDavid van Moolenbroek #include <isccfg/namedconf.h>
41*00b67f09SDavid van Moolenbroek
42*00b67f09SDavid van Moolenbroek #include <bind9/check.h>
43*00b67f09SDavid van Moolenbroek
44*00b67f09SDavid van Moolenbroek #include <isccc/alist.h>
45*00b67f09SDavid van Moolenbroek #include <isccc/cc.h>
46*00b67f09SDavid van Moolenbroek #include <isccc/ccmsg.h>
47*00b67f09SDavid van Moolenbroek #include <isccc/events.h>
48*00b67f09SDavid van Moolenbroek #include <isccc/result.h>
49*00b67f09SDavid van Moolenbroek #include <isccc/sexpr.h>
50*00b67f09SDavid van Moolenbroek #include <isccc/symtab.h>
51*00b67f09SDavid van Moolenbroek #include <isccc/util.h>
52*00b67f09SDavid van Moolenbroek
53*00b67f09SDavid van Moolenbroek #include <dns/result.h>
54*00b67f09SDavid van Moolenbroek
55*00b67f09SDavid van Moolenbroek #include <named/config.h>
56*00b67f09SDavid van Moolenbroek #include <named/control.h>
57*00b67f09SDavid van Moolenbroek #include <named/log.h>
58*00b67f09SDavid van Moolenbroek #include <named/server.h>
59*00b67f09SDavid van Moolenbroek
60*00b67f09SDavid van Moolenbroek /*
61*00b67f09SDavid van Moolenbroek * Note: Listeners and connections are not locked. All event handlers are
62*00b67f09SDavid van Moolenbroek * executed by the server task, and all callers of exported routines must
63*00b67f09SDavid van Moolenbroek * be running under the server task.
64*00b67f09SDavid van Moolenbroek */
65*00b67f09SDavid van Moolenbroek
66*00b67f09SDavid van Moolenbroek typedef struct controlkey controlkey_t;
67*00b67f09SDavid van Moolenbroek typedef ISC_LIST(controlkey_t) controlkeylist_t;
68*00b67f09SDavid van Moolenbroek
69*00b67f09SDavid van Moolenbroek typedef struct controlconnection controlconnection_t;
70*00b67f09SDavid van Moolenbroek typedef ISC_LIST(controlconnection_t) controlconnectionlist_t;
71*00b67f09SDavid van Moolenbroek
72*00b67f09SDavid van Moolenbroek typedef struct controllistener controllistener_t;
73*00b67f09SDavid van Moolenbroek typedef ISC_LIST(controllistener_t) controllistenerlist_t;
74*00b67f09SDavid van Moolenbroek
75*00b67f09SDavid van Moolenbroek struct controlkey {
76*00b67f09SDavid van Moolenbroek char * keyname;
77*00b67f09SDavid van Moolenbroek isc_uint32_t algorithm;
78*00b67f09SDavid van Moolenbroek isc_region_t secret;
79*00b67f09SDavid van Moolenbroek ISC_LINK(controlkey_t) link;
80*00b67f09SDavid van Moolenbroek };
81*00b67f09SDavid van Moolenbroek
82*00b67f09SDavid van Moolenbroek struct controlconnection {
83*00b67f09SDavid van Moolenbroek isc_socket_t * sock;
84*00b67f09SDavid van Moolenbroek isccc_ccmsg_t ccmsg;
85*00b67f09SDavid van Moolenbroek isc_boolean_t ccmsg_valid;
86*00b67f09SDavid van Moolenbroek isc_boolean_t sending;
87*00b67f09SDavid van Moolenbroek isc_timer_t * timer;
88*00b67f09SDavid van Moolenbroek unsigned char buffer[2048];
89*00b67f09SDavid van Moolenbroek controllistener_t * listener;
90*00b67f09SDavid van Moolenbroek isc_uint32_t nonce;
91*00b67f09SDavid van Moolenbroek ISC_LINK(controlconnection_t) link;
92*00b67f09SDavid van Moolenbroek };
93*00b67f09SDavid van Moolenbroek
94*00b67f09SDavid van Moolenbroek struct controllistener {
95*00b67f09SDavid van Moolenbroek ns_controls_t * controls;
96*00b67f09SDavid van Moolenbroek isc_mem_t * mctx;
97*00b67f09SDavid van Moolenbroek isc_task_t * task;
98*00b67f09SDavid van Moolenbroek isc_sockaddr_t address;
99*00b67f09SDavid van Moolenbroek isc_socket_t * sock;
100*00b67f09SDavid van Moolenbroek dns_acl_t * acl;
101*00b67f09SDavid van Moolenbroek isc_boolean_t listening;
102*00b67f09SDavid van Moolenbroek isc_boolean_t exiting;
103*00b67f09SDavid van Moolenbroek controlkeylist_t keys;
104*00b67f09SDavid van Moolenbroek controlconnectionlist_t connections;
105*00b67f09SDavid van Moolenbroek isc_sockettype_t type;
106*00b67f09SDavid van Moolenbroek isc_uint32_t perm;
107*00b67f09SDavid van Moolenbroek isc_uint32_t owner;
108*00b67f09SDavid van Moolenbroek isc_uint32_t group;
109*00b67f09SDavid van Moolenbroek ISC_LINK(controllistener_t) link;
110*00b67f09SDavid van Moolenbroek };
111*00b67f09SDavid van Moolenbroek
112*00b67f09SDavid van Moolenbroek struct ns_controls {
113*00b67f09SDavid van Moolenbroek ns_server_t *server;
114*00b67f09SDavid van Moolenbroek controllistenerlist_t listeners;
115*00b67f09SDavid van Moolenbroek isc_boolean_t shuttingdown;
116*00b67f09SDavid van Moolenbroek isccc_symtab_t *symtab;
117*00b67f09SDavid van Moolenbroek };
118*00b67f09SDavid van Moolenbroek
119*00b67f09SDavid van Moolenbroek static void control_newconn(isc_task_t *task, isc_event_t *event);
120*00b67f09SDavid van Moolenbroek static void control_recvmessage(isc_task_t *task, isc_event_t *event);
121*00b67f09SDavid van Moolenbroek
122*00b67f09SDavid van Moolenbroek #define CLOCKSKEW 300
123*00b67f09SDavid van Moolenbroek
124*00b67f09SDavid van Moolenbroek static void
free_controlkey(controlkey_t * key,isc_mem_t * mctx)125*00b67f09SDavid van Moolenbroek free_controlkey(controlkey_t *key, isc_mem_t *mctx) {
126*00b67f09SDavid van Moolenbroek if (key->keyname != NULL)
127*00b67f09SDavid van Moolenbroek isc_mem_free(mctx, key->keyname);
128*00b67f09SDavid van Moolenbroek if (key->secret.base != NULL)
129*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, key->secret.base, key->secret.length);
130*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, key, sizeof(*key));
131*00b67f09SDavid van Moolenbroek }
132*00b67f09SDavid van Moolenbroek
133*00b67f09SDavid van Moolenbroek static void
free_controlkeylist(controlkeylist_t * keylist,isc_mem_t * mctx)134*00b67f09SDavid van Moolenbroek free_controlkeylist(controlkeylist_t *keylist, isc_mem_t *mctx) {
135*00b67f09SDavid van Moolenbroek while (!ISC_LIST_EMPTY(*keylist)) {
136*00b67f09SDavid van Moolenbroek controlkey_t *key = ISC_LIST_HEAD(*keylist);
137*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(*keylist, key, link);
138*00b67f09SDavid van Moolenbroek free_controlkey(key, mctx);
139*00b67f09SDavid van Moolenbroek }
140*00b67f09SDavid van Moolenbroek }
141*00b67f09SDavid van Moolenbroek
142*00b67f09SDavid van Moolenbroek static void
free_listener(controllistener_t * listener)143*00b67f09SDavid van Moolenbroek free_listener(controllistener_t *listener) {
144*00b67f09SDavid van Moolenbroek INSIST(listener->exiting);
145*00b67f09SDavid van Moolenbroek INSIST(!listener->listening);
146*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(listener->connections));
147*00b67f09SDavid van Moolenbroek
148*00b67f09SDavid van Moolenbroek if (listener->sock != NULL)
149*00b67f09SDavid van Moolenbroek isc_socket_detach(&listener->sock);
150*00b67f09SDavid van Moolenbroek
151*00b67f09SDavid van Moolenbroek free_controlkeylist(&listener->keys, listener->mctx);
152*00b67f09SDavid van Moolenbroek
153*00b67f09SDavid van Moolenbroek if (listener->acl != NULL)
154*00b67f09SDavid van Moolenbroek dns_acl_detach(&listener->acl);
155*00b67f09SDavid van Moolenbroek
156*00b67f09SDavid van Moolenbroek isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
157*00b67f09SDavid van Moolenbroek }
158*00b67f09SDavid van Moolenbroek
159*00b67f09SDavid van Moolenbroek static void
maybe_free_listener(controllistener_t * listener)160*00b67f09SDavid van Moolenbroek maybe_free_listener(controllistener_t *listener) {
161*00b67f09SDavid van Moolenbroek if (listener->exiting &&
162*00b67f09SDavid van Moolenbroek !listener->listening &&
163*00b67f09SDavid van Moolenbroek ISC_LIST_EMPTY(listener->connections))
164*00b67f09SDavid van Moolenbroek free_listener(listener);
165*00b67f09SDavid van Moolenbroek }
166*00b67f09SDavid van Moolenbroek
167*00b67f09SDavid van Moolenbroek static void
maybe_free_connection(controlconnection_t * conn)168*00b67f09SDavid van Moolenbroek maybe_free_connection(controlconnection_t *conn) {
169*00b67f09SDavid van Moolenbroek controllistener_t *listener = conn->listener;
170*00b67f09SDavid van Moolenbroek
171*00b67f09SDavid van Moolenbroek if (conn->timer != NULL)
172*00b67f09SDavid van Moolenbroek isc_timer_detach(&conn->timer);
173*00b67f09SDavid van Moolenbroek
174*00b67f09SDavid van Moolenbroek if (conn->ccmsg_valid) {
175*00b67f09SDavid van Moolenbroek isccc_ccmsg_cancelread(&conn->ccmsg);
176*00b67f09SDavid van Moolenbroek return;
177*00b67f09SDavid van Moolenbroek }
178*00b67f09SDavid van Moolenbroek
179*00b67f09SDavid van Moolenbroek if (conn->sending) {
180*00b67f09SDavid van Moolenbroek isc_socket_cancel(conn->sock, listener->task,
181*00b67f09SDavid van Moolenbroek ISC_SOCKCANCEL_SEND);
182*00b67f09SDavid van Moolenbroek return;
183*00b67f09SDavid van Moolenbroek }
184*00b67f09SDavid van Moolenbroek
185*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(listener->connections, conn, link);
186*00b67f09SDavid van Moolenbroek isc_mem_put(listener->mctx, conn, sizeof(*conn));
187*00b67f09SDavid van Moolenbroek }
188*00b67f09SDavid van Moolenbroek
189*00b67f09SDavid van Moolenbroek static void
shutdown_listener(controllistener_t * listener)190*00b67f09SDavid van Moolenbroek shutdown_listener(controllistener_t *listener) {
191*00b67f09SDavid van Moolenbroek controlconnection_t *conn;
192*00b67f09SDavid van Moolenbroek controlconnection_t *next;
193*00b67f09SDavid van Moolenbroek
194*00b67f09SDavid van Moolenbroek if (!listener->exiting) {
195*00b67f09SDavid van Moolenbroek char socktext[ISC_SOCKADDR_FORMATSIZE];
196*00b67f09SDavid van Moolenbroek
197*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(listener->controls->listeners, listener, link);
198*00b67f09SDavid van Moolenbroek
199*00b67f09SDavid van Moolenbroek isc_sockaddr_format(&listener->address, socktext,
200*00b67f09SDavid van Moolenbroek sizeof(socktext));
201*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
202*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
203*00b67f09SDavid van Moolenbroek "stopping command channel on %s", socktext);
204*00b67f09SDavid van Moolenbroek if (listener->type == isc_sockettype_unix)
205*00b67f09SDavid van Moolenbroek isc_socket_cleanunix(&listener->address, ISC_TRUE);
206*00b67f09SDavid van Moolenbroek listener->exiting = ISC_TRUE;
207*00b67f09SDavid van Moolenbroek }
208*00b67f09SDavid van Moolenbroek
209*00b67f09SDavid van Moolenbroek for (conn = ISC_LIST_HEAD(listener->connections);
210*00b67f09SDavid van Moolenbroek conn != NULL;
211*00b67f09SDavid van Moolenbroek conn = next)
212*00b67f09SDavid van Moolenbroek {
213*00b67f09SDavid van Moolenbroek next = ISC_LIST_NEXT(conn, link);
214*00b67f09SDavid van Moolenbroek maybe_free_connection(conn);
215*00b67f09SDavid van Moolenbroek }
216*00b67f09SDavid van Moolenbroek
217*00b67f09SDavid van Moolenbroek if (listener->listening)
218*00b67f09SDavid van Moolenbroek isc_socket_cancel(listener->sock, listener->task,
219*00b67f09SDavid van Moolenbroek ISC_SOCKCANCEL_ACCEPT);
220*00b67f09SDavid van Moolenbroek
221*00b67f09SDavid van Moolenbroek maybe_free_listener(listener);
222*00b67f09SDavid van Moolenbroek }
223*00b67f09SDavid van Moolenbroek
224*00b67f09SDavid van Moolenbroek static isc_boolean_t
address_ok(isc_sockaddr_t * sockaddr,dns_acl_t * acl)225*00b67f09SDavid van Moolenbroek address_ok(isc_sockaddr_t *sockaddr, dns_acl_t *acl) {
226*00b67f09SDavid van Moolenbroek isc_netaddr_t netaddr;
227*00b67f09SDavid van Moolenbroek isc_result_t result;
228*00b67f09SDavid van Moolenbroek int match;
229*00b67f09SDavid van Moolenbroek
230*00b67f09SDavid van Moolenbroek isc_netaddr_fromsockaddr(&netaddr, sockaddr);
231*00b67f09SDavid van Moolenbroek
232*00b67f09SDavid van Moolenbroek result = dns_acl_match(&netaddr, NULL, acl,
233*00b67f09SDavid van Moolenbroek &ns_g_server->aclenv, &match, NULL);
234*00b67f09SDavid van Moolenbroek
235*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS || match <= 0)
236*00b67f09SDavid van Moolenbroek return (ISC_FALSE);
237*00b67f09SDavid van Moolenbroek else
238*00b67f09SDavid van Moolenbroek return (ISC_TRUE);
239*00b67f09SDavid van Moolenbroek }
240*00b67f09SDavid van Moolenbroek
241*00b67f09SDavid van Moolenbroek static isc_result_t
control_accept(controllistener_t * listener)242*00b67f09SDavid van Moolenbroek control_accept(controllistener_t *listener) {
243*00b67f09SDavid van Moolenbroek isc_result_t result;
244*00b67f09SDavid van Moolenbroek result = isc_socket_accept(listener->sock,
245*00b67f09SDavid van Moolenbroek listener->task,
246*00b67f09SDavid van Moolenbroek control_newconn, listener);
247*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
248*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
249*00b67f09SDavid van Moolenbroek "isc_socket_accept() failed: %s",
250*00b67f09SDavid van Moolenbroek isc_result_totext(result));
251*00b67f09SDavid van Moolenbroek else
252*00b67f09SDavid van Moolenbroek listener->listening = ISC_TRUE;
253*00b67f09SDavid van Moolenbroek return (result);
254*00b67f09SDavid van Moolenbroek }
255*00b67f09SDavid van Moolenbroek
256*00b67f09SDavid van Moolenbroek static isc_result_t
control_listen(controllistener_t * listener)257*00b67f09SDavid van Moolenbroek control_listen(controllistener_t *listener) {
258*00b67f09SDavid van Moolenbroek isc_result_t result;
259*00b67f09SDavid van Moolenbroek
260*00b67f09SDavid van Moolenbroek result = isc_socket_listen(listener->sock, 0);
261*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
262*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
263*00b67f09SDavid van Moolenbroek "isc_socket_listen() failed: %s",
264*00b67f09SDavid van Moolenbroek isc_result_totext(result));
265*00b67f09SDavid van Moolenbroek return (result);
266*00b67f09SDavid van Moolenbroek }
267*00b67f09SDavid van Moolenbroek
268*00b67f09SDavid van Moolenbroek static void
control_next(controllistener_t * listener)269*00b67f09SDavid van Moolenbroek control_next(controllistener_t *listener) {
270*00b67f09SDavid van Moolenbroek (void)control_accept(listener);
271*00b67f09SDavid van Moolenbroek }
272*00b67f09SDavid van Moolenbroek
273*00b67f09SDavid van Moolenbroek static void
control_senddone(isc_task_t * task,isc_event_t * event)274*00b67f09SDavid van Moolenbroek control_senddone(isc_task_t *task, isc_event_t *event) {
275*00b67f09SDavid van Moolenbroek isc_socketevent_t *sevent = (isc_socketevent_t *) event;
276*00b67f09SDavid van Moolenbroek controlconnection_t *conn = event->ev_arg;
277*00b67f09SDavid van Moolenbroek controllistener_t *listener = conn->listener;
278*00b67f09SDavid van Moolenbroek isc_socket_t *sock = (isc_socket_t *)sevent->ev_sender;
279*00b67f09SDavid van Moolenbroek isc_result_t result;
280*00b67f09SDavid van Moolenbroek
281*00b67f09SDavid van Moolenbroek REQUIRE(conn->sending);
282*00b67f09SDavid van Moolenbroek
283*00b67f09SDavid van Moolenbroek UNUSED(task);
284*00b67f09SDavid van Moolenbroek
285*00b67f09SDavid van Moolenbroek conn->sending = ISC_FALSE;
286*00b67f09SDavid van Moolenbroek
287*00b67f09SDavid van Moolenbroek if (sevent->result != ISC_R_SUCCESS &&
288*00b67f09SDavid van Moolenbroek sevent->result != ISC_R_CANCELED)
289*00b67f09SDavid van Moolenbroek {
290*00b67f09SDavid van Moolenbroek char socktext[ISC_SOCKADDR_FORMATSIZE];
291*00b67f09SDavid van Moolenbroek isc_sockaddr_t peeraddr;
292*00b67f09SDavid van Moolenbroek
293*00b67f09SDavid van Moolenbroek (void)isc_socket_getpeername(sock, &peeraddr);
294*00b67f09SDavid van Moolenbroek isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
295*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
296*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
297*00b67f09SDavid van Moolenbroek "error sending command response to %s: %s",
298*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(sevent->result));
299*00b67f09SDavid van Moolenbroek }
300*00b67f09SDavid van Moolenbroek isc_event_free(&event);
301*00b67f09SDavid van Moolenbroek
302*00b67f09SDavid van Moolenbroek result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
303*00b67f09SDavid van Moolenbroek control_recvmessage, conn);
304*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
305*00b67f09SDavid van Moolenbroek isc_socket_detach(&conn->sock);
306*00b67f09SDavid van Moolenbroek maybe_free_connection(conn);
307*00b67f09SDavid van Moolenbroek maybe_free_listener(listener);
308*00b67f09SDavid van Moolenbroek }
309*00b67f09SDavid van Moolenbroek }
310*00b67f09SDavid van Moolenbroek
311*00b67f09SDavid van Moolenbroek static inline void
log_invalid(isccc_ccmsg_t * ccmsg,isc_result_t result)312*00b67f09SDavid van Moolenbroek log_invalid(isccc_ccmsg_t *ccmsg, isc_result_t result) {
313*00b67f09SDavid van Moolenbroek char socktext[ISC_SOCKADDR_FORMATSIZE];
314*00b67f09SDavid van Moolenbroek isc_sockaddr_t peeraddr;
315*00b67f09SDavid van Moolenbroek
316*00b67f09SDavid van Moolenbroek (void)isc_socket_getpeername(ccmsg->sock, &peeraddr);
317*00b67f09SDavid van Moolenbroek isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
318*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
319*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_ERROR,
320*00b67f09SDavid van Moolenbroek "invalid command from %s: %s",
321*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(result));
322*00b67f09SDavid van Moolenbroek }
323*00b67f09SDavid van Moolenbroek
324*00b67f09SDavid van Moolenbroek static void
control_recvmessage(isc_task_t * task,isc_event_t * event)325*00b67f09SDavid van Moolenbroek control_recvmessage(isc_task_t *task, isc_event_t *event) {
326*00b67f09SDavid van Moolenbroek controlconnection_t *conn;
327*00b67f09SDavid van Moolenbroek controllistener_t *listener;
328*00b67f09SDavid van Moolenbroek controlkey_t *key;
329*00b67f09SDavid van Moolenbroek isccc_sexpr_t *request = NULL;
330*00b67f09SDavid van Moolenbroek isccc_sexpr_t *response = NULL;
331*00b67f09SDavid van Moolenbroek isccc_region_t ccregion;
332*00b67f09SDavid van Moolenbroek isc_uint32_t algorithm;
333*00b67f09SDavid van Moolenbroek isccc_region_t secret;
334*00b67f09SDavid van Moolenbroek isc_stdtime_t now;
335*00b67f09SDavid van Moolenbroek isc_buffer_t b;
336*00b67f09SDavid van Moolenbroek isc_region_t r;
337*00b67f09SDavid van Moolenbroek isc_uint32_t len;
338*00b67f09SDavid van Moolenbroek isc_buffer_t text;
339*00b67f09SDavid van Moolenbroek char textarray[2*1024];
340*00b67f09SDavid van Moolenbroek isc_result_t result;
341*00b67f09SDavid van Moolenbroek isc_result_t eresult;
342*00b67f09SDavid van Moolenbroek isccc_sexpr_t *_ctrl;
343*00b67f09SDavid van Moolenbroek isccc_time_t sent;
344*00b67f09SDavid van Moolenbroek isccc_time_t exp;
345*00b67f09SDavid van Moolenbroek isc_uint32_t nonce;
346*00b67f09SDavid van Moolenbroek
347*00b67f09SDavid van Moolenbroek REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG);
348*00b67f09SDavid van Moolenbroek
349*00b67f09SDavid van Moolenbroek conn = event->ev_arg;
350*00b67f09SDavid van Moolenbroek listener = conn->listener;
351*00b67f09SDavid van Moolenbroek algorithm = DST_ALG_UNKNOWN;
352*00b67f09SDavid van Moolenbroek secret.rstart = NULL;
353*00b67f09SDavid van Moolenbroek
354*00b67f09SDavid van Moolenbroek /* Is the server shutting down? */
355*00b67f09SDavid van Moolenbroek if (listener->controls->shuttingdown)
356*00b67f09SDavid van Moolenbroek goto cleanup;
357*00b67f09SDavid van Moolenbroek
358*00b67f09SDavid van Moolenbroek if (conn->ccmsg.result != ISC_R_SUCCESS) {
359*00b67f09SDavid van Moolenbroek if (conn->ccmsg.result != ISC_R_CANCELED &&
360*00b67f09SDavid van Moolenbroek conn->ccmsg.result != ISC_R_EOF)
361*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, conn->ccmsg.result);
362*00b67f09SDavid van Moolenbroek goto cleanup;
363*00b67f09SDavid van Moolenbroek }
364*00b67f09SDavid van Moolenbroek
365*00b67f09SDavid van Moolenbroek request = NULL;
366*00b67f09SDavid van Moolenbroek
367*00b67f09SDavid van Moolenbroek for (key = ISC_LIST_HEAD(listener->keys);
368*00b67f09SDavid van Moolenbroek key != NULL;
369*00b67f09SDavid van Moolenbroek key = ISC_LIST_NEXT(key, link))
370*00b67f09SDavid van Moolenbroek {
371*00b67f09SDavid van Moolenbroek ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer);
372*00b67f09SDavid van Moolenbroek ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer);
373*00b67f09SDavid van Moolenbroek secret.rstart = isc_mem_get(listener->mctx, key->secret.length);
374*00b67f09SDavid van Moolenbroek if (secret.rstart == NULL)
375*00b67f09SDavid van Moolenbroek goto cleanup;
376*00b67f09SDavid van Moolenbroek memmove(secret.rstart, key->secret.base, key->secret.length);
377*00b67f09SDavid van Moolenbroek secret.rend = secret.rstart + key->secret.length;
378*00b67f09SDavid van Moolenbroek algorithm = key->algorithm;
379*00b67f09SDavid van Moolenbroek result = isccc_cc_fromwire(&ccregion, &request,
380*00b67f09SDavid van Moolenbroek algorithm, &secret);
381*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
382*00b67f09SDavid van Moolenbroek break;
383*00b67f09SDavid van Moolenbroek isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
384*00b67f09SDavid van Moolenbroek if (result != ISCCC_R_BADAUTH) {
385*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, result);
386*00b67f09SDavid van Moolenbroek goto cleanup;
387*00b67f09SDavid van Moolenbroek }
388*00b67f09SDavid van Moolenbroek }
389*00b67f09SDavid van Moolenbroek
390*00b67f09SDavid van Moolenbroek if (key == NULL) {
391*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
392*00b67f09SDavid van Moolenbroek goto cleanup;
393*00b67f09SDavid van Moolenbroek }
394*00b67f09SDavid van Moolenbroek
395*00b67f09SDavid van Moolenbroek /* We shouldn't be getting a reply. */
396*00b67f09SDavid van Moolenbroek if (isccc_cc_isreply(request)) {
397*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, ISC_R_FAILURE);
398*00b67f09SDavid van Moolenbroek goto cleanup_request;
399*00b67f09SDavid van Moolenbroek }
400*00b67f09SDavid van Moolenbroek
401*00b67f09SDavid van Moolenbroek isc_stdtime_get(&now);
402*00b67f09SDavid van Moolenbroek
403*00b67f09SDavid van Moolenbroek /*
404*00b67f09SDavid van Moolenbroek * Limit exposure to replay attacks.
405*00b67f09SDavid van Moolenbroek */
406*00b67f09SDavid van Moolenbroek _ctrl = isccc_alist_lookup(request, "_ctrl");
407*00b67f09SDavid van Moolenbroek if (_ctrl == NULL) {
408*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, ISC_R_FAILURE);
409*00b67f09SDavid van Moolenbroek goto cleanup_request;
410*00b67f09SDavid van Moolenbroek }
411*00b67f09SDavid van Moolenbroek
412*00b67f09SDavid van Moolenbroek if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) {
413*00b67f09SDavid van Moolenbroek if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) {
414*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW);
415*00b67f09SDavid van Moolenbroek goto cleanup_request;
416*00b67f09SDavid van Moolenbroek }
417*00b67f09SDavid van Moolenbroek } else {
418*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, ISC_R_FAILURE);
419*00b67f09SDavid van Moolenbroek goto cleanup_request;
420*00b67f09SDavid van Moolenbroek }
421*00b67f09SDavid van Moolenbroek
422*00b67f09SDavid van Moolenbroek /*
423*00b67f09SDavid van Moolenbroek * Expire messages that are too old.
424*00b67f09SDavid van Moolenbroek */
425*00b67f09SDavid van Moolenbroek if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS &&
426*00b67f09SDavid van Moolenbroek now > exp) {
427*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED);
428*00b67f09SDavid van Moolenbroek goto cleanup_request;
429*00b67f09SDavid van Moolenbroek }
430*00b67f09SDavid van Moolenbroek
431*00b67f09SDavid van Moolenbroek /*
432*00b67f09SDavid van Moolenbroek * Duplicate suppression (required for UDP).
433*00b67f09SDavid van Moolenbroek */
434*00b67f09SDavid van Moolenbroek isccc_cc_cleansymtab(listener->controls->symtab, now);
435*00b67f09SDavid van Moolenbroek result = isccc_cc_checkdup(listener->controls->symtab, request, now);
436*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
437*00b67f09SDavid van Moolenbroek if (result == ISC_R_EXISTS)
438*00b67f09SDavid van Moolenbroek result = ISCCC_R_DUPLICATE;
439*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, result);
440*00b67f09SDavid van Moolenbroek goto cleanup_request;
441*00b67f09SDavid van Moolenbroek }
442*00b67f09SDavid van Moolenbroek
443*00b67f09SDavid van Moolenbroek if (conn->nonce != 0 &&
444*00b67f09SDavid van Moolenbroek (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS ||
445*00b67f09SDavid van Moolenbroek conn->nonce != nonce)) {
446*00b67f09SDavid van Moolenbroek log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
447*00b67f09SDavid van Moolenbroek goto cleanup_request;
448*00b67f09SDavid van Moolenbroek }
449*00b67f09SDavid van Moolenbroek
450*00b67f09SDavid van Moolenbroek isc_buffer_init(&text, textarray, sizeof(textarray));
451*00b67f09SDavid van Moolenbroek
452*00b67f09SDavid van Moolenbroek /*
453*00b67f09SDavid van Moolenbroek * Establish nonce.
454*00b67f09SDavid van Moolenbroek */
455*00b67f09SDavid van Moolenbroek if (conn->nonce == 0) {
456*00b67f09SDavid van Moolenbroek while (conn->nonce == 0)
457*00b67f09SDavid van Moolenbroek isc_random_get(&conn->nonce);
458*00b67f09SDavid van Moolenbroek eresult = ISC_R_SUCCESS;
459*00b67f09SDavid van Moolenbroek } else
460*00b67f09SDavid van Moolenbroek eresult = ns_control_docommand(request, &text);
461*00b67f09SDavid van Moolenbroek
462*00b67f09SDavid van Moolenbroek result = isccc_cc_createresponse(request, now, now + 60, &response);
463*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
464*00b67f09SDavid van Moolenbroek goto cleanup_request;
465*00b67f09SDavid van Moolenbroek if (eresult != ISC_R_SUCCESS) {
466*00b67f09SDavid van Moolenbroek isccc_sexpr_t *data;
467*00b67f09SDavid van Moolenbroek
468*00b67f09SDavid van Moolenbroek data = isccc_alist_lookup(response, "_data");
469*00b67f09SDavid van Moolenbroek if (data != NULL) {
470*00b67f09SDavid van Moolenbroek const char *estr = isc_result_totext(eresult);
471*00b67f09SDavid van Moolenbroek if (isccc_cc_definestring(data, "err", estr) == NULL)
472*00b67f09SDavid van Moolenbroek goto cleanup_response;
473*00b67f09SDavid van Moolenbroek }
474*00b67f09SDavid van Moolenbroek }
475*00b67f09SDavid van Moolenbroek
476*00b67f09SDavid van Moolenbroek if (isc_buffer_usedlength(&text) > 0) {
477*00b67f09SDavid van Moolenbroek isccc_sexpr_t *data;
478*00b67f09SDavid van Moolenbroek
479*00b67f09SDavid van Moolenbroek data = isccc_alist_lookup(response, "_data");
480*00b67f09SDavid van Moolenbroek if (data != NULL) {
481*00b67f09SDavid van Moolenbroek char *str = (char *)isc_buffer_base(&text);
482*00b67f09SDavid van Moolenbroek if (isccc_cc_definestring(data, "text", str) == NULL)
483*00b67f09SDavid van Moolenbroek goto cleanup_response;
484*00b67f09SDavid van Moolenbroek }
485*00b67f09SDavid van Moolenbroek }
486*00b67f09SDavid van Moolenbroek
487*00b67f09SDavid van Moolenbroek _ctrl = isccc_alist_lookup(response, "_ctrl");
488*00b67f09SDavid van Moolenbroek if (_ctrl == NULL ||
489*00b67f09SDavid van Moolenbroek isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL)
490*00b67f09SDavid van Moolenbroek goto cleanup_response;
491*00b67f09SDavid van Moolenbroek
492*00b67f09SDavid van Moolenbroek ccregion.rstart = conn->buffer + 4;
493*00b67f09SDavid van Moolenbroek ccregion.rend = conn->buffer + sizeof(conn->buffer);
494*00b67f09SDavid van Moolenbroek result = isccc_cc_towire(response, &ccregion, algorithm, &secret);
495*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
496*00b67f09SDavid van Moolenbroek goto cleanup_response;
497*00b67f09SDavid van Moolenbroek isc_buffer_init(&b, conn->buffer, 4);
498*00b67f09SDavid van Moolenbroek len = sizeof(conn->buffer) - REGION_SIZE(ccregion);
499*00b67f09SDavid van Moolenbroek isc_buffer_putuint32(&b, len - 4);
500*00b67f09SDavid van Moolenbroek r.base = conn->buffer;
501*00b67f09SDavid van Moolenbroek r.length = len;
502*00b67f09SDavid van Moolenbroek
503*00b67f09SDavid van Moolenbroek result = isc_socket_send(conn->sock, &r, task, control_senddone, conn);
504*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
505*00b67f09SDavid van Moolenbroek goto cleanup_response;
506*00b67f09SDavid van Moolenbroek conn->sending = ISC_TRUE;
507*00b67f09SDavid van Moolenbroek
508*00b67f09SDavid van Moolenbroek isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
509*00b67f09SDavid van Moolenbroek isccc_sexpr_free(&request);
510*00b67f09SDavid van Moolenbroek isccc_sexpr_free(&response);
511*00b67f09SDavid van Moolenbroek return;
512*00b67f09SDavid van Moolenbroek
513*00b67f09SDavid van Moolenbroek cleanup_response:
514*00b67f09SDavid van Moolenbroek isccc_sexpr_free(&response);
515*00b67f09SDavid van Moolenbroek
516*00b67f09SDavid van Moolenbroek cleanup_request:
517*00b67f09SDavid van Moolenbroek isccc_sexpr_free(&request);
518*00b67f09SDavid van Moolenbroek isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
519*00b67f09SDavid van Moolenbroek
520*00b67f09SDavid van Moolenbroek cleanup:
521*00b67f09SDavid van Moolenbroek isc_socket_detach(&conn->sock);
522*00b67f09SDavid van Moolenbroek isccc_ccmsg_invalidate(&conn->ccmsg);
523*00b67f09SDavid van Moolenbroek conn->ccmsg_valid = ISC_FALSE;
524*00b67f09SDavid van Moolenbroek maybe_free_connection(conn);
525*00b67f09SDavid van Moolenbroek maybe_free_listener(listener);
526*00b67f09SDavid van Moolenbroek }
527*00b67f09SDavid van Moolenbroek
528*00b67f09SDavid van Moolenbroek static void
control_timeout(isc_task_t * task,isc_event_t * event)529*00b67f09SDavid van Moolenbroek control_timeout(isc_task_t *task, isc_event_t *event) {
530*00b67f09SDavid van Moolenbroek controlconnection_t *conn = event->ev_arg;
531*00b67f09SDavid van Moolenbroek
532*00b67f09SDavid van Moolenbroek UNUSED(task);
533*00b67f09SDavid van Moolenbroek
534*00b67f09SDavid van Moolenbroek isc_timer_detach(&conn->timer);
535*00b67f09SDavid van Moolenbroek maybe_free_connection(conn);
536*00b67f09SDavid van Moolenbroek
537*00b67f09SDavid van Moolenbroek isc_event_free(&event);
538*00b67f09SDavid van Moolenbroek }
539*00b67f09SDavid van Moolenbroek
540*00b67f09SDavid van Moolenbroek static isc_result_t
newconnection(controllistener_t * listener,isc_socket_t * sock)541*00b67f09SDavid van Moolenbroek newconnection(controllistener_t *listener, isc_socket_t *sock) {
542*00b67f09SDavid van Moolenbroek controlconnection_t *conn;
543*00b67f09SDavid van Moolenbroek isc_interval_t interval;
544*00b67f09SDavid van Moolenbroek isc_result_t result;
545*00b67f09SDavid van Moolenbroek
546*00b67f09SDavid van Moolenbroek conn = isc_mem_get(listener->mctx, sizeof(*conn));
547*00b67f09SDavid van Moolenbroek if (conn == NULL)
548*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
549*00b67f09SDavid van Moolenbroek
550*00b67f09SDavid van Moolenbroek conn->sock = sock;
551*00b67f09SDavid van Moolenbroek isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg);
552*00b67f09SDavid van Moolenbroek conn->ccmsg_valid = ISC_TRUE;
553*00b67f09SDavid van Moolenbroek conn->sending = ISC_FALSE;
554*00b67f09SDavid van Moolenbroek conn->timer = NULL;
555*00b67f09SDavid van Moolenbroek isc_interval_set(&interval, 60, 0);
556*00b67f09SDavid van Moolenbroek result = isc_timer_create(ns_g_timermgr, isc_timertype_once,
557*00b67f09SDavid van Moolenbroek NULL, &interval, listener->task,
558*00b67f09SDavid van Moolenbroek control_timeout, conn, &conn->timer);
559*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
560*00b67f09SDavid van Moolenbroek goto cleanup;
561*00b67f09SDavid van Moolenbroek
562*00b67f09SDavid van Moolenbroek conn->listener = listener;
563*00b67f09SDavid van Moolenbroek conn->nonce = 0;
564*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(conn, link);
565*00b67f09SDavid van Moolenbroek
566*00b67f09SDavid van Moolenbroek result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
567*00b67f09SDavid van Moolenbroek control_recvmessage, conn);
568*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
569*00b67f09SDavid van Moolenbroek goto cleanup;
570*00b67f09SDavid van Moolenbroek isccc_ccmsg_setmaxsize(&conn->ccmsg, 2048);
571*00b67f09SDavid van Moolenbroek
572*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(listener->connections, conn, link);
573*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
574*00b67f09SDavid van Moolenbroek
575*00b67f09SDavid van Moolenbroek cleanup:
576*00b67f09SDavid van Moolenbroek isccc_ccmsg_invalidate(&conn->ccmsg);
577*00b67f09SDavid van Moolenbroek if (conn->timer != NULL)
578*00b67f09SDavid van Moolenbroek isc_timer_detach(&conn->timer);
579*00b67f09SDavid van Moolenbroek isc_mem_put(listener->mctx, conn, sizeof(*conn));
580*00b67f09SDavid van Moolenbroek return (result);
581*00b67f09SDavid van Moolenbroek }
582*00b67f09SDavid van Moolenbroek
583*00b67f09SDavid van Moolenbroek static void
control_newconn(isc_task_t * task,isc_event_t * event)584*00b67f09SDavid van Moolenbroek control_newconn(isc_task_t *task, isc_event_t *event) {
585*00b67f09SDavid van Moolenbroek isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
586*00b67f09SDavid van Moolenbroek controllistener_t *listener = event->ev_arg;
587*00b67f09SDavid van Moolenbroek isc_socket_t *sock;
588*00b67f09SDavid van Moolenbroek isc_sockaddr_t peeraddr;
589*00b67f09SDavid van Moolenbroek isc_result_t result;
590*00b67f09SDavid van Moolenbroek
591*00b67f09SDavid van Moolenbroek UNUSED(task);
592*00b67f09SDavid van Moolenbroek
593*00b67f09SDavid van Moolenbroek listener->listening = ISC_FALSE;
594*00b67f09SDavid van Moolenbroek
595*00b67f09SDavid van Moolenbroek if (nevent->result != ISC_R_SUCCESS) {
596*00b67f09SDavid van Moolenbroek if (nevent->result == ISC_R_CANCELED) {
597*00b67f09SDavid van Moolenbroek shutdown_listener(listener);
598*00b67f09SDavid van Moolenbroek goto cleanup;
599*00b67f09SDavid van Moolenbroek }
600*00b67f09SDavid van Moolenbroek goto restart;
601*00b67f09SDavid van Moolenbroek }
602*00b67f09SDavid van Moolenbroek
603*00b67f09SDavid van Moolenbroek sock = nevent->newsocket;
604*00b67f09SDavid van Moolenbroek isc_socket_setname(sock, "control", NULL);
605*00b67f09SDavid van Moolenbroek (void)isc_socket_getpeername(sock, &peeraddr);
606*00b67f09SDavid van Moolenbroek if (listener->type == isc_sockettype_tcp &&
607*00b67f09SDavid van Moolenbroek !address_ok(&peeraddr, listener->acl)) {
608*00b67f09SDavid van Moolenbroek char socktext[ISC_SOCKADDR_FORMATSIZE];
609*00b67f09SDavid van Moolenbroek isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
610*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
611*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
612*00b67f09SDavid van Moolenbroek "rejected command channel message from %s",
613*00b67f09SDavid van Moolenbroek socktext);
614*00b67f09SDavid van Moolenbroek isc_socket_detach(&sock);
615*00b67f09SDavid van Moolenbroek goto restart;
616*00b67f09SDavid van Moolenbroek }
617*00b67f09SDavid van Moolenbroek
618*00b67f09SDavid van Moolenbroek result = newconnection(listener, sock);
619*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
620*00b67f09SDavid van Moolenbroek char socktext[ISC_SOCKADDR_FORMATSIZE];
621*00b67f09SDavid van Moolenbroek isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
622*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
623*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
624*00b67f09SDavid van Moolenbroek "dropped command channel from %s: %s",
625*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(result));
626*00b67f09SDavid van Moolenbroek isc_socket_detach(&sock);
627*00b67f09SDavid van Moolenbroek goto restart;
628*00b67f09SDavid van Moolenbroek }
629*00b67f09SDavid van Moolenbroek
630*00b67f09SDavid van Moolenbroek restart:
631*00b67f09SDavid van Moolenbroek control_next(listener);
632*00b67f09SDavid van Moolenbroek cleanup:
633*00b67f09SDavid van Moolenbroek isc_event_free(&event);
634*00b67f09SDavid van Moolenbroek }
635*00b67f09SDavid van Moolenbroek
636*00b67f09SDavid van Moolenbroek static void
controls_shutdown(ns_controls_t * controls)637*00b67f09SDavid van Moolenbroek controls_shutdown(ns_controls_t *controls) {
638*00b67f09SDavid van Moolenbroek controllistener_t *listener;
639*00b67f09SDavid van Moolenbroek controllistener_t *next;
640*00b67f09SDavid van Moolenbroek
641*00b67f09SDavid van Moolenbroek for (listener = ISC_LIST_HEAD(controls->listeners);
642*00b67f09SDavid van Moolenbroek listener != NULL;
643*00b67f09SDavid van Moolenbroek listener = next)
644*00b67f09SDavid van Moolenbroek {
645*00b67f09SDavid van Moolenbroek /*
646*00b67f09SDavid van Moolenbroek * This is asynchronous. As listeners shut down, they will
647*00b67f09SDavid van Moolenbroek * call their callbacks.
648*00b67f09SDavid van Moolenbroek */
649*00b67f09SDavid van Moolenbroek next = ISC_LIST_NEXT(listener, link);
650*00b67f09SDavid van Moolenbroek shutdown_listener(listener);
651*00b67f09SDavid van Moolenbroek }
652*00b67f09SDavid van Moolenbroek }
653*00b67f09SDavid van Moolenbroek
654*00b67f09SDavid van Moolenbroek void
ns_controls_shutdown(ns_controls_t * controls)655*00b67f09SDavid van Moolenbroek ns_controls_shutdown(ns_controls_t *controls) {
656*00b67f09SDavid van Moolenbroek controls_shutdown(controls);
657*00b67f09SDavid van Moolenbroek controls->shuttingdown = ISC_TRUE;
658*00b67f09SDavid van Moolenbroek }
659*00b67f09SDavid van Moolenbroek
660*00b67f09SDavid van Moolenbroek static isc_result_t
cfgkeylist_find(const cfg_obj_t * keylist,const char * keyname,const cfg_obj_t ** objp)661*00b67f09SDavid van Moolenbroek cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname,
662*00b67f09SDavid van Moolenbroek const cfg_obj_t **objp)
663*00b67f09SDavid van Moolenbroek {
664*00b67f09SDavid van Moolenbroek const cfg_listelt_t *element;
665*00b67f09SDavid van Moolenbroek const char *str;
666*00b67f09SDavid van Moolenbroek const cfg_obj_t *obj;
667*00b67f09SDavid van Moolenbroek
668*00b67f09SDavid van Moolenbroek for (element = cfg_list_first(keylist);
669*00b67f09SDavid van Moolenbroek element != NULL;
670*00b67f09SDavid van Moolenbroek element = cfg_list_next(element))
671*00b67f09SDavid van Moolenbroek {
672*00b67f09SDavid van Moolenbroek obj = cfg_listelt_value(element);
673*00b67f09SDavid van Moolenbroek str = cfg_obj_asstring(cfg_map_getname(obj));
674*00b67f09SDavid van Moolenbroek if (strcasecmp(str, keyname) == 0)
675*00b67f09SDavid van Moolenbroek break;
676*00b67f09SDavid van Moolenbroek }
677*00b67f09SDavid van Moolenbroek if (element == NULL)
678*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
679*00b67f09SDavid van Moolenbroek obj = cfg_listelt_value(element);
680*00b67f09SDavid van Moolenbroek *objp = obj;
681*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
682*00b67f09SDavid van Moolenbroek }
683*00b67f09SDavid van Moolenbroek
684*00b67f09SDavid van Moolenbroek static isc_result_t
controlkeylist_fromcfg(const cfg_obj_t * keylist,isc_mem_t * mctx,controlkeylist_t * keyids)685*00b67f09SDavid van Moolenbroek controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx,
686*00b67f09SDavid van Moolenbroek controlkeylist_t *keyids)
687*00b67f09SDavid van Moolenbroek {
688*00b67f09SDavid van Moolenbroek const cfg_listelt_t *element;
689*00b67f09SDavid van Moolenbroek char *newstr = NULL;
690*00b67f09SDavid van Moolenbroek const char *str;
691*00b67f09SDavid van Moolenbroek const cfg_obj_t *obj;
692*00b67f09SDavid van Moolenbroek controlkey_t *key;
693*00b67f09SDavid van Moolenbroek
694*00b67f09SDavid van Moolenbroek for (element = cfg_list_first(keylist);
695*00b67f09SDavid van Moolenbroek element != NULL;
696*00b67f09SDavid van Moolenbroek element = cfg_list_next(element))
697*00b67f09SDavid van Moolenbroek {
698*00b67f09SDavid van Moolenbroek obj = cfg_listelt_value(element);
699*00b67f09SDavid van Moolenbroek str = cfg_obj_asstring(obj);
700*00b67f09SDavid van Moolenbroek newstr = isc_mem_strdup(mctx, str);
701*00b67f09SDavid van Moolenbroek if (newstr == NULL)
702*00b67f09SDavid van Moolenbroek goto cleanup;
703*00b67f09SDavid van Moolenbroek key = isc_mem_get(mctx, sizeof(*key));
704*00b67f09SDavid van Moolenbroek if (key == NULL)
705*00b67f09SDavid van Moolenbroek goto cleanup;
706*00b67f09SDavid van Moolenbroek key->keyname = newstr;
707*00b67f09SDavid van Moolenbroek key->algorithm = DST_ALG_UNKNOWN;
708*00b67f09SDavid van Moolenbroek key->secret.base = NULL;
709*00b67f09SDavid van Moolenbroek key->secret.length = 0;
710*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(key, link);
711*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(*keyids, key, link);
712*00b67f09SDavid van Moolenbroek newstr = NULL;
713*00b67f09SDavid van Moolenbroek }
714*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
715*00b67f09SDavid van Moolenbroek
716*00b67f09SDavid van Moolenbroek cleanup:
717*00b67f09SDavid van Moolenbroek if (newstr != NULL)
718*00b67f09SDavid van Moolenbroek isc_mem_free(mctx, newstr);
719*00b67f09SDavid van Moolenbroek free_controlkeylist(keyids, mctx);
720*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
721*00b67f09SDavid van Moolenbroek }
722*00b67f09SDavid van Moolenbroek
723*00b67f09SDavid van Moolenbroek static void
register_keys(const cfg_obj_t * control,const cfg_obj_t * keylist,controlkeylist_t * keyids,isc_mem_t * mctx,const char * socktext)724*00b67f09SDavid van Moolenbroek register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist,
725*00b67f09SDavid van Moolenbroek controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext)
726*00b67f09SDavid van Moolenbroek {
727*00b67f09SDavid van Moolenbroek controlkey_t *keyid, *next;
728*00b67f09SDavid van Moolenbroek const cfg_obj_t *keydef;
729*00b67f09SDavid van Moolenbroek char secret[1024];
730*00b67f09SDavid van Moolenbroek isc_buffer_t b;
731*00b67f09SDavid van Moolenbroek isc_result_t result;
732*00b67f09SDavid van Moolenbroek
733*00b67f09SDavid van Moolenbroek /*
734*00b67f09SDavid van Moolenbroek * Find the keys corresponding to the keyids used by this listener.
735*00b67f09SDavid van Moolenbroek */
736*00b67f09SDavid van Moolenbroek for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) {
737*00b67f09SDavid van Moolenbroek next = ISC_LIST_NEXT(keyid, link);
738*00b67f09SDavid van Moolenbroek
739*00b67f09SDavid van Moolenbroek result = cfgkeylist_find(keylist, keyid->keyname, &keydef);
740*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
741*00b67f09SDavid van Moolenbroek cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
742*00b67f09SDavid van Moolenbroek "couldn't find key '%s' for use with "
743*00b67f09SDavid van Moolenbroek "command channel %s",
744*00b67f09SDavid van Moolenbroek keyid->keyname, socktext);
745*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(*keyids, keyid, link);
746*00b67f09SDavid van Moolenbroek free_controlkey(keyid, mctx);
747*00b67f09SDavid van Moolenbroek } else {
748*00b67f09SDavid van Moolenbroek const cfg_obj_t *algobj = NULL;
749*00b67f09SDavid van Moolenbroek const cfg_obj_t *secretobj = NULL;
750*00b67f09SDavid van Moolenbroek const char *algstr = NULL;
751*00b67f09SDavid van Moolenbroek const char *secretstr = NULL;
752*00b67f09SDavid van Moolenbroek unsigned int algtype;
753*00b67f09SDavid van Moolenbroek
754*00b67f09SDavid van Moolenbroek (void)cfg_map_get(keydef, "algorithm", &algobj);
755*00b67f09SDavid van Moolenbroek (void)cfg_map_get(keydef, "secret", &secretobj);
756*00b67f09SDavid van Moolenbroek INSIST(algobj != NULL && secretobj != NULL);
757*00b67f09SDavid van Moolenbroek
758*00b67f09SDavid van Moolenbroek algstr = cfg_obj_asstring(algobj);
759*00b67f09SDavid van Moolenbroek secretstr = cfg_obj_asstring(secretobj);
760*00b67f09SDavid van Moolenbroek
761*00b67f09SDavid van Moolenbroek if (ns_config_getkeyalgorithm2(algstr, NULL,
762*00b67f09SDavid van Moolenbroek &algtype, NULL) != ISC_R_SUCCESS)
763*00b67f09SDavid van Moolenbroek {
764*00b67f09SDavid van Moolenbroek cfg_obj_log(control, ns_g_lctx,
765*00b67f09SDavid van Moolenbroek ISC_LOG_WARNING,
766*00b67f09SDavid van Moolenbroek "unsupported algorithm '%s' in "
767*00b67f09SDavid van Moolenbroek "key '%s' for use with command "
768*00b67f09SDavid van Moolenbroek "channel %s",
769*00b67f09SDavid van Moolenbroek algstr, keyid->keyname, socktext);
770*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(*keyids, keyid, link);
771*00b67f09SDavid van Moolenbroek free_controlkey(keyid, mctx);
772*00b67f09SDavid van Moolenbroek continue;
773*00b67f09SDavid van Moolenbroek }
774*00b67f09SDavid van Moolenbroek
775*00b67f09SDavid van Moolenbroek keyid->algorithm = algtype;
776*00b67f09SDavid van Moolenbroek isc_buffer_init(&b, secret, sizeof(secret));
777*00b67f09SDavid van Moolenbroek result = isc_base64_decodestring(secretstr, &b);
778*00b67f09SDavid van Moolenbroek
779*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
780*00b67f09SDavid van Moolenbroek cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
781*00b67f09SDavid van Moolenbroek "secret for key '%s' on "
782*00b67f09SDavid van Moolenbroek "command channel %s: %s",
783*00b67f09SDavid van Moolenbroek keyid->keyname, socktext,
784*00b67f09SDavid van Moolenbroek isc_result_totext(result));
785*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(*keyids, keyid, link);
786*00b67f09SDavid van Moolenbroek free_controlkey(keyid, mctx);
787*00b67f09SDavid van Moolenbroek continue;
788*00b67f09SDavid van Moolenbroek }
789*00b67f09SDavid van Moolenbroek
790*00b67f09SDavid van Moolenbroek keyid->secret.length = isc_buffer_usedlength(&b);
791*00b67f09SDavid van Moolenbroek keyid->secret.base = isc_mem_get(mctx,
792*00b67f09SDavid van Moolenbroek keyid->secret.length);
793*00b67f09SDavid van Moolenbroek if (keyid->secret.base == NULL) {
794*00b67f09SDavid van Moolenbroek cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
795*00b67f09SDavid van Moolenbroek "couldn't register key '%s': "
796*00b67f09SDavid van Moolenbroek "out of memory", keyid->keyname);
797*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(*keyids, keyid, link);
798*00b67f09SDavid van Moolenbroek free_controlkey(keyid, mctx);
799*00b67f09SDavid van Moolenbroek break;
800*00b67f09SDavid van Moolenbroek }
801*00b67f09SDavid van Moolenbroek memmove(keyid->secret.base, isc_buffer_base(&b),
802*00b67f09SDavid van Moolenbroek keyid->secret.length);
803*00b67f09SDavid van Moolenbroek }
804*00b67f09SDavid van Moolenbroek }
805*00b67f09SDavid van Moolenbroek }
806*00b67f09SDavid van Moolenbroek
807*00b67f09SDavid van Moolenbroek #define CHECK(x) \
808*00b67f09SDavid van Moolenbroek do { \
809*00b67f09SDavid van Moolenbroek result = (x); \
810*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) \
811*00b67f09SDavid van Moolenbroek goto cleanup; \
812*00b67f09SDavid van Moolenbroek } while (/*CONSTCOND*/0)
813*00b67f09SDavid van Moolenbroek
814*00b67f09SDavid van Moolenbroek static isc_result_t
get_rndckey(isc_mem_t * mctx,controlkeylist_t * keyids)815*00b67f09SDavid van Moolenbroek get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) {
816*00b67f09SDavid van Moolenbroek isc_result_t result;
817*00b67f09SDavid van Moolenbroek cfg_parser_t *pctx = NULL;
818*00b67f09SDavid van Moolenbroek cfg_obj_t *config = NULL;
819*00b67f09SDavid van Moolenbroek const cfg_obj_t *key = NULL;
820*00b67f09SDavid van Moolenbroek const cfg_obj_t *algobj = NULL;
821*00b67f09SDavid van Moolenbroek const cfg_obj_t *secretobj = NULL;
822*00b67f09SDavid van Moolenbroek const char *algstr = NULL;
823*00b67f09SDavid van Moolenbroek const char *secretstr = NULL;
824*00b67f09SDavid van Moolenbroek controlkey_t *keyid = NULL;
825*00b67f09SDavid van Moolenbroek char secret[1024];
826*00b67f09SDavid van Moolenbroek unsigned int algtype;
827*00b67f09SDavid van Moolenbroek isc_buffer_t b;
828*00b67f09SDavid van Moolenbroek
829*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
830*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_INFO,
831*00b67f09SDavid van Moolenbroek "configuring command channel from '%s'",
832*00b67f09SDavid van Moolenbroek ns_g_keyfile);
833*00b67f09SDavid van Moolenbroek if (! isc_file_exists(ns_g_keyfile))
834*00b67f09SDavid van Moolenbroek return (ISC_R_FILENOTFOUND);
835*00b67f09SDavid van Moolenbroek
836*00b67f09SDavid van Moolenbroek CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx));
837*00b67f09SDavid van Moolenbroek CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config));
838*00b67f09SDavid van Moolenbroek CHECK(cfg_map_get(config, "key", &key));
839*00b67f09SDavid van Moolenbroek
840*00b67f09SDavid van Moolenbroek keyid = isc_mem_get(mctx, sizeof(*keyid));
841*00b67f09SDavid van Moolenbroek if (keyid == NULL)
842*00b67f09SDavid van Moolenbroek CHECK(ISC_R_NOMEMORY);
843*00b67f09SDavid van Moolenbroek keyid->keyname = isc_mem_strdup(mctx,
844*00b67f09SDavid van Moolenbroek cfg_obj_asstring(cfg_map_getname(key)));
845*00b67f09SDavid van Moolenbroek keyid->secret.base = NULL;
846*00b67f09SDavid van Moolenbroek keyid->secret.length = 0;
847*00b67f09SDavid van Moolenbroek keyid->algorithm = DST_ALG_UNKNOWN;
848*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(keyid, link);
849*00b67f09SDavid van Moolenbroek if (keyid->keyname == NULL)
850*00b67f09SDavid van Moolenbroek CHECK(ISC_R_NOMEMORY);
851*00b67f09SDavid van Moolenbroek
852*00b67f09SDavid van Moolenbroek CHECK(bind9_check_key(key, ns_g_lctx));
853*00b67f09SDavid van Moolenbroek
854*00b67f09SDavid van Moolenbroek (void)cfg_map_get(key, "algorithm", &algobj);
855*00b67f09SDavid van Moolenbroek (void)cfg_map_get(key, "secret", &secretobj);
856*00b67f09SDavid van Moolenbroek INSIST(algobj != NULL && secretobj != NULL);
857*00b67f09SDavid van Moolenbroek
858*00b67f09SDavid van Moolenbroek algstr = cfg_obj_asstring(algobj);
859*00b67f09SDavid van Moolenbroek secretstr = cfg_obj_asstring(secretobj);
860*00b67f09SDavid van Moolenbroek
861*00b67f09SDavid van Moolenbroek if (ns_config_getkeyalgorithm2(algstr, NULL,
862*00b67f09SDavid van Moolenbroek &algtype, NULL) != ISC_R_SUCCESS) {
863*00b67f09SDavid van Moolenbroek cfg_obj_log(key, ns_g_lctx,
864*00b67f09SDavid van Moolenbroek ISC_LOG_WARNING,
865*00b67f09SDavid van Moolenbroek "unsupported algorithm '%s' in "
866*00b67f09SDavid van Moolenbroek "key '%s' for use with command "
867*00b67f09SDavid van Moolenbroek "channel",
868*00b67f09SDavid van Moolenbroek algstr, keyid->keyname);
869*00b67f09SDavid van Moolenbroek goto cleanup;
870*00b67f09SDavid van Moolenbroek }
871*00b67f09SDavid van Moolenbroek
872*00b67f09SDavid van Moolenbroek keyid->algorithm = algtype;
873*00b67f09SDavid van Moolenbroek isc_buffer_init(&b, secret, sizeof(secret));
874*00b67f09SDavid van Moolenbroek result = isc_base64_decodestring(secretstr, &b);
875*00b67f09SDavid van Moolenbroek
876*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
877*00b67f09SDavid van Moolenbroek cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
878*00b67f09SDavid van Moolenbroek "secret for key '%s' on command channel: %s",
879*00b67f09SDavid van Moolenbroek keyid->keyname, isc_result_totext(result));
880*00b67f09SDavid van Moolenbroek goto cleanup;
881*00b67f09SDavid van Moolenbroek }
882*00b67f09SDavid van Moolenbroek
883*00b67f09SDavid van Moolenbroek keyid->secret.length = isc_buffer_usedlength(&b);
884*00b67f09SDavid van Moolenbroek keyid->secret.base = isc_mem_get(mctx,
885*00b67f09SDavid van Moolenbroek keyid->secret.length);
886*00b67f09SDavid van Moolenbroek if (keyid->secret.base == NULL) {
887*00b67f09SDavid van Moolenbroek cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
888*00b67f09SDavid van Moolenbroek "couldn't register key '%s': "
889*00b67f09SDavid van Moolenbroek "out of memory", keyid->keyname);
890*00b67f09SDavid van Moolenbroek CHECK(ISC_R_NOMEMORY);
891*00b67f09SDavid van Moolenbroek }
892*00b67f09SDavid van Moolenbroek memmove(keyid->secret.base, isc_buffer_base(&b),
893*00b67f09SDavid van Moolenbroek keyid->secret.length);
894*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(*keyids, keyid, link);
895*00b67f09SDavid van Moolenbroek keyid = NULL;
896*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
897*00b67f09SDavid van Moolenbroek
898*00b67f09SDavid van Moolenbroek cleanup:
899*00b67f09SDavid van Moolenbroek if (keyid != NULL)
900*00b67f09SDavid van Moolenbroek free_controlkey(keyid, mctx);
901*00b67f09SDavid van Moolenbroek if (config != NULL)
902*00b67f09SDavid van Moolenbroek cfg_obj_destroy(pctx, &config);
903*00b67f09SDavid van Moolenbroek if (pctx != NULL)
904*00b67f09SDavid van Moolenbroek cfg_parser_destroy(&pctx);
905*00b67f09SDavid van Moolenbroek return (result);
906*00b67f09SDavid van Moolenbroek }
907*00b67f09SDavid van Moolenbroek
908*00b67f09SDavid van Moolenbroek /*
909*00b67f09SDavid van Moolenbroek * Ensures that both '*global_keylistp' and '*control_keylistp' are
910*00b67f09SDavid van Moolenbroek * valid or both are NULL.
911*00b67f09SDavid van Moolenbroek */
912*00b67f09SDavid van Moolenbroek static void
get_key_info(const cfg_obj_t * config,const cfg_obj_t * control,const cfg_obj_t ** global_keylistp,const cfg_obj_t ** control_keylistp)913*00b67f09SDavid van Moolenbroek get_key_info(const cfg_obj_t *config, const cfg_obj_t *control,
914*00b67f09SDavid van Moolenbroek const cfg_obj_t **global_keylistp,
915*00b67f09SDavid van Moolenbroek const cfg_obj_t **control_keylistp)
916*00b67f09SDavid van Moolenbroek {
917*00b67f09SDavid van Moolenbroek isc_result_t result;
918*00b67f09SDavid van Moolenbroek const cfg_obj_t *control_keylist = NULL;
919*00b67f09SDavid van Moolenbroek const cfg_obj_t *global_keylist = NULL;
920*00b67f09SDavid van Moolenbroek
921*00b67f09SDavid van Moolenbroek REQUIRE(global_keylistp != NULL && *global_keylistp == NULL);
922*00b67f09SDavid van Moolenbroek REQUIRE(control_keylistp != NULL && *control_keylistp == NULL);
923*00b67f09SDavid van Moolenbroek
924*00b67f09SDavid van Moolenbroek control_keylist = cfg_tuple_get(control, "keys");
925*00b67f09SDavid van Moolenbroek
926*00b67f09SDavid van Moolenbroek if (!cfg_obj_isvoid(control_keylist) &&
927*00b67f09SDavid van Moolenbroek cfg_list_first(control_keylist) != NULL) {
928*00b67f09SDavid van Moolenbroek result = cfg_map_get(config, "key", &global_keylist);
929*00b67f09SDavid van Moolenbroek
930*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
931*00b67f09SDavid van Moolenbroek *global_keylistp = global_keylist;
932*00b67f09SDavid van Moolenbroek *control_keylistp = control_keylist;
933*00b67f09SDavid van Moolenbroek }
934*00b67f09SDavid van Moolenbroek }
935*00b67f09SDavid van Moolenbroek }
936*00b67f09SDavid van Moolenbroek
937*00b67f09SDavid van Moolenbroek static void
update_listener(ns_controls_t * cp,controllistener_t ** listenerp,const cfg_obj_t * control,const cfg_obj_t * config,isc_sockaddr_t * addr,cfg_aclconfctx_t * aclconfctx,const char * socktext,isc_sockettype_t type)938*00b67f09SDavid van Moolenbroek update_listener(ns_controls_t *cp, controllistener_t **listenerp,
939*00b67f09SDavid van Moolenbroek const cfg_obj_t *control, const cfg_obj_t *config,
940*00b67f09SDavid van Moolenbroek isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
941*00b67f09SDavid van Moolenbroek const char *socktext, isc_sockettype_t type)
942*00b67f09SDavid van Moolenbroek {
943*00b67f09SDavid van Moolenbroek controllistener_t *listener;
944*00b67f09SDavid van Moolenbroek const cfg_obj_t *allow;
945*00b67f09SDavid van Moolenbroek const cfg_obj_t *global_keylist = NULL;
946*00b67f09SDavid van Moolenbroek const cfg_obj_t *control_keylist = NULL;
947*00b67f09SDavid van Moolenbroek dns_acl_t *new_acl = NULL;
948*00b67f09SDavid van Moolenbroek controlkeylist_t keys;
949*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
950*00b67f09SDavid van Moolenbroek
951*00b67f09SDavid van Moolenbroek for (listener = ISC_LIST_HEAD(cp->listeners);
952*00b67f09SDavid van Moolenbroek listener != NULL;
953*00b67f09SDavid van Moolenbroek listener = ISC_LIST_NEXT(listener, link))
954*00b67f09SDavid van Moolenbroek if (isc_sockaddr_equal(addr, &listener->address))
955*00b67f09SDavid van Moolenbroek break;
956*00b67f09SDavid van Moolenbroek
957*00b67f09SDavid van Moolenbroek if (listener == NULL) {
958*00b67f09SDavid van Moolenbroek *listenerp = NULL;
959*00b67f09SDavid van Moolenbroek return;
960*00b67f09SDavid van Moolenbroek }
961*00b67f09SDavid van Moolenbroek
962*00b67f09SDavid van Moolenbroek /*
963*00b67f09SDavid van Moolenbroek * There is already a listener for this sockaddr.
964*00b67f09SDavid van Moolenbroek * Update the access list and key information.
965*00b67f09SDavid van Moolenbroek *
966*00b67f09SDavid van Moolenbroek * First try to deal with the key situation. There are a few
967*00b67f09SDavid van Moolenbroek * possibilities:
968*00b67f09SDavid van Moolenbroek * (a) It had an explicit keylist and still has an explicit keylist.
969*00b67f09SDavid van Moolenbroek * (b) It had an automagic key and now has an explicit keylist.
970*00b67f09SDavid van Moolenbroek * (c) It had an explicit keylist and now needs an automagic key.
971*00b67f09SDavid van Moolenbroek * (d) It has an automagic key and still needs the automagic key.
972*00b67f09SDavid van Moolenbroek *
973*00b67f09SDavid van Moolenbroek * (c) and (d) are the annoying ones. The caller needs to know
974*00b67f09SDavid van Moolenbroek * that it should use the automagic configuration for key information
975*00b67f09SDavid van Moolenbroek * in place of the named.conf configuration.
976*00b67f09SDavid van Moolenbroek *
977*00b67f09SDavid van Moolenbroek * XXXDCL There is one other hazard that has not been dealt with,
978*00b67f09SDavid van Moolenbroek * the problem that if a key change is being caused by a control
979*00b67f09SDavid van Moolenbroek * channel reload, then the response will be with the new key
980*00b67f09SDavid van Moolenbroek * and not able to be decrypted by the client.
981*00b67f09SDavid van Moolenbroek */
982*00b67f09SDavid van Moolenbroek if (control != NULL)
983*00b67f09SDavid van Moolenbroek get_key_info(config, control, &global_keylist,
984*00b67f09SDavid van Moolenbroek &control_keylist);
985*00b67f09SDavid van Moolenbroek
986*00b67f09SDavid van Moolenbroek if (control_keylist != NULL) {
987*00b67f09SDavid van Moolenbroek INSIST(global_keylist != NULL);
988*00b67f09SDavid van Moolenbroek
989*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(keys);
990*00b67f09SDavid van Moolenbroek result = controlkeylist_fromcfg(control_keylist,
991*00b67f09SDavid van Moolenbroek listener->mctx, &keys);
992*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
993*00b67f09SDavid van Moolenbroek free_controlkeylist(&listener->keys, listener->mctx);
994*00b67f09SDavid van Moolenbroek listener->keys = keys;
995*00b67f09SDavid van Moolenbroek register_keys(control, global_keylist, &listener->keys,
996*00b67f09SDavid van Moolenbroek listener->mctx, socktext);
997*00b67f09SDavid van Moolenbroek }
998*00b67f09SDavid van Moolenbroek } else {
999*00b67f09SDavid van Moolenbroek free_controlkeylist(&listener->keys, listener->mctx);
1000*00b67f09SDavid van Moolenbroek result = get_rndckey(listener->mctx, &listener->keys);
1001*00b67f09SDavid van Moolenbroek }
1002*00b67f09SDavid van Moolenbroek
1003*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS && global_keylist != NULL) {
1004*00b67f09SDavid van Moolenbroek /*
1005*00b67f09SDavid van Moolenbroek * This message might be a little misleading since the
1006*00b67f09SDavid van Moolenbroek * "new keys" might in fact be identical to the old ones,
1007*00b67f09SDavid van Moolenbroek * but tracking whether they are identical just for the
1008*00b67f09SDavid van Moolenbroek * sake of avoiding this message would be too much trouble.
1009*00b67f09SDavid van Moolenbroek */
1010*00b67f09SDavid van Moolenbroek if (control != NULL)
1011*00b67f09SDavid van Moolenbroek cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
1012*00b67f09SDavid van Moolenbroek "couldn't install new keys for "
1013*00b67f09SDavid van Moolenbroek "command channel %s: %s",
1014*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(result));
1015*00b67f09SDavid van Moolenbroek else
1016*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1017*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
1018*00b67f09SDavid van Moolenbroek "couldn't install new keys for "
1019*00b67f09SDavid van Moolenbroek "command channel %s: %s",
1020*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(result));
1021*00b67f09SDavid van Moolenbroek }
1022*00b67f09SDavid van Moolenbroek
1023*00b67f09SDavid van Moolenbroek /*
1024*00b67f09SDavid van Moolenbroek * Now, keep the old access list unless a new one can be made.
1025*00b67f09SDavid van Moolenbroek */
1026*00b67f09SDavid van Moolenbroek if (control != NULL && type == isc_sockettype_tcp) {
1027*00b67f09SDavid van Moolenbroek allow = cfg_tuple_get(control, "allow");
1028*00b67f09SDavid van Moolenbroek result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
1029*00b67f09SDavid van Moolenbroek aclconfctx, listener->mctx, 0,
1030*00b67f09SDavid van Moolenbroek &new_acl);
1031*00b67f09SDavid van Moolenbroek } else {
1032*00b67f09SDavid van Moolenbroek result = dns_acl_any(listener->mctx, &new_acl);
1033*00b67f09SDavid van Moolenbroek }
1034*00b67f09SDavid van Moolenbroek
1035*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
1036*00b67f09SDavid van Moolenbroek dns_acl_detach(&listener->acl);
1037*00b67f09SDavid van Moolenbroek dns_acl_attach(new_acl, &listener->acl);
1038*00b67f09SDavid van Moolenbroek dns_acl_detach(&new_acl);
1039*00b67f09SDavid van Moolenbroek /* XXXDCL say the old acl is still used? */
1040*00b67f09SDavid van Moolenbroek } else if (control != NULL)
1041*00b67f09SDavid van Moolenbroek cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
1042*00b67f09SDavid van Moolenbroek "couldn't install new acl for "
1043*00b67f09SDavid van Moolenbroek "command channel %s: %s",
1044*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(result));
1045*00b67f09SDavid van Moolenbroek else
1046*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1047*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
1048*00b67f09SDavid van Moolenbroek "couldn't install new acl for "
1049*00b67f09SDavid van Moolenbroek "command channel %s: %s",
1050*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(result));
1051*00b67f09SDavid van Moolenbroek
1052*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
1053*00b67f09SDavid van Moolenbroek isc_uint32_t perm, owner, group;
1054*00b67f09SDavid van Moolenbroek perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
1055*00b67f09SDavid van Moolenbroek owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner"));
1056*00b67f09SDavid van Moolenbroek group = cfg_obj_asuint32(cfg_tuple_get(control, "group"));
1057*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
1058*00b67f09SDavid van Moolenbroek if (listener->perm != perm || listener->owner != owner ||
1059*00b67f09SDavid van Moolenbroek listener->group != group)
1060*00b67f09SDavid van Moolenbroek result = isc_socket_permunix(&listener->address, perm,
1061*00b67f09SDavid van Moolenbroek owner, group);
1062*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
1063*00b67f09SDavid van Moolenbroek listener->perm = perm;
1064*00b67f09SDavid van Moolenbroek listener->owner = owner;
1065*00b67f09SDavid van Moolenbroek listener->group = group;
1066*00b67f09SDavid van Moolenbroek } else if (control != NULL)
1067*00b67f09SDavid van Moolenbroek cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
1068*00b67f09SDavid van Moolenbroek "couldn't update ownership/permission for "
1069*00b67f09SDavid van Moolenbroek "command channel %s", socktext);
1070*00b67f09SDavid van Moolenbroek }
1071*00b67f09SDavid van Moolenbroek
1072*00b67f09SDavid van Moolenbroek *listenerp = listener;
1073*00b67f09SDavid van Moolenbroek }
1074*00b67f09SDavid van Moolenbroek
1075*00b67f09SDavid van Moolenbroek static void
add_listener(ns_controls_t * cp,controllistener_t ** listenerp,const cfg_obj_t * control,const cfg_obj_t * config,isc_sockaddr_t * addr,cfg_aclconfctx_t * aclconfctx,const char * socktext,isc_sockettype_t type)1076*00b67f09SDavid van Moolenbroek add_listener(ns_controls_t *cp, controllistener_t **listenerp,
1077*00b67f09SDavid van Moolenbroek const cfg_obj_t *control, const cfg_obj_t *config,
1078*00b67f09SDavid van Moolenbroek isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
1079*00b67f09SDavid van Moolenbroek const char *socktext, isc_sockettype_t type)
1080*00b67f09SDavid van Moolenbroek {
1081*00b67f09SDavid van Moolenbroek isc_mem_t *mctx = cp->server->mctx;
1082*00b67f09SDavid van Moolenbroek controllistener_t *listener;
1083*00b67f09SDavid van Moolenbroek const cfg_obj_t *allow;
1084*00b67f09SDavid van Moolenbroek const cfg_obj_t *global_keylist = NULL;
1085*00b67f09SDavid van Moolenbroek const cfg_obj_t *control_keylist = NULL;
1086*00b67f09SDavid van Moolenbroek dns_acl_t *new_acl = NULL;
1087*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
1088*00b67f09SDavid van Moolenbroek
1089*00b67f09SDavid van Moolenbroek listener = isc_mem_get(mctx, sizeof(*listener));
1090*00b67f09SDavid van Moolenbroek if (listener == NULL)
1091*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
1092*00b67f09SDavid van Moolenbroek
1093*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
1094*00b67f09SDavid van Moolenbroek listener->mctx = NULL;
1095*00b67f09SDavid van Moolenbroek isc_mem_attach(mctx, &listener->mctx);
1096*00b67f09SDavid van Moolenbroek listener->controls = cp;
1097*00b67f09SDavid van Moolenbroek listener->task = cp->server->task;
1098*00b67f09SDavid van Moolenbroek listener->address = *addr;
1099*00b67f09SDavid van Moolenbroek listener->sock = NULL;
1100*00b67f09SDavid van Moolenbroek listener->listening = ISC_FALSE;
1101*00b67f09SDavid van Moolenbroek listener->exiting = ISC_FALSE;
1102*00b67f09SDavid van Moolenbroek listener->acl = NULL;
1103*00b67f09SDavid van Moolenbroek listener->type = type;
1104*00b67f09SDavid van Moolenbroek listener->perm = 0;
1105*00b67f09SDavid van Moolenbroek listener->owner = 0;
1106*00b67f09SDavid van Moolenbroek listener->group = 0;
1107*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(listener, link);
1108*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(listener->keys);
1109*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(listener->connections);
1110*00b67f09SDavid van Moolenbroek
1111*00b67f09SDavid van Moolenbroek /*
1112*00b67f09SDavid van Moolenbroek * Make the acl.
1113*00b67f09SDavid van Moolenbroek */
1114*00b67f09SDavid van Moolenbroek if (control != NULL && type == isc_sockettype_tcp) {
1115*00b67f09SDavid van Moolenbroek allow = cfg_tuple_get(control, "allow");
1116*00b67f09SDavid van Moolenbroek result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
1117*00b67f09SDavid van Moolenbroek aclconfctx, mctx, 0,
1118*00b67f09SDavid van Moolenbroek &new_acl);
1119*00b67f09SDavid van Moolenbroek } else {
1120*00b67f09SDavid van Moolenbroek result = dns_acl_any(mctx, &new_acl);
1121*00b67f09SDavid van Moolenbroek }
1122*00b67f09SDavid van Moolenbroek }
1123*00b67f09SDavid van Moolenbroek
1124*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
1125*00b67f09SDavid van Moolenbroek dns_acl_attach(new_acl, &listener->acl);
1126*00b67f09SDavid van Moolenbroek dns_acl_detach(&new_acl);
1127*00b67f09SDavid van Moolenbroek
1128*00b67f09SDavid van Moolenbroek if (config != NULL)
1129*00b67f09SDavid van Moolenbroek get_key_info(config, control, &global_keylist,
1130*00b67f09SDavid van Moolenbroek &control_keylist);
1131*00b67f09SDavid van Moolenbroek
1132*00b67f09SDavid van Moolenbroek if (control_keylist != NULL) {
1133*00b67f09SDavid van Moolenbroek result = controlkeylist_fromcfg(control_keylist,
1134*00b67f09SDavid van Moolenbroek listener->mctx,
1135*00b67f09SDavid van Moolenbroek &listener->keys);
1136*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
1137*00b67f09SDavid van Moolenbroek register_keys(control, global_keylist,
1138*00b67f09SDavid van Moolenbroek &listener->keys,
1139*00b67f09SDavid van Moolenbroek listener->mctx, socktext);
1140*00b67f09SDavid van Moolenbroek } else
1141*00b67f09SDavid van Moolenbroek result = get_rndckey(mctx, &listener->keys);
1142*00b67f09SDavid van Moolenbroek
1143*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS && control != NULL)
1144*00b67f09SDavid van Moolenbroek cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
1145*00b67f09SDavid van Moolenbroek "couldn't install keys for "
1146*00b67f09SDavid van Moolenbroek "command channel %s: %s",
1147*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(result));
1148*00b67f09SDavid van Moolenbroek }
1149*00b67f09SDavid van Moolenbroek
1150*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
1151*00b67f09SDavid van Moolenbroek int pf = isc_sockaddr_pf(&listener->address);
1152*00b67f09SDavid van Moolenbroek if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
1153*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVESYSUNH
1154*00b67f09SDavid van Moolenbroek (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) ||
1155*00b67f09SDavid van Moolenbroek #endif
1156*00b67f09SDavid van Moolenbroek (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
1157*00b67f09SDavid van Moolenbroek result = ISC_R_FAMILYNOSUPPORT;
1158*00b67f09SDavid van Moolenbroek }
1159*00b67f09SDavid van Moolenbroek
1160*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS && type == isc_sockettype_unix)
1161*00b67f09SDavid van Moolenbroek isc_socket_cleanunix(&listener->address, ISC_FALSE);
1162*00b67f09SDavid van Moolenbroek
1163*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
1164*00b67f09SDavid van Moolenbroek result = isc_socket_create(ns_g_socketmgr,
1165*00b67f09SDavid van Moolenbroek isc_sockaddr_pf(&listener->address),
1166*00b67f09SDavid van Moolenbroek type, &listener->sock);
1167*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
1168*00b67f09SDavid van Moolenbroek isc_socket_setname(listener->sock, "control", NULL);
1169*00b67f09SDavid van Moolenbroek
1170*00b67f09SDavid van Moolenbroek #ifndef ISC_ALLOW_MAPPED
1171*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
1172*00b67f09SDavid van Moolenbroek isc_socket_ipv6only(listener->sock, ISC_TRUE);
1173*00b67f09SDavid van Moolenbroek #endif
1174*00b67f09SDavid van Moolenbroek
1175*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
1176*00b67f09SDavid van Moolenbroek result = isc_socket_bind(listener->sock, &listener->address,
1177*00b67f09SDavid van Moolenbroek ISC_SOCKET_REUSEADDRESS);
1178*00b67f09SDavid van Moolenbroek
1179*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
1180*00b67f09SDavid van Moolenbroek listener->perm = cfg_obj_asuint32(cfg_tuple_get(control,
1181*00b67f09SDavid van Moolenbroek "perm"));
1182*00b67f09SDavid van Moolenbroek listener->owner = cfg_obj_asuint32(cfg_tuple_get(control,
1183*00b67f09SDavid van Moolenbroek "owner"));
1184*00b67f09SDavid van Moolenbroek listener->group = cfg_obj_asuint32(cfg_tuple_get(control,
1185*00b67f09SDavid van Moolenbroek "group"));
1186*00b67f09SDavid van Moolenbroek result = isc_socket_permunix(&listener->address, listener->perm,
1187*00b67f09SDavid van Moolenbroek listener->owner, listener->group);
1188*00b67f09SDavid van Moolenbroek }
1189*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
1190*00b67f09SDavid van Moolenbroek result = control_listen(listener);
1191*00b67f09SDavid van Moolenbroek
1192*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
1193*00b67f09SDavid van Moolenbroek result = control_accept(listener);
1194*00b67f09SDavid van Moolenbroek
1195*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
1196*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1197*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
1198*00b67f09SDavid van Moolenbroek "command channel listening on %s", socktext);
1199*00b67f09SDavid van Moolenbroek *listenerp = listener;
1200*00b67f09SDavid van Moolenbroek
1201*00b67f09SDavid van Moolenbroek } else {
1202*00b67f09SDavid van Moolenbroek if (listener != NULL) {
1203*00b67f09SDavid van Moolenbroek listener->exiting = ISC_TRUE;
1204*00b67f09SDavid van Moolenbroek free_listener(listener);
1205*00b67f09SDavid van Moolenbroek }
1206*00b67f09SDavid van Moolenbroek
1207*00b67f09SDavid van Moolenbroek if (control != NULL)
1208*00b67f09SDavid van Moolenbroek cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
1209*00b67f09SDavid van Moolenbroek "couldn't add command channel %s: %s",
1210*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(result));
1211*00b67f09SDavid van Moolenbroek else
1212*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1213*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
1214*00b67f09SDavid van Moolenbroek "couldn't add command channel %s: %s",
1215*00b67f09SDavid van Moolenbroek socktext, isc_result_totext(result));
1216*00b67f09SDavid van Moolenbroek
1217*00b67f09SDavid van Moolenbroek *listenerp = NULL;
1218*00b67f09SDavid van Moolenbroek }
1219*00b67f09SDavid van Moolenbroek
1220*00b67f09SDavid van Moolenbroek /* XXXDCL return error results? fail hard? */
1221*00b67f09SDavid van Moolenbroek }
1222*00b67f09SDavid van Moolenbroek
1223*00b67f09SDavid van Moolenbroek isc_result_t
ns_controls_configure(ns_controls_t * cp,const cfg_obj_t * config,cfg_aclconfctx_t * aclconfctx)1224*00b67f09SDavid van Moolenbroek ns_controls_configure(ns_controls_t *cp, const cfg_obj_t *config,
1225*00b67f09SDavid van Moolenbroek cfg_aclconfctx_t *aclconfctx)
1226*00b67f09SDavid van Moolenbroek {
1227*00b67f09SDavid van Moolenbroek controllistener_t *listener;
1228*00b67f09SDavid van Moolenbroek controllistenerlist_t new_listeners;
1229*00b67f09SDavid van Moolenbroek const cfg_obj_t *controlslist = NULL;
1230*00b67f09SDavid van Moolenbroek const cfg_listelt_t *element, *element2;
1231*00b67f09SDavid van Moolenbroek char socktext[ISC_SOCKADDR_FORMATSIZE];
1232*00b67f09SDavid van Moolenbroek
1233*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(new_listeners);
1234*00b67f09SDavid van Moolenbroek
1235*00b67f09SDavid van Moolenbroek /*
1236*00b67f09SDavid van Moolenbroek * Get the list of named.conf 'controls' statements.
1237*00b67f09SDavid van Moolenbroek */
1238*00b67f09SDavid van Moolenbroek (void)cfg_map_get(config, "controls", &controlslist);
1239*00b67f09SDavid van Moolenbroek
1240*00b67f09SDavid van Moolenbroek /*
1241*00b67f09SDavid van Moolenbroek * Run through the new control channel list, noting sockets that
1242*00b67f09SDavid van Moolenbroek * are already being listened on and moving them to the new list.
1243*00b67f09SDavid van Moolenbroek *
1244*00b67f09SDavid van Moolenbroek * Identifying duplicate addr/port combinations is left to either
1245*00b67f09SDavid van Moolenbroek * the underlying config code, or to the bind attempt getting an
1246*00b67f09SDavid van Moolenbroek * address-in-use error.
1247*00b67f09SDavid van Moolenbroek */
1248*00b67f09SDavid van Moolenbroek if (controlslist != NULL) {
1249*00b67f09SDavid van Moolenbroek for (element = cfg_list_first(controlslist);
1250*00b67f09SDavid van Moolenbroek element != NULL;
1251*00b67f09SDavid van Moolenbroek element = cfg_list_next(element)) {
1252*00b67f09SDavid van Moolenbroek const cfg_obj_t *controls;
1253*00b67f09SDavid van Moolenbroek const cfg_obj_t *inetcontrols = NULL;
1254*00b67f09SDavid van Moolenbroek
1255*00b67f09SDavid van Moolenbroek controls = cfg_listelt_value(element);
1256*00b67f09SDavid van Moolenbroek (void)cfg_map_get(controls, "inet", &inetcontrols);
1257*00b67f09SDavid van Moolenbroek if (inetcontrols == NULL)
1258*00b67f09SDavid van Moolenbroek continue;
1259*00b67f09SDavid van Moolenbroek
1260*00b67f09SDavid van Moolenbroek for (element2 = cfg_list_first(inetcontrols);
1261*00b67f09SDavid van Moolenbroek element2 != NULL;
1262*00b67f09SDavid van Moolenbroek element2 = cfg_list_next(element2)) {
1263*00b67f09SDavid van Moolenbroek const cfg_obj_t *control;
1264*00b67f09SDavid van Moolenbroek const cfg_obj_t *obj;
1265*00b67f09SDavid van Moolenbroek isc_sockaddr_t addr;
1266*00b67f09SDavid van Moolenbroek
1267*00b67f09SDavid van Moolenbroek /*
1268*00b67f09SDavid van Moolenbroek * The parser handles BIND 8 configuration file
1269*00b67f09SDavid van Moolenbroek * syntax, so it allows unix phrases as well
1270*00b67f09SDavid van Moolenbroek * inet phrases with no keys{} clause.
1271*00b67f09SDavid van Moolenbroek */
1272*00b67f09SDavid van Moolenbroek control = cfg_listelt_value(element2);
1273*00b67f09SDavid van Moolenbroek
1274*00b67f09SDavid van Moolenbroek obj = cfg_tuple_get(control, "address");
1275*00b67f09SDavid van Moolenbroek addr = *cfg_obj_assockaddr(obj);
1276*00b67f09SDavid van Moolenbroek if (isc_sockaddr_getport(&addr) == 0)
1277*00b67f09SDavid van Moolenbroek isc_sockaddr_setport(&addr,
1278*00b67f09SDavid van Moolenbroek NS_CONTROL_PORT);
1279*00b67f09SDavid van Moolenbroek
1280*00b67f09SDavid van Moolenbroek isc_sockaddr_format(&addr, socktext,
1281*00b67f09SDavid van Moolenbroek sizeof(socktext));
1282*00b67f09SDavid van Moolenbroek
1283*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx,
1284*00b67f09SDavid van Moolenbroek NS_LOGCATEGORY_GENERAL,
1285*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL,
1286*00b67f09SDavid van Moolenbroek ISC_LOG_DEBUG(9),
1287*00b67f09SDavid van Moolenbroek "processing control channel %s",
1288*00b67f09SDavid van Moolenbroek socktext);
1289*00b67f09SDavid van Moolenbroek
1290*00b67f09SDavid van Moolenbroek update_listener(cp, &listener, control, config,
1291*00b67f09SDavid van Moolenbroek &addr, aclconfctx, socktext,
1292*00b67f09SDavid van Moolenbroek isc_sockettype_tcp);
1293*00b67f09SDavid van Moolenbroek
1294*00b67f09SDavid van Moolenbroek if (listener != NULL)
1295*00b67f09SDavid van Moolenbroek /*
1296*00b67f09SDavid van Moolenbroek * Remove the listener from the old
1297*00b67f09SDavid van Moolenbroek * list, so it won't be shut down.
1298*00b67f09SDavid van Moolenbroek */
1299*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(cp->listeners,
1300*00b67f09SDavid van Moolenbroek listener, link);
1301*00b67f09SDavid van Moolenbroek else
1302*00b67f09SDavid van Moolenbroek /*
1303*00b67f09SDavid van Moolenbroek * This is a new listener.
1304*00b67f09SDavid van Moolenbroek */
1305*00b67f09SDavid van Moolenbroek add_listener(cp, &listener, control,
1306*00b67f09SDavid van Moolenbroek config, &addr, aclconfctx,
1307*00b67f09SDavid van Moolenbroek socktext,
1308*00b67f09SDavid van Moolenbroek isc_sockettype_tcp);
1309*00b67f09SDavid van Moolenbroek
1310*00b67f09SDavid van Moolenbroek if (listener != NULL)
1311*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(new_listeners,
1312*00b67f09SDavid van Moolenbroek listener, link);
1313*00b67f09SDavid van Moolenbroek }
1314*00b67f09SDavid van Moolenbroek }
1315*00b67f09SDavid van Moolenbroek for (element = cfg_list_first(controlslist);
1316*00b67f09SDavid van Moolenbroek element != NULL;
1317*00b67f09SDavid van Moolenbroek element = cfg_list_next(element)) {
1318*00b67f09SDavid van Moolenbroek const cfg_obj_t *controls;
1319*00b67f09SDavid van Moolenbroek const cfg_obj_t *unixcontrols = NULL;
1320*00b67f09SDavid van Moolenbroek
1321*00b67f09SDavid van Moolenbroek controls = cfg_listelt_value(element);
1322*00b67f09SDavid van Moolenbroek (void)cfg_map_get(controls, "unix", &unixcontrols);
1323*00b67f09SDavid van Moolenbroek if (unixcontrols == NULL)
1324*00b67f09SDavid van Moolenbroek continue;
1325*00b67f09SDavid van Moolenbroek
1326*00b67f09SDavid van Moolenbroek for (element2 = cfg_list_first(unixcontrols);
1327*00b67f09SDavid van Moolenbroek element2 != NULL;
1328*00b67f09SDavid van Moolenbroek element2 = cfg_list_next(element2)) {
1329*00b67f09SDavid van Moolenbroek const cfg_obj_t *control;
1330*00b67f09SDavid van Moolenbroek const cfg_obj_t *path;
1331*00b67f09SDavid van Moolenbroek isc_sockaddr_t addr;
1332*00b67f09SDavid van Moolenbroek isc_result_t result;
1333*00b67f09SDavid van Moolenbroek
1334*00b67f09SDavid van Moolenbroek /*
1335*00b67f09SDavid van Moolenbroek * The parser handles BIND 8 configuration file
1336*00b67f09SDavid van Moolenbroek * syntax, so it allows unix phrases as well
1337*00b67f09SDavid van Moolenbroek * inet phrases with no keys{} clause.
1338*00b67f09SDavid van Moolenbroek */
1339*00b67f09SDavid van Moolenbroek control = cfg_listelt_value(element2);
1340*00b67f09SDavid van Moolenbroek
1341*00b67f09SDavid van Moolenbroek path = cfg_tuple_get(control, "path");
1342*00b67f09SDavid van Moolenbroek result = isc_sockaddr_frompath(&addr,
1343*00b67f09SDavid van Moolenbroek cfg_obj_asstring(path));
1344*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
1345*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx,
1346*00b67f09SDavid van Moolenbroek NS_LOGCATEGORY_GENERAL,
1347*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL,
1348*00b67f09SDavid van Moolenbroek ISC_LOG_DEBUG(9),
1349*00b67f09SDavid van Moolenbroek "control channel '%s': %s",
1350*00b67f09SDavid van Moolenbroek cfg_obj_asstring(path),
1351*00b67f09SDavid van Moolenbroek isc_result_totext(result));
1352*00b67f09SDavid van Moolenbroek continue;
1353*00b67f09SDavid van Moolenbroek }
1354*00b67f09SDavid van Moolenbroek
1355*00b67f09SDavid van Moolenbroek isc_log_write(ns_g_lctx,
1356*00b67f09SDavid van Moolenbroek NS_LOGCATEGORY_GENERAL,
1357*00b67f09SDavid van Moolenbroek NS_LOGMODULE_CONTROL,
1358*00b67f09SDavid van Moolenbroek ISC_LOG_DEBUG(9),
1359*00b67f09SDavid van Moolenbroek "processing control channel '%s'",
1360*00b67f09SDavid van Moolenbroek cfg_obj_asstring(path));
1361*00b67f09SDavid van Moolenbroek
1362*00b67f09SDavid van Moolenbroek update_listener(cp, &listener, control, config,
1363*00b67f09SDavid van Moolenbroek &addr, aclconfctx,
1364*00b67f09SDavid van Moolenbroek cfg_obj_asstring(path),
1365*00b67f09SDavid van Moolenbroek isc_sockettype_unix);
1366*00b67f09SDavid van Moolenbroek
1367*00b67f09SDavid van Moolenbroek if (listener != NULL)
1368*00b67f09SDavid van Moolenbroek /*
1369*00b67f09SDavid van Moolenbroek * Remove the listener from the old
1370*00b67f09SDavid van Moolenbroek * list, so it won't be shut down.
1371*00b67f09SDavid van Moolenbroek */
1372*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(cp->listeners,
1373*00b67f09SDavid van Moolenbroek listener, link);
1374*00b67f09SDavid van Moolenbroek else
1375*00b67f09SDavid van Moolenbroek /*
1376*00b67f09SDavid van Moolenbroek * This is a new listener.
1377*00b67f09SDavid van Moolenbroek */
1378*00b67f09SDavid van Moolenbroek add_listener(cp, &listener, control,
1379*00b67f09SDavid van Moolenbroek config, &addr, aclconfctx,
1380*00b67f09SDavid van Moolenbroek cfg_obj_asstring(path),
1381*00b67f09SDavid van Moolenbroek isc_sockettype_unix);
1382*00b67f09SDavid van Moolenbroek
1383*00b67f09SDavid van Moolenbroek if (listener != NULL)
1384*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(new_listeners,
1385*00b67f09SDavid van Moolenbroek listener, link);
1386*00b67f09SDavid van Moolenbroek }
1387*00b67f09SDavid van Moolenbroek }
1388*00b67f09SDavid van Moolenbroek } else {
1389*00b67f09SDavid van Moolenbroek int i;
1390*00b67f09SDavid van Moolenbroek
1391*00b67f09SDavid van Moolenbroek for (i = 0; i < 2; i++) {
1392*00b67f09SDavid van Moolenbroek isc_sockaddr_t addr;
1393*00b67f09SDavid van Moolenbroek
1394*00b67f09SDavid van Moolenbroek if (i == 0) {
1395*00b67f09SDavid van Moolenbroek struct in_addr localhost;
1396*00b67f09SDavid van Moolenbroek
1397*00b67f09SDavid van Moolenbroek if (isc_net_probeipv4() != ISC_R_SUCCESS)
1398*00b67f09SDavid van Moolenbroek continue;
1399*00b67f09SDavid van Moolenbroek localhost.s_addr = htonl(INADDR_LOOPBACK);
1400*00b67f09SDavid van Moolenbroek isc_sockaddr_fromin(&addr, &localhost, 0);
1401*00b67f09SDavid van Moolenbroek } else {
1402*00b67f09SDavid van Moolenbroek if (isc_net_probeipv6() != ISC_R_SUCCESS)
1403*00b67f09SDavid van Moolenbroek continue;
1404*00b67f09SDavid van Moolenbroek isc_sockaddr_fromin6(&addr,
1405*00b67f09SDavid van Moolenbroek &in6addr_loopback, 0);
1406*00b67f09SDavid van Moolenbroek }
1407*00b67f09SDavid van Moolenbroek isc_sockaddr_setport(&addr, NS_CONTROL_PORT);
1408*00b67f09SDavid van Moolenbroek
1409*00b67f09SDavid van Moolenbroek isc_sockaddr_format(&addr, socktext, sizeof(socktext));
1410*00b67f09SDavid van Moolenbroek
1411*00b67f09SDavid van Moolenbroek update_listener(cp, &listener, NULL, NULL,
1412*00b67f09SDavid van Moolenbroek &addr, NULL, socktext,
1413*00b67f09SDavid van Moolenbroek isc_sockettype_tcp);
1414*00b67f09SDavid van Moolenbroek
1415*00b67f09SDavid van Moolenbroek if (listener != NULL)
1416*00b67f09SDavid van Moolenbroek /*
1417*00b67f09SDavid van Moolenbroek * Remove the listener from the old
1418*00b67f09SDavid van Moolenbroek * list, so it won't be shut down.
1419*00b67f09SDavid van Moolenbroek */
1420*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(cp->listeners,
1421*00b67f09SDavid van Moolenbroek listener, link);
1422*00b67f09SDavid van Moolenbroek else
1423*00b67f09SDavid van Moolenbroek /*
1424*00b67f09SDavid van Moolenbroek * This is a new listener.
1425*00b67f09SDavid van Moolenbroek */
1426*00b67f09SDavid van Moolenbroek add_listener(cp, &listener, NULL, NULL,
1427*00b67f09SDavid van Moolenbroek &addr, NULL, socktext,
1428*00b67f09SDavid van Moolenbroek isc_sockettype_tcp);
1429*00b67f09SDavid van Moolenbroek
1430*00b67f09SDavid van Moolenbroek if (listener != NULL)
1431*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(new_listeners,
1432*00b67f09SDavid van Moolenbroek listener, link);
1433*00b67f09SDavid van Moolenbroek }
1434*00b67f09SDavid van Moolenbroek }
1435*00b67f09SDavid van Moolenbroek
1436*00b67f09SDavid van Moolenbroek /*
1437*00b67f09SDavid van Moolenbroek * ns_control_shutdown() will stop whatever is on the global
1438*00b67f09SDavid van Moolenbroek * listeners list, which currently only has whatever sockaddrs
1439*00b67f09SDavid van Moolenbroek * were in the previous configuration (if any) that do not
1440*00b67f09SDavid van Moolenbroek * remain in the current configuration.
1441*00b67f09SDavid van Moolenbroek */
1442*00b67f09SDavid van Moolenbroek controls_shutdown(cp);
1443*00b67f09SDavid van Moolenbroek
1444*00b67f09SDavid van Moolenbroek /*
1445*00b67f09SDavid van Moolenbroek * Put all of the valid listeners on the listeners list.
1446*00b67f09SDavid van Moolenbroek * Anything already on listeners in the process of shutting
1447*00b67f09SDavid van Moolenbroek * down will be taken care of by listen_done().
1448*00b67f09SDavid van Moolenbroek */
1449*00b67f09SDavid van Moolenbroek ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link);
1450*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
1451*00b67f09SDavid van Moolenbroek }
1452*00b67f09SDavid van Moolenbroek
1453*00b67f09SDavid van Moolenbroek isc_result_t
ns_controls_create(ns_server_t * server,ns_controls_t ** ctrlsp)1454*00b67f09SDavid van Moolenbroek ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) {
1455*00b67f09SDavid van Moolenbroek isc_mem_t *mctx = server->mctx;
1456*00b67f09SDavid van Moolenbroek isc_result_t result;
1457*00b67f09SDavid van Moolenbroek ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls));
1458*00b67f09SDavid van Moolenbroek
1459*00b67f09SDavid van Moolenbroek if (controls == NULL)
1460*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
1461*00b67f09SDavid van Moolenbroek controls->server = server;
1462*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(controls->listeners);
1463*00b67f09SDavid van Moolenbroek controls->shuttingdown = ISC_FALSE;
1464*00b67f09SDavid van Moolenbroek controls->symtab = NULL;
1465*00b67f09SDavid van Moolenbroek result = isccc_cc_createsymtab(&controls->symtab);
1466*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
1467*00b67f09SDavid van Moolenbroek isc_mem_put(server->mctx, controls, sizeof(*controls));
1468*00b67f09SDavid van Moolenbroek return (result);
1469*00b67f09SDavid van Moolenbroek }
1470*00b67f09SDavid van Moolenbroek *ctrlsp = controls;
1471*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
1472*00b67f09SDavid van Moolenbroek }
1473*00b67f09SDavid van Moolenbroek
1474*00b67f09SDavid van Moolenbroek void
ns_controls_destroy(ns_controls_t ** ctrlsp)1475*00b67f09SDavid van Moolenbroek ns_controls_destroy(ns_controls_t **ctrlsp) {
1476*00b67f09SDavid van Moolenbroek ns_controls_t *controls = *ctrlsp;
1477*00b67f09SDavid van Moolenbroek
1478*00b67f09SDavid van Moolenbroek REQUIRE(ISC_LIST_EMPTY(controls->listeners));
1479*00b67f09SDavid van Moolenbroek
1480*00b67f09SDavid van Moolenbroek isccc_symtab_destroy(&controls->symtab);
1481*00b67f09SDavid van Moolenbroek isc_mem_put(controls->server->mctx, controls, sizeof(*controls));
1482*00b67f09SDavid van Moolenbroek *ctrlsp = NULL;
1483*00b67f09SDavid van Moolenbroek }
1484