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