File: | src/usr.sbin/nsd/remote.c |
Warning: | line 429, column 5 Array access (from variable 'ip') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * remote.c - remote control for the NSD daemon. | |||
3 | * | |||
4 | * Copyright (c) 2008, NLnet Labs. All rights reserved. | |||
5 | * | |||
6 | * This software is open source. | |||
7 | * | |||
8 | * Redistribution and use in source and binary forms, with or without | |||
9 | * modification, are permitted provided that the following conditions | |||
10 | * are met: | |||
11 | * | |||
12 | * Redistributions of source code must retain the above copyright notice, | |||
13 | * this list of conditions and the following disclaimer. | |||
14 | * | |||
15 | * Redistributions in binary form must reproduce the above copyright notice, | |||
16 | * this list of conditions and the following disclaimer in the documentation | |||
17 | * and/or other materials provided with the distribution. | |||
18 | * | |||
19 | * Neither the name of the NLNET LABS nor the names of its contributors may | |||
20 | * be used to endorse or promote products derived from this software without | |||
21 | * specific prior written permission. | |||
22 | * | |||
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||
26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||
27 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |||
29 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |||
30 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |||
31 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |||
32 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
34 | */ | |||
35 | ||||
36 | /** | |||
37 | * \file | |||
38 | * | |||
39 | * This file contains the remote control functionality for the daemon. | |||
40 | * The remote control can be performed using either the commandline | |||
41 | * nsd-control tool, or a TLS capable web browser. | |||
42 | * The channel is secured using TLSv1, and certificates. | |||
43 | * Both the server and the client(control tool) have their own keys. | |||
44 | */ | |||
45 | #include "config.h" | |||
46 | #ifdef HAVE_SSL | |||
47 | ||||
48 | #ifdef HAVE_OPENSSL_SSL_H1 | |||
49 | #include "openssl/ssl.h" | |||
50 | #endif | |||
51 | #ifdef HAVE_OPENSSL_ERR_H1 | |||
52 | #include <openssl/err.h> | |||
53 | #endif | |||
54 | #ifdef HAVE_OPENSSL_RAND_H1 | |||
55 | #include <openssl/rand.h> | |||
56 | #endif | |||
57 | #include <ctype.h> | |||
58 | #include <unistd.h> | |||
59 | #include <assert.h> | |||
60 | #include <fcntl.h> | |||
61 | #ifndef USE_MINI_EVENT | |||
62 | # ifdef HAVE_EVENT_H1 | |||
63 | # include <event.h> | |||
64 | # else | |||
65 | # include <event2/event.h> | |||
66 | # include "event2/event_struct.h" | |||
67 | # include "event2/event_compat.h" | |||
68 | # endif | |||
69 | #else | |||
70 | # include "mini_event.h" | |||
71 | #endif | |||
72 | #include "remote.h" | |||
73 | #include "util.h" | |||
74 | #include "xfrd.h" | |||
75 | #include "xfrd-notify.h" | |||
76 | #include "xfrd-tcp.h" | |||
77 | #include "nsd.h" | |||
78 | #include "options.h" | |||
79 | #include "difffile.h" | |||
80 | #include "ipc.h" | |||
81 | ||||
82 | #ifdef HAVE_SYS_TYPES_H1 | |||
83 | # include <sys/types.h> | |||
84 | #endif | |||
85 | #ifdef HAVE_SYS_STAT_H1 | |||
86 | # include <sys/stat.h> | |||
87 | #endif | |||
88 | #ifdef HAVE_NETDB_H1 | |||
89 | # include <netdb.h> | |||
90 | #endif | |||
91 | #ifdef HAVE_SYS_UN_H1 | |||
92 | # include <sys/un.h> | |||
93 | #endif | |||
94 | #ifndef AF_LOCAL1 | |||
95 | #define AF_LOCAL1 AF_UNIX1 | |||
96 | #endif | |||
97 | ||||
98 | /** number of seconds timeout on incoming remote control handshake */ | |||
99 | #define REMOTE_CONTROL_TCP_TIMEOUT120 120 | |||
100 | ||||
101 | /** repattern to master or slave */ | |||
102 | #define REPAT_SLAVE1 1 | |||
103 | #define REPAT_MASTER2 2 | |||
104 | ||||
105 | /** if you want zero to be inhibited in stats output. | |||
106 | * it omits zeroes for types that have no acronym and unused-rcodes */ | |||
107 | const int inhibit_zero = 1; | |||
108 | ||||
109 | /** | |||
110 | * a busy control command connection, SSL state | |||
111 | * Defined here to keep the definition private, and keep SSL out of the .h | |||
112 | */ | |||
113 | struct rc_state { | |||
114 | /** the next item in list */ | |||
115 | struct rc_state* next, *prev; | |||
116 | /* if the event was added to the event_base */ | |||
117 | int event_added; | |||
118 | /** the commpoint */ | |||
119 | struct event c; | |||
120 | /** timeout for this state */ | |||
121 | struct timeval tval; | |||
122 | /** in the handshake part */ | |||
123 | enum { rc_none, rc_hs_read, rc_hs_write } shake_state; | |||
124 | /** the ssl state */ | |||
125 | SSL* ssl; | |||
126 | /** file descriptor */ | |||
127 | int fd; | |||
128 | /** the rc this is part of */ | |||
129 | struct daemon_remote* rc; | |||
130 | /** stats list next item */ | |||
131 | struct rc_state* stats_next; | |||
132 | /** stats list indicator (0 is not part of stats list, 1 is stats, | |||
133 | * 2 is stats_noreset. */ | |||
134 | int in_stats_list; | |||
135 | }; | |||
136 | ||||
137 | /** | |||
138 | * list of events for accepting connections | |||
139 | */ | |||
140 | struct acceptlist { | |||
141 | struct acceptlist* next; | |||
142 | int event_added; | |||
143 | struct event c; | |||
144 | char* ident; | |||
145 | struct daemon_remote* rc; | |||
146 | }; | |||
147 | ||||
148 | /** | |||
149 | * The remote control state. | |||
150 | */ | |||
151 | struct daemon_remote { | |||
152 | /** the master process for this remote control */ | |||
153 | struct xfrd_state* xfrd; | |||
154 | /** commpoints for accepting remote control connections */ | |||
155 | struct acceptlist* accept_list; | |||
156 | /* if certificates are used */ | |||
157 | int use_cert; | |||
158 | /** number of active commpoints that are handling remote control */ | |||
159 | int active; | |||
160 | /** max active commpoints */ | |||
161 | int max_active; | |||
162 | /** current commpoints busy; double linked, malloced */ | |||
163 | struct rc_state* busy_list; | |||
164 | /** commpoints waiting for stats to complete (also in busy_list) */ | |||
165 | struct rc_state* stats_list; | |||
166 | /** last time stats was reported */ | |||
167 | struct timeval stats_time, boot_time; | |||
168 | /** the SSL context for creating new SSL streams */ | |||
169 | SSL_CTX* ctx; | |||
170 | }; | |||
171 | ||||
172 | /** | |||
173 | * Connection to print to, either SSL or plain over fd | |||
174 | */ | |||
175 | struct remote_stream { | |||
176 | /** SSL structure, nonNULL if using SSL */ | |||
177 | SSL* ssl; | |||
178 | /** file descriptor for plain transfer */ | |||
179 | int fd; | |||
180 | }; | |||
181 | typedef struct remote_stream RES; | |||
182 | ||||
183 | /** | |||
184 | * Print fixed line of text over ssl connection in blocking mode | |||
185 | * @param res: print to | |||
186 | * @param text: the text. | |||
187 | * @return false on connection failure. | |||
188 | */ | |||
189 | static int ssl_print_text(RES* res, const char* text); | |||
190 | ||||
191 | /** | |||
192 | * printf style printing to the ssl connection | |||
193 | * @param res: the RES connection to print to. Blocking. | |||
194 | * @param format: printf style format string. | |||
195 | * @return success or false on a network failure. | |||
196 | */ | |||
197 | static int ssl_printf(RES* res, const char* format, ...) | |||
198 | ATTR_FORMAT(printf, 2, 3)__attribute__ ((format (printf, 2, 3))); | |||
199 | ||||
200 | /** | |||
201 | * Read until \n is encountered | |||
202 | * If stream signals EOF, the string up to then is returned (without \n). | |||
203 | * @param res: the RES connection to read from. blocking. | |||
204 | * @param buf: buffer to read to. | |||
205 | * @param max: size of buffer. | |||
206 | * @return false on connection failure. | |||
207 | */ | |||
208 | static int ssl_read_line(RES* res, char* buf, size_t max); | |||
209 | ||||
210 | /** perform the accept of a new remote control connection */ | |||
211 | static void | |||
212 | remote_accept_callback(int fd, short event, void* arg); | |||
213 | ||||
214 | /** perform remote control */ | |||
215 | static void | |||
216 | remote_control_callback(int fd, short event, void* arg); | |||
217 | ||||
218 | ||||
219 | /** ---- end of private defines ---- **/ | |||
220 | ||||
221 | ||||
222 | /** log ssl crypto err */ | |||
223 | static void | |||
224 | log_crypto_err(const char* str) | |||
225 | { | |||
226 | /* error:[error code]:[library name]:[function name]:[reason string] */ | |||
227 | char buf[128]; | |||
228 | unsigned long e; | |||
229 | ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); | |||
230 | log_msg(LOG_ERR3, "%s crypto %s", str, buf); | |||
231 | while( (e=ERR_get_error()) ) { | |||
232 | ERR_error_string_n(e, buf, sizeof(buf)); | |||
233 | log_msg(LOG_ERR3, "and additionally crypto %s", buf); | |||
234 | } | |||
235 | } | |||
236 | ||||
237 | #ifdef BIND8_STATS | |||
238 | /** subtract timers and the values do not overflow or become negative */ | |||
239 | static void | |||
240 | timeval_subtract(struct timeval* d, const struct timeval* end, | |||
241 | const struct timeval* start) | |||
242 | { | |||
243 | #ifndef S_SPLINT_S | |||
244 | time_t end_usec = end->tv_usec; | |||
245 | d->tv_sec = end->tv_sec - start->tv_sec; | |||
246 | if(end_usec < start->tv_usec) { | |||
247 | end_usec += 1000000; | |||
248 | d->tv_sec--; | |||
249 | } | |||
250 | d->tv_usec = end_usec - start->tv_usec; | |||
251 | #endif | |||
252 | } | |||
253 | #endif /* BIND8_STATS */ | |||
254 | ||||
255 | static int | |||
256 | remote_setup_ctx(struct daemon_remote* rc, struct nsd_options* cfg) | |||
257 | { | |||
258 | char* s_cert = cfg->server_cert_file; | |||
259 | char* s_key = cfg->server_key_file; | |||
260 | rc->ctx = server_tls_ctx_setup(s_key, s_cert, s_cert); | |||
261 | if(!rc->ctx) { | |||
262 | log_msg(LOG_ERR3, "could not setup remote control TLS context"); | |||
263 | return 0; | |||
264 | } | |||
265 | return 1; | |||
266 | } | |||
267 | ||||
268 | struct daemon_remote* | |||
269 | daemon_remote_create(struct nsd_options* cfg) | |||
270 | { | |||
271 | struct daemon_remote* rc = (struct daemon_remote*)xalloc_zero( | |||
272 | sizeof(*rc)); | |||
273 | rc->max_active = 10; | |||
274 | assert(cfg->control_enable)((void)0); | |||
275 | ||||
276 | if(options_remote_is_address(cfg)) { | |||
| ||||
277 | if(!remote_setup_ctx(rc, cfg)) { | |||
278 | daemon_remote_delete(rc); | |||
279 | return NULL((void*)0); | |||
280 | } | |||
281 | rc->use_cert = 1; | |||
282 | } else { | |||
283 | struct ip_address_option* o; | |||
284 | rc->ctx = NULL((void*)0); | |||
285 | rc->use_cert = 0; | |||
286 | for(o = cfg->control_interface; o; o = o->next) { | |||
287 | if(o->address && o->address[0] != '/') | |||
288 | log_msg(LOG_WARNING4, "control-interface %s is not using TLS, but plain transfer, because first control-interface in config file is a local socket (starts with a /).", o->address); | |||
289 | } | |||
290 | } | |||
291 | ||||
292 | /* and try to open the ports */ | |||
293 | if(!daemon_remote_open_ports(rc, cfg)) { | |||
294 | log_msg(LOG_ERR3, "could not open remote control port"); | |||
295 | daemon_remote_delete(rc); | |||
296 | return NULL((void*)0); | |||
297 | } | |||
298 | ||||
299 | if(gettimeofday(&rc->boot_time, NULL((void*)0)) == -1) | |||
300 | log_msg(LOG_ERR3, "gettimeofday: %s", strerror(errno(*__errno()))); | |||
301 | rc->stats_time = rc->boot_time; | |||
302 | ||||
303 | return rc; | |||
304 | } | |||
305 | ||||
306 | void daemon_remote_close(struct daemon_remote* rc) | |||
307 | { | |||
308 | struct rc_state* p, *np; | |||
309 | struct acceptlist* h, *nh; | |||
310 | if(!rc) return; | |||
311 | ||||
312 | /* close listen sockets */ | |||
313 | h = rc->accept_list; | |||
314 | while(h) { | |||
315 | nh = h->next; | |||
316 | if(h->event_added) | |||
317 | event_del(&h->c); | |||
318 | close(h->c.ev_fd); | |||
319 | free(h->ident); | |||
320 | free(h); | |||
321 | h = nh; | |||
322 | } | |||
323 | rc->accept_list = NULL((void*)0); | |||
324 | ||||
325 | /* close busy connection sockets */ | |||
326 | p = rc->busy_list; | |||
327 | while(p) { | |||
328 | np = p->next; | |||
329 | if(p->event_added) | |||
330 | event_del(&p->c); | |||
331 | if(p->ssl) | |||
332 | SSL_free(p->ssl); | |||
333 | close(p->c.ev_fd); | |||
334 | free(p); | |||
335 | p = np; | |||
336 | } | |||
337 | rc->busy_list = NULL((void*)0); | |||
338 | rc->active = 0; | |||
339 | } | |||
340 | ||||
341 | void daemon_remote_delete(struct daemon_remote* rc) | |||
342 | { | |||
343 | if(!rc) return; | |||
344 | daemon_remote_close(rc); | |||
345 | if(rc->ctx) { | |||
346 | SSL_CTX_free(rc->ctx); | |||
347 | } | |||
348 | free(rc); | |||
349 | } | |||
350 | ||||
351 | static int | |||
352 | create_tcp_accept_sock(struct addrinfo* addr, int* noproto) | |||
353 | { | |||
354 | #if defined(SO_REUSEADDR0x0004) || (defined(INET6) && (defined(IPV6_V6ONLY27) || defined(IPV6_USE_MIN_MTU42) || defined(IPV6_MTU))) | |||
355 | int on = 1; | |||
356 | #endif | |||
357 | int s; | |||
358 | *noproto = 0; | |||
359 | if ((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { | |||
360 | #if defined(INET6) | |||
361 | if (addr->ai_family == AF_INET624 && | |||
362 | errno(*__errno()) == EAFNOSUPPORT47) { | |||
363 | *noproto = 1; | |||
364 | log_msg(LOG_WARNING4, "fallback to TCP4, no IPv6: not supported"); | |||
365 | return -1; | |||
366 | } | |||
367 | #endif /* INET6 */ | |||
368 | log_msg(LOG_ERR3, "can't create a socket: %s", strerror(errno(*__errno()))); | |||
369 | return -1; | |||
370 | } | |||
371 | #ifdef SO_REUSEADDR0x0004 | |||
372 | if (setsockopt(s, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &on, sizeof(on)) < 0) { | |||
373 | log_msg(LOG_ERR3, "setsockopt(..., SO_REUSEADDR, ...) failed: %s", strerror(errno(*__errno()))); | |||
374 | } | |||
375 | #endif /* SO_REUSEADDR */ | |||
376 | #if defined(INET6) && defined(IPV6_V6ONLY27) | |||
377 | if (addr->ai_family == AF_INET624 && | |||
378 | setsockopt(s, IPPROTO_IPV641, IPV6_V6ONLY27, &on, sizeof(on)) < 0) | |||
379 | { | |||
380 | log_msg(LOG_ERR3, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno(*__errno()))); | |||
381 | close(s); | |||
382 | return -1; | |||
383 | } | |||
384 | #endif | |||
385 | /* set it nonblocking */ | |||
386 | /* (StevensUNP p463), if tcp listening socket is blocking, then | |||
387 | it may block in accept, even if select() says readable. */ | |||
388 | if (fcntl(s, F_SETFL4, O_NONBLOCK0x0004) == -1) { | |||
389 | log_msg(LOG_ERR3, "cannot fcntl tcp: %s", strerror(errno(*__errno()))); | |||
390 | } | |||
391 | /* Bind it... */ | |||
392 | if (bind(s, (struct sockaddr *)addr->ai_addr, addr->ai_addrlen) != 0) { | |||
393 | log_msg(LOG_ERR3, "can't bind tcp socket: %s", strerror(errno(*__errno()))); | |||
394 | close(s); | |||
395 | return -1; | |||
396 | } | |||
397 | /* Listen to it... */ | |||
398 | if (listen(s, TCP_BACKLOG_REMOTE16) == -1) { | |||
399 | log_msg(LOG_ERR3, "can't listen: %s", strerror(errno(*__errno()))); | |||
400 | close(s); | |||
401 | return -1; | |||
402 | } | |||
403 | return s; | |||
404 | } | |||
405 | ||||
406 | /** | |||
407 | * Add and open a new control port | |||
408 | * @param rc: rc with result list. | |||
409 | * @param ip: ip str | |||
410 | * @param nr: port nr | |||
411 | * @param noproto_is_err: if lack of protocol support is an error. | |||
412 | * @return false on failure. | |||
413 | */ | |||
414 | static int | |||
415 | add_open(struct daemon_remote* rc, struct nsd_options* cfg, const char* ip, | |||
416 | int nr, int noproto_is_err) | |||
417 | { | |||
418 | struct addrinfo hints; | |||
419 | struct addrinfo* res; | |||
420 | struct acceptlist* hl; | |||
421 | int noproto = 0; | |||
422 | int fd, r; | |||
423 | char port[15]; | |||
424 | snprintf(port, sizeof(port), "%d", nr); | |||
425 | port[sizeof(port)-1]=0; | |||
426 | memset(&hints, 0, sizeof(hints)); | |||
427 | assert(ip)((void)0); | |||
428 | ||||
429 | if(ip[0] == '/') { | |||
| ||||
430 | /* This looks like a local socket */ | |||
431 | fd = create_local_accept_sock(ip, &noproto); | |||
432 | /* | |||
433 | * Change socket ownership and permissions so users other | |||
434 | * than root can access it provided they are in the same | |||
435 | * group as the user we run as. | |||
436 | */ | |||
437 | if(fd != -1) { | |||
438 | #ifdef HAVE_CHOWN1 | |||
439 | if (cfg->username && cfg->username[0] && | |||
440 | nsd.uid != (uid_t)-1) { | |||
441 | if(chown(ip, nsd.uid, nsd.gid) == -1) | |||
442 | VERBOSITY(2, (LOG_INFO, "cannot chown %u.%u %s: %s",do { if ((2) <= verbosity) { log_msg (6, "cannot chown %u.%u %s: %s" , (unsigned)nsd.uid, (unsigned)nsd.gid, ip, strerror((*__errno ()))) ; } } while (0) | |||
443 | (unsigned)nsd.uid, (unsigned)nsd.gid,do { if ((2) <= verbosity) { log_msg (6, "cannot chown %u.%u %s: %s" , (unsigned)nsd.uid, (unsigned)nsd.gid, ip, strerror((*__errno ()))) ; } } while (0) | |||
444 | ip, strerror(errno)))do { if ((2) <= verbosity) { log_msg (6, "cannot chown %u.%u %s: %s" , (unsigned)nsd.uid, (unsigned)nsd.gid, ip, strerror((*__errno ()))) ; } } while (0); | |||
445 | } | |||
446 | if(chmod(ip, (mode_t)(S_IRUSR0000400 | S_IWUSR0000200 | S_IRGRP0000040 | S_IWGRP0000020)) == -1) { | |||
447 | VERBOSITY(3, (LOG_INFO, "cannot chmod control socket %s: %s", ip, strerror(errno)))do { if ((3) <= verbosity) { log_msg (6, "cannot chmod control socket %s: %s" , ip, strerror((*__errno()))) ; } } while (0); | |||
448 | } | |||
449 | #else | |||
450 | (void)cfg; | |||
451 | #endif | |||
452 | } | |||
453 | } else { | |||
454 | hints.ai_socktype = SOCK_STREAM1; | |||
455 | hints.ai_flags = AI_PASSIVE1 | AI_NUMERICHOST4; | |||
456 | /* if we had no interface ip name, "default" is what we | |||
457 | * would do getaddrinfo for. */ | |||
458 | if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) { | |||
459 | log_msg(LOG_ERR3, "control interface %s:%s getaddrinfo: %s %s", | |||
460 | ip, port, gai_strerror(r), | |||
461 | #ifdef EAI_SYSTEM-11 | |||
462 | r==EAI_SYSTEM-11?(char*)strerror(errno(*__errno())):"" | |||
463 | #else | |||
464 | "" | |||
465 | #endif | |||
466 | ); | |||
467 | return 0; | |||
468 | } | |||
469 | ||||
470 | /* open fd */ | |||
471 | fd = create_tcp_accept_sock(res, &noproto); | |||
472 | freeaddrinfo(res); | |||
473 | } | |||
474 | ||||
475 | if(fd == -1 && noproto) { | |||
476 | if(!noproto_is_err) | |||
477 | return 1; /* return success, but do nothing */ | |||
478 | log_msg(LOG_ERR3, "cannot open control interface %s %d : " | |||
479 | "protocol not supported", ip, nr); | |||
480 | return 0; | |||
481 | } | |||
482 | if(fd == -1) { | |||
483 | log_msg(LOG_ERR3, "cannot open control interface %s %d", ip, nr); | |||
484 | return 0; | |||
485 | } | |||
486 | ||||
487 | /* alloc */ | |||
488 | hl = (struct acceptlist*)xalloc_zero(sizeof(*hl)); | |||
489 | hl->rc = rc; | |||
490 | hl->ident = strdup(ip); | |||
491 | if(!hl->ident) { | |||
492 | log_msg(LOG_ERR3, "malloc failure"); | |||
493 | close(fd); | |||
494 | free(hl); | |||
495 | return 0; | |||
496 | } | |||
497 | hl->next = rc->accept_list; | |||
498 | rc->accept_list = hl; | |||
499 | ||||
500 | hl->c.ev_fd = fd; | |||
501 | hl->event_added = 0; | |||
502 | return 1; | |||
503 | } | |||
504 | ||||
505 | int | |||
506 | daemon_remote_open_ports(struct daemon_remote* rc, struct nsd_options* cfg) | |||
507 | { | |||
508 | assert(cfg->control_enable && cfg->control_port)((void)0); | |||
509 | if(cfg->control_interface
| |||
510 | ip_address_option_type* p; | |||
511 | for(p = cfg->control_interface; p; p = p->next) { | |||
512 | if(!add_open(rc, cfg, p->address, cfg->control_port, 1)) { | |||
513 | return 0; | |||
514 | } | |||
515 | } | |||
516 | } else { | |||
517 | /* defaults */ | |||
518 | if(cfg->do_ip6 && !add_open(rc, cfg, "::1", cfg->control_port, 0)) { | |||
519 | return 0; | |||
520 | } | |||
521 | if(cfg->do_ip4 && | |||
522 | !add_open(rc, cfg, "127.0.0.1", cfg->control_port, 1)) { | |||
523 | return 0; | |||
524 | } | |||
525 | } | |||
526 | return 1; | |||
527 | } | |||
528 | ||||
529 | void | |||
530 | daemon_remote_attach(struct daemon_remote* rc, struct xfrd_state* xfrd) | |||
531 | { | |||
532 | int fd; | |||
533 | struct acceptlist* p; | |||
534 | if(!rc) return; | |||
535 | rc->xfrd = xfrd; | |||
536 | for(p = rc->accept_list; p; p = p->next) { | |||
537 | /* add event */ | |||
538 | fd = p->c.ev_fd; | |||
539 | memset(&p->c, 0, sizeof(p->c)); | |||
540 | event_set(&p->c, fd, EV_PERSIST0x10|EV_READ0x02, remote_accept_callback, | |||
541 | p); | |||
542 | if(event_base_set(xfrd->event_base, &p->c) != 0) | |||
543 | log_msg(LOG_ERR3, "remote: cannot set event_base"); | |||
544 | if(event_add(&p->c, NULL((void*)0)) != 0) | |||
545 | log_msg(LOG_ERR3, "remote: cannot add event"); | |||
546 | p->event_added = 1; | |||
547 | } | |||
548 | } | |||
549 | ||||
550 | static void | |||
551 | remote_accept_callback(int fd, short event, void* arg) | |||
552 | { | |||
553 | struct acceptlist *hl = (struct acceptlist*)arg; | |||
554 | struct daemon_remote *rc = hl->rc; | |||
555 | #ifdef INET6 | |||
556 | struct sockaddr_storage addr; | |||
557 | #else | |||
558 | struct sockaddr_in addr; | |||
559 | #endif | |||
560 | socklen_t addrlen; | |||
561 | int newfd; | |||
562 | struct rc_state* n; | |||
563 | ||||
564 | if (!(event & EV_READ0x02)) { | |||
565 | return; | |||
566 | } | |||
567 | ||||
568 | /* perform the accept */ | |||
569 | addrlen = sizeof(addr); | |||
570 | #ifndef HAVE_ACCEPT41 | |||
571 | newfd = accept(fd, (struct sockaddr*)&addr, &addrlen); | |||
572 | #else | |||
573 | newfd = accept4(fd, (struct sockaddr*)&addr, &addrlen, SOCK_NONBLOCK0x4000); | |||
574 | #endif | |||
575 | if(newfd == -1) { | |||
576 | if ( errno(*__errno()) != EINTR4 | |||
577 | && errno(*__errno()) != EWOULDBLOCK35 | |||
578 | #ifdef ECONNABORTED53 | |||
579 | && errno(*__errno()) != ECONNABORTED53 | |||
580 | #endif /* ECONNABORTED */ | |||
581 | #ifdef EPROTO95 | |||
582 | && errno(*__errno()) != EPROTO95 | |||
583 | #endif /* EPROTO */ | |||
584 | ) { | |||
585 | log_msg(LOG_ERR3, "accept failed: %s", strerror(errno(*__errno()))); | |||
586 | } | |||
587 | return; | |||
588 | } | |||
589 | ||||
590 | /* create new commpoint unless we are servicing already */ | |||
591 | if(rc->active >= rc->max_active) { | |||
592 | log_msg(LOG_WARNING4, "drop incoming remote control: " | |||
593 | "too many connections"); | |||
594 | close_exit: | |||
595 | close(newfd); | |||
596 | return; | |||
597 | } | |||
598 | ||||
599 | #ifndef HAVE_ACCEPT41 | |||
600 | if (fcntl(newfd, F_SETFL4, O_NONBLOCK0x0004) == -1) { | |||
601 | log_msg(LOG_ERR3, "fcntl failed: %s", strerror(errno(*__errno()))); | |||
602 | goto close_exit; | |||
603 | } | |||
604 | #endif | |||
605 | ||||
606 | /* setup state to service the remote control command */ | |||
607 | n = (struct rc_state*)calloc(1, sizeof(*n)); | |||
608 | if(!n) { | |||
609 | log_msg(LOG_ERR3, "out of memory"); | |||
610 | goto close_exit; | |||
611 | } | |||
612 | ||||
613 | n->tval.tv_sec = REMOTE_CONTROL_TCP_TIMEOUT120; | |||
614 | n->tval.tv_usec = 0L; | |||
615 | n->fd = newfd; | |||
616 | ||||
617 | memset(&n->c, 0, sizeof(n->c)); | |||
618 | event_set(&n->c, newfd, EV_PERSIST0x10|EV_TIMEOUT0x01|EV_READ0x02, | |||
619 | remote_control_callback, n); | |||
620 | if(event_base_set(xfrd->event_base, &n->c) != 0) { | |||
621 | log_msg(LOG_ERR3, "remote_accept: cannot set event_base"); | |||
622 | free(n); | |||
623 | goto close_exit; | |||
624 | } | |||
625 | if(event_add(&n->c, &n->tval) != 0) { | |||
626 | log_msg(LOG_ERR3, "remote_accept: cannot add event"); | |||
627 | free(n); | |||
628 | goto close_exit; | |||
629 | } | |||
630 | n->event_added = 1; | |||
631 | ||||
632 | if(2 <= verbosity) { | |||
633 | if(hl->ident && hl->ident[0] == '/') { | |||
634 | VERBOSITY(2, (LOG_INFO, "new control connection from %s", hl->ident))do { if ((2) <= verbosity) { log_msg (6, "new control connection from %s" , hl->ident) ; } } while (0); | |||
635 | } else { | |||
636 | char s[128]; | |||
637 | addr2str(&addr, s, sizeof(s)); | |||
638 | VERBOSITY(2, (LOG_INFO, "new control connection from %s", s))do { if ((2) <= verbosity) { log_msg (6, "new control connection from %s" , s) ; } } while (0); | |||
639 | } | |||
640 | } | |||
641 | ||||
642 | if(rc->ctx) { | |||
643 | n->shake_state = rc_hs_read; | |||
644 | n->ssl = SSL_new(rc->ctx); | |||
645 | if(!n->ssl) { | |||
646 | log_crypto_err("could not SSL_new"); | |||
647 | event_del(&n->c); | |||
648 | free(n); | |||
649 | goto close_exit; | |||
650 | } | |||
651 | SSL_set_accept_state(n->ssl); | |||
652 | (void)SSL_set_mode(n->ssl, SSL_MODE_AUTO_RETRY)SSL_ctrl((n->ssl),33,(0x00000004L),((void*)0)); | |||
653 | if(!SSL_set_fd(n->ssl, newfd)) { | |||
654 | log_crypto_err("could not SSL_set_fd"); | |||
655 | event_del(&n->c); | |||
656 | SSL_free(n->ssl); | |||
657 | free(n); | |||
658 | goto close_exit; | |||
659 | } | |||
660 | } else { | |||
661 | n->ssl = NULL((void*)0); | |||
662 | } | |||
663 | ||||
664 | n->rc = rc; | |||
665 | n->stats_next = NULL((void*)0); | |||
666 | n->in_stats_list = 0; | |||
667 | n->prev = NULL((void*)0); | |||
668 | n->next = rc->busy_list; | |||
669 | if(n->next) n->next->prev = n; | |||
670 | rc->busy_list = n; | |||
671 | rc->active ++; | |||
672 | ||||
673 | /* perform the first nonblocking read already, for windows, | |||
674 | * so it can return wouldblock. could be faster too. */ | |||
675 | remote_control_callback(newfd, EV_READ0x02, n); | |||
676 | } | |||
677 | ||||
678 | /** delete from list */ | |||
679 | static void | |||
680 | state_list_remove_elem(struct rc_state** list, struct rc_state* todel) | |||
681 | { | |||
682 | if(todel->prev) todel->prev->next = todel->next; | |||
683 | else *list = todel->next; | |||
684 | if(todel->next) todel->next->prev = todel->prev; | |||
685 | } | |||
686 | ||||
687 | /** delete from stats list */ | |||
688 | static void | |||
689 | stats_list_remove_elem(struct rc_state** list, struct rc_state* todel) | |||
690 | { | |||
691 | struct rc_state* prev = NULL((void*)0); | |||
692 | struct rc_state* n = *list; | |||
693 | while(n) { | |||
694 | /* delete this one? */ | |||
695 | if(n == todel) { | |||
696 | if(prev) prev->next = n->next; | |||
697 | else (*list) = n->next; | |||
698 | /* go on and delete further elements */ | |||
699 | /* prev = prev; */ | |||
700 | n = n->next; | |||
701 | continue; | |||
702 | } | |||
703 | ||||
704 | /* go to the next element */ | |||
705 | prev = n; | |||
706 | n = n->next; | |||
707 | } | |||
708 | } | |||
709 | ||||
710 | /** decrease active count and remove commpoint from busy list */ | |||
711 | static void | |||
712 | clean_point(struct daemon_remote* rc, struct rc_state* s) | |||
713 | { | |||
714 | if(s->in_stats_list) | |||
715 | stats_list_remove_elem(&rc->stats_list, s); | |||
716 | state_list_remove_elem(&rc->busy_list, s); | |||
717 | rc->active --; | |||
718 | if(s->event_added) | |||
719 | event_del(&s->c); | |||
720 | if(s->ssl) { | |||
721 | SSL_shutdown(s->ssl); | |||
722 | SSL_free(s->ssl); | |||
723 | } | |||
724 | close(s->c.ev_fd); | |||
725 | free(s); | |||
726 | } | |||
727 | ||||
728 | static int | |||
729 | ssl_print_text(RES* res, const char* text) | |||
730 | { | |||
731 | int r; | |||
732 | if(!res) | |||
733 | return 0; | |||
734 | if(res->ssl) { | |||
735 | ERR_clear_error(); | |||
736 | if((r=SSL_write(res->ssl, text, (int)strlen(text))) <= 0) { | |||
737 | if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN6) { | |||
738 | VERBOSITY(2, (LOG_WARNING, "in SSL_write, peer "do { if ((2) <= verbosity) { log_msg (4, "in SSL_write, peer " "closed connection") ; } } while (0) | |||
739 | "closed connection"))do { if ((2) <= verbosity) { log_msg (4, "in SSL_write, peer " "closed connection") ; } } while (0); | |||
740 | return 0; | |||
741 | } | |||
742 | log_crypto_err("could not SSL_write"); | |||
743 | return 0; | |||
744 | } | |||
745 | } else { | |||
746 | if(write_socket(res->fd, text, strlen(text)) <= 0) { | |||
747 | log_msg(LOG_ERR3, "could not write: %s", | |||
748 | strerror(errno(*__errno()))); | |||
749 | return 0; | |||
750 | } | |||
751 | } | |||
752 | return 1; | |||
753 | } | |||
754 | ||||
755 | /** print text over the ssl connection */ | |||
756 | static int | |||
757 | ssl_print_vmsg(RES* ssl, const char* format, va_list args) | |||
758 | { | |||
759 | char msg[1024]; | |||
760 | vsnprintf(msg, sizeof(msg), format, args); | |||
761 | return ssl_print_text(ssl, msg); | |||
762 | } | |||
763 | ||||
764 | /** printf style printing to the ssl connection */ | |||
765 | static int | |||
766 | ssl_printf(RES* ssl, const char* format, ...) | |||
767 | { | |||
768 | va_list args; | |||
769 | int ret; | |||
770 | va_start(args, format)__builtin_va_start(args, format); | |||
771 | ret = ssl_print_vmsg(ssl, format, args); | |||
772 | va_end(args)__builtin_va_end(args); | |||
773 | return ret; | |||
774 | } | |||
775 | ||||
776 | static int | |||
777 | ssl_read_line(RES* res, char* buf, size_t max) | |||
778 | { | |||
779 | int r; | |||
780 | size_t len = 0; | |||
781 | if(!res) | |||
782 | return 0; | |||
783 | while(len < max) { | |||
784 | buf[len] = 0; /* terminate for safety and please checkers */ | |||
785 | /* this byte is written if we read a byte from the input */ | |||
786 | if(res->ssl) { | |||
787 | ERR_clear_error(); | |||
788 | if((r=SSL_read(res->ssl, buf+len, 1)) <= 0) { | |||
789 | if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN6) { | |||
790 | buf[len] = 0; | |||
791 | return 1; | |||
792 | } | |||
793 | log_crypto_err("could not SSL_read"); | |||
794 | return 0; | |||
795 | } | |||
796 | } else { | |||
797 | while(1) { | |||
798 | ssize_t rr = read(res->fd, buf+len, 1); | |||
799 | if(rr <= 0) { | |||
800 | if(rr == 0) { | |||
801 | buf[len] = 0; | |||
802 | return 1; | |||
803 | } | |||
804 | if(errno(*__errno()) == EINTR4 || errno(*__errno()) == EAGAIN35) | |||
805 | continue; | |||
806 | log_msg(LOG_ERR3, "could not read: %s", | |||
807 | strerror(errno(*__errno()))); | |||
808 | return 0; | |||
809 | } | |||
810 | break; | |||
811 | } | |||
812 | } | |||
813 | if(buf[len] == '\n') { | |||
814 | /* return string without \n */ | |||
815 | buf[len] = 0; | |||
816 | return 1; | |||
817 | } | |||
818 | len++; | |||
819 | } | |||
820 | buf[max-1] = 0; | |||
821 | log_msg(LOG_ERR3, "control line too long (%d): %s", (int)max, buf); | |||
822 | return 0; | |||
823 | } | |||
824 | ||||
825 | /** skip whitespace, return new pointer into string */ | |||
826 | static char* | |||
827 | skipwhite(char* str) | |||
828 | { | |||
829 | /* EOS \0 is not a space */ | |||
830 | while( isspace((unsigned char)*str) ) | |||
831 | str++; | |||
832 | return str; | |||
833 | } | |||
834 | ||||
835 | /** send the OK to the control client */ | |||
836 | static void | |||
837 | send_ok(RES* ssl) | |||
838 | { | |||
839 | (void)ssl_printf(ssl, "ok\n"); | |||
840 | } | |||
841 | ||||
842 | /** get zone argument (if any) or NULL, false on error */ | |||
843 | static int | |||
844 | get_zone_arg(RES* ssl, xfrd_state_type* xfrd, char* arg, | |||
845 | struct zone_options** zo) | |||
846 | { | |||
847 | const dname_type* dname; | |||
848 | if(!arg[0]) { | |||
849 | /* no argument present, return NULL */ | |||
850 | *zo = NULL((void*)0); | |||
851 | return 1; | |||
852 | } | |||
853 | dname = dname_parse(xfrd->region, arg); | |||
854 | if(!dname) { | |||
855 | (void)ssl_printf(ssl, "error cannot parse zone name '%s'\n", arg); | |||
856 | *zo = NULL((void*)0); | |||
857 | return 0; | |||
858 | } | |||
859 | *zo = zone_options_find(xfrd->nsd->options, dname); | |||
860 | region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); | |||
861 | if(!*zo) { | |||
862 | (void)ssl_printf(ssl, "error zone %s not configured\n", arg); | |||
863 | return 0; | |||
864 | } | |||
865 | return 1; | |||
866 | } | |||
867 | ||||
868 | /** do the stop command */ | |||
869 | static void | |||
870 | do_stop(RES* ssl, xfrd_state_type* xfrd) | |||
871 | { | |||
872 | xfrd->need_to_send_shutdown = 1; | |||
873 | ||||
874 | if(!(xfrd->ipc_handler_flags&EV_WRITE0x04)) { | |||
875 | ipc_xfrd_set_listening(xfrd, EV_PERSIST0x10|EV_READ0x02|EV_WRITE0x04); | |||
876 | } | |||
877 | ||||
878 | send_ok(ssl); | |||
879 | } | |||
880 | ||||
881 | /** do the log_reopen command, it only needs reload_now */ | |||
882 | static void | |||
883 | do_log_reopen(RES* ssl, xfrd_state_type* xfrd) | |||
884 | { | |||
885 | xfrd_set_reload_now(xfrd); | |||
886 | send_ok(ssl); | |||
887 | } | |||
888 | ||||
889 | /** do the reload command */ | |||
890 | static void | |||
891 | do_reload(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
892 | { | |||
893 | struct zone_options* zo; | |||
894 | if(!get_zone_arg(ssl, xfrd, arg, &zo)) | |||
895 | return; | |||
896 | task_new_check_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], | |||
897 | xfrd->last_task, zo?(const dname_type*)zo->node.key:NULL((void*)0)); | |||
898 | xfrd_set_reload_now(xfrd); | |||
899 | send_ok(ssl); | |||
900 | } | |||
901 | ||||
902 | /** do the write command */ | |||
903 | static void | |||
904 | do_write(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
905 | { | |||
906 | struct zone_options* zo; | |||
907 | if(!get_zone_arg(ssl, xfrd, arg, &zo)) | |||
908 | return; | |||
909 | task_new_write_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], | |||
910 | xfrd->last_task, zo?(const dname_type*)zo->node.key:NULL((void*)0)); | |||
911 | xfrd_set_reload_now(xfrd); | |||
912 | send_ok(ssl); | |||
913 | } | |||
914 | ||||
915 | /** do the notify command */ | |||
916 | static void | |||
917 | do_notify(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
918 | { | |||
919 | struct zone_options* zo; | |||
920 | if(!get_zone_arg(ssl, xfrd, arg, &zo)) | |||
921 | return; | |||
922 | if(zo) { | |||
923 | struct notify_zone* n = (struct notify_zone*)rbtree_search( | |||
924 | xfrd->notify_zones, (const dname_type*)zo->node.key); | |||
925 | if(n) { | |||
926 | xfrd_notify_start(n, xfrd); | |||
927 | send_ok(ssl); | |||
928 | } else { | |||
929 | (void)ssl_printf(ssl, "error zone does not have notify\n"); | |||
930 | } | |||
931 | } else { | |||
932 | struct notify_zone* n; | |||
933 | RBTREE_FOR(n, struct notify_zone*, xfrd->notify_zones)for(n=(struct notify_zone*)rbtree_first(xfrd->notify_zones ); (rbnode_type*)n != &rbtree_null_node; n = (struct notify_zone *)rbtree_next((rbnode_type*)n)) { | |||
934 | xfrd_notify_start(n, xfrd); | |||
935 | } | |||
936 | send_ok(ssl); | |||
937 | } | |||
938 | } | |||
939 | ||||
940 | /** do the transfer command */ | |||
941 | static void | |||
942 | do_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
943 | { | |||
944 | struct zone_options* zo; | |||
945 | xfrd_zone_type* zone; | |||
946 | if(!get_zone_arg(ssl, xfrd, arg, &zo)) | |||
947 | return; | |||
948 | if(zo) { | |||
949 | zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const | |||
950 | dname_type*)zo->node.key); | |||
951 | if(zone) { | |||
952 | xfrd_handle_notify_and_start_xfr(zone, NULL((void*)0)); | |||
953 | send_ok(ssl); | |||
954 | } else { | |||
955 | (void)ssl_printf(ssl, "error zone not slave\n"); | |||
956 | } | |||
957 | } else { | |||
958 | RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones)for(zone=(xfrd_zone_type*)rbtree_first(xfrd->zones); (rbnode_type *)zone != &rbtree_null_node; zone = (xfrd_zone_type*)rbtree_next ((rbnode_type*)zone)) { | |||
959 | xfrd_handle_notify_and_start_xfr(zone, NULL((void*)0)); | |||
960 | } | |||
961 | (void)ssl_printf(ssl, "ok, %lu zones\n", (unsigned long)xfrd->zones->count); | |||
962 | } | |||
963 | } | |||
964 | ||||
965 | /** force transfer a zone */ | |||
966 | static void | |||
967 | force_transfer_zone(xfrd_zone_type* zone) | |||
968 | { | |||
969 | /* if in TCP transaction, stop it immediately. */ | |||
970 | if(zone->tcp_conn != -1) | |||
971 | xfrd_tcp_release(xfrd->tcp_set, zone); | |||
972 | else if(zone->zone_handler.ev_fd != -1) | |||
973 | xfrd_udp_release(zone); | |||
974 | /* pretend we not longer have it and force any | |||
975 | * zone to be downloaded (even same serial, w AXFR) */ | |||
976 | zone->soa_disk_acquired = 0; | |||
977 | zone->soa_nsd_acquired = 0; | |||
978 | xfrd_handle_notify_and_start_xfr(zone, NULL((void*)0)); | |||
979 | } | |||
980 | ||||
981 | /** do the force transfer command */ | |||
982 | static void | |||
983 | do_force_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
984 | { | |||
985 | struct zone_options* zo; | |||
986 | xfrd_zone_type* zone; | |||
987 | if(!get_zone_arg(ssl, xfrd, arg, &zo)) | |||
988 | return; | |||
989 | if(zo) { | |||
990 | zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const | |||
991 | dname_type*)zo->node.key); | |||
992 | if(zone) { | |||
993 | force_transfer_zone(zone); | |||
994 | send_ok(ssl); | |||
995 | } else { | |||
996 | (void)ssl_printf(ssl, "error zone not slave\n"); | |||
997 | } | |||
998 | } else { | |||
999 | RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones)for(zone=(xfrd_zone_type*)rbtree_first(xfrd->zones); (rbnode_type *)zone != &rbtree_null_node; zone = (xfrd_zone_type*)rbtree_next ((rbnode_type*)zone)) { | |||
1000 | force_transfer_zone(zone); | |||
1001 | } | |||
1002 | (void)ssl_printf(ssl, "ok, %lu zones\n", (unsigned long)xfrd->zones->count); | |||
1003 | } | |||
1004 | } | |||
1005 | ||||
1006 | static int | |||
1007 | print_soa_status(RES* ssl, const char* str, xfrd_soa_type* soa, time_t acq) | |||
1008 | { | |||
1009 | if(acq) { | |||
1010 | if(!ssl_printf(ssl, " %s: \"%u since %s\"\n", str, | |||
1011 | (unsigned)ntohl(soa->serial)(__uint32_t)(__builtin_constant_p(soa->serial) ? (__uint32_t )(((__uint32_t)(soa->serial) & 0xff) << 24 | ((__uint32_t )(soa->serial) & 0xff00) << 8 | ((__uint32_t)(soa ->serial) & 0xff0000) >> 8 | ((__uint32_t)(soa-> serial) & 0xff000000) >> 24) : __swap32md(soa->serial )), xfrd_pretty_time(acq))) | |||
1012 | return 0; | |||
1013 | } else { | |||
1014 | if(!ssl_printf(ssl, " %s: none\n", str)) | |||
1015 | return 0; | |||
1016 | } | |||
1017 | return 1; | |||
1018 | } | |||
1019 | ||||
1020 | /** print zonestatus for one domain */ | |||
1021 | static int | |||
1022 | print_zonestatus(RES* ssl, xfrd_state_type* xfrd, struct zone_options* zo) | |||
1023 | { | |||
1024 | xfrd_zone_type* xz = (xfrd_zone_type*)rbtree_search(xfrd->zones, | |||
1025 | (const dname_type*)zo->node.key); | |||
1026 | struct notify_zone* nz = (struct notify_zone*)rbtree_search( | |||
1027 | xfrd->notify_zones, (const dname_type*)zo->node.key); | |||
1028 | if(!ssl_printf(ssl, "zone: %s\n", zo->name)) | |||
1029 | return 0; | |||
1030 | if(!zo->part_of_config) { | |||
1031 | if(!ssl_printf(ssl, " pattern: %s\n", zo->pattern->pname)) | |||
1032 | return 0; | |||
1033 | } | |||
1034 | if(nz) { | |||
1035 | if(nz->is_waiting) { | |||
1036 | if(!ssl_printf(ssl, " notify: \"waiting-for-fd\"\n")) | |||
1037 | return 0; | |||
1038 | } else if(nz->notify_send_enable || nz->notify_send6_enable) { | |||
1039 | int i; | |||
1040 | if(!ssl_printf(ssl, " notify: \"send")) | |||
1041 | return 0; | |||
1042 | for(i=0; i<NOTIFY_CONCURRENT_MAX16; i++) { | |||
1043 | if(!nz->pkts[i].dest) continue; | |||
1044 | if(!ssl_printf(ssl, " %s", | |||
1045 | nz->pkts[i].dest->ip_address_spec)) | |||
1046 | return 0; | |||
1047 | } | |||
1048 | if(!ssl_printf(ssl, " with serial %u\"\n", | |||
1049 | (unsigned)ntohl(nz->current_soa->serial)(__uint32_t)(__builtin_constant_p(nz->current_soa->serial ) ? (__uint32_t)(((__uint32_t)(nz->current_soa->serial) & 0xff) << 24 | ((__uint32_t)(nz->current_soa-> serial) & 0xff00) << 8 | ((__uint32_t)(nz->current_soa ->serial) & 0xff0000) >> 8 | ((__uint32_t)(nz-> current_soa->serial) & 0xff000000) >> 24) : __swap32md (nz->current_soa->serial)))) | |||
1050 | return 0; | |||
1051 | } | |||
1052 | } | |||
1053 | if(!xz) { | |||
1054 | if(!ssl_printf(ssl, " state: master\n")) | |||
1055 | return 0; | |||
1056 | return 1; | |||
1057 | } | |||
1058 | if(!ssl_printf(ssl, " state: %s\n", | |||
1059 | (xz->state == xfrd_zone_ok)?"ok":( | |||
1060 | (xz->state == xfrd_zone_expired)?"expired":"refreshing"))) | |||
1061 | return 0; | |||
1062 | if(!print_soa_status(ssl, "served-serial", &xz->soa_nsd, | |||
1063 | xz->soa_nsd_acquired)) | |||
1064 | return 0; | |||
1065 | if(!print_soa_status(ssl, "commit-serial", &xz->soa_disk, | |||
1066 | xz->soa_disk_acquired)) | |||
1067 | return 0; | |||
1068 | if(xz->round_num != -1) { | |||
1069 | if(!print_soa_status(ssl, "notified-serial", &xz->soa_notified, | |||
1070 | xz->soa_notified_acquired)) | |||
1071 | return 0; | |||
1072 | } else if(xz->event_added) { | |||
1073 | if(!ssl_printf(ssl, "\twait: \"%lu sec between attempts\"\n", | |||
1074 | (unsigned long)xz->timeout.tv_sec)) | |||
1075 | return 0; | |||
1076 | } | |||
1077 | ||||
1078 | /* UDP */ | |||
1079 | if(xz->udp_waiting) { | |||
1080 | if(!ssl_printf(ssl, " transfer: \"waiting-for-UDP-fd\"\n")) | |||
1081 | return 0; | |||
1082 | } else if(xz->zone_handler.ev_fd != -1 && xz->tcp_conn == -1) { | |||
1083 | if(!ssl_printf(ssl, " transfer: \"sent UDP to %s\"\n", | |||
1084 | xz->master->ip_address_spec)) | |||
1085 | return 0; | |||
1086 | } | |||
1087 | ||||
1088 | /* TCP */ | |||
1089 | if(xz->tcp_waiting) { | |||
1090 | if(!ssl_printf(ssl, " transfer: \"waiting-for-TCP-fd\"\n")) | |||
1091 | return 0; | |||
1092 | } else if(xz->tcp_conn != -1) { | |||
1093 | if(!ssl_printf(ssl, " transfer: \"TCP connected to %s\"\n", | |||
1094 | xz->master->ip_address_spec)) | |||
1095 | return 0; | |||
1096 | } | |||
1097 | ||||
1098 | return 1; | |||
1099 | } | |||
1100 | ||||
1101 | /** do the zonestatus command */ | |||
1102 | static void | |||
1103 | do_zonestatus(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1104 | { | |||
1105 | struct zone_options* zo; | |||
1106 | if(!get_zone_arg(ssl, xfrd, arg, &zo)) | |||
1107 | return; | |||
1108 | if(zo) (void)print_zonestatus(ssl, xfrd, zo); | |||
1109 | else { | |||
1110 | RBTREE_FOR(zo, struct zone_options*,for(zo=(struct zone_options*)rbtree_first(xfrd->nsd->options ->zone_options); (rbnode_type*)zo != &rbtree_null_node ; zo = (struct zone_options*)rbtree_next((rbnode_type*)zo)) | |||
1111 | xfrd->nsd->options->zone_options)for(zo=(struct zone_options*)rbtree_first(xfrd->nsd->options ->zone_options); (rbnode_type*)zo != &rbtree_null_node ; zo = (struct zone_options*)rbtree_next((rbnode_type*)zo)) { | |||
1112 | if(!print_zonestatus(ssl, xfrd, zo)) | |||
1113 | return; | |||
1114 | } | |||
1115 | } | |||
1116 | } | |||
1117 | ||||
1118 | /** do the verbosity command */ | |||
1119 | static void | |||
1120 | do_verbosity(RES* ssl, char* str) | |||
1121 | { | |||
1122 | int val = atoi(str); | |||
1123 | if(strcmp(str, "") == 0) { | |||
1124 | (void)ssl_printf(ssl, "verbosity %d\n", verbosity); | |||
1125 | return; | |||
1126 | } | |||
1127 | if(val == 0 && strcmp(str, "0") != 0) { | |||
1128 | (void)ssl_printf(ssl, "error in verbosity number syntax: %s\n", str); | |||
1129 | return; | |||
1130 | } | |||
1131 | verbosity = val; | |||
1132 | task_new_set_verbosity(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1133 | xfrd->last_task, val); | |||
1134 | xfrd_set_reload_now(xfrd); | |||
1135 | send_ok(ssl); | |||
1136 | } | |||
1137 | ||||
1138 | /** find second argument, modifies string */ | |||
1139 | static int | |||
1140 | find_arg2(RES* ssl, char* arg, char** arg2) | |||
1141 | { | |||
1142 | char* as = strrchr(arg, ' '); | |||
1143 | if(as) { | |||
1144 | as[0]=0; | |||
1145 | *arg2 = as+1; | |||
1146 | while(isspace((unsigned char)*as) && as > arg) | |||
1147 | as--; | |||
1148 | as[0]=0; | |||
1149 | return 1; | |||
1150 | } | |||
1151 | *arg2 = NULL((void*)0); | |||
1152 | (void)ssl_printf(ssl, "error could not find next argument " | |||
1153 | "after %s\n", arg); | |||
1154 | return 0; | |||
1155 | } | |||
1156 | ||||
1157 | /** find second and third arguments, modifies string, | |||
1158 | * does not print error for missing arg3 so that if it does not find an | |||
1159 | * arg3, the caller can use two arguments. */ | |||
1160 | static int | |||
1161 | find_arg3(RES* ssl, char* arg, char** arg2, char** arg3) | |||
1162 | { | |||
1163 | if(find_arg2(ssl, arg, arg2)) { | |||
1164 | char* as; | |||
1165 | *arg3 = *arg2; | |||
1166 | as = strrchr(arg, ' '); | |||
1167 | if(as) { | |||
1168 | as[0]=0; | |||
1169 | *arg2 = as+1; | |||
1170 | while(isspace((unsigned char)*as) && as > arg) | |||
1171 | as--; | |||
1172 | as[0]=0; | |||
1173 | return 1; | |||
1174 | } | |||
1175 | } | |||
1176 | *arg3 = NULL((void*)0); | |||
1177 | return 0; | |||
1178 | } | |||
1179 | ||||
1180 | /** do the status command */ | |||
1181 | static void | |||
1182 | do_status(RES* ssl, xfrd_state_type* xfrd) | |||
1183 | { | |||
1184 | if(!ssl_printf(ssl, "version: %s\n", PACKAGE_VERSION"4.3.9")) | |||
1185 | return; | |||
1186 | if(!ssl_printf(ssl, "verbosity: %d\n", verbosity)) | |||
1187 | return; | |||
1188 | #ifdef RATELIMIT | |||
1189 | if(!ssl_printf(ssl, "ratelimit: %d\n", | |||
1190 | (int)xfrd->nsd->options->rrl_ratelimit)) | |||
1191 | return; | |||
1192 | #else | |||
1193 | (void)xfrd; | |||
1194 | #endif | |||
1195 | } | |||
1196 | ||||
1197 | /** do the stats command */ | |||
1198 | static void | |||
1199 | do_stats(struct daemon_remote* rc, int peek, struct rc_state* rs) | |||
1200 | { | |||
1201 | #ifdef BIND8_STATS | |||
1202 | /* queue up to get stats after a reload is done (to gather statistics | |||
1203 | * from the servers) */ | |||
1204 | assert(!rs->in_stats_list)((void)0); | |||
1205 | if(peek) rs->in_stats_list = 2; | |||
1206 | else rs->in_stats_list = 1; | |||
1207 | rs->stats_next = rc->stats_list; | |||
1208 | rc->stats_list = rs; | |||
1209 | /* block the tcp waiting for the reload */ | |||
1210 | event_del(&rs->c); | |||
1211 | rs->event_added = 0; | |||
1212 | /* force a reload */ | |||
1213 | xfrd_set_reload_now(xfrd); | |||
1214 | #else | |||
1215 | (void)rc; (void)peek; | |||
1216 | (void)ssl_printf(rs->ssl, "error no stats enabled at compile time\n"); | |||
1217 | #endif /* BIND8_STATS */ | |||
1218 | } | |||
1219 | ||||
1220 | /** see if we have more zonestatistics entries and it has to be incremented */ | |||
1221 | static void | |||
1222 | zonestat_inc_ifneeded(xfrd_state_type* xfrd) | |||
1223 | { | |||
1224 | #ifdef USE_ZONE_STATS | |||
1225 | if(xfrd->nsd->options->zonestatnames->count != xfrd->zonestat_safe) | |||
1226 | task_new_zonestat_inc(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1227 | xfrd->last_task, | |||
1228 | xfrd->nsd->options->zonestatnames->count); | |||
1229 | #else | |||
1230 | (void)xfrd; | |||
1231 | #endif /* USE_ZONE_STATS */ | |||
1232 | } | |||
1233 | ||||
1234 | /** perform the changezone command for one zone */ | |||
1235 | static int | |||
1236 | perform_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1237 | { | |||
1238 | const dname_type* dname; | |||
1239 | struct zone_options* zopt; | |||
1240 | char* arg2 = NULL((void*)0); | |||
1241 | if(!find_arg2(ssl, arg, &arg2)) | |||
1242 | return 0; | |||
1243 | ||||
1244 | /* if we add it to the xfrd now, then xfrd could download AXFR and | |||
1245 | * store it and the NSD-reload would see it in the difffile before | |||
1246 | * it sees the add-config task. | |||
1247 | */ | |||
1248 | /* thus: AXFRs and IXFRs must store the pattern name in the | |||
1249 | * difffile, so that it can be added when the AXFR or IXFR is seen. | |||
1250 | */ | |||
1251 | ||||
1252 | /* check that the pattern exists */ | |||
1253 | if(!rbtree_search(xfrd->nsd->options->patterns, arg2)) { | |||
1254 | (void)ssl_printf(ssl, "error pattern %s does not exist\n", | |||
1255 | arg2); | |||
1256 | return 0; | |||
1257 | } | |||
1258 | ||||
1259 | dname = dname_parse(xfrd->region, arg); | |||
1260 | if(!dname) { | |||
1261 | (void)ssl_printf(ssl, "error cannot parse zone name\n"); | |||
1262 | return 0; | |||
1263 | } | |||
1264 | ||||
1265 | /* see if zone is a duplicate */ | |||
1266 | if( (zopt=zone_options_find(xfrd->nsd->options, dname)) ) { | |||
1267 | if(zopt->part_of_config) { | |||
1268 | (void)ssl_printf(ssl, "error zone defined in nsd.conf, " | |||
1269 | "cannot delete it in this manner: remove it from " | |||
1270 | "nsd.conf yourself and repattern\n"); | |||
1271 | region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); | |||
1272 | dname = NULL((void*)0); | |||
1273 | return 0; | |||
1274 | } | |||
1275 | /* found the zone, now delete it */ | |||
1276 | /* create deletion task */ | |||
1277 | /* this deletion task is processed before the addition task, | |||
1278 | * that is created below, in the same reload process, causing | |||
1279 | * a seamless change from one to the other, with no downtime | |||
1280 | * for the zone. */ | |||
1281 | task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1282 | xfrd->last_task, dname); | |||
1283 | xfrd_set_reload_now(xfrd); | |||
1284 | /* delete it in xfrd */ | |||
1285 | if(zone_is_slave(zopt)) { | |||
1286 | xfrd_del_slave_zone(xfrd, dname); | |||
1287 | } | |||
1288 | xfrd_del_notify(xfrd, dname); | |||
1289 | /* delete from config */ | |||
1290 | zone_list_del(xfrd->nsd->options, zopt); | |||
1291 | } else { | |||
1292 | (void)ssl_printf(ssl, "zone %s did not exist, creating", arg); | |||
1293 | } | |||
1294 | region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); | |||
1295 | dname = NULL((void*)0); | |||
1296 | ||||
1297 | /* add to zonelist and adds to config in memory */ | |||
1298 | zopt = zone_list_add(xfrd->nsd->options, arg, arg2); | |||
1299 | if(!zopt) { | |||
1300 | /* also dname parse error here */ | |||
1301 | (void)ssl_printf(ssl, "error could not add zonelist entry\n"); | |||
1302 | return 0; | |||
1303 | } | |||
1304 | /* make addzone task and schedule reload */ | |||
1305 | task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1306 | xfrd->last_task, arg, arg2, | |||
1307 | getzonestatid(xfrd->nsd->options, zopt)); | |||
1308 | zonestat_inc_ifneeded(xfrd); | |||
1309 | xfrd_set_reload_now(xfrd); | |||
1310 | /* add to xfrd - notify (for master and slaves) */ | |||
1311 | init_notify_send(xfrd->notify_zones, xfrd->region, zopt); | |||
1312 | /* add to xfrd - slave */ | |||
1313 | if(zone_is_slave(zopt)) { | |||
1314 | xfrd_init_slave_zone(xfrd, zopt); | |||
1315 | } | |||
1316 | return 1; | |||
1317 | } | |||
1318 | ||||
1319 | /** perform the addzone command for one zone */ | |||
1320 | static int | |||
1321 | perform_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1322 | { | |||
1323 | const dname_type* dname; | |||
1324 | struct zone_options* zopt; | |||
1325 | char* arg2 = NULL((void*)0); | |||
1326 | if(!find_arg2(ssl, arg, &arg2)) | |||
1327 | return 0; | |||
1328 | ||||
1329 | /* if we add it to the xfrd now, then xfrd could download AXFR and | |||
1330 | * store it and the NSD-reload would see it in the difffile before | |||
1331 | * it sees the add-config task. | |||
1332 | */ | |||
1333 | /* thus: AXFRs and IXFRs must store the pattern name in the | |||
1334 | * difffile, so that it can be added when the AXFR or IXFR is seen. | |||
1335 | */ | |||
1336 | ||||
1337 | /* check that the pattern exists */ | |||
1338 | if(!rbtree_search(xfrd->nsd->options->patterns, arg2)) { | |||
1339 | (void)ssl_printf(ssl, "error pattern %s does not exist\n", | |||
1340 | arg2); | |||
1341 | return 0; | |||
1342 | } | |||
1343 | ||||
1344 | dname = dname_parse(xfrd->region, arg); | |||
1345 | if(!dname) { | |||
1346 | (void)ssl_printf(ssl, "error cannot parse zone name\n"); | |||
1347 | return 0; | |||
1348 | } | |||
1349 | ||||
1350 | /* see if zone is a duplicate */ | |||
1351 | if( zone_options_find(xfrd->nsd->options, dname) ) { | |||
1352 | region_recycle(xfrd->region, (void*)dname, | |||
1353 | dname_total_size(dname)); | |||
1354 | (void)ssl_printf(ssl, "zone %s already exists\n", arg); | |||
1355 | return 1; | |||
1356 | } | |||
1357 | region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); | |||
1358 | dname = NULL((void*)0); | |||
1359 | ||||
1360 | /* add to zonelist and adds to config in memory */ | |||
1361 | zopt = zone_list_add(xfrd->nsd->options, arg, arg2); | |||
1362 | if(!zopt) { | |||
1363 | /* also dname parse error here */ | |||
1364 | (void)ssl_printf(ssl, "error could not add zonelist entry\n"); | |||
1365 | return 0; | |||
1366 | } | |||
1367 | /* make addzone task and schedule reload */ | |||
1368 | task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1369 | xfrd->last_task, arg, arg2, | |||
1370 | getzonestatid(xfrd->nsd->options, zopt)); | |||
1371 | zonestat_inc_ifneeded(xfrd); | |||
1372 | xfrd_set_reload_now(xfrd); | |||
1373 | /* add to xfrd - notify (for master and slaves) */ | |||
1374 | init_notify_send(xfrd->notify_zones, xfrd->region, zopt); | |||
1375 | /* add to xfrd - slave */ | |||
1376 | if(zone_is_slave(zopt)) { | |||
1377 | xfrd_init_slave_zone(xfrd, zopt); | |||
1378 | } | |||
1379 | return 1; | |||
1380 | } | |||
1381 | ||||
1382 | /** perform the delzone command for one zone */ | |||
1383 | static int | |||
1384 | perform_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1385 | { | |||
1386 | const dname_type* dname; | |||
1387 | struct zone_options* zopt; | |||
1388 | ||||
1389 | dname = dname_parse(xfrd->region, arg); | |||
1390 | if(!dname) { | |||
1391 | (void)ssl_printf(ssl, "error cannot parse zone name\n"); | |||
1392 | return 0; | |||
1393 | } | |||
1394 | ||||
1395 | /* see if we have the zone in question */ | |||
1396 | zopt = zone_options_find(xfrd->nsd->options, dname); | |||
1397 | if(!zopt) { | |||
1398 | region_recycle(xfrd->region, (void*)dname, | |||
1399 | dname_total_size(dname)); | |||
1400 | /* nothing to do */ | |||
1401 | (void)ssl_printf(ssl, "warning zone %s not present\n", arg); | |||
1402 | return 0; | |||
1403 | } | |||
1404 | ||||
1405 | /* see if it can be deleted */ | |||
1406 | if(zopt->part_of_config) { | |||
1407 | region_recycle(xfrd->region, (void*)dname, | |||
1408 | dname_total_size(dname)); | |||
1409 | (void)ssl_printf(ssl, "error zone defined in nsd.conf, " | |||
1410 | "cannot delete it in this manner: remove it from " | |||
1411 | "nsd.conf yourself and repattern\n"); | |||
1412 | return 0; | |||
1413 | } | |||
1414 | ||||
1415 | /* create deletion task */ | |||
1416 | task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1417 | xfrd->last_task, dname); | |||
1418 | xfrd_set_reload_now(xfrd); | |||
1419 | /* delete it in xfrd */ | |||
1420 | if(zone_is_slave(zopt)) { | |||
1421 | xfrd_del_slave_zone(xfrd, dname); | |||
1422 | } | |||
1423 | xfrd_del_notify(xfrd, dname); | |||
1424 | /* delete from config */ | |||
1425 | zone_list_del(xfrd->nsd->options, zopt); | |||
1426 | ||||
1427 | region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); | |||
1428 | return 1; | |||
1429 | } | |||
1430 | ||||
1431 | /** do the addzone command */ | |||
1432 | static void | |||
1433 | do_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1434 | { | |||
1435 | if(!perform_addzone(ssl, xfrd, arg)) | |||
1436 | return; | |||
1437 | send_ok(ssl); | |||
1438 | } | |||
1439 | ||||
1440 | /** do the delzone command */ | |||
1441 | static void | |||
1442 | do_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1443 | { | |||
1444 | if(!perform_delzone(ssl, xfrd, arg)) | |||
1445 | return; | |||
1446 | send_ok(ssl); | |||
1447 | } | |||
1448 | ||||
1449 | /** do the changezone command */ | |||
1450 | static void | |||
1451 | do_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1452 | { | |||
1453 | if(!perform_changezone(ssl, xfrd, arg)) | |||
1454 | return; | |||
1455 | send_ok(ssl); | |||
1456 | } | |||
1457 | ||||
1458 | /** do the addzones command */ | |||
1459 | static void | |||
1460 | do_addzones(RES* ssl, xfrd_state_type* xfrd) | |||
1461 | { | |||
1462 | char buf[2048]; | |||
1463 | int num = 0; | |||
1464 | while(ssl_read_line(ssl, buf, sizeof(buf))) { | |||
1465 | if(buf[0] == 0x04 && buf[1] == 0) | |||
1466 | break; /* end of transmission */ | |||
1467 | if(!perform_addzone(ssl, xfrd, buf)) { | |||
1468 | if(!ssl_printf(ssl, "error for input line '%s'\n", | |||
1469 | buf)) | |||
1470 | return; | |||
1471 | } else { | |||
1472 | if(!ssl_printf(ssl, "added: %s\n", buf)) | |||
1473 | return; | |||
1474 | num++; | |||
1475 | } | |||
1476 | } | |||
1477 | (void)ssl_printf(ssl, "added %d zones\n", num); | |||
1478 | } | |||
1479 | ||||
1480 | /** do the delzones command */ | |||
1481 | static void | |||
1482 | do_delzones(RES* ssl, xfrd_state_type* xfrd) | |||
1483 | { | |||
1484 | char buf[2048]; | |||
1485 | int num = 0; | |||
1486 | while(ssl_read_line(ssl, buf, sizeof(buf))) { | |||
1487 | if(buf[0] == 0x04 && buf[1] == 0) | |||
1488 | break; /* end of transmission */ | |||
1489 | if(!perform_delzone(ssl, xfrd, buf)) { | |||
1490 | if(!ssl_printf(ssl, "error for input line '%s'\n", | |||
1491 | buf)) | |||
1492 | return; | |||
1493 | } else { | |||
1494 | if(!ssl_printf(ssl, "removed: %s\n", buf)) | |||
1495 | return; | |||
1496 | num++; | |||
1497 | } | |||
1498 | } | |||
1499 | (void)ssl_printf(ssl, "deleted %d zones\n", num); | |||
1500 | } | |||
1501 | ||||
1502 | ||||
1503 | /** remove TSIG key from config and add task so that reload does too */ | |||
1504 | static void remove_key(xfrd_state_type* xfrd, const char* kname) | |||
1505 | { | |||
1506 | /* add task before deletion because the name string could be deleted */ | |||
1507 | task_new_del_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, | |||
1508 | kname); | |||
1509 | key_options_remove(xfrd->nsd->options, kname); | |||
1510 | xfrd_set_reload_now(xfrd); /* this is executed when the current control | |||
1511 | command ends, thus the entire config changes are bunched up */ | |||
1512 | } | |||
1513 | ||||
1514 | /** add TSIG key to config and add task so that reload does too */ | |||
1515 | static void add_key(xfrd_state_type* xfrd, struct key_options* k) | |||
1516 | { | |||
1517 | key_options_add_modify(xfrd->nsd->options, k); | |||
1518 | task_new_add_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, | |||
1519 | k); | |||
1520 | xfrd_set_reload_now(xfrd); | |||
1521 | } | |||
1522 | ||||
1523 | /** check if keys have changed */ | |||
1524 | static void repat_keys(xfrd_state_type* xfrd, struct nsd_options* newopt) | |||
1525 | { | |||
1526 | struct nsd_options* oldopt = xfrd->nsd->options; | |||
1527 | struct key_options* k; | |||
1528 | /* find deleted keys */ | |||
1529 | k = (struct key_options*)rbtree_first(oldopt->keys); | |||
1530 | while((rbnode_type*)k != RBTREE_NULL&rbtree_null_node) { | |||
1531 | struct key_options* next = (struct key_options*)rbtree_next( | |||
1532 | (rbnode_type*)k); | |||
1533 | if(!key_options_find(newopt, k->name)) | |||
1534 | remove_key(xfrd, k->name); | |||
1535 | k = next; | |||
1536 | } | |||
1537 | /* find added or changed keys */ | |||
1538 | RBTREE_FOR(k, struct key_options*, newopt->keys)for(k=(struct key_options*)rbtree_first(newopt->keys); (rbnode_type *)k != &rbtree_null_node; k = (struct key_options*)rbtree_next ((rbnode_type*)k)) { | |||
1539 | struct key_options* origk = key_options_find(oldopt, k->name); | |||
1540 | if(!origk) | |||
1541 | add_key(xfrd, k); | |||
1542 | else if(!key_options_equal(k, origk)) | |||
1543 | add_key(xfrd, k); | |||
1544 | } | |||
1545 | } | |||
1546 | ||||
1547 | /** find zone given the implicit pattern */ | |||
1548 | static const dname_type* | |||
1549 | parse_implicit_name(xfrd_state_type* xfrd,const char* pname) | |||
1550 | { | |||
1551 | if(strncmp(pname, PATTERN_IMPLICIT_MARKER"_implicit_", | |||
1552 | strlen(PATTERN_IMPLICIT_MARKER"_implicit_")) != 0) | |||
1553 | return NULL((void*)0); | |||
1554 | return dname_parse(xfrd->region, pname + | |||
1555 | strlen(PATTERN_IMPLICIT_MARKER"_implicit_")); | |||
1556 | } | |||
1557 | ||||
1558 | /** remove cfgzone and add task so that reload does too */ | |||
1559 | static void | |||
1560 | remove_cfgzone(xfrd_state_type* xfrd, const char* pname) | |||
1561 | { | |||
1562 | /* dname and find the zone for the implicit pattern */ | |||
1563 | struct zone_options* zopt = NULL((void*)0); | |||
1564 | const dname_type* dname = parse_implicit_name(xfrd, pname); | |||
1565 | if(!dname) { | |||
1566 | /* should have a parseable name, but it did not */ | |||
1567 | return; | |||
1568 | } | |||
1569 | ||||
1570 | /* find the zone entry for the implicit pattern */ | |||
1571 | zopt = zone_options_find(xfrd->nsd->options, dname); | |||
1572 | if(!zopt) { | |||
1573 | /* this should not happen; implicit pattern has zone entry */ | |||
1574 | region_recycle(xfrd->region, (void*)dname, | |||
1575 | dname_total_size(dname)); | |||
1576 | return; | |||
1577 | } | |||
1578 | ||||
1579 | /* create deletion task */ | |||
1580 | task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1581 | xfrd->last_task, dname); | |||
1582 | xfrd_set_reload_now(xfrd); | |||
1583 | /* delete it in xfrd */ | |||
1584 | if(zone_is_slave(zopt)) { | |||
1585 | xfrd_del_slave_zone(xfrd, dname); | |||
1586 | } | |||
1587 | xfrd_del_notify(xfrd, dname); | |||
1588 | ||||
1589 | /* delete from zoneoptions */ | |||
1590 | zone_options_delete(xfrd->nsd->options, zopt); | |||
1591 | ||||
1592 | /* recycle parsed dname */ | |||
1593 | region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); | |||
1594 | } | |||
1595 | ||||
1596 | /** add cfgzone and add task so that reload does too */ | |||
1597 | static void | |||
1598 | add_cfgzone(xfrd_state_type* xfrd, const char* pname) | |||
1599 | { | |||
1600 | /* add to our zonelist */ | |||
1601 | struct zone_options* zopt = zone_options_create( | |||
1602 | xfrd->nsd->options->region); | |||
1603 | if(!zopt) | |||
1604 | return; | |||
1605 | zopt->part_of_config = 1; | |||
1606 | zopt->name = region_strdup(xfrd->nsd->options->region, | |||
1607 | pname + strlen(PATTERN_IMPLICIT_MARKER"_implicit_")); | |||
1608 | zopt->pattern = pattern_options_find(xfrd->nsd->options, pname); | |||
1609 | if(!zopt->name || !zopt->pattern) | |||
1610 | return; | |||
1611 | if(!nsd_options_insert_zone(xfrd->nsd->options, zopt)) { | |||
1612 | log_msg(LOG_ERR3, "bad domain name or duplicate zone '%s' " | |||
1613 | "pattern %s", zopt->name, pname); | |||
1614 | } | |||
1615 | ||||
1616 | /* make addzone task and schedule reload */ | |||
1617 | task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1618 | xfrd->last_task, zopt->name, pname, | |||
1619 | getzonestatid(xfrd->nsd->options, zopt)); | |||
1620 | /* zonestat_inc is done after the entire config file has been done */ | |||
1621 | xfrd_set_reload_now(xfrd); | |||
1622 | /* add to xfrd - notify (for master and slaves) */ | |||
1623 | init_notify_send(xfrd->notify_zones, xfrd->region, zopt); | |||
1624 | /* add to xfrd - slave */ | |||
1625 | if(zone_is_slave(zopt)) { | |||
1626 | xfrd_init_slave_zone(xfrd, zopt); | |||
1627 | } | |||
1628 | } | |||
1629 | ||||
1630 | /** remove pattern and add task so that reload does too */ | |||
1631 | static void | |||
1632 | remove_pat(xfrd_state_type* xfrd, const char* name) | |||
1633 | { | |||
1634 | /* add task before deletion, because name-string could be deleted */ | |||
1635 | task_new_del_pattern(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1636 | xfrd->last_task, name); | |||
1637 | pattern_options_remove(xfrd->nsd->options, name); | |||
1638 | xfrd_set_reload_now(xfrd); | |||
1639 | } | |||
1640 | ||||
1641 | /** add pattern and add task so that reload does too */ | |||
1642 | static void | |||
1643 | add_pat(xfrd_state_type* xfrd, struct pattern_options* p) | |||
1644 | { | |||
1645 | pattern_options_add_modify(xfrd->nsd->options, p); | |||
1646 | task_new_add_pattern(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1647 | xfrd->last_task, p); | |||
1648 | xfrd_set_reload_now(xfrd); | |||
1649 | } | |||
1650 | ||||
1651 | /** interrupt zones that are using changed or removed patterns */ | |||
1652 | static void | |||
1653 | repat_interrupt_zones(xfrd_state_type* xfrd, struct nsd_options* newopt) | |||
1654 | { | |||
1655 | /* if masterlist changed: | |||
1656 | * interrupt slave zone (UDP or TCP) transfers. | |||
1657 | * slave zones reset master to start of list. | |||
1658 | */ | |||
1659 | xfrd_zone_type* xz; | |||
1660 | struct notify_zone* nz; | |||
1661 | RBTREE_FOR(xz, xfrd_zone_type*, xfrd->zones)for(xz=(xfrd_zone_type*)rbtree_first(xfrd->zones); (rbnode_type *)xz != &rbtree_null_node; xz = (xfrd_zone_type*)rbtree_next ((rbnode_type*)xz)) { | |||
1662 | struct pattern_options* oldp = xz->zone_options->pattern; | |||
1663 | struct pattern_options* newp = pattern_options_find(newopt, | |||
1664 | oldp->pname); | |||
1665 | if(!newp || !acl_list_equal(oldp->request_xfr, | |||
1666 | newp->request_xfr)) { | |||
1667 | /* interrupt transfer */ | |||
1668 | if(xz->tcp_conn != -1) { | |||
1669 | xfrd_tcp_release(xfrd->tcp_set, xz); | |||
1670 | xfrd_set_refresh_now(xz); | |||
1671 | } else if(xz->zone_handler.ev_fd != -1) { | |||
1672 | xfrd_udp_release(xz); | |||
1673 | xfrd_set_refresh_now(xz); | |||
1674 | } | |||
1675 | xz->master = 0; | |||
1676 | xz->master_num = 0; | |||
1677 | xz->next_master = -1; | |||
1678 | xz->round_num = -1; /* fresh set of retries */ | |||
1679 | } | |||
1680 | } | |||
1681 | /* if notify list changed: | |||
1682 | * interrupt notify that is busy. | |||
1683 | * reset notify to start of list. (clear all other reset_notify) | |||
1684 | */ | |||
1685 | RBTREE_FOR(nz, struct notify_zone*, xfrd->notify_zones)for(nz=(struct notify_zone*)rbtree_first(xfrd->notify_zones ); (rbnode_type*)nz != &rbtree_null_node; nz = (struct notify_zone *)rbtree_next((rbnode_type*)nz)) { | |||
1686 | struct pattern_options* oldp = nz->options->pattern; | |||
1687 | struct pattern_options* newp = pattern_options_find(newopt, | |||
1688 | oldp->pname); | |||
1689 | if(!newp || !acl_list_equal(oldp->notify, newp->notify)) { | |||
1690 | /* interrupt notify */ | |||
1691 | if(nz->notify_send_enable) { | |||
1692 | notify_disable(nz); | |||
1693 | /* set to restart the notify after the | |||
1694 | * pattern has been changed. */ | |||
1695 | nz->notify_restart = 2; | |||
1696 | } else { | |||
1697 | nz->notify_restart = 1; | |||
1698 | } | |||
1699 | } else { | |||
1700 | nz->notify_restart = 0; | |||
1701 | } | |||
1702 | } | |||
1703 | } | |||
1704 | ||||
1705 | /** for notify, after the pattern changes, restart the affected notifies */ | |||
1706 | static void | |||
1707 | repat_interrupt_notify_start(xfrd_state_type* xfrd) | |||
1708 | { | |||
1709 | struct notify_zone* nz; | |||
1710 | RBTREE_FOR(nz, struct notify_zone*, xfrd->notify_zones)for(nz=(struct notify_zone*)rbtree_first(xfrd->notify_zones ); (rbnode_type*)nz != &rbtree_null_node; nz = (struct notify_zone *)rbtree_next((rbnode_type*)nz)) { | |||
1711 | if(nz->notify_restart) { | |||
1712 | if(nz->notify_current) | |||
1713 | nz->notify_current = nz->options->pattern->notify; | |||
1714 | if(nz->notify_restart == 2) { | |||
1715 | if(nz->notify_restart) | |||
1716 | xfrd_notify_start(nz, xfrd); | |||
1717 | } | |||
1718 | } | |||
1719 | } | |||
1720 | } | |||
1721 | ||||
1722 | /** check if patterns have changed */ | |||
1723 | static void | |||
1724 | repat_patterns(xfrd_state_type* xfrd, struct nsd_options* newopt) | |||
1725 | { | |||
1726 | /* zones that use changed patterns must have: | |||
1727 | * - their AXFR/IXFR interrupted: try again, acl may have changed. | |||
1728 | * if the old master/key still exists, OK, fix master-numptrs and | |||
1729 | * keep going. Otherwise, stop xfer and reset TSIG. | |||
1730 | * - send NOTIFY reset to start of NOTIFY list (and TSIG reset). | |||
1731 | */ | |||
1732 | struct nsd_options* oldopt = xfrd->nsd->options; | |||
1733 | struct pattern_options* p; | |||
1734 | int search_zones = 0; | |||
1735 | ||||
1736 | repat_interrupt_zones(xfrd, newopt); | |||
1737 | /* find deleted patterns */ | |||
1738 | p = (struct pattern_options*)rbtree_first(oldopt->patterns); | |||
1739 | while((rbnode_type*)p != RBTREE_NULL&rbtree_null_node) { | |||
1740 | struct pattern_options* next = (struct pattern_options*) | |||
1741 | rbtree_next((rbnode_type*)p); | |||
1742 | if(!pattern_options_find(newopt, p->pname)) { | |||
1743 | if(p->implicit) { | |||
1744 | /* first remove its zone */ | |||
1745 | VERBOSITY(1, (LOG_INFO, "zone removed from config: %s", p->pname + strlen(PATTERN_IMPLICIT_MARKER)))do { if ((1) <= verbosity) { log_msg (6, "zone removed from config: %s" , p->pname + strlen("_implicit_")) ; } } while (0); | |||
1746 | remove_cfgzone(xfrd, p->pname); | |||
1747 | } | |||
1748 | remove_pat(xfrd, p->pname); | |||
1749 | } | |||
1750 | p = next; | |||
1751 | } | |||
1752 | /* find added or changed patterns */ | |||
1753 | RBTREE_FOR(p, struct pattern_options*, newopt->patterns)for(p=(struct pattern_options*)rbtree_first(newopt->patterns ); (rbnode_type*)p != &rbtree_null_node; p = (struct pattern_options *)rbtree_next((rbnode_type*)p)) { | |||
1754 | struct pattern_options* origp = pattern_options_find(oldopt, | |||
1755 | p->pname); | |||
1756 | if(!origp) { | |||
1757 | /* no zones can use it, no zone_interrupt needed */ | |||
1758 | add_pat(xfrd, p); | |||
1759 | if(p->implicit) { | |||
1760 | VERBOSITY(1, (LOG_INFO, "zone added to config: %s", p->pname + strlen(PATTERN_IMPLICIT_MARKER)))do { if ((1) <= verbosity) { log_msg (6, "zone added to config: %s" , p->pname + strlen("_implicit_")) ; } } while (0); | |||
1761 | add_cfgzone(xfrd, p->pname); | |||
1762 | } | |||
1763 | } else if(!pattern_options_equal(p, origp)) { | |||
1764 | uint8_t newstate = 0; | |||
1765 | if (p->request_xfr && !origp->request_xfr) { | |||
1766 | newstate = REPAT_SLAVE1; | |||
1767 | } else if (!p->request_xfr && origp->request_xfr) { | |||
1768 | newstate = REPAT_MASTER2; | |||
1769 | } | |||
1770 | add_pat(xfrd, p); | |||
1771 | if (p->implicit && newstate) { | |||
1772 | const dname_type* dname = | |||
1773 | parse_implicit_name(xfrd, p->pname); | |||
1774 | if (dname) { | |||
1775 | if (newstate == REPAT_SLAVE1) { | |||
1776 | struct zone_options* zopt = | |||
1777 | zone_options_find( | |||
1778 | oldopt, dname); | |||
1779 | if (zopt) { | |||
1780 | xfrd_init_slave_zone( | |||
1781 | xfrd, zopt); | |||
1782 | } | |||
1783 | } else if (newstate == REPAT_MASTER2) { | |||
1784 | xfrd_del_slave_zone(xfrd, | |||
1785 | dname); | |||
1786 | } | |||
1787 | region_recycle(xfrd->region, | |||
1788 | (void*)dname, | |||
1789 | dname_total_size(dname)); | |||
1790 | } | |||
1791 | } else if(!p->implicit && newstate) { | |||
1792 | /* search all zones with this pattern */ | |||
1793 | search_zones = 1; | |||
1794 | origp->xfrd_flags = newstate; | |||
1795 | } | |||
1796 | } | |||
1797 | } | |||
1798 | if (search_zones) { | |||
1799 | struct zone_options* zone_opt; | |||
1800 | /* search in oldopt because 1) it contains zonelist zones, | |||
1801 | * and 2) you need oldopt(existing) to call xfrd_init */ | |||
1802 | RBTREE_FOR(zone_opt, struct zone_options*, oldopt->zone_options)for(zone_opt=(struct zone_options*)rbtree_first(oldopt->zone_options ); (rbnode_type*)zone_opt != &rbtree_null_node; zone_opt = (struct zone_options*)rbtree_next((rbnode_type*)zone_opt)) { | |||
1803 | struct pattern_options* oldp = zone_opt->pattern; | |||
1804 | if (!oldp->implicit) { | |||
1805 | if (oldp->xfrd_flags == REPAT_SLAVE1) { | |||
1806 | /* xfrd needs stable reference so get | |||
1807 | * it from the oldopt(modified) tree */ | |||
1808 | xfrd_init_slave_zone(xfrd, zone_opt); | |||
1809 | } else if (oldp->xfrd_flags == REPAT_MASTER2) { | |||
1810 | xfrd_del_slave_zone(xfrd, | |||
1811 | (const dname_type*) | |||
1812 | zone_opt->node.key); | |||
1813 | } | |||
1814 | oldp->xfrd_flags = 0; | |||
1815 | } | |||
1816 | } | |||
1817 | } | |||
1818 | repat_interrupt_notify_start(xfrd); | |||
1819 | } | |||
1820 | ||||
1821 | /** true if options are different that can be set via repat. */ | |||
1822 | static int | |||
1823 | repat_options_changed(xfrd_state_type* xfrd, struct nsd_options* newopt) | |||
1824 | { | |||
1825 | #ifdef RATELIMIT | |||
1826 | if(xfrd->nsd->options->rrl_ratelimit != newopt->rrl_ratelimit) | |||
1827 | return 1; | |||
1828 | if(xfrd->nsd->options->rrl_whitelist_ratelimit != newopt->rrl_whitelist_ratelimit) | |||
1829 | return 1; | |||
1830 | if(xfrd->nsd->options->rrl_slip != newopt->rrl_slip) | |||
1831 | return 1; | |||
1832 | #else | |||
1833 | (void)xfrd; (void)newopt; | |||
1834 | #endif | |||
1835 | return 0; | |||
1836 | } | |||
1837 | ||||
1838 | /** check if global options have changed */ | |||
1839 | static void | |||
1840 | repat_options(xfrd_state_type* xfrd, struct nsd_options* newopt) | |||
1841 | { | |||
1842 | if(repat_options_changed(xfrd, newopt)) { | |||
1843 | /* update our options */ | |||
1844 | #ifdef RATELIMIT | |||
1845 | xfrd->nsd->options->rrl_ratelimit = newopt->rrl_ratelimit; | |||
1846 | xfrd->nsd->options->rrl_whitelist_ratelimit = newopt->rrl_whitelist_ratelimit; | |||
1847 | xfrd->nsd->options->rrl_slip = newopt->rrl_slip; | |||
1848 | #endif | |||
1849 | task_new_opt_change(xfrd->nsd->task[xfrd->nsd->mytask], | |||
1850 | xfrd->last_task, newopt); | |||
1851 | xfrd_set_reload_now(xfrd); | |||
1852 | } | |||
1853 | } | |||
1854 | ||||
1855 | /** print errors over ssl, gets pointer-to-pointer to ssl, so it can set | |||
1856 | * the pointer to NULL on failure and stop printing */ | |||
1857 | static void | |||
1858 | print_ssl_cfg_err(void* arg, const char* str) | |||
1859 | { | |||
1860 | RES** ssl = (RES**)arg; | |||
1861 | if(!*ssl) return; | |||
1862 | if(!ssl_printf(*ssl, "%s", str)) | |||
1863 | *ssl = NULL((void*)0); /* failed, stop printing */ | |||
1864 | } | |||
1865 | ||||
1866 | /** do the repattern command: reread config file and apply keys, patterns */ | |||
1867 | static void | |||
1868 | do_repattern(RES* ssl, xfrd_state_type* xfrd) | |||
1869 | { | |||
1870 | region_type* region = region_create(xalloc, free); | |||
1871 | struct nsd_options* opt; | |||
1872 | const char* cfgfile = xfrd->nsd->options->configfile; | |||
1873 | ||||
1874 | /* check chroot and configfile, if possible to reread */ | |||
1875 | if(xfrd->nsd->chrootdir) { | |||
1876 | size_t l = strlen(xfrd->nsd->chrootdir); | |||
1877 | while(l>0 && xfrd->nsd->chrootdir[l-1] == '/') | |||
1878 | --l; | |||
1879 | if(strncmp(xfrd->nsd->chrootdir, cfgfile, l) != 0) { | |||
1880 | (void)ssl_printf(ssl, "error %s is not relative to %s: " | |||
1881 | "chroot prevents reread of config\n", | |||
1882 | cfgfile, xfrd->nsd->chrootdir); | |||
1883 | region_destroy(region); | |||
1884 | return; | |||
1885 | } | |||
1886 | cfgfile += l; | |||
1887 | } | |||
1888 | ||||
1889 | (void)ssl_printf(ssl, "reconfig start, read %s\n", cfgfile); | |||
1890 | opt = nsd_options_create(region); | |||
1891 | if(!parse_options_file(opt, cfgfile, &print_ssl_cfg_err, &ssl)) { | |||
1892 | /* error already printed */ | |||
1893 | region_destroy(region); | |||
1894 | return; | |||
1895 | } | |||
1896 | /* check for differences in TSIG keys and patterns, and apply, | |||
1897 | * first the keys, so that pattern->keyptr can be set right. */ | |||
1898 | repat_keys(xfrd, opt); | |||
1899 | repat_patterns(xfrd, opt); | |||
1900 | repat_options(xfrd, opt); | |||
1901 | zonestat_inc_ifneeded(xfrd); | |||
1902 | send_ok(ssl); | |||
1903 | region_destroy(region); | |||
1904 | } | |||
1905 | ||||
1906 | /** do the serverpid command: printout pid of server process */ | |||
1907 | static void | |||
1908 | do_serverpid(RES* ssl, xfrd_state_type* xfrd) | |||
1909 | { | |||
1910 | (void)ssl_printf(ssl, "%u\n", (unsigned)xfrd->reload_pid); | |||
1911 | } | |||
1912 | ||||
1913 | /** do the print_tsig command: printout tsig info */ | |||
1914 | static void | |||
1915 | do_print_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1916 | { | |||
1917 | if(*arg == '\0') { | |||
1918 | struct key_options* key; | |||
1919 | RBTREE_FOR(key, struct key_options*, xfrd->nsd->options->keys)for(key=(struct key_options*)rbtree_first(xfrd->nsd->options ->keys); (rbnode_type*)key != &rbtree_null_node; key = (struct key_options*)rbtree_next((rbnode_type*)key)) { | |||
1920 | if(!ssl_printf(ssl, "key: name: \"%s\" secret: \"%s\" algorithm: %s\n", key->name, key->secret, key->algorithm)) | |||
1921 | return; | |||
1922 | } | |||
1923 | return; | |||
1924 | } else { | |||
1925 | struct key_options* key_opts = key_options_find(xfrd->nsd->options, arg); | |||
1926 | if(!key_opts) { | |||
1927 | (void)ssl_printf(ssl, "error: no such key with name: %s\n", arg); | |||
1928 | return; | |||
1929 | } else { | |||
1930 | (void)ssl_printf(ssl, "key: name: \"%s\" secret: \"%s\" algorithm: %s\n", arg, key_opts->secret, key_opts->algorithm); | |||
1931 | } | |||
1932 | } | |||
1933 | } | |||
1934 | ||||
1935 | /** do the update_tsig command: change existing tsig to new secret */ | |||
1936 | static void | |||
1937 | do_update_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1938 | { | |||
1939 | struct region* region = xfrd->nsd->options->region; | |||
1940 | char* arg2 = NULL((void*)0); | |||
1941 | uint8_t data[65536]; /* 64K */ | |||
1942 | struct key_options* key_opt; | |||
1943 | ||||
1944 | if(*arg == '\0') { | |||
1945 | (void)ssl_printf(ssl, "error: missing argument (keyname)\n"); | |||
1946 | return; | |||
1947 | } | |||
1948 | if(!find_arg2(ssl, arg, &arg2)) { | |||
1949 | (void)ssl_printf(ssl, "error: missing argument (secret)\n"); | |||
1950 | return; | |||
1951 | } | |||
1952 | key_opt = key_options_find(xfrd->nsd->options, arg); | |||
1953 | if(!key_opt) { | |||
1954 | (void)ssl_printf(ssl, "error: no such key with name: %s\n", arg); | |||
1955 | memset(arg2, 0xdd, strlen(arg2)); | |||
1956 | return; | |||
1957 | } | |||
1958 | if(__b64_pton(arg2, data, sizeof(data)) == -1) { | |||
1959 | (void)ssl_printf(ssl, "error: the secret: %s is not in b64 format\n", arg2); | |||
1960 | memset(data, 0xdd, sizeof(data)); /* wipe secret */ | |||
1961 | memset(arg2, 0xdd, strlen(arg2)); | |||
1962 | return; | |||
1963 | } | |||
1964 | log_msg(LOG_INFO6, "changing secret provided with the key: %s with old secret %s and algo: %s\n", arg, key_opt->secret, key_opt->algorithm); | |||
1965 | if(key_opt->secret) { | |||
1966 | /* wipe old secret */ | |||
1967 | memset(key_opt->secret, 0xdd, strlen(key_opt->secret)); | |||
1968 | region_recycle(region, key_opt->secret, | |||
1969 | strlen(key_opt->secret)+1); | |||
1970 | } | |||
1971 | key_opt->secret = region_strdup(region, arg2); | |||
1972 | log_msg(LOG_INFO6, "the key: %s has new secret %s and algorithm: %s\n", arg, key_opt->secret, key_opt->algorithm); | |||
1973 | /* wipe secret from temp parse buffer */ | |||
1974 | memset(arg2, 0xdd, strlen(arg2)); | |||
1975 | memset(data, 0xdd, sizeof(data)); | |||
1976 | ||||
1977 | key_options_desetup(region, key_opt); | |||
1978 | key_options_setup(region, key_opt); | |||
1979 | task_new_add_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, | |||
1980 | key_opt); | |||
1981 | xfrd_set_reload_now(xfrd); | |||
1982 | ||||
1983 | send_ok(ssl); | |||
1984 | } | |||
1985 | ||||
1986 | /** do the add tsig command, add new key with name, secret and algo given */ | |||
1987 | static void | |||
1988 | do_add_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
1989 | { | |||
1990 | char* arg2 = NULL((void*)0); | |||
1991 | char* arg3 = NULL((void*)0); | |||
1992 | uint8_t data[65536]; /* 64KB */ | |||
1993 | uint8_t dname[MAXDOMAINLEN255+1]; | |||
1994 | char algo[256]; | |||
1995 | region_type* region = xfrd->nsd->options->region; | |||
1996 | struct key_options* new_key_opt; | |||
1997 | ||||
1998 | if(*arg == '\0') { | |||
1999 | (void)ssl_printf(ssl, "error: missing argument (keyname)\n"); | |||
2000 | return; | |||
2001 | } | |||
2002 | if(!find_arg3(ssl, arg, &arg2, &arg3)) { | |||
2003 | strlcpy(algo, "hmac-sha256", sizeof(algo)); | |||
2004 | } else { | |||
2005 | strlcpy(algo, arg3, sizeof(algo)); | |||
2006 | } | |||
2007 | if(!arg2) { | |||
2008 | (void)ssl_printf(ssl, "error: missing argument (secret)\n"); | |||
2009 | return; | |||
2010 | } | |||
2011 | if(key_options_find(xfrd->nsd->options, arg)) { | |||
2012 | (void)ssl_printf(ssl, "error: key %s already exists\n", arg); | |||
2013 | memset(arg2, 0xdd, strlen(arg2)); | |||
2014 | return; | |||
2015 | } | |||
2016 | if(__b64_pton(arg2, data, sizeof(data)) == -1) { | |||
2017 | (void)ssl_printf(ssl, "error: the secret: %s is not in b64 format\n", arg2); | |||
2018 | memset(data, 0xdd, sizeof(data)); /* wipe secret */ | |||
2019 | memset(arg2, 0xdd, strlen(arg2)); | |||
2020 | return; | |||
2021 | } | |||
2022 | memset(data, 0xdd, sizeof(data)); /* wipe secret from temp buffer */ | |||
2023 | if(!dname_parse_wire(dname, arg)) { | |||
2024 | (void)ssl_printf(ssl, "error: could not parse key name: %s\n", arg); | |||
2025 | memset(arg2, 0xdd, strlen(arg2)); | |||
2026 | return; | |||
2027 | } | |||
2028 | if(tsig_get_algorithm_by_name(algo) == NULL((void*)0)) { | |||
2029 | (void)ssl_printf(ssl, "error: unknown algorithm: %s\n", algo); | |||
2030 | memset(arg2, 0xdd, strlen(arg2)); | |||
2031 | return; | |||
2032 | } | |||
2033 | log_msg(LOG_INFO6, "adding key with name: %s and secret: %s with algo: %s\n", arg, arg2, algo); | |||
2034 | new_key_opt = key_options_create(region); | |||
2035 | new_key_opt->name = region_strdup(region, arg); | |||
2036 | new_key_opt->secret = region_strdup(region, arg2); | |||
2037 | new_key_opt->algorithm = region_strdup(region, algo); | |||
2038 | add_key(xfrd, new_key_opt); | |||
2039 | ||||
2040 | /* wipe secret from temp buffer */ | |||
2041 | memset(arg2, 0xdd, strlen(arg2)); | |||
2042 | send_ok(ssl); | |||
2043 | } | |||
2044 | ||||
2045 | /** set acl entries to use the given TSIG key */ | |||
2046 | static void | |||
2047 | zopt_set_acl_to_tsig(struct acl_options* acl, struct region* region, | |||
2048 | const char* key_name, struct key_options* key_opt) | |||
2049 | { | |||
2050 | while(acl) { | |||
2051 | if(acl->blocked) { | |||
2052 | acl = acl->next; | |||
2053 | continue; | |||
2054 | } | |||
2055 | acl->nokey = 0; | |||
2056 | if(acl->key_name) | |||
2057 | region_recycle(region, (void*)acl->key_name, | |||
2058 | strlen(acl->key_name)+1); | |||
2059 | acl->key_name = region_strdup(region, key_name); | |||
2060 | acl->key_options = key_opt; | |||
2061 | acl = acl->next; | |||
2062 | } | |||
2063 | } | |||
2064 | ||||
2065 | /** do the assoc_tsig command: associate the zone to use the tsig name */ | |||
2066 | static void | |||
2067 | do_assoc_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) | |||
2068 | { | |||
2069 | region_type* region = xfrd->nsd->options->region; | |||
2070 | char* arg2 = NULL((void*)0); | |||
2071 | struct zone_options* zone; | |||
2072 | struct key_options* key_opt; | |||
2073 | ||||
2074 | if(*arg == '\0') { | |||
2075 | (void)ssl_printf(ssl, "error: missing argument (zonename)\n"); | |||
2076 | return; | |||
2077 | } | |||
2078 | if(!find_arg2(ssl, arg, &arg2)) { | |||
2079 | (void)ssl_printf(ssl, "error: missing argument (keyname)\n"); | |||
2080 | return; | |||
2081 | } | |||
2082 | ||||
2083 | if(!get_zone_arg(ssl, xfrd, arg, &zone)) | |||
2084 | return; | |||
2085 | if(!zone) { | |||
2086 | (void)ssl_printf(ssl, "error: missing argument (zone)\n"); | |||
2087 | return; | |||
2088 | } | |||
2089 | key_opt = key_options_find(xfrd->nsd->options, arg2); | |||
2090 | if(!key_opt) { | |||
2091 | (void)ssl_printf(ssl, "error: key: %s does not exist\n", arg2); | |||
2092 | return; | |||
2093 | } | |||
2094 | ||||
2095 | zopt_set_acl_to_tsig(zone->pattern->allow_notify, region, arg2, | |||
2096 | key_opt); | |||
2097 | zopt_set_acl_to_tsig(zone->pattern->notify, region, arg2, key_opt); | |||
2098 | zopt_set_acl_to_tsig(zone->pattern->request_xfr, region, arg2, | |||
2099 | key_opt); | |||
2100 | zopt_set_acl_to_tsig(zone->pattern->provide_xfr, region, arg2, | |||
2101 | key_opt); | |||
2102 | zopt_set_acl_to_tsig(zone->pattern->allow_query, region, arg2, | |||
2103 | key_opt); | |||
2104 | ||||
2105 | task_new_add_pattern(xfrd->nsd->task[xfrd->nsd->mytask], | |||
2106 | xfrd->last_task, zone->pattern); | |||
2107 | xfrd_set_reload_now(xfrd); | |||
2108 | ||||
2109 | send_ok(ssl); | |||
2110 | } | |||
2111 | ||||
2112 | /** see if TSIG key is used in the acl */ | |||
2113 | static int | |||
2114 | acl_contains_tsig_key(struct acl_options* acl, const char* name) | |||
2115 | { | |||
2116 | while(acl) { | |||
2117 | if(acl->key_name && strcmp(acl->key_name, name) == 0) | |||
2118 | return 1; | |||
2119 | acl = acl->next; | |||
2120 | } | |||
2121 | return 0; | |||
2122 | } | |||
2123 | ||||
2124 | /** do the del_tsig command, remove an (unused) tsig */ | |||
2125 | static void | |||
2126 | do_del_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) { | |||
2127 | int used_key = 0; | |||
2128 | struct zone_options* zone; | |||
2129 | struct key_options* key_opt; | |||
2130 | ||||
2131 | if(*arg == '\0') { | |||
2132 | (void)ssl_printf(ssl, "error: missing argument (keyname)\n"); | |||
2133 | return; | |||
2134 | } | |||
2135 | key_opt = key_options_find(xfrd->nsd->options, arg); | |||
2136 | if(!key_opt) { | |||
2137 | (void)ssl_printf(ssl, "key %s does not exist, nothing to be deleted\n", arg); | |||
2138 | return; | |||
2139 | } | |||
2140 | RBTREE_FOR(zone, struct zone_options*, xfrd->nsd->options->zone_options)for(zone=(struct zone_options*)rbtree_first(xfrd->nsd-> options->zone_options); (rbnode_type*)zone != &rbtree_null_node ; zone = (struct zone_options*)rbtree_next((rbnode_type*)zone )) | |||
2141 | { | |||
2142 | if(acl_contains_tsig_key(zone->pattern->allow_notify, arg) || | |||
2143 | acl_contains_tsig_key(zone->pattern->notify, arg) || | |||
2144 | acl_contains_tsig_key(zone->pattern->request_xfr, arg) || | |||
2145 | acl_contains_tsig_key(zone->pattern->provide_xfr, arg) || | |||
2146 | acl_contains_tsig_key(zone->pattern->allow_query, arg)) { | |||
2147 | if(!ssl_printf(ssl, "zone %s uses key %s\n", | |||
2148 | zone->name, arg)) | |||
2149 | return; | |||
2150 | used_key = 1; | |||
2151 | break; | |||
2152 | } | |||
2153 | } | |||
2154 | ||||
2155 | if(used_key) { | |||
2156 | (void)ssl_printf(ssl, "error: key: %s is in use and cannot be deleted\n", arg); | |||
2157 | return; | |||
2158 | } else { | |||
2159 | remove_key(xfrd, arg); | |||
2160 | log_msg(LOG_INFO6, "key: %s is successfully deleted\n", arg); | |||
2161 | } | |||
2162 | ||||
2163 | send_ok(ssl); | |||
2164 | } | |||
2165 | ||||
2166 | /* returns `0` on failure */ | |||
2167 | static int | |||
2168 | cookie_secret_file_dump(RES* ssl, nsd_type const* nsd) { | |||
2169 | char const* secret_file = nsd->options->cookie_secret_file; | |||
2170 | char secret_hex[NSD_COOKIE_SECRET_SIZE16 * 2 + 1]; | |||
2171 | FILE* f; | |||
2172 | size_t i; | |||
2173 | assert( secret_file != NULL )((void)0); | |||
2174 | ||||
2175 | /* open write only and truncate */ | |||
2176 | if((f = fopen(secret_file, "w")) == NULL((void*)0) ) { | |||
2177 | (void)ssl_printf(ssl, "unable to open cookie secret file %s: %s", | |||
2178 | secret_file, strerror(errno(*__errno()))); | |||
2179 | return 0; | |||
2180 | } | |||
2181 | for(i = 0; i < nsd->cookie_count; i++) { | |||
2182 | struct cookie_secret const* cs = &nsd->cookie_secrets[i]; | |||
2183 | ssize_t const len = hex_ntop(cs->cookie_secret, NSD_COOKIE_SECRET_SIZE16, | |||
2184 | secret_hex, sizeof(secret_hex)); | |||
2185 | (void)len; /* silence unused variable warning with -DNDEBUG */ | |||
2186 | assert( len == NSD_COOKIE_SECRET_SIZE * 2 )((void)0); | |||
2187 | secret_hex[NSD_COOKIE_SECRET_SIZE16 * 2] = '\0'; | |||
2188 | fprintf(f, "%s\n", secret_hex); | |||
2189 | } | |||
2190 | explicit_bzero(secret_hex, sizeof(secret_hex)); | |||
2191 | fclose(f); | |||
2192 | return 1; | |||
2193 | } | |||
2194 | ||||
2195 | static void | |||
2196 | do_activate_cookie_secret(RES* ssl, xfrd_state_type* xrfd, char* arg) { | |||
2197 | nsd_type* nsd = xrfd->nsd; | |||
2198 | (void)arg; | |||
2199 | ||||
2200 | if(nsd->cookie_count <= 1 ) { | |||
2201 | (void)ssl_printf(ssl, "error: no staging cookie secret to activate\n"); | |||
2202 | return; | |||
2203 | } | |||
2204 | if(!nsd->options->cookie_secret_file || !nsd->options->cookie_secret_file[0]) { | |||
2205 | (void)ssl_printf(ssl, "error: no cookie secret file configured\n"); | |||
2206 | return; | |||
2207 | } | |||
2208 | if(!cookie_secret_file_dump(ssl, nsd)) { | |||
2209 | (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n", | |||
2210 | nsd->options->cookie_secret_file); | |||
2211 | return; | |||
2212 | } | |||
2213 | activate_cookie_secret(nsd); | |||
2214 | (void)cookie_secret_file_dump(ssl, nsd); | |||
2215 | task_new_activate_cookie_secret(xfrd->nsd->task[xfrd->nsd->mytask], | |||
2216 | xfrd->last_task); | |||
2217 | xfrd_set_reload_now(xfrd); | |||
2218 | send_ok(ssl); | |||
2219 | } | |||
2220 | ||||
2221 | static void | |||
2222 | do_drop_cookie_secret(RES* ssl, xfrd_state_type* xrfd, char* arg) { | |||
2223 | nsd_type* nsd = xrfd->nsd; | |||
2224 | (void)arg; | |||
2225 | ||||
2226 | if(nsd->cookie_count <= 1 ) { | |||
2227 | (void)ssl_printf(ssl, "error: can not drop the currently active cookie secret\n"); | |||
2228 | return; | |||
2229 | } | |||
2230 | if(!nsd->options->cookie_secret_file || !nsd->options->cookie_secret_file[0]) { | |||
2231 | (void)ssl_printf(ssl, "error: no cookie secret file configured\n"); | |||
2232 | return; | |||
2233 | } | |||
2234 | if(!cookie_secret_file_dump(ssl, nsd)) { | |||
2235 | (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n", | |||
2236 | nsd->options->cookie_secret_file); | |||
2237 | return; | |||
2238 | } | |||
2239 | drop_cookie_secret(nsd); | |||
2240 | (void)cookie_secret_file_dump(ssl, nsd); | |||
2241 | task_new_drop_cookie_secret(xfrd->nsd->task[xfrd->nsd->mytask], | |||
2242 | xfrd->last_task); | |||
2243 | xfrd_set_reload_now(xfrd); | |||
2244 | send_ok(ssl); | |||
2245 | } | |||
2246 | ||||
2247 | static void | |||
2248 | do_add_cookie_secret(RES* ssl, xfrd_state_type* xrfd, char* arg) { | |||
2249 | nsd_type* nsd = xrfd->nsd; | |||
2250 | uint8_t secret[NSD_COOKIE_SECRET_SIZE16]; | |||
2251 | ||||
2252 | if(*arg == '\0') { | |||
2253 | (void)ssl_printf(ssl, "error: missing argument (cookie_secret)\n"); | |||
2254 | return; | |||
2255 | } | |||
2256 | if(strlen(arg) != 32) { | |||
2257 | explicit_bzero(arg, strlen(arg)); | |||
2258 | (void)ssl_printf(ssl, "invalid cookie secret: invalid argument length\n"); | |||
2259 | (void)ssl_printf(ssl, "please provide a 128bit hex encoded secret\n"); | |||
2260 | return; | |||
2261 | } | |||
2262 | if(hex_pton(arg, secret, NSD_COOKIE_SECRET_SIZE16) != NSD_COOKIE_SECRET_SIZE16 ) { | |||
2263 | explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE16); | |||
2264 | explicit_bzero(arg, strlen(arg)); | |||
2265 | (void)ssl_printf(ssl, "invalid cookie secret: parse error\n"); | |||
2266 | (void)ssl_printf(ssl, "please provide a 128bit hex encoded secret\n"); | |||
2267 | return; | |||
2268 | } | |||
2269 | if(!nsd->options->cookie_secret_file || !nsd->options->cookie_secret_file[0]) { | |||
2270 | explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE16); | |||
2271 | explicit_bzero(arg, strlen(arg)); | |||
2272 | (void)ssl_printf(ssl, "error: no cookie secret file configured\n"); | |||
2273 | return; | |||
2274 | } | |||
2275 | if(!cookie_secret_file_dump(ssl, nsd)) { | |||
2276 | explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE16); | |||
2277 | explicit_bzero(arg, strlen(arg)); | |||
2278 | (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n", | |||
2279 | nsd->options->cookie_secret_file); | |||
2280 | return; | |||
2281 | } | |||
2282 | add_cookie_secret(nsd, secret); | |||
2283 | explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE16); | |||
2284 | (void)cookie_secret_file_dump(ssl, nsd); | |||
2285 | task_new_add_cookie_secret(xfrd->nsd->task[xfrd->nsd->mytask], | |||
2286 | xfrd->last_task, arg); | |||
2287 | explicit_bzero(arg, strlen(arg)); | |||
2288 | xfrd_set_reload_now(xfrd); | |||
2289 | send_ok(ssl); | |||
2290 | } | |||
2291 | ||||
2292 | static void | |||
2293 | do_print_cookie_secrets(RES* ssl, xfrd_state_type* xrfd, char* arg) { | |||
2294 | nsd_type* nsd = xrfd->nsd; | |||
2295 | char secret_hex[NSD_COOKIE_SECRET_SIZE16 * 2 + 1]; | |||
2296 | int i; | |||
2297 | (void)arg; | |||
2298 | ||||
2299 | /* (void)ssl_printf(ssl, "cookie_secret_count=%zu\n", nsd->cookie_count); */ | |||
2300 | for(i = 0; (size_t)i < nsd->cookie_count; i++) { | |||
2301 | struct cookie_secret const* cs = &nsd->cookie_secrets[i]; | |||
2302 | ssize_t const len = hex_ntop(cs->cookie_secret, NSD_COOKIE_SECRET_SIZE16, | |||
2303 | secret_hex, sizeof(secret_hex)); | |||
2304 | (void)len; /* silence unused variable warning with -DNDEBUG */ | |||
2305 | assert( len == NSD_COOKIE_SECRET_SIZE * 2 )((void)0); | |||
2306 | secret_hex[NSD_COOKIE_SECRET_SIZE16 * 2] = '\0'; | |||
2307 | if (i == 0) | |||
2308 | (void)ssl_printf(ssl, "active : %s\n", secret_hex); | |||
2309 | else if (nsd->cookie_count == 2) | |||
2310 | (void)ssl_printf(ssl, "staging: %s\n", secret_hex); | |||
2311 | else | |||
2312 | (void)ssl_printf(ssl, "staging[%d]: %s\n", i, secret_hex); | |||
2313 | } | |||
2314 | explicit_bzero(secret_hex, sizeof(secret_hex)); | |||
2315 | } | |||
2316 | ||||
2317 | /** check for name with end-of-string, space or tab after it */ | |||
2318 | static int | |||
2319 | cmdcmp(char* p, const char* cmd, size_t len) | |||
2320 | { | |||
2321 | return strncmp(p,cmd,len)==0 && (p[len]==0||p[len]==' '||p[len]=='\t'); | |||
2322 | } | |||
2323 | ||||
2324 | /** execute a remote control command */ | |||
2325 | static void | |||
2326 | execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd, struct rc_state* rs) | |||
2327 | { | |||
2328 | char* p = skipwhite(cmd); | |||
2329 | /* compare command */ | |||
2330 | if(cmdcmp(p, "stop", 4)) { | |||
2331 | do_stop(ssl, rc->xfrd); | |||
2332 | } else if(cmdcmp(p, "reload", 6)) { | |||
2333 | do_reload(ssl, rc->xfrd, skipwhite(p+6)); | |||
2334 | } else if(cmdcmp(p, "write", 5)) { | |||
2335 | do_write(ssl, rc->xfrd, skipwhite(p+5)); | |||
2336 | } else if(cmdcmp(p, "status", 6)) { | |||
2337 | do_status(ssl, rc->xfrd); | |||
2338 | } else if(cmdcmp(p, "stats_noreset", 13)) { | |||
2339 | do_stats(rc, 1, rs); | |||
2340 | } else if(cmdcmp(p, "stats", 5)) { | |||
2341 | do_stats(rc, 0, rs); | |||
2342 | } else if(cmdcmp(p, "log_reopen", 10)) { | |||
2343 | do_log_reopen(ssl, rc->xfrd); | |||
2344 | } else if(cmdcmp(p, "addzone", 7)) { | |||
2345 | do_addzone(ssl, rc->xfrd, skipwhite(p+7)); | |||
2346 | } else if(cmdcmp(p, "delzone", 7)) { | |||
2347 | do_delzone(ssl, rc->xfrd, skipwhite(p+7)); | |||
2348 | } else if(cmdcmp(p, "changezone", 10)) { | |||
2349 | do_changezone(ssl, rc->xfrd, skipwhite(p+10)); | |||
2350 | } else if(cmdcmp(p, "addzones", 8)) { | |||
2351 | do_addzones(ssl, rc->xfrd); | |||
2352 | } else if(cmdcmp(p, "delzones", 8)) { | |||
2353 | do_delzones(ssl, rc->xfrd); | |||
2354 | } else if(cmdcmp(p, "notify", 6)) { | |||
2355 | do_notify(ssl, rc->xfrd, skipwhite(p+6)); | |||
2356 | } else if(cmdcmp(p, "transfer", 8)) { | |||
2357 | do_transfer(ssl, rc->xfrd, skipwhite(p+8)); | |||
2358 | } else if(cmdcmp(p, "force_transfer", 14)) { | |||
2359 | do_force_transfer(ssl, rc->xfrd, skipwhite(p+14)); | |||
2360 | } else if(cmdcmp(p, "zonestatus", 10)) { | |||
2361 | do_zonestatus(ssl, rc->xfrd, skipwhite(p+10)); | |||
2362 | } else if(cmdcmp(p, "verbosity", 9)) { | |||
2363 | do_verbosity(ssl, skipwhite(p+9)); | |||
2364 | } else if(cmdcmp(p, "repattern", 9)) { | |||
2365 | do_repattern(ssl, rc->xfrd); | |||
2366 | } else if(cmdcmp(p, "reconfig", 8)) { | |||
2367 | do_repattern(ssl, rc->xfrd); | |||
2368 | } else if(cmdcmp(p, "serverpid", 9)) { | |||
2369 | do_serverpid(ssl, rc->xfrd); | |||
2370 | } else if(cmdcmp(p, "print_tsig", 10)) { | |||
2371 | do_print_tsig(ssl, rc->xfrd, skipwhite(p+10)); | |||
2372 | } else if(cmdcmp(p, "update_tsig", 11)) { | |||
2373 | do_update_tsig(ssl, rc->xfrd, skipwhite(p+11)); | |||
2374 | } else if(cmdcmp(p, "add_tsig", 8)) { | |||
2375 | do_add_tsig(ssl, rc->xfrd, skipwhite(p+8)); | |||
2376 | } else if(cmdcmp(p, "assoc_tsig", 10)) { | |||
2377 | do_assoc_tsig(ssl, rc->xfrd, skipwhite(p+10)); | |||
2378 | } else if(cmdcmp(p, "del_tsig", 8)) { | |||
2379 | do_del_tsig(ssl, rc->xfrd, skipwhite(p+8)); | |||
2380 | } else if(cmdcmp(p, "add_cookie_secret", 17)) { | |||
2381 | do_add_cookie_secret(ssl, rc->xfrd, skipwhite(p+17)); | |||
2382 | } else if(cmdcmp(p, "drop_cookie_secret", 18)) { | |||
2383 | do_drop_cookie_secret(ssl, rc->xfrd, skipwhite(p+18)); | |||
2384 | } else if(cmdcmp(p, "print_cookie_secrets", 20)) { | |||
2385 | do_print_cookie_secrets(ssl, rc->xfrd, skipwhite(p+20)); | |||
2386 | } else if(cmdcmp(p, "activate_cookie_secret", 22)) { | |||
2387 | do_activate_cookie_secret(ssl, rc->xfrd, skipwhite(p+22)); | |||
2388 | } else { | |||
2389 | (void)ssl_printf(ssl, "error unknown command '%s'\n", p); | |||
2390 | } | |||
2391 | } | |||
2392 | ||||
2393 | /** handle remote control request */ | |||
2394 | static void | |||
2395 | handle_req(struct daemon_remote* rc, struct rc_state* s, RES* res) | |||
2396 | { | |||
2397 | int r; | |||
2398 | char pre[10]; | |||
2399 | char magic[8]; | |||
2400 | char buf[1024]; | |||
2401 | if (fcntl(s->c.ev_fd, F_SETFL4, 0) == -1) { /* set blocking */ | |||
2402 | log_msg(LOG_ERR3, "cannot fcntl rc: %s", strerror(errno(*__errno()))); | |||
2403 | } | |||
2404 | ||||
2405 | /* try to read magic UBCT[version]_space_ string */ | |||
2406 | if(res->ssl) { | |||
2407 | ERR_clear_error(); | |||
2408 | if((r=SSL_read(res->ssl, magic, (int)sizeof(magic)-1)) <= 0) { | |||
2409 | if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN6) | |||
2410 | return; | |||
2411 | log_crypto_err("could not SSL_read"); | |||
2412 | return; | |||
2413 | } | |||
2414 | } else { | |||
2415 | while(1) { | |||
2416 | ssize_t rr = read(res->fd, magic, sizeof(magic)-1); | |||
2417 | if(rr <= 0) { | |||
2418 | if(rr == 0) return; | |||
2419 | if(errno(*__errno()) == EINTR4 || errno(*__errno()) == EAGAIN35) | |||
2420 | continue; | |||
2421 | log_msg(LOG_ERR3, "could not read: %s", strerror(errno(*__errno()))); | |||
2422 | return; | |||
2423 | } | |||
2424 | r = (int)rr; | |||
2425 | break; | |||
2426 | } | |||
2427 | } | |||
2428 | magic[7] = 0; | |||
2429 | if( r != 7 || strncmp(magic, "NSDCT", 5) != 0) { | |||
2430 | VERBOSITY(2, (LOG_INFO, "control connection has bad header"))do { if ((2) <= verbosity) { log_msg (6, "control connection has bad header" ) ; } } while (0); | |||
2431 | /* probably wrong tool connected, ignore it completely */ | |||
2432 | return; | |||
2433 | } | |||
2434 | ||||
2435 | /* read the command line */ | |||
2436 | if(!ssl_read_line(res, buf, sizeof(buf))) { | |||
2437 | return; | |||
2438 | } | |||
2439 | snprintf(pre, sizeof(pre), "NSDCT%d ", NSD_CONTROL_VERSION1); | |||
2440 | if(strcmp(magic, pre) != 0) { | |||
2441 | VERBOSITY(2, (LOG_INFO, "control connection had bad "do { if ((2) <= verbosity) { log_msg (6, "control connection had bad " "version %s, cmd: %s", magic, buf) ; } } while (0) | |||
2442 | "version %s, cmd: %s", magic, buf))do { if ((2) <= verbosity) { log_msg (6, "control connection had bad " "version %s, cmd: %s", magic, buf) ; } } while (0); | |||
2443 | (void)ssl_printf(res, "error version mismatch\n"); | |||
2444 | return; | |||
2445 | } | |||
2446 | VERBOSITY(2, (LOG_INFO, "control cmd: %s", buf))do { if ((2) <= verbosity) { log_msg (6, "control cmd: %s" , buf) ; } } while (0); | |||
2447 | ||||
2448 | /* figure out what to do */ | |||
2449 | execute_cmd(rc, res, buf, s); | |||
2450 | } | |||
2451 | ||||
2452 | /** handle SSL_do_handshake changes to the file descriptor to wait for later */ | |||
2453 | static void | |||
2454 | remote_handshake_later(struct daemon_remote* rc, struct rc_state* s, int fd, | |||
2455 | int r, int r2) | |||
2456 | { | |||
2457 | if(r2 == SSL_ERROR_WANT_READ2) { | |||
2458 | if(s->shake_state == rc_hs_read) { | |||
2459 | /* try again later */ | |||
2460 | return; | |||
2461 | } | |||
2462 | s->shake_state = rc_hs_read; | |||
2463 | event_del(&s->c); | |||
2464 | memset(&s->c, 0, sizeof(s->c)); | |||
2465 | event_set(&s->c, fd, EV_PERSIST0x10|EV_TIMEOUT0x01|EV_READ0x02, | |||
2466 | remote_control_callback, s); | |||
2467 | if(event_base_set(xfrd->event_base, &s->c) != 0) | |||
2468 | log_msg(LOG_ERR3, "remote_accept: cannot set event_base"); | |||
2469 | if(event_add(&s->c, &s->tval) != 0) | |||
2470 | log_msg(LOG_ERR3, "remote_accept: cannot add event"); | |||
2471 | return; | |||
2472 | } else if(r2 == SSL_ERROR_WANT_WRITE3) { | |||
2473 | if(s->shake_state == rc_hs_write) { | |||
2474 | /* try again later */ | |||
2475 | return; | |||
2476 | } | |||
2477 | s->shake_state = rc_hs_write; | |||
2478 | event_del(&s->c); | |||
2479 | memset(&s->c, 0, sizeof(s->c)); | |||
2480 | event_set(&s->c, fd, EV_PERSIST0x10|EV_TIMEOUT0x01|EV_WRITE0x04, | |||
2481 | remote_control_callback, s); | |||
2482 | if(event_base_set(xfrd->event_base, &s->c) != 0) | |||
2483 | log_msg(LOG_ERR3, "remote_accept: cannot set event_base"); | |||
2484 | if(event_add(&s->c, &s->tval) != 0) | |||
2485 | log_msg(LOG_ERR3, "remote_accept: cannot add event"); | |||
2486 | return; | |||
2487 | } else { | |||
2488 | if(r == 0) | |||
2489 | log_msg(LOG_ERR3, "remote control connection closed prematurely"); | |||
2490 | log_crypto_err("remote control failed ssl"); | |||
2491 | clean_point(rc, s); | |||
2492 | } | |||
2493 | } | |||
2494 | ||||
2495 | static void | |||
2496 | remote_control_callback(int fd, short event, void* arg) | |||
2497 | { | |||
2498 | RES res; | |||
2499 | struct rc_state* s = (struct rc_state*)arg; | |||
2500 | struct daemon_remote* rc = s->rc; | |||
2501 | int r; | |||
2502 | if( (event&EV_TIMEOUT0x01) ) { | |||
2503 | log_msg(LOG_ERR3, "remote control timed out"); | |||
2504 | clean_point(rc, s); | |||
2505 | return; | |||
2506 | } | |||
2507 | if(s->ssl) { | |||
2508 | /* (continue to) setup the SSL connection */ | |||
2509 | ERR_clear_error(); | |||
2510 | r = SSL_do_handshake(s->ssl); | |||
2511 | if(r != 1) { | |||
2512 | int r2 = SSL_get_error(s->ssl, r); | |||
2513 | remote_handshake_later(rc, s, fd, r, r2); | |||
2514 | return; | |||
2515 | } | |||
2516 | s->shake_state = rc_none; | |||
2517 | } | |||
2518 | ||||
2519 | /* once handshake has completed, check authentication */ | |||
2520 | if (!rc->use_cert) { | |||
2521 | VERBOSITY(3, (LOG_INFO, "unauthenticated remote control connection"))do { if ((3) <= verbosity) { log_msg (6, "unauthenticated remote control connection" ) ; } } while (0); | |||
2522 | } else if(SSL_get_verify_result(s->ssl) == X509_V_OK0) { | |||
2523 | X509* x = SSL_get_peer_certificate(s->ssl); | |||
2524 | if(!x) { | |||
2525 | VERBOSITY(2, (LOG_INFO, "remote control connection "do { if ((2) <= verbosity) { log_msg (6, "remote control connection " "provided no client certificate") ; } } while (0) | |||
2526 | "provided no client certificate"))do { if ((2) <= verbosity) { log_msg (6, "remote control connection " "provided no client certificate") ; } } while (0); | |||
2527 | clean_point(rc, s); | |||
2528 | return; | |||
2529 | } | |||
2530 | VERBOSITY(3, (LOG_INFO, "remote control connection authenticated"))do { if ((3) <= verbosity) { log_msg (6, "remote control connection authenticated" ) ; } } while (0); | |||
2531 | X509_free(x); | |||
2532 | } else { | |||
2533 | VERBOSITY(2, (LOG_INFO, "remote control connection failed to "do { if ((2) <= verbosity) { log_msg (6, "remote control connection failed to " "authenticate with client certificate") ; } } while (0) | |||
2534 | "authenticate with client certificate"))do { if ((2) <= verbosity) { log_msg (6, "remote control connection failed to " "authenticate with client certificate") ; } } while (0); | |||
2535 | clean_point(rc, s); | |||
2536 | return; | |||
2537 | } | |||
2538 | ||||
2539 | /* if OK start to actually handle the request */ | |||
2540 | res.ssl = s->ssl; | |||
2541 | res.fd = fd; | |||
2542 | handle_req(rc, s, &res); | |||
2543 | ||||
2544 | if(!s->in_stats_list) { | |||
2545 | VERBOSITY(3, (LOG_INFO, "remote control operation completed"))do { if ((3) <= verbosity) { log_msg (6, "remote control operation completed" ) ; } } while (0); | |||
2546 | clean_point(rc, s); | |||
2547 | } | |||
2548 | } | |||
2549 | ||||
2550 | #ifdef BIND8_STATS | |||
2551 | static const char* | |||
2552 | opcode2str(int o) | |||
2553 | { | |||
2554 | switch(o) { | |||
2555 | case OPCODE_QUERY0: return "QUERY"; | |||
2556 | case OPCODE_IQUERY1: return "IQUERY"; | |||
2557 | case OPCODE_STATUS2: return "STATUS"; | |||
2558 | case OPCODE_NOTIFY4: return "NOTIFY"; | |||
2559 | case OPCODE_UPDATE5: return "UPDATE"; | |||
2560 | default: return "OTHER"; | |||
2561 | } | |||
2562 | } | |||
2563 | ||||
2564 | /** print long number */ | |||
2565 | static int | |||
2566 | print_longnum(RES* ssl, char* desc, uint64_t x) | |||
2567 | { | |||
2568 | if(x > (uint64_t)1024*1024*1024) { | |||
2569 | /* more than a Gb */ | |||
2570 | size_t front = (size_t)(x / (uint64_t)1000000); | |||
2571 | size_t back = (size_t)(x % (uint64_t)1000000); | |||
2572 | return ssl_printf(ssl, "%s%lu%6.6lu\n", desc, | |||
2573 | (unsigned long)front, (unsigned long)back); | |||
2574 | } else { | |||
2575 | return ssl_printf(ssl, "%s%lu\n", desc, (unsigned long)x); | |||
2576 | } | |||
2577 | } | |||
2578 | ||||
2579 | /* print one block of statistics. n is name and d is delimiter */ | |||
2580 | static void | |||
2581 | print_stat_block(RES* ssl, char* n, char* d, struct nsdst* st) | |||
2582 | { | |||
2583 | const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", | |||
2584 | "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", | |||
2585 | "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15", | |||
2586 | "BADVERS" | |||
2587 | }; | |||
2588 | size_t i; | |||
2589 | for(i=0; i<= 255; i++) { | |||
2590 | if(inhibit_zero && st->qtype[i] == 0 && | |||
2591 | strncmp(rrtype_to_string(i), "TYPE", 4) == 0) | |||
2592 | continue; | |||
2593 | if(!ssl_printf(ssl, "%s%snum.type.%s=%lu\n", n, d, | |||
2594 | rrtype_to_string(i), (unsigned long)st->qtype[i])) | |||
2595 | return; | |||
2596 | } | |||
2597 | ||||
2598 | /* opcode */ | |||
2599 | for(i=0; i<6; i++) { | |||
2600 | if(inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY0) | |||
2601 | continue; | |||
2602 | if(!ssl_printf(ssl, "%s%snum.opcode.%s=%lu\n", n, d, | |||
2603 | opcode2str(i), (unsigned long)st->opcode[i])) | |||
2604 | return; | |||
2605 | } | |||
2606 | ||||
2607 | /* qclass */ | |||
2608 | for(i=0; i<4; i++) { | |||
2609 | if(inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN1) | |||
2610 | continue; | |||
2611 | if(!ssl_printf(ssl, "%s%snum.class.%s=%lu\n", n, d, | |||
2612 | rrclass_to_string(i), (unsigned long)st->qclass[i])) | |||
2613 | return; | |||
2614 | } | |||
2615 | ||||
2616 | /* rcode */ | |||
2617 | for(i=0; i<17; i++) { | |||
2618 | if(inhibit_zero && st->rcode[i] == 0 && | |||
2619 | i > RCODE_YXDOMAIN6) /* NSD does not use larger */ | |||
2620 | continue; | |||
2621 | if(!ssl_printf(ssl, "%s%snum.rcode.%s=%lu\n", n, d, rcstr[i], | |||
2622 | (unsigned long)st->rcode[i])) | |||
2623 | return; | |||
2624 | } | |||
2625 | ||||
2626 | /* edns */ | |||
2627 | if(!ssl_printf(ssl, "%s%snum.edns=%lu\n", n, d, (unsigned long)st->edns)) | |||
2628 | return; | |||
2629 | ||||
2630 | /* ednserr */ | |||
2631 | if(!ssl_printf(ssl, "%s%snum.ednserr=%lu\n", n, d, | |||
2632 | (unsigned long)st->ednserr)) | |||
2633 | return; | |||
2634 | ||||
2635 | /* qudp */ | |||
2636 | if(!ssl_printf(ssl, "%s%snum.udp=%lu\n", n, d, (unsigned long)st->qudp)) | |||
2637 | return; | |||
2638 | /* qudp6 */ | |||
2639 | if(!ssl_printf(ssl, "%s%snum.udp6=%lu\n", n, d, (unsigned long)st->qudp6)) | |||
2640 | return; | |||
2641 | /* ctcp */ | |||
2642 | if(!ssl_printf(ssl, "%s%snum.tcp=%lu\n", n, d, (unsigned long)st->ctcp)) | |||
2643 | return; | |||
2644 | /* ctcp6 */ | |||
2645 | if(!ssl_printf(ssl, "%s%snum.tcp6=%lu\n", n, d, (unsigned long)st->ctcp6)) | |||
2646 | return; | |||
2647 | /* ctls */ | |||
2648 | if(!ssl_printf(ssl, "%s%snum.tls=%lu\n", n, d, (unsigned long)st->ctls)) | |||
2649 | return; | |||
2650 | /* ctls6 */ | |||
2651 | if(!ssl_printf(ssl, "%s%snum.tls6=%lu\n", n, d, (unsigned long)st->ctls6)) | |||
2652 | return; | |||
2653 | ||||
2654 | /* nona */ | |||
2655 | if(!ssl_printf(ssl, "%s%snum.answer_wo_aa=%lu\n", n, d, | |||
2656 | (unsigned long)st->nona)) | |||
2657 | return; | |||
2658 | ||||
2659 | /* rxerr */ | |||
2660 | if(!ssl_printf(ssl, "%s%snum.rxerr=%lu\n", n, d, (unsigned long)st->rxerr)) | |||
2661 | return; | |||
2662 | ||||
2663 | /* txerr */ | |||
2664 | if(!ssl_printf(ssl, "%s%snum.txerr=%lu\n", n, d, (unsigned long)st->txerr)) | |||
2665 | return; | |||
2666 | ||||
2667 | /* number of requested-axfr, number of times axfr served to clients */ | |||
2668 | if(!ssl_printf(ssl, "%s%snum.raxfr=%lu\n", n, d, (unsigned long)st->raxfr)) | |||
2669 | return; | |||
2670 | ||||
2671 | /* truncated */ | |||
2672 | if(!ssl_printf(ssl, "%s%snum.truncated=%lu\n", n, d, | |||
2673 | (unsigned long)st->truncated)) | |||
2674 | return; | |||
2675 | ||||
2676 | /* dropped */ | |||
2677 | if(!ssl_printf(ssl, "%s%snum.dropped=%lu\n", n, d, | |||
2678 | (unsigned long)st->dropped)) | |||
2679 | return; | |||
2680 | } | |||
2681 | ||||
2682 | #ifdef USE_ZONE_STATS | |||
2683 | static void | |||
2684 | resize_zonestat(xfrd_state_type* xfrd, size_t num) | |||
2685 | { | |||
2686 | struct nsdst** a = xalloc_array_zero(num, sizeof(struct nsdst*)); | |||
2687 | if(xfrd->zonestat_clear_num != 0) | |||
2688 | memcpy(a, xfrd->zonestat_clear, xfrd->zonestat_clear_num | |||
2689 | * sizeof(struct nsdst*)); | |||
2690 | free(xfrd->zonestat_clear); | |||
2691 | xfrd->zonestat_clear = a; | |||
2692 | xfrd->zonestat_clear_num = num; | |||
2693 | } | |||
2694 | ||||
2695 | static void | |||
2696 | zonestat_print(RES* ssl, xfrd_state_type* xfrd, int clear) | |||
2697 | { | |||
2698 | struct zonestatname* n; | |||
2699 | struct nsdst stat0, stat1; | |||
2700 | RBTREE_FOR(n, struct zonestatname*, xfrd->nsd->options->zonestatnames)for(n=(struct zonestatname*)rbtree_first(xfrd->nsd->options ->zonestatnames); (rbnode_type*)n != &rbtree_null_node ; n = (struct zonestatname*)rbtree_next((rbnode_type*)n)){ | |||
2701 | char* name = (char*)n->node.key; | |||
2702 | if(n->id >= xfrd->zonestat_safe) | |||
2703 | continue; /* newly allocated and reload has not yet | |||
2704 | done and replied with new size */ | |||
2705 | if(name == NULL((void*)0) || name[0]==0) | |||
2706 | continue; /* empty name, do not output */ | |||
2707 | /* the statistics are stored in two blocks, during reload | |||
2708 | * the newly forked processes get the other block to use, | |||
2709 | * these blocks are mmapped and are currently in use to | |||
2710 | * add statistics to */ | |||
2711 | memcpy(&stat0, &xfrd->nsd->zonestat[0][n->id], sizeof(stat0)); | |||
2712 | memcpy(&stat1, &xfrd->nsd->zonestat[1][n->id], sizeof(stat1)); | |||
2713 | stats_add(&stat0, &stat1); | |||
2714 | ||||
2715 | /* save a copy of current (cumulative) stats in stat1 */ | |||
2716 | memcpy(&stat1, &stat0, sizeof(stat1)); | |||
2717 | /* subtract last total of stats that was 'cleared' */ | |||
2718 | if(n->id < xfrd->zonestat_clear_num && | |||
2719 | xfrd->zonestat_clear[n->id]) | |||
2720 | stats_subtract(&stat0, xfrd->zonestat_clear[n->id]); | |||
2721 | if(clear) { | |||
2722 | /* extend storage array if needed */ | |||
2723 | if(n->id >= xfrd->zonestat_clear_num) { | |||
2724 | if(n->id+1 < xfrd->nsd->options->zonestatnames->count) | |||
2725 | resize_zonestat(xfrd, xfrd->nsd->options->zonestatnames->count); | |||
2726 | else | |||
2727 | resize_zonestat(xfrd, n->id+1); | |||
2728 | } | |||
2729 | if(!xfrd->zonestat_clear[n->id]) | |||
2730 | xfrd->zonestat_clear[n->id] = xalloc( | |||
2731 | sizeof(struct nsdst)); | |||
2732 | /* store last total of stats */ | |||
2733 | memcpy(xfrd->zonestat_clear[n->id], &stat1, | |||
2734 | sizeof(struct nsdst)); | |||
2735 | } | |||
2736 | ||||
2737 | /* stat0 contains the details that we want to print */ | |||
2738 | if(!ssl_printf(ssl, "%s%snum.queries=%lu\n", name, ".", | |||
2739 | (unsigned long)(stat0.qudp + stat0.qudp6 + stat0.ctcp + | |||
2740 | stat0.ctcp6 + stat0.ctls + stat0.ctls6))) | |||
2741 | return; | |||
2742 | print_stat_block(ssl, name, ".", &stat0); | |||
2743 | } | |||
2744 | } | |||
2745 | #endif /* USE_ZONE_STATS */ | |||
2746 | ||||
2747 | static void | |||
2748 | print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear) | |||
2749 | { | |||
2750 | size_t i; | |||
2751 | stc_type total = 0; | |||
2752 | struct timeval elapsed, uptime; | |||
2753 | ||||
2754 | /* per CPU and total */ | |||
2755 | for(i=0; i<xfrd->nsd->child_count; i++) { | |||
2756 | if(!ssl_printf(ssl, "server%d.queries=%lu\n", (int)i, | |||
2757 | (unsigned long)xfrd->nsd->children[i].query_count)) | |||
2758 | return; | |||
2759 | total += xfrd->nsd->children[i].query_count; | |||
2760 | } | |||
2761 | if(!ssl_printf(ssl, "num.queries=%lu\n", (unsigned long)total)) | |||
2762 | return; | |||
2763 | ||||
2764 | /* time elapsed and uptime (in seconds) */ | |||
2765 | timeval_subtract(&uptime, now, &xfrd->nsd->rc->boot_time); | |||
2766 | timeval_subtract(&elapsed, now, &xfrd->nsd->rc->stats_time); | |||
2767 | if(!ssl_printf(ssl, "time.boot=%lu.%6.6lu\n", | |||
2768 | (unsigned long)uptime.tv_sec, (unsigned long)uptime.tv_usec)) | |||
2769 | return; | |||
2770 | if(!ssl_printf(ssl, "time.elapsed=%lu.%6.6lu\n", | |||
2771 | (unsigned long)elapsed.tv_sec, (unsigned long)elapsed.tv_usec)) | |||
2772 | return; | |||
2773 | ||||
2774 | /* mem info, database on disksize */ | |||
2775 | if(!print_longnum(ssl, "size.db.disk=", xfrd->nsd->st.db_disk)) | |||
2776 | return; | |||
2777 | if(!print_longnum(ssl, "size.db.mem=", xfrd->nsd->st.db_mem)) | |||
2778 | return; | |||
2779 | if(!print_longnum(ssl, "size.xfrd.mem=", region_get_mem(xfrd->region))) | |||
2780 | return; | |||
2781 | if(!print_longnum(ssl, "size.config.disk=", | |||
2782 | xfrd->nsd->options->zonelist_off)) | |||
2783 | return; | |||
2784 | if(!print_longnum(ssl, "size.config.mem=", region_get_mem( | |||
2785 | xfrd->nsd->options->region))) | |||
2786 | return; | |||
2787 | print_stat_block(ssl, "", "", &xfrd->nsd->st); | |||
2788 | ||||
2789 | /* zone statistics */ | |||
2790 | if(!ssl_printf(ssl, "zone.master=%lu\n", | |||
2791 | (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count))) | |||
2792 | return; | |||
2793 | if(!ssl_printf(ssl, "zone.slave=%lu\n", (unsigned long)xfrd->zones->count)) | |||
2794 | return; | |||
2795 | #ifdef USE_ZONE_STATS | |||
2796 | zonestat_print(ssl, xfrd, clear); /* per-zone statistics */ | |||
2797 | #else | |||
2798 | (void)clear; | |||
2799 | #endif | |||
2800 | } | |||
2801 | ||||
2802 | static void | |||
2803 | clear_stats(xfrd_state_type* xfrd) | |||
2804 | { | |||
2805 | size_t i; | |||
2806 | uint64_t dbd = xfrd->nsd->st.db_disk; | |||
2807 | uint64_t dbm = xfrd->nsd->st.db_mem; | |||
2808 | for(i=0; i<xfrd->nsd->child_count; i++) { | |||
2809 | xfrd->nsd->children[i].query_count = 0; | |||
2810 | } | |||
2811 | memset(&xfrd->nsd->st, 0, sizeof(struct nsdst)); | |||
2812 | /* zonestats are cleared by storing the cumulative value that | |||
2813 | * was last printed in the zonestat_clear array, and subtracting | |||
2814 | * that before the next stats printout */ | |||
2815 | xfrd->nsd->st.db_disk = dbd; | |||
2816 | xfrd->nsd->st.db_mem = dbm; | |||
2817 | } | |||
2818 | ||||
2819 | void | |||
2820 | daemon_remote_process_stats(struct daemon_remote* rc) | |||
2821 | { | |||
2822 | RES res; | |||
2823 | struct rc_state* s; | |||
2824 | struct timeval now; | |||
2825 | if(!rc) return; | |||
2826 | if(gettimeofday(&now, NULL((void*)0)) == -1) | |||
2827 | log_msg(LOG_ERR3, "gettimeofday: %s", strerror(errno(*__errno()))); | |||
2828 | /* pop one and give it stats */ | |||
2829 | while((s = rc->stats_list)) { | |||
2830 | assert(s->in_stats_list)((void)0); | |||
2831 | res.ssl = s->ssl; | |||
2832 | res.fd = s->fd; | |||
2833 | print_stats(&res, rc->xfrd, &now, (s->in_stats_list == 1)); | |||
2834 | if(s->in_stats_list == 1) { | |||
2835 | clear_stats(rc->xfrd); | |||
2836 | rc->stats_time = now; | |||
2837 | } | |||
2838 | VERBOSITY(3, (LOG_INFO, "remote control stats printed"))do { if ((3) <= verbosity) { log_msg (6, "remote control stats printed" ) ; } } while (0); | |||
2839 | rc->stats_list = s->next; | |||
2840 | s->in_stats_list = 0; | |||
2841 | clean_point(rc, s); | |||
2842 | } | |||
2843 | } | |||
2844 | #endif /* BIND8_STATS */ | |||
2845 | ||||
2846 | int | |||
2847 | create_local_accept_sock(const char *path, int* noproto) | |||
2848 | { | |||
2849 | #ifdef HAVE_SYS_UN_H1 | |||
2850 | int s; | |||
2851 | struct sockaddr_un usock; | |||
2852 | ||||
2853 | VERBOSITY(3, (LOG_INFO, "creating unix socket %s", path))do { if ((3) <= verbosity) { log_msg (6, "creating unix socket %s" , path) ; } } while (0); | |||
2854 | #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN1 | |||
2855 | /* this member exists on BSDs, not Linux */ | |||
2856 | usock.sun_len = (unsigned)sizeof(usock); | |||
2857 | #endif | |||
2858 | usock.sun_family = AF_LOCAL1; | |||
2859 | /* length is 92-108, 104 on FreeBSD */ | |||
2860 | (void)strlcpy(usock.sun_path, path, sizeof(usock.sun_path)); | |||
2861 | ||||
2862 | if ((s = socket(AF_LOCAL1, SOCK_STREAM1, 0)) == -1) { | |||
2863 | log_msg(LOG_ERR3, "Cannot create local socket %s (%s)", | |||
2864 | path, strerror(errno(*__errno()))); | |||
2865 | return -1; | |||
2866 | } | |||
2867 | ||||
2868 | if (unlink(path) && errno(*__errno()) != ENOENT2) { | |||
2869 | /* The socket already exists and cannot be removed */ | |||
2870 | log_msg(LOG_ERR3, "Cannot remove old local socket %s (%s)", | |||
2871 | path, strerror(errno(*__errno()))); | |||
2872 | goto err; | |||
2873 | } | |||
2874 | ||||
2875 | if (bind(s, (struct sockaddr *)&usock, | |||
2876 | (socklen_t)sizeof(struct sockaddr_un)) == -1) { | |||
2877 | log_msg(LOG_ERR3, "Cannot bind local socket %s (%s)", | |||
2878 | path, strerror(errno(*__errno()))); | |||
2879 | goto err; | |||
2880 | } | |||
2881 | ||||
2882 | if (fcntl(s, F_SETFL4, O_NONBLOCK0x0004) == -1) { | |||
2883 | log_msg(LOG_ERR3, "Cannot set non-blocking mode"); | |||
2884 | goto err; | |||
2885 | } | |||
2886 | ||||
2887 | if (listen(s, TCP_BACKLOG256) == -1) { | |||
2888 | log_msg(LOG_ERR3, "can't listen: %s", strerror(errno(*__errno()))); | |||
2889 | goto err; | |||
2890 | } | |||
2891 | ||||
2892 | (void)noproto; /*unused*/ | |||
2893 | return s; | |||
2894 | ||||
2895 | err: | |||
2896 | close(s); | |||
2897 | return -1; | |||
2898 | ||||
2899 | #else | |||
2900 | (void)path; | |||
2901 | log_msg(LOG_ERR3, "Local sockets are not supported"); | |||
2902 | *noproto = 1; | |||
2903 | return -1; | |||
2904 | #endif | |||
2905 | } | |||
2906 | ||||
2907 | #endif /* HAVE_SSL */ |