1d3fecca9Ssthen /*
2d3fecca9Ssthen * remote.c - remote control for the NSD daemon.
3d3fecca9Ssthen *
4d3fecca9Ssthen * Copyright (c) 2008, NLnet Labs. All rights reserved.
5d3fecca9Ssthen *
6d3fecca9Ssthen * This software is open source.
7d3fecca9Ssthen *
8d3fecca9Ssthen * Redistribution and use in source and binary forms, with or without
9d3fecca9Ssthen * modification, are permitted provided that the following conditions
10d3fecca9Ssthen * are met:
11d3fecca9Ssthen *
12d3fecca9Ssthen * Redistributions of source code must retain the above copyright notice,
13d3fecca9Ssthen * this list of conditions and the following disclaimer.
14d3fecca9Ssthen *
15d3fecca9Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16d3fecca9Ssthen * this list of conditions and the following disclaimer in the documentation
17d3fecca9Ssthen * and/or other materials provided with the distribution.
18d3fecca9Ssthen *
19d3fecca9Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20d3fecca9Ssthen * be used to endorse or promote products derived from this software without
21d3fecca9Ssthen * specific prior written permission.
22d3fecca9Ssthen *
23d3fecca9Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24cbbc2d6cSbrad * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25cbbc2d6cSbrad * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26cbbc2d6cSbrad * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27cbbc2d6cSbrad * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28cbbc2d6cSbrad * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29cbbc2d6cSbrad * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30cbbc2d6cSbrad * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31cbbc2d6cSbrad * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32cbbc2d6cSbrad * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33cbbc2d6cSbrad * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34d3fecca9Ssthen */
35d3fecca9Ssthen
36d3fecca9Ssthen /**
37d3fecca9Ssthen * \file
38d3fecca9Ssthen *
39d3fecca9Ssthen * This file contains the remote control functionality for the daemon.
40d3fecca9Ssthen * The remote control can be performed using either the commandline
41c1404d4fSbrad * nsd-control tool, or a TLS capable web browser.
42c1404d4fSbrad * The channel is secured using TLSv1, and certificates.
43d3fecca9Ssthen * Both the server and the client(control tool) have their own keys.
44d3fecca9Ssthen */
45d3fecca9Ssthen #include "config.h"
46d3fecca9Ssthen
473efee2e1Sflorian #ifdef HAVE_SSL
48d3fecca9Ssthen #ifdef HAVE_OPENSSL_SSL_H
493efee2e1Sflorian #include <openssl/ssl.h>
50d3fecca9Ssthen #endif
51d3fecca9Ssthen #ifdef HAVE_OPENSSL_ERR_H
52d3fecca9Ssthen #include <openssl/err.h>
53d3fecca9Ssthen #endif
54cdb6bbddSbrad #ifdef HAVE_OPENSSL_RAND_H
55cdb6bbddSbrad #include <openssl/rand.h>
56cdb6bbddSbrad #endif
573efee2e1Sflorian #endif /* HAVE_SSL */
58d3fecca9Ssthen #include <ctype.h>
59d3fecca9Ssthen #include <unistd.h>
60d3fecca9Ssthen #include <assert.h>
61d3fecca9Ssthen #include <fcntl.h>
623efee2e1Sflorian #include <errno.h>
63d3fecca9Ssthen #ifndef USE_MINI_EVENT
64cbbc2d6cSbrad # ifdef HAVE_EVENT_H
65d3fecca9Ssthen # include <event.h>
66d3fecca9Ssthen # else
67cbbc2d6cSbrad # include <event2/event.h>
68cbbc2d6cSbrad # include "event2/event_struct.h"
69cbbc2d6cSbrad # include "event2/event_compat.h"
70cbbc2d6cSbrad # endif
71cbbc2d6cSbrad #else
72d3fecca9Ssthen # include "mini_event.h"
73d3fecca9Ssthen #endif
74d3fecca9Ssthen #include "remote.h"
75d3fecca9Ssthen #include "util.h"
76d3fecca9Ssthen #include "xfrd.h"
77*bf87c3c0Sflorian #include "xfrd-catalog-zones.h"
78d3fecca9Ssthen #include "xfrd-notify.h"
79d3fecca9Ssthen #include "xfrd-tcp.h"
80d3fecca9Ssthen #include "nsd.h"
81d3fecca9Ssthen #include "options.h"
82d3fecca9Ssthen #include "difffile.h"
83d3fecca9Ssthen #include "ipc.h"
84d3fecca9Ssthen
85d3fecca9Ssthen #ifdef HAVE_SYS_TYPES_H
86d3fecca9Ssthen # include <sys/types.h>
87d3fecca9Ssthen #endif
8818e77612Sflorian #ifdef HAVE_SYS_STAT_H
8918e77612Sflorian # include <sys/stat.h>
9018e77612Sflorian #endif
91d3fecca9Ssthen #ifdef HAVE_NETDB_H
92d3fecca9Ssthen # include <netdb.h>
93d3fecca9Ssthen #endif
9418e77612Sflorian #ifdef HAVE_SYS_UN_H
9518e77612Sflorian # include <sys/un.h>
9618e77612Sflorian #endif
978d298c9fSsthen #ifndef AF_LOCAL
988d298c9fSsthen #define AF_LOCAL AF_UNIX
998d298c9fSsthen #endif
100d3fecca9Ssthen
101d3fecca9Ssthen /** number of seconds timeout on incoming remote control handshake */
102d3fecca9Ssthen #define REMOTE_CONTROL_TCP_TIMEOUT 120
103d3fecca9Ssthen
104d3fecca9Ssthen /** repattern to master or slave */
105d3fecca9Ssthen #define REPAT_SLAVE 1
106d3fecca9Ssthen #define REPAT_MASTER 2
107*bf87c3c0Sflorian #define REPAT_CATALOG_CONSUMER 4
108*bf87c3c0Sflorian #define REPAT_CATALOG_CONSUMER_DEINIT 8
109d3fecca9Ssthen
110d3fecca9Ssthen /** if you want zero to be inhibited in stats output.
111d3fecca9Ssthen * it omits zeroes for types that have no acronym and unused-rcodes */
112d3fecca9Ssthen const int inhibit_zero = 1;
113d3fecca9Ssthen
114d3fecca9Ssthen /**
115d3fecca9Ssthen * a busy control command connection, SSL state
116d3fecca9Ssthen * Defined here to keep the definition private, and keep SSL out of the .h
117d3fecca9Ssthen */
118d3fecca9Ssthen struct rc_state {
119d3fecca9Ssthen /** the next item in list */
120d3fecca9Ssthen struct rc_state* next, *prev;
121d3fecca9Ssthen /* if the event was added to the event_base */
122d3fecca9Ssthen int event_added;
123d3fecca9Ssthen /** the commpoint */
124d3fecca9Ssthen struct event c;
125d3fecca9Ssthen /** timeout for this state */
126d3fecca9Ssthen struct timeval tval;
127d3fecca9Ssthen /** in the handshake part */
128d3fecca9Ssthen enum { rc_none, rc_hs_read, rc_hs_write } shake_state;
1293efee2e1Sflorian #ifdef HAVE_SSL
130d3fecca9Ssthen /** the ssl state */
131d3fecca9Ssthen SSL* ssl;
1323efee2e1Sflorian #endif
13318e77612Sflorian /** file descriptor */
13418e77612Sflorian int fd;
135d3fecca9Ssthen /** the rc this is part of */
136d3fecca9Ssthen struct daemon_remote* rc;
137d3fecca9Ssthen /** stats list next item */
138d3fecca9Ssthen struct rc_state* stats_next;
139d3fecca9Ssthen };
140d3fecca9Ssthen
141d3fecca9Ssthen /**
142d3fecca9Ssthen * list of events for accepting connections
143d3fecca9Ssthen */
144d3fecca9Ssthen struct acceptlist {
145d3fecca9Ssthen struct acceptlist* next;
146d3fecca9Ssthen int event_added;
147d3fecca9Ssthen struct event c;
1484b6a9f59Sflorian char* ident;
1494b6a9f59Sflorian struct daemon_remote* rc;
150d3fecca9Ssthen };
151d3fecca9Ssthen
152d3fecca9Ssthen /**
153d3fecca9Ssthen * The remote control state.
154d3fecca9Ssthen */
155d3fecca9Ssthen struct daemon_remote {
156d3fecca9Ssthen /** the master process for this remote control */
157d3fecca9Ssthen struct xfrd_state* xfrd;
158d3fecca9Ssthen /** commpoints for accepting remote control connections */
159d3fecca9Ssthen struct acceptlist* accept_list;
16018e77612Sflorian /* if certificates are used */
16118e77612Sflorian int use_cert;
162d3fecca9Ssthen /** number of active commpoints that are handling remote control */
163d3fecca9Ssthen int active;
164d3fecca9Ssthen /** max active commpoints */
165d3fecca9Ssthen int max_active;
166d3fecca9Ssthen /** current commpoints busy; double linked, malloced */
167d3fecca9Ssthen struct rc_state* busy_list;
168d3fecca9Ssthen /** last time stats was reported */
169d3fecca9Ssthen struct timeval stats_time, boot_time;
1703efee2e1Sflorian #ifdef HAVE_SSL
171d3fecca9Ssthen /** the SSL context for creating new SSL streams */
172d3fecca9Ssthen SSL_CTX* ctx;
1733efee2e1Sflorian #endif
174d3fecca9Ssthen };
175d3fecca9Ssthen
176d3fecca9Ssthen /**
17718e77612Sflorian * Connection to print to, either SSL or plain over fd
17818e77612Sflorian */
17918e77612Sflorian struct remote_stream {
1803efee2e1Sflorian #ifdef HAVE_SSL
18118e77612Sflorian /** SSL structure, nonNULL if using SSL */
18218e77612Sflorian SSL* ssl;
1833efee2e1Sflorian #endif
18418e77612Sflorian /** file descriptor for plain transfer */
18518e77612Sflorian int fd;
18618e77612Sflorian };
18718e77612Sflorian typedef struct remote_stream RES;
18818e77612Sflorian
18918e77612Sflorian /**
190d3fecca9Ssthen * Print fixed line of text over ssl connection in blocking mode
19118e77612Sflorian * @param res: print to
192d3fecca9Ssthen * @param text: the text.
193d3fecca9Ssthen * @return false on connection failure.
194d3fecca9Ssthen */
19518e77612Sflorian static int ssl_print_text(RES* res, const char* text);
196d3fecca9Ssthen
197d3fecca9Ssthen /**
198d3fecca9Ssthen * printf style printing to the ssl connection
19918e77612Sflorian * @param res: the RES connection to print to. Blocking.
200d3fecca9Ssthen * @param format: printf style format string.
201d3fecca9Ssthen * @return success or false on a network failure.
202d3fecca9Ssthen */
20318e77612Sflorian static int ssl_printf(RES* res, const char* format, ...)
204d3fecca9Ssthen ATTR_FORMAT(printf, 2, 3);
205d3fecca9Ssthen
206d3fecca9Ssthen /**
207d3fecca9Ssthen * Read until \n is encountered
20818e77612Sflorian * If stream signals EOF, the string up to then is returned (without \n).
20918e77612Sflorian * @param res: the RES connection to read from. blocking.
210d3fecca9Ssthen * @param buf: buffer to read to.
211d3fecca9Ssthen * @param max: size of buffer.
212d3fecca9Ssthen * @return false on connection failure.
213d3fecca9Ssthen */
21418e77612Sflorian static int ssl_read_line(RES* res, char* buf, size_t max);
215d3fecca9Ssthen
216d3fecca9Ssthen /** perform the accept of a new remote control connection */
217d3fecca9Ssthen static void
218d3fecca9Ssthen remote_accept_callback(int fd, short event, void* arg);
219d3fecca9Ssthen
220d3fecca9Ssthen /** perform remote control */
221d3fecca9Ssthen static void
222d3fecca9Ssthen remote_control_callback(int fd, short event, void* arg);
223d3fecca9Ssthen
224b71395eaSflorian #ifdef BIND8_STATS
225b71395eaSflorian /* process the statistics and output them */
226b71395eaSflorian static void process_stats(RES* ssl, xfrd_state_type* xfrd, int peek);
227b71395eaSflorian #endif
228d3fecca9Ssthen
229d3fecca9Ssthen /** ---- end of private defines ---- **/
230d3fecca9Ssthen
2313efee2e1Sflorian #ifdef HAVE_SSL
232d3fecca9Ssthen /** log ssl crypto err */
233d3fecca9Ssthen static void
log_crypto_err(const char * str)234d3fecca9Ssthen log_crypto_err(const char* str)
235d3fecca9Ssthen {
236d3fecca9Ssthen /* error:[error code]:[library name]:[function name]:[reason string] */
237d3fecca9Ssthen char buf[128];
238d3fecca9Ssthen unsigned long e;
239d3fecca9Ssthen ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
240d3fecca9Ssthen log_msg(LOG_ERR, "%s crypto %s", str, buf);
241d3fecca9Ssthen while( (e=ERR_get_error()) ) {
242d3fecca9Ssthen ERR_error_string_n(e, buf, sizeof(buf));
243d3fecca9Ssthen log_msg(LOG_ERR, "and additionally crypto %s", buf);
244d3fecca9Ssthen }
245d3fecca9Ssthen }
2463efee2e1Sflorian #endif /* HAVE_SSL */
247d3fecca9Ssthen
248d3fecca9Ssthen #ifdef BIND8_STATS
249d3fecca9Ssthen /** subtract timers and the values do not overflow or become negative */
250d3fecca9Ssthen static void
timeval_subtract(struct timeval * d,const struct timeval * end,const struct timeval * start)251d3fecca9Ssthen timeval_subtract(struct timeval* d, const struct timeval* end,
252d3fecca9Ssthen const struct timeval* start)
253d3fecca9Ssthen {
254d3fecca9Ssthen #ifndef S_SPLINT_S
255d3fecca9Ssthen time_t end_usec = end->tv_usec;
256d3fecca9Ssthen d->tv_sec = end->tv_sec - start->tv_sec;
257d3fecca9Ssthen if(end_usec < start->tv_usec) {
258d3fecca9Ssthen end_usec += 1000000;
259d3fecca9Ssthen d->tv_sec--;
260d3fecca9Ssthen }
261d3fecca9Ssthen d->tv_usec = end_usec - start->tv_usec;
262d3fecca9Ssthen #endif
263d3fecca9Ssthen }
264d3fecca9Ssthen #endif /* BIND8_STATS */
265d3fecca9Ssthen
2663efee2e1Sflorian #ifdef HAVE_SSL
26718e77612Sflorian static int
remote_setup_ctx(struct daemon_remote * rc,struct nsd_options * cfg)26818e77612Sflorian remote_setup_ctx(struct daemon_remote* rc, struct nsd_options* cfg)
269d3fecca9Ssthen {
270eab1363eSsthen char* s_cert = cfg->server_cert_file;
271eab1363eSsthen char* s_key = cfg->server_key_file;
272eab1363eSsthen rc->ctx = server_tls_ctx_setup(s_key, s_cert, s_cert);
27318e77612Sflorian if(!rc->ctx) {
274eab1363eSsthen log_msg(LOG_ERR, "could not setup remote control TLS context");
27518e77612Sflorian return 0;
27618e77612Sflorian }
27718e77612Sflorian return 1;
27818e77612Sflorian }
2793efee2e1Sflorian #endif /* HAVE_SSL */
28018e77612Sflorian
28118e77612Sflorian struct daemon_remote*
daemon_remote_create(struct nsd_options * cfg)28218e77612Sflorian daemon_remote_create(struct nsd_options* cfg)
28318e77612Sflorian {
284d3fecca9Ssthen struct daemon_remote* rc = (struct daemon_remote*)xalloc_zero(
285d3fecca9Ssthen sizeof(*rc));
286d3fecca9Ssthen rc->max_active = 10;
287d3fecca9Ssthen assert(cfg->control_enable);
288d3fecca9Ssthen
28918e77612Sflorian if(options_remote_is_address(cfg)) {
2903efee2e1Sflorian #ifdef HAVE_SSL
29118e77612Sflorian if(!remote_setup_ctx(rc, cfg)) {
292d3fecca9Ssthen daemon_remote_delete(rc);
293d3fecca9Ssthen return NULL;
294d3fecca9Ssthen }
29518e77612Sflorian rc->use_cert = 1;
2963efee2e1Sflorian #else
2973efee2e1Sflorian log_msg(LOG_ERR, "Could not setup remote control: NSD was compiled without SSL.");
2983efee2e1Sflorian #endif /* HAVE_SSL */
29918e77612Sflorian } else {
30018e77612Sflorian struct ip_address_option* o;
3013efee2e1Sflorian #ifdef HAVE_SSL
30218e77612Sflorian rc->ctx = NULL;
3033efee2e1Sflorian #endif
30418e77612Sflorian rc->use_cert = 0;
30518e77612Sflorian for(o = cfg->control_interface; o; o = o->next) {
30618e77612Sflorian if(o->address && o->address[0] != '/')
30718e77612Sflorian log_msg(LOG_WARNING, "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);
308c1404d4fSbrad }
309d3fecca9Ssthen }
310d3fecca9Ssthen
311d3fecca9Ssthen /* and try to open the ports */
312d3fecca9Ssthen if(!daemon_remote_open_ports(rc, cfg)) {
313d3fecca9Ssthen log_msg(LOG_ERR, "could not open remote control port");
31418e77612Sflorian daemon_remote_delete(rc);
31518e77612Sflorian return NULL;
316d3fecca9Ssthen }
317d3fecca9Ssthen
318d3fecca9Ssthen if(gettimeofday(&rc->boot_time, NULL) == -1)
319d3fecca9Ssthen log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno));
320d3fecca9Ssthen rc->stats_time = rc->boot_time;
321d3fecca9Ssthen
322d3fecca9Ssthen return rc;
323d3fecca9Ssthen }
324d3fecca9Ssthen
daemon_remote_close(struct daemon_remote * rc)325d3fecca9Ssthen void daemon_remote_close(struct daemon_remote* rc)
326d3fecca9Ssthen {
327d3fecca9Ssthen struct rc_state* p, *np;
328d3fecca9Ssthen struct acceptlist* h, *nh;
329d3fecca9Ssthen if(!rc) return;
330d3fecca9Ssthen
331d3fecca9Ssthen /* close listen sockets */
332d3fecca9Ssthen h = rc->accept_list;
333d3fecca9Ssthen while(h) {
334d3fecca9Ssthen nh = h->next;
335d3fecca9Ssthen if(h->event_added)
336d3fecca9Ssthen event_del(&h->c);
337d3fecca9Ssthen close(h->c.ev_fd);
3384b6a9f59Sflorian free(h->ident);
339d3fecca9Ssthen free(h);
340d3fecca9Ssthen h = nh;
341d3fecca9Ssthen }
342d3fecca9Ssthen rc->accept_list = NULL;
343d3fecca9Ssthen
344d3fecca9Ssthen /* close busy connection sockets */
345d3fecca9Ssthen p = rc->busy_list;
346d3fecca9Ssthen while(p) {
347d3fecca9Ssthen np = p->next;
348d3fecca9Ssthen if(p->event_added)
349d3fecca9Ssthen event_del(&p->c);
3503efee2e1Sflorian #ifdef HAVE_SSL
351d3fecca9Ssthen if(p->ssl)
352d3fecca9Ssthen SSL_free(p->ssl);
3533efee2e1Sflorian #endif
354d3fecca9Ssthen close(p->c.ev_fd);
355d3fecca9Ssthen free(p);
356d3fecca9Ssthen p = np;
357d3fecca9Ssthen }
358d3fecca9Ssthen rc->busy_list = NULL;
359d3fecca9Ssthen rc->active = 0;
360d3fecca9Ssthen }
361d3fecca9Ssthen
daemon_remote_delete(struct daemon_remote * rc)362d3fecca9Ssthen void daemon_remote_delete(struct daemon_remote* rc)
363d3fecca9Ssthen {
364d3fecca9Ssthen if(!rc) return;
365d3fecca9Ssthen daemon_remote_close(rc);
3663efee2e1Sflorian #ifdef HAVE_SSL
367d3fecca9Ssthen if(rc->ctx) {
368d3fecca9Ssthen SSL_CTX_free(rc->ctx);
369d3fecca9Ssthen }
3703efee2e1Sflorian #endif
371d3fecca9Ssthen free(rc);
372d3fecca9Ssthen }
373d3fecca9Ssthen
374d3fecca9Ssthen static int
create_tcp_accept_sock(struct addrinfo * addr,int * noproto)375d3fecca9Ssthen create_tcp_accept_sock(struct addrinfo* addr, int* noproto)
376d3fecca9Ssthen {
377d3fecca9Ssthen #if defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU)))
378d3fecca9Ssthen int on = 1;
379d3fecca9Ssthen #endif
380d3fecca9Ssthen int s;
381d3fecca9Ssthen *noproto = 0;
382d3fecca9Ssthen if ((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) {
383d3fecca9Ssthen #if defined(INET6)
384d3fecca9Ssthen if (addr->ai_family == AF_INET6 &&
385d3fecca9Ssthen errno == EAFNOSUPPORT) {
386d3fecca9Ssthen *noproto = 1;
387d3fecca9Ssthen log_msg(LOG_WARNING, "fallback to TCP4, no IPv6: not supported");
388d3fecca9Ssthen return -1;
389d3fecca9Ssthen }
390d3fecca9Ssthen #endif /* INET6 */
391d3fecca9Ssthen log_msg(LOG_ERR, "can't create a socket: %s", strerror(errno));
392d3fecca9Ssthen return -1;
393d3fecca9Ssthen }
394d3fecca9Ssthen #ifdef SO_REUSEADDR
395d3fecca9Ssthen if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
396d3fecca9Ssthen log_msg(LOG_ERR, "setsockopt(..., SO_REUSEADDR, ...) failed: %s", strerror(errno));
397d3fecca9Ssthen }
398d3fecca9Ssthen #endif /* SO_REUSEADDR */
399d3fecca9Ssthen #if defined(INET6) && defined(IPV6_V6ONLY)
400d3fecca9Ssthen if (addr->ai_family == AF_INET6 &&
401d3fecca9Ssthen setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
402d3fecca9Ssthen {
403d3fecca9Ssthen log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno));
404308d2509Sflorian close(s);
405d3fecca9Ssthen return -1;
406d3fecca9Ssthen }
407d3fecca9Ssthen #endif
408d3fecca9Ssthen /* set it nonblocking */
409d3fecca9Ssthen /* (StevensUNP p463), if tcp listening socket is blocking, then
410d3fecca9Ssthen it may block in accept, even if select() says readable. */
411d3fecca9Ssthen if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
412d3fecca9Ssthen log_msg(LOG_ERR, "cannot fcntl tcp: %s", strerror(errno));
413d3fecca9Ssthen }
414d3fecca9Ssthen /* Bind it... */
415d3fecca9Ssthen if (bind(s, (struct sockaddr *)addr->ai_addr, addr->ai_addrlen) != 0) {
416d3fecca9Ssthen log_msg(LOG_ERR, "can't bind tcp socket: %s", strerror(errno));
417308d2509Sflorian close(s);
418d3fecca9Ssthen return -1;
419d3fecca9Ssthen }
420d3fecca9Ssthen /* Listen to it... */
421d3fecca9Ssthen if (listen(s, TCP_BACKLOG_REMOTE) == -1) {
422d3fecca9Ssthen log_msg(LOG_ERR, "can't listen: %s", strerror(errno));
423308d2509Sflorian close(s);
424d3fecca9Ssthen return -1;
425d3fecca9Ssthen }
426d3fecca9Ssthen return s;
427d3fecca9Ssthen }
428d3fecca9Ssthen
429d3fecca9Ssthen /**
430d3fecca9Ssthen * Add and open a new control port
431d3fecca9Ssthen * @param rc: rc with result list.
432d3fecca9Ssthen * @param ip: ip str
433d3fecca9Ssthen * @param nr: port nr
434d3fecca9Ssthen * @param noproto_is_err: if lack of protocol support is an error.
435d3fecca9Ssthen * @return false on failure.
436d3fecca9Ssthen */
437d3fecca9Ssthen static int
add_open(struct daemon_remote * rc,struct nsd_options * cfg,const char * ip,int nr,int noproto_is_err)43818e77612Sflorian add_open(struct daemon_remote* rc, struct nsd_options* cfg, const char* ip,
43918e77612Sflorian int nr, int noproto_is_err)
440d3fecca9Ssthen {
441d3fecca9Ssthen struct addrinfo hints;
442d3fecca9Ssthen struct addrinfo* res;
443d3fecca9Ssthen struct acceptlist* hl;
4444b6a9f59Sflorian int noproto = 0;
445d3fecca9Ssthen int fd, r;
446d3fecca9Ssthen char port[15];
447d3fecca9Ssthen snprintf(port, sizeof(port), "%d", nr);
448d3fecca9Ssthen port[sizeof(port)-1]=0;
449d3fecca9Ssthen memset(&hints, 0, sizeof(hints));
4504b6a9f59Sflorian assert(ip);
45118e77612Sflorian
45218e77612Sflorian if(ip[0] == '/') {
45318e77612Sflorian /* This looks like a local socket */
45418e77612Sflorian fd = create_local_accept_sock(ip, &noproto);
45518e77612Sflorian /*
45618e77612Sflorian * Change socket ownership and permissions so users other
45718e77612Sflorian * than root can access it provided they are in the same
45818e77612Sflorian * group as the user we run as.
45918e77612Sflorian */
46018e77612Sflorian if(fd != -1) {
46118e77612Sflorian #ifdef HAVE_CHOWN
462bc6311d7Sflorian if(chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) {
463bc6311d7Sflorian VERBOSITY(3, (LOG_INFO, "cannot chmod control socket %s: %s", ip, strerror(errno)));
464bc6311d7Sflorian }
46518e77612Sflorian if (cfg->username && cfg->username[0] &&
46618e77612Sflorian nsd.uid != (uid_t)-1) {
46718e77612Sflorian if(chown(ip, nsd.uid, nsd.gid) == -1)
46818e77612Sflorian VERBOSITY(2, (LOG_INFO, "cannot chown %u.%u %s: %s",
46918e77612Sflorian (unsigned)nsd.uid, (unsigned)nsd.gid,
47018e77612Sflorian ip, strerror(errno)));
47118e77612Sflorian }
47218e77612Sflorian #else
47318e77612Sflorian (void)cfg;
47418e77612Sflorian #endif
47518e77612Sflorian }
47618e77612Sflorian } else {
477d3fecca9Ssthen hints.ai_socktype = SOCK_STREAM;
478d3fecca9Ssthen hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
479308d2509Sflorian /* if we had no interface ip name, "default" is what we
480308d2509Sflorian * would do getaddrinfo for. */
481d3fecca9Ssthen if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) {
482d3fecca9Ssthen log_msg(LOG_ERR, "control interface %s:%s getaddrinfo: %s %s",
483308d2509Sflorian ip, port, gai_strerror(r),
484d3fecca9Ssthen #ifdef EAI_SYSTEM
485d3fecca9Ssthen r==EAI_SYSTEM?(char*)strerror(errno):""
486d3fecca9Ssthen #else
487d3fecca9Ssthen ""
488d3fecca9Ssthen #endif
489d3fecca9Ssthen );
490d3fecca9Ssthen return 0;
491d3fecca9Ssthen }
492d3fecca9Ssthen
493d3fecca9Ssthen /* open fd */
494d3fecca9Ssthen fd = create_tcp_accept_sock(res, &noproto);
495d3fecca9Ssthen freeaddrinfo(res);
49618e77612Sflorian }
49718e77612Sflorian
498d3fecca9Ssthen if(fd == -1 && noproto) {
499d3fecca9Ssthen if(!noproto_is_err)
500d3fecca9Ssthen return 1; /* return success, but do nothing */
501d3fecca9Ssthen log_msg(LOG_ERR, "cannot open control interface %s %d : "
502d3fecca9Ssthen "protocol not supported", ip, nr);
503d3fecca9Ssthen return 0;
504d3fecca9Ssthen }
505d3fecca9Ssthen if(fd == -1) {
506d3fecca9Ssthen log_msg(LOG_ERR, "cannot open control interface %s %d", ip, nr);
507d3fecca9Ssthen return 0;
508d3fecca9Ssthen }
509d3fecca9Ssthen
510d3fecca9Ssthen /* alloc */
511d3fecca9Ssthen hl = (struct acceptlist*)xalloc_zero(sizeof(*hl));
5124b6a9f59Sflorian hl->rc = rc;
5134b6a9f59Sflorian hl->ident = strdup(ip);
5144b6a9f59Sflorian if(!hl->ident) {
5154b6a9f59Sflorian log_msg(LOG_ERR, "malloc failure");
5164b6a9f59Sflorian close(fd);
5174b6a9f59Sflorian free(hl);
5184b6a9f59Sflorian return 0;
5194b6a9f59Sflorian }
520d3fecca9Ssthen hl->next = rc->accept_list;
521d3fecca9Ssthen rc->accept_list = hl;
522d3fecca9Ssthen
523d3fecca9Ssthen hl->c.ev_fd = fd;
524d3fecca9Ssthen hl->event_added = 0;
525d3fecca9Ssthen return 1;
526d3fecca9Ssthen }
527d3fecca9Ssthen
528d3fecca9Ssthen int
daemon_remote_open_ports(struct daemon_remote * rc,struct nsd_options * cfg)529fe5fe5f6Sflorian daemon_remote_open_ports(struct daemon_remote* rc, struct nsd_options* cfg)
530d3fecca9Ssthen {
531d3fecca9Ssthen assert(cfg->control_enable && cfg->control_port);
532d3fecca9Ssthen if(cfg->control_interface) {
533fe5fe5f6Sflorian ip_address_option_type* p;
534d3fecca9Ssthen for(p = cfg->control_interface; p; p = p->next) {
53518e77612Sflorian if(!add_open(rc, cfg, p->address, cfg->control_port, 1)) {
536d3fecca9Ssthen return 0;
537d3fecca9Ssthen }
538d3fecca9Ssthen }
539d3fecca9Ssthen } else {
540d3fecca9Ssthen /* defaults */
54118e77612Sflorian if(cfg->do_ip6 && !add_open(rc, cfg, "::1", cfg->control_port, 0)) {
542d3fecca9Ssthen return 0;
543d3fecca9Ssthen }
544d3fecca9Ssthen if(cfg->do_ip4 &&
54518e77612Sflorian !add_open(rc, cfg, "127.0.0.1", cfg->control_port, 1)) {
546d3fecca9Ssthen return 0;
547d3fecca9Ssthen }
548d3fecca9Ssthen }
549d3fecca9Ssthen return 1;
550d3fecca9Ssthen }
551d3fecca9Ssthen
552d3fecca9Ssthen void
daemon_remote_attach(struct daemon_remote * rc,struct xfrd_state * xfrd)553d3fecca9Ssthen daemon_remote_attach(struct daemon_remote* rc, struct xfrd_state* xfrd)
554d3fecca9Ssthen {
555d3fecca9Ssthen int fd;
556d3fecca9Ssthen struct acceptlist* p;
557d3fecca9Ssthen if(!rc) return;
558d3fecca9Ssthen rc->xfrd = xfrd;
559d3fecca9Ssthen for(p = rc->accept_list; p; p = p->next) {
560d3fecca9Ssthen /* add event */
561d3fecca9Ssthen fd = p->c.ev_fd;
562eab1363eSsthen memset(&p->c, 0, sizeof(p->c));
563d3fecca9Ssthen event_set(&p->c, fd, EV_PERSIST|EV_READ, remote_accept_callback,
5644b6a9f59Sflorian p);
565d3fecca9Ssthen if(event_base_set(xfrd->event_base, &p->c) != 0)
566d3fecca9Ssthen log_msg(LOG_ERR, "remote: cannot set event_base");
567d3fecca9Ssthen if(event_add(&p->c, NULL) != 0)
568d3fecca9Ssthen log_msg(LOG_ERR, "remote: cannot add event");
569d3fecca9Ssthen p->event_added = 1;
570d3fecca9Ssthen }
571d3fecca9Ssthen }
572d3fecca9Ssthen
573d3fecca9Ssthen static void
remote_accept_callback(int fd,short event,void * arg)574d3fecca9Ssthen remote_accept_callback(int fd, short event, void* arg)
575d3fecca9Ssthen {
5764b6a9f59Sflorian struct acceptlist *hl = (struct acceptlist*)arg;
5774b6a9f59Sflorian struct daemon_remote *rc = hl->rc;
57815ed76cbSbrad #ifdef INET6
579d3fecca9Ssthen struct sockaddr_storage addr;
58015ed76cbSbrad #else
58115ed76cbSbrad struct sockaddr_in addr;
58215ed76cbSbrad #endif
583d3fecca9Ssthen socklen_t addrlen;
584d3fecca9Ssthen int newfd;
585d3fecca9Ssthen struct rc_state* n;
586d3fecca9Ssthen
587d3fecca9Ssthen if (!(event & EV_READ)) {
588d3fecca9Ssthen return;
589d3fecca9Ssthen }
590d3fecca9Ssthen
591d3fecca9Ssthen /* perform the accept */
592d3fecca9Ssthen addrlen = sizeof(addr);
593b8cbfafcSflorian #ifndef HAVE_ACCEPT4
594d3fecca9Ssthen newfd = accept(fd, (struct sockaddr*)&addr, &addrlen);
595b8cbfafcSflorian #else
596b8cbfafcSflorian newfd = accept4(fd, (struct sockaddr*)&addr, &addrlen, SOCK_NONBLOCK);
597b8cbfafcSflorian #endif
598d3fecca9Ssthen if(newfd == -1) {
599d3fecca9Ssthen if ( errno != EINTR
600d3fecca9Ssthen && errno != EWOULDBLOCK
601d3fecca9Ssthen #ifdef ECONNABORTED
602d3fecca9Ssthen && errno != ECONNABORTED
603d3fecca9Ssthen #endif /* ECONNABORTED */
604d3fecca9Ssthen #ifdef EPROTO
605d3fecca9Ssthen && errno != EPROTO
606d3fecca9Ssthen #endif /* EPROTO */
607d3fecca9Ssthen ) {
608d3fecca9Ssthen log_msg(LOG_ERR, "accept failed: %s", strerror(errno));
609d3fecca9Ssthen }
610d3fecca9Ssthen return;
611d3fecca9Ssthen }
612d3fecca9Ssthen
613d3fecca9Ssthen /* create new commpoint unless we are servicing already */
614d3fecca9Ssthen if(rc->active >= rc->max_active) {
615d3fecca9Ssthen log_msg(LOG_WARNING, "drop incoming remote control: "
616d3fecca9Ssthen "too many connections");
617d3fecca9Ssthen close_exit:
618d3fecca9Ssthen close(newfd);
619d3fecca9Ssthen return;
620d3fecca9Ssthen }
621b8cbfafcSflorian
622b8cbfafcSflorian #ifndef HAVE_ACCEPT4
623d3fecca9Ssthen if (fcntl(newfd, F_SETFL, O_NONBLOCK) == -1) {
624d3fecca9Ssthen log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno));
625d3fecca9Ssthen goto close_exit;
626d3fecca9Ssthen }
627b8cbfafcSflorian #endif
628d3fecca9Ssthen
629d3fecca9Ssthen /* setup state to service the remote control command */
630d3fecca9Ssthen n = (struct rc_state*)calloc(1, sizeof(*n));
631d3fecca9Ssthen if(!n) {
632d3fecca9Ssthen log_msg(LOG_ERR, "out of memory");
633d3fecca9Ssthen goto close_exit;
634d3fecca9Ssthen }
635d3fecca9Ssthen
636d3fecca9Ssthen n->tval.tv_sec = REMOTE_CONTROL_TCP_TIMEOUT;
637d3fecca9Ssthen n->tval.tv_usec = 0L;
63818e77612Sflorian n->fd = newfd;
639d3fecca9Ssthen
640eab1363eSsthen memset(&n->c, 0, sizeof(n->c));
641d3fecca9Ssthen event_set(&n->c, newfd, EV_PERSIST|EV_TIMEOUT|EV_READ,
642d3fecca9Ssthen remote_control_callback, n);
64303739794Sbrad if(event_base_set(xfrd->event_base, &n->c) != 0) {
644d3fecca9Ssthen log_msg(LOG_ERR, "remote_accept: cannot set event_base");
64503739794Sbrad free(n);
64603739794Sbrad goto close_exit;
64703739794Sbrad }
64803739794Sbrad if(event_add(&n->c, &n->tval) != 0) {
649d3fecca9Ssthen log_msg(LOG_ERR, "remote_accept: cannot add event");
65003739794Sbrad free(n);
65103739794Sbrad goto close_exit;
65203739794Sbrad }
653d3fecca9Ssthen n->event_added = 1;
654d3fecca9Ssthen
655d3fecca9Ssthen if(2 <= verbosity) {
6564b6a9f59Sflorian if(hl->ident && hl->ident[0] == '/') {
6574b6a9f59Sflorian VERBOSITY(2, (LOG_INFO, "new control connection from %s", hl->ident));
6584b6a9f59Sflorian } else {
659d3fecca9Ssthen char s[128];
660d3fecca9Ssthen addr2str(&addr, s, sizeof(s));
661d3fecca9Ssthen VERBOSITY(2, (LOG_INFO, "new control connection from %s", s));
662d3fecca9Ssthen }
6634b6a9f59Sflorian }
664d3fecca9Ssthen
6653efee2e1Sflorian #ifdef HAVE_SSL
66618e77612Sflorian if(rc->ctx) {
667d3fecca9Ssthen n->shake_state = rc_hs_read;
668d3fecca9Ssthen n->ssl = SSL_new(rc->ctx);
669d3fecca9Ssthen if(!n->ssl) {
670d3fecca9Ssthen log_crypto_err("could not SSL_new");
671*bf87c3c0Sflorian if(n->event_added)
672d3fecca9Ssthen event_del(&n->c);
673d3fecca9Ssthen free(n);
674d3fecca9Ssthen goto close_exit;
675d3fecca9Ssthen }
676d3fecca9Ssthen SSL_set_accept_state(n->ssl);
677d3fecca9Ssthen (void)SSL_set_mode(n->ssl, SSL_MODE_AUTO_RETRY);
678d3fecca9Ssthen if(!SSL_set_fd(n->ssl, newfd)) {
679d3fecca9Ssthen log_crypto_err("could not SSL_set_fd");
680*bf87c3c0Sflorian if(n->event_added)
681d3fecca9Ssthen event_del(&n->c);
682d3fecca9Ssthen SSL_free(n->ssl);
683d3fecca9Ssthen free(n);
684d3fecca9Ssthen goto close_exit;
685d3fecca9Ssthen }
68618e77612Sflorian } else {
68718e77612Sflorian n->ssl = NULL;
68818e77612Sflorian }
6893efee2e1Sflorian #endif /* HAVE_SSL */
690d3fecca9Ssthen
691d3fecca9Ssthen n->rc = rc;
692d3fecca9Ssthen n->stats_next = NULL;
693d3fecca9Ssthen n->prev = NULL;
694d3fecca9Ssthen n->next = rc->busy_list;
695d3fecca9Ssthen if(n->next) n->next->prev = n;
696d3fecca9Ssthen rc->busy_list = n;
697d3fecca9Ssthen rc->active ++;
698d3fecca9Ssthen
699d3fecca9Ssthen /* perform the first nonblocking read already, for windows,
700d3fecca9Ssthen * so it can return wouldblock. could be faster too. */
701d3fecca9Ssthen remote_control_callback(newfd, EV_READ, n);
702d3fecca9Ssthen }
703d3fecca9Ssthen
704d3fecca9Ssthen /** delete from list */
705d3fecca9Ssthen static void
state_list_remove_elem(struct rc_state ** list,struct rc_state * todel)706d3fecca9Ssthen state_list_remove_elem(struct rc_state** list, struct rc_state* todel)
707d3fecca9Ssthen {
708d3fecca9Ssthen if(todel->prev) todel->prev->next = todel->next;
709d3fecca9Ssthen else *list = todel->next;
710d3fecca9Ssthen if(todel->next) todel->next->prev = todel->prev;
711d3fecca9Ssthen }
712d3fecca9Ssthen
713d3fecca9Ssthen /** decrease active count and remove commpoint from busy list */
714d3fecca9Ssthen static void
clean_point(struct daemon_remote * rc,struct rc_state * s)715d3fecca9Ssthen clean_point(struct daemon_remote* rc, struct rc_state* s)
716d3fecca9Ssthen {
717d3fecca9Ssthen state_list_remove_elem(&rc->busy_list, s);
718d3fecca9Ssthen rc->active --;
719d3fecca9Ssthen if(s->event_added)
720d3fecca9Ssthen event_del(&s->c);
7213efee2e1Sflorian #ifdef HAVE_SSL
722d3fecca9Ssthen if(s->ssl) {
723d3fecca9Ssthen SSL_shutdown(s->ssl);
724d3fecca9Ssthen SSL_free(s->ssl);
725d3fecca9Ssthen }
7263efee2e1Sflorian #endif /* HAVE_SSL */
727d3fecca9Ssthen close(s->c.ev_fd);
728d3fecca9Ssthen free(s);
729d3fecca9Ssthen }
730d3fecca9Ssthen
731d3fecca9Ssthen static int
ssl_print_text(RES * res,const char * text)73218e77612Sflorian ssl_print_text(RES* res, const char* text)
733d3fecca9Ssthen {
73418e77612Sflorian if(!res)
735d3fecca9Ssthen return 0;
7363efee2e1Sflorian #ifdef HAVE_SSL
73718e77612Sflorian if(res->ssl) {
7383efee2e1Sflorian int r;
739d3fecca9Ssthen ERR_clear_error();
74018e77612Sflorian if((r=SSL_write(res->ssl, text, (int)strlen(text))) <= 0) {
74118e77612Sflorian if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) {
742d3fecca9Ssthen VERBOSITY(2, (LOG_WARNING, "in SSL_write, peer "
743d3fecca9Ssthen "closed connection"));
744d3fecca9Ssthen return 0;
745d3fecca9Ssthen }
746d3fecca9Ssthen log_crypto_err("could not SSL_write");
747d3fecca9Ssthen return 0;
748d3fecca9Ssthen }
74918e77612Sflorian } else {
7503efee2e1Sflorian #endif /* HAVE_SSL */
75118e77612Sflorian if(write_socket(res->fd, text, strlen(text)) <= 0) {
75218e77612Sflorian log_msg(LOG_ERR, "could not write: %s",
75318e77612Sflorian strerror(errno));
75418e77612Sflorian return 0;
75518e77612Sflorian }
7563efee2e1Sflorian #ifdef HAVE_SSL
75718e77612Sflorian }
7583efee2e1Sflorian #endif /* HAVE_SSL */
759d3fecca9Ssthen return 1;
760d3fecca9Ssthen }
761d3fecca9Ssthen
762d3fecca9Ssthen /** print text over the ssl connection */
763d3fecca9Ssthen static int
ssl_print_vmsg(RES * ssl,const char * format,va_list args)76418e77612Sflorian ssl_print_vmsg(RES* ssl, const char* format, va_list args)
765d3fecca9Ssthen {
766d3fecca9Ssthen char msg[1024];
767d3fecca9Ssthen vsnprintf(msg, sizeof(msg), format, args);
768d3fecca9Ssthen return ssl_print_text(ssl, msg);
769d3fecca9Ssthen }
770d3fecca9Ssthen
771d3fecca9Ssthen /** printf style printing to the ssl connection */
772d3fecca9Ssthen static int
ssl_printf(RES * ssl,const char * format,...)77318e77612Sflorian ssl_printf(RES* ssl, const char* format, ...)
774d3fecca9Ssthen {
775d3fecca9Ssthen va_list args;
776d3fecca9Ssthen int ret;
777d3fecca9Ssthen va_start(args, format);
778d3fecca9Ssthen ret = ssl_print_vmsg(ssl, format, args);
779d3fecca9Ssthen va_end(args);
780d3fecca9Ssthen return ret;
781d3fecca9Ssthen }
782d3fecca9Ssthen
783d3fecca9Ssthen static int
ssl_read_line(RES * res,char * buf,size_t max)78418e77612Sflorian ssl_read_line(RES* res, char* buf, size_t max)
785d3fecca9Ssthen {
786d3fecca9Ssthen size_t len = 0;
78718e77612Sflorian if(!res)
788d3fecca9Ssthen return 0;
789d3fecca9Ssthen while(len < max) {
790308d2509Sflorian buf[len] = 0; /* terminate for safety and please checkers */
791308d2509Sflorian /* this byte is written if we read a byte from the input */
7923efee2e1Sflorian #ifdef HAVE_SSL
79318e77612Sflorian if(res->ssl) {
7943efee2e1Sflorian int r;
795d3fecca9Ssthen ERR_clear_error();
79618e77612Sflorian if((r=SSL_read(res->ssl, buf+len, 1)) <= 0) {
79718e77612Sflorian if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) {
798d3fecca9Ssthen buf[len] = 0;
799d3fecca9Ssthen return 1;
800d3fecca9Ssthen }
801d3fecca9Ssthen log_crypto_err("could not SSL_read");
802d3fecca9Ssthen return 0;
803d3fecca9Ssthen }
80418e77612Sflorian } else {
8053efee2e1Sflorian #endif /* HAVE_SSL */
80618e77612Sflorian while(1) {
80718e77612Sflorian ssize_t rr = read(res->fd, buf+len, 1);
80818e77612Sflorian if(rr <= 0) {
80918e77612Sflorian if(rr == 0) {
81018e77612Sflorian buf[len] = 0;
81118e77612Sflorian return 1;
81218e77612Sflorian }
81318e77612Sflorian if(errno == EINTR || errno == EAGAIN)
81418e77612Sflorian continue;
81518e77612Sflorian log_msg(LOG_ERR, "could not read: %s",
81618e77612Sflorian strerror(errno));
81718e77612Sflorian return 0;
81818e77612Sflorian }
81918e77612Sflorian break;
82018e77612Sflorian }
8213efee2e1Sflorian #ifdef HAVE_SSL
82218e77612Sflorian }
8233efee2e1Sflorian #endif /* HAVE_SSL */
824d3fecca9Ssthen if(buf[len] == '\n') {
825d3fecca9Ssthen /* return string without \n */
826d3fecca9Ssthen buf[len] = 0;
827d3fecca9Ssthen return 1;
828d3fecca9Ssthen }
829d3fecca9Ssthen len++;
830d3fecca9Ssthen }
831d3fecca9Ssthen buf[max-1] = 0;
832d3fecca9Ssthen log_msg(LOG_ERR, "control line too long (%d): %s", (int)max, buf);
833d3fecca9Ssthen return 0;
834d3fecca9Ssthen }
835d3fecca9Ssthen
836d3fecca9Ssthen /** skip whitespace, return new pointer into string */
837d3fecca9Ssthen static char*
skipwhite(char * str)838d3fecca9Ssthen skipwhite(char* str)
839d3fecca9Ssthen {
840d3fecca9Ssthen /* EOS \0 is not a space */
84182cafdebSmillert while( isspace((unsigned char)*str) )
842d3fecca9Ssthen str++;
843d3fecca9Ssthen return str;
844d3fecca9Ssthen }
845d3fecca9Ssthen
846d3fecca9Ssthen /** send the OK to the control client */
847d3fecca9Ssthen static void
send_ok(RES * ssl)84818e77612Sflorian send_ok(RES* ssl)
849d3fecca9Ssthen {
850d3fecca9Ssthen (void)ssl_printf(ssl, "ok\n");
851d3fecca9Ssthen }
852d3fecca9Ssthen
853d3fecca9Ssthen /** get zone argument (if any) or NULL, false on error */
854d3fecca9Ssthen static int
get_zone_arg(RES * ssl,xfrd_state_type * xfrd,char * arg,struct zone_options ** zo)85518e77612Sflorian get_zone_arg(RES* ssl, xfrd_state_type* xfrd, char* arg,
856fe5fe5f6Sflorian struct zone_options** zo)
857d3fecca9Ssthen {
858d3fecca9Ssthen const dname_type* dname;
859d3fecca9Ssthen if(!arg[0]) {
860d3fecca9Ssthen /* no argument present, return NULL */
861d3fecca9Ssthen *zo = NULL;
862d3fecca9Ssthen return 1;
863d3fecca9Ssthen }
864d3fecca9Ssthen dname = dname_parse(xfrd->region, arg);
865d3fecca9Ssthen if(!dname) {
866308d2509Sflorian (void)ssl_printf(ssl, "error cannot parse zone name '%s'\n", arg);
867d3fecca9Ssthen *zo = NULL;
868d3fecca9Ssthen return 0;
869d3fecca9Ssthen }
870d3fecca9Ssthen *zo = zone_options_find(xfrd->nsd->options, dname);
871d3fecca9Ssthen region_recycle(xfrd->region, (void*)dname, dname_total_size(dname));
872d3fecca9Ssthen if(!*zo) {
873308d2509Sflorian (void)ssl_printf(ssl, "error zone %s not configured\n", arg);
874d3fecca9Ssthen return 0;
875d3fecca9Ssthen }
876d3fecca9Ssthen return 1;
877d3fecca9Ssthen }
878d3fecca9Ssthen
879d3fecca9Ssthen /** do the stop command */
880d3fecca9Ssthen static void
do_stop(RES * ssl,xfrd_state_type * xfrd)88118e77612Sflorian do_stop(RES* ssl, xfrd_state_type* xfrd)
882d3fecca9Ssthen {
883d3fecca9Ssthen xfrd->need_to_send_shutdown = 1;
884d3fecca9Ssthen
885d3fecca9Ssthen if(!(xfrd->ipc_handler_flags&EV_WRITE)) {
886d3fecca9Ssthen ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE);
887d3fecca9Ssthen }
888d3fecca9Ssthen
889d3fecca9Ssthen send_ok(ssl);
890d3fecca9Ssthen }
891d3fecca9Ssthen
892d3fecca9Ssthen /** do the log_reopen command, it only needs reload_now */
893d3fecca9Ssthen static void
do_log_reopen(RES * ssl,xfrd_state_type * xfrd)89418e77612Sflorian do_log_reopen(RES* ssl, xfrd_state_type* xfrd)
895d3fecca9Ssthen {
896d3fecca9Ssthen xfrd_set_reload_now(xfrd);
897d3fecca9Ssthen send_ok(ssl);
898d3fecca9Ssthen }
899d3fecca9Ssthen
900d3fecca9Ssthen /** do the reload command */
901d3fecca9Ssthen static void
do_reload(RES * ssl,xfrd_state_type * xfrd,char * arg)90218e77612Sflorian do_reload(RES* ssl, xfrd_state_type* xfrd, char* arg)
903d3fecca9Ssthen {
904fe5fe5f6Sflorian struct zone_options* zo;
905d3fecca9Ssthen if(!get_zone_arg(ssl, xfrd, arg, &zo))
906d3fecca9Ssthen return;
907d3fecca9Ssthen task_new_check_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask],
908d3fecca9Ssthen xfrd->last_task, zo?(const dname_type*)zo->node.key:NULL);
909d3fecca9Ssthen xfrd_set_reload_now(xfrd);
910d3fecca9Ssthen send_ok(ssl);
911d3fecca9Ssthen }
912d3fecca9Ssthen
913d3fecca9Ssthen /** do the write command */
914d3fecca9Ssthen static void
do_write(RES * ssl,xfrd_state_type * xfrd,char * arg)91518e77612Sflorian do_write(RES* ssl, xfrd_state_type* xfrd, char* arg)
916d3fecca9Ssthen {
917fe5fe5f6Sflorian struct zone_options* zo;
918d3fecca9Ssthen if(!get_zone_arg(ssl, xfrd, arg, &zo))
919d3fecca9Ssthen return;
920d3fecca9Ssthen task_new_write_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask],
921d3fecca9Ssthen xfrd->last_task, zo?(const dname_type*)zo->node.key:NULL);
922d3fecca9Ssthen xfrd_set_reload_now(xfrd);
923d3fecca9Ssthen send_ok(ssl);
924d3fecca9Ssthen }
925d3fecca9Ssthen
926d3fecca9Ssthen /** do the notify command */
927d3fecca9Ssthen static void
do_notify(RES * ssl,xfrd_state_type * xfrd,char * arg)92818e77612Sflorian do_notify(RES* ssl, xfrd_state_type* xfrd, char* arg)
929d3fecca9Ssthen {
930fe5fe5f6Sflorian struct zone_options* zo;
931d3fecca9Ssthen if(!get_zone_arg(ssl, xfrd, arg, &zo))
932d3fecca9Ssthen return;
933d3fecca9Ssthen if(zo) {
934fe5fe5f6Sflorian struct notify_zone* n = (struct notify_zone*)rbtree_search(
935d3fecca9Ssthen xfrd->notify_zones, (const dname_type*)zo->node.key);
936d3fecca9Ssthen if(n) {
937e3d8a0a5Ssthen xfrd_notify_start(n, xfrd);
938d3fecca9Ssthen send_ok(ssl);
939d3fecca9Ssthen } else {
940308d2509Sflorian (void)ssl_printf(ssl, "error zone does not have notify\n");
941d3fecca9Ssthen }
942d3fecca9Ssthen } else {
943fe5fe5f6Sflorian struct notify_zone* n;
944fe5fe5f6Sflorian RBTREE_FOR(n, struct notify_zone*, xfrd->notify_zones) {
945e3d8a0a5Ssthen xfrd_notify_start(n, xfrd);
946d3fecca9Ssthen }
947d3fecca9Ssthen send_ok(ssl);
948d3fecca9Ssthen }
949d3fecca9Ssthen }
950d3fecca9Ssthen
951d3fecca9Ssthen /** do the transfer command */
952d3fecca9Ssthen static void
do_transfer(RES * ssl,xfrd_state_type * xfrd,char * arg)95318e77612Sflorian do_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg)
954d3fecca9Ssthen {
955fe5fe5f6Sflorian struct zone_options* zo;
956fe5fe5f6Sflorian xfrd_zone_type* zone;
957d3fecca9Ssthen if(!get_zone_arg(ssl, xfrd, arg, &zo))
958d3fecca9Ssthen return;
959d3fecca9Ssthen if(zo) {
960fe5fe5f6Sflorian zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const
961d3fecca9Ssthen dname_type*)zo->node.key);
962d3fecca9Ssthen if(zone) {
963d3fecca9Ssthen xfrd_handle_notify_and_start_xfr(zone, NULL);
964d3fecca9Ssthen send_ok(ssl);
965d3fecca9Ssthen } else {
966*bf87c3c0Sflorian (void)ssl_printf(ssl, "error zone not secondary\n");
967d3fecca9Ssthen }
968d3fecca9Ssthen } else {
969fe5fe5f6Sflorian RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) {
970d3fecca9Ssthen xfrd_handle_notify_and_start_xfr(zone, NULL);
971d3fecca9Ssthen }
972308d2509Sflorian (void)ssl_printf(ssl, "ok, %lu zones\n", (unsigned long)xfrd->zones->count);
973d3fecca9Ssthen }
974d3fecca9Ssthen }
975d3fecca9Ssthen
976d3fecca9Ssthen /** force transfer a zone */
977d3fecca9Ssthen static void
force_transfer_zone(xfrd_zone_type * zone)978fe5fe5f6Sflorian force_transfer_zone(xfrd_zone_type* zone)
979d3fecca9Ssthen {
980d3fecca9Ssthen /* if in TCP transaction, stop it immediately. */
981d3fecca9Ssthen if(zone->tcp_conn != -1)
982d3fecca9Ssthen xfrd_tcp_release(xfrd->tcp_set, zone);
983d3fecca9Ssthen else if(zone->zone_handler.ev_fd != -1)
984d3fecca9Ssthen xfrd_udp_release(zone);
985d3fecca9Ssthen /* pretend we not longer have it and force any
986d3fecca9Ssthen * zone to be downloaded (even same serial, w AXFR) */
987d3fecca9Ssthen zone->soa_disk_acquired = 0;
98815ed76cbSbrad zone->soa_nsd_acquired = 0;
989d3fecca9Ssthen xfrd_handle_notify_and_start_xfr(zone, NULL);
990d3fecca9Ssthen }
991d3fecca9Ssthen
992d3fecca9Ssthen /** do the force transfer command */
993d3fecca9Ssthen static void
do_force_transfer(RES * ssl,xfrd_state_type * xfrd,char * arg)99418e77612Sflorian do_force_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg)
995d3fecca9Ssthen {
996fe5fe5f6Sflorian struct zone_options* zo;
997fe5fe5f6Sflorian xfrd_zone_type* zone;
998d3fecca9Ssthen if(!get_zone_arg(ssl, xfrd, arg, &zo))
999d3fecca9Ssthen return;
1000d3fecca9Ssthen if(zo) {
1001fe5fe5f6Sflorian zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const
1002d3fecca9Ssthen dname_type*)zo->node.key);
1003d3fecca9Ssthen if(zone) {
1004d3fecca9Ssthen force_transfer_zone(zone);
1005d3fecca9Ssthen send_ok(ssl);
1006d3fecca9Ssthen } else {
1007*bf87c3c0Sflorian (void)ssl_printf(ssl, "error zone not secondary\n");
1008d3fecca9Ssthen }
1009d3fecca9Ssthen } else {
1010fe5fe5f6Sflorian RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) {
1011d3fecca9Ssthen force_transfer_zone(zone);
1012d3fecca9Ssthen }
1013308d2509Sflorian (void)ssl_printf(ssl, "ok, %lu zones\n", (unsigned long)xfrd->zones->count);
1014d3fecca9Ssthen }
1015d3fecca9Ssthen }
1016d3fecca9Ssthen
1017d3fecca9Ssthen static int
print_soa_status(RES * ssl,const char * str,xfrd_soa_type * soa,time_t acq)101818e77612Sflorian print_soa_status(RES* ssl, const char* str, xfrd_soa_type* soa, time_t acq)
1019d3fecca9Ssthen {
1020d3fecca9Ssthen if(acq) {
1021d3fecca9Ssthen if(!ssl_printf(ssl, " %s: \"%u since %s\"\n", str,
1022d3fecca9Ssthen (unsigned)ntohl(soa->serial), xfrd_pretty_time(acq)))
1023d3fecca9Ssthen return 0;
1024d3fecca9Ssthen } else {
1025d3fecca9Ssthen if(!ssl_printf(ssl, " %s: none\n", str))
1026d3fecca9Ssthen return 0;
1027d3fecca9Ssthen }
1028d3fecca9Ssthen return 1;
1029d3fecca9Ssthen }
1030d3fecca9Ssthen
1031d3fecca9Ssthen /** print zonestatus for one domain */
1032d3fecca9Ssthen static int
print_zonestatus(RES * ssl,xfrd_state_type * xfrd,struct zone_options * zo)103318e77612Sflorian print_zonestatus(RES* ssl, xfrd_state_type* xfrd, struct zone_options* zo)
1034d3fecca9Ssthen {
1035fe5fe5f6Sflorian xfrd_zone_type* xz = (xfrd_zone_type*)rbtree_search(xfrd->zones,
1036d3fecca9Ssthen (const dname_type*)zo->node.key);
1037fe5fe5f6Sflorian struct notify_zone* nz = (struct notify_zone*)rbtree_search(
1038d3fecca9Ssthen xfrd->notify_zones, (const dname_type*)zo->node.key);
1039d3fecca9Ssthen if(!ssl_printf(ssl, "zone: %s\n", zo->name))
1040d3fecca9Ssthen return 0;
1041d3fecca9Ssthen if(!zo->part_of_config) {
1042d3fecca9Ssthen if(!ssl_printf(ssl, " pattern: %s\n", zo->pattern->pname))
1043d3fecca9Ssthen return 0;
1044d3fecca9Ssthen }
1045*bf87c3c0Sflorian if(zone_is_catalog_consumer(zo)) {
1046*bf87c3c0Sflorian zone_type* zone = namedb_find_zone(xfrd->nsd->db,
1047*bf87c3c0Sflorian (const dname_type*)zo->node.key);
1048*bf87c3c0Sflorian struct xfrd_catalog_consumer_zone* consumer_zone =
1049*bf87c3c0Sflorian (struct xfrd_catalog_consumer_zone*)
1050*bf87c3c0Sflorian rbtree_search( xfrd->catalog_consumer_zones
1051*bf87c3c0Sflorian , zo->node.key);
1052*bf87c3c0Sflorian
1053*bf87c3c0Sflorian if(!ssl_printf(ssl, " catalog: consumer"))
1054*bf87c3c0Sflorian return 0;
1055*bf87c3c0Sflorian if(zone && zone->soa_rrset && zone->soa_rrset->rrs
1056*bf87c3c0Sflorian && zone->soa_rrset->rrs[0].rdata_count > 2
1057*bf87c3c0Sflorian && rdata_atom_size(zone->soa_rrset->rrs[0].rdatas[2]) ==
1058*bf87c3c0Sflorian sizeof(uint32_t)) {
1059*bf87c3c0Sflorian if(!ssl_printf(ssl, " (serial: %u, # members: %zu)\n",
1060*bf87c3c0Sflorian read_uint32(rdata_atom_data(
1061*bf87c3c0Sflorian zone->soa_rrset->rrs[0].rdatas[2])),
1062*bf87c3c0Sflorian consumer_zone
1063*bf87c3c0Sflorian ? consumer_zone->member_ids.count : 0))
1064*bf87c3c0Sflorian return 0;
1065*bf87c3c0Sflorian
1066*bf87c3c0Sflorian } else if(!ssl_printf(ssl, "\n"))
1067*bf87c3c0Sflorian return 0;
1068*bf87c3c0Sflorian if(invalid_catalog_consumer_zone(zo)) {
1069*bf87c3c0Sflorian if(!ssl_printf(ssl, " catalog-invalid: %s\n",
1070*bf87c3c0Sflorian invalid_catalog_consumer_zone(zo)))
1071*bf87c3c0Sflorian return 0;
1072*bf87c3c0Sflorian }
1073*bf87c3c0Sflorian }
1074*bf87c3c0Sflorian if(zone_is_catalog_producer(zo)) {
1075*bf87c3c0Sflorian struct xfrd_catalog_producer_zone* producer_zone =
1076*bf87c3c0Sflorian (struct xfrd_catalog_producer_zone*)
1077*bf87c3c0Sflorian rbtree_search( xfrd->catalog_producer_zones
1078*bf87c3c0Sflorian , zo->node.key);
1079*bf87c3c0Sflorian if(!ssl_printf(ssl, " catalog: producer"))
1080*bf87c3c0Sflorian return 0;
1081*bf87c3c0Sflorian if(producer_zone) {
1082*bf87c3c0Sflorian if(!ssl_printf(ssl, " (serial: %u, # members: %zu)\n",
1083*bf87c3c0Sflorian (unsigned)producer_zone->serial,
1084*bf87c3c0Sflorian producer_zone->member_ids.count))
1085*bf87c3c0Sflorian return 0;
1086*bf87c3c0Sflorian } else if(!ssl_printf(ssl, "\n"))
1087*bf87c3c0Sflorian return 0;
1088*bf87c3c0Sflorian if (zone_is_slave(zo)) {
1089*bf87c3c0Sflorian if(!ssl_printf(ssl, " catalog-invalid: a catalog "
1090*bf87c3c0Sflorian "producer cannot be a secondary zone"))
1091*bf87c3c0Sflorian return 0;
1092*bf87c3c0Sflorian }
1093*bf87c3c0Sflorian }
1094*bf87c3c0Sflorian if(zone_is_catalog_member(zo)) {
1095*bf87c3c0Sflorian if(!ssl_printf(ssl, " catalog-member-id: %s\n",
1096*bf87c3c0Sflorian as_catalog_member_zone(zo)->member_id
1097*bf87c3c0Sflorian ? dname_to_string(as_catalog_member_zone(zo)->member_id, NULL)
1098*bf87c3c0Sflorian : "ERROR member-id is missing!"))
1099*bf87c3c0Sflorian return 0;
1100*bf87c3c0Sflorian }
1101d3fecca9Ssthen if(nz) {
1102d3fecca9Ssthen if(nz->is_waiting) {
1103d3fecca9Ssthen if(!ssl_printf(ssl, " notify: \"waiting-for-fd\"\n"))
1104d3fecca9Ssthen return 0;
1105ee5153b7Sflorian } else if(nz->notify_send_enable || nz->notify_send6_enable) {
1106ee5153b7Sflorian int i;
1107ee5153b7Sflorian if(!ssl_printf(ssl, " notify: \"send"))
1108ee5153b7Sflorian return 0;
1109ee5153b7Sflorian for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
1110ee5153b7Sflorian if(!nz->pkts[i].dest) continue;
1111ee5153b7Sflorian if(!ssl_printf(ssl, " %s",
1112ee5153b7Sflorian nz->pkts[i].dest->ip_address_spec))
1113ee5153b7Sflorian return 0;
1114ee5153b7Sflorian }
1115ee5153b7Sflorian if(!ssl_printf(ssl, " with serial %u\"\n",
1116d3fecca9Ssthen (unsigned)ntohl(nz->current_soa->serial)))
1117d3fecca9Ssthen return 0;
1118d3fecca9Ssthen }
1119d3fecca9Ssthen }
1120d3fecca9Ssthen if(!xz) {
1121*bf87c3c0Sflorian if(!ssl_printf(ssl, " state: primary\n"))
1122d3fecca9Ssthen return 0;
1123d3fecca9Ssthen return 1;
1124d3fecca9Ssthen }
1125d3fecca9Ssthen if(!ssl_printf(ssl, " state: %s\n",
1126d3fecca9Ssthen (xz->state == xfrd_zone_ok)?"ok":(
1127d3fecca9Ssthen (xz->state == xfrd_zone_expired)?"expired":"refreshing")))
1128d3fecca9Ssthen return 0;
1129d3fecca9Ssthen if(!print_soa_status(ssl, "served-serial", &xz->soa_nsd,
1130d3fecca9Ssthen xz->soa_nsd_acquired))
1131d3fecca9Ssthen return 0;
1132d3fecca9Ssthen if(!print_soa_status(ssl, "commit-serial", &xz->soa_disk,
1133d3fecca9Ssthen xz->soa_disk_acquired))
1134d3fecca9Ssthen return 0;
1135d3fecca9Ssthen if(xz->round_num != -1) {
1136d3fecca9Ssthen if(!print_soa_status(ssl, "notified-serial", &xz->soa_notified,
1137d3fecca9Ssthen xz->soa_notified_acquired))
1138d3fecca9Ssthen return 0;
1139ee5153b7Sflorian } else if(xz->event_added) {
114018e77612Sflorian if(!ssl_printf(ssl, "\twait: \"%lu sec between attempts\"\n",
114118e77612Sflorian (unsigned long)xz->timeout.tv_sec))
1142ee5153b7Sflorian return 0;
1143d3fecca9Ssthen }
1144d3fecca9Ssthen
1145d3fecca9Ssthen /* UDP */
1146d3fecca9Ssthen if(xz->udp_waiting) {
1147d3fecca9Ssthen if(!ssl_printf(ssl, " transfer: \"waiting-for-UDP-fd\"\n"))
1148d3fecca9Ssthen return 0;
1149d3fecca9Ssthen } else if(xz->zone_handler.ev_fd != -1 && xz->tcp_conn == -1) {
1150d3fecca9Ssthen if(!ssl_printf(ssl, " transfer: \"sent UDP to %s\"\n",
1151d3fecca9Ssthen xz->master->ip_address_spec))
1152d3fecca9Ssthen return 0;
1153d3fecca9Ssthen }
1154d3fecca9Ssthen
1155d3fecca9Ssthen /* TCP */
1156d3fecca9Ssthen if(xz->tcp_waiting) {
1157d3fecca9Ssthen if(!ssl_printf(ssl, " transfer: \"waiting-for-TCP-fd\"\n"))
1158d3fecca9Ssthen return 0;
1159d3fecca9Ssthen } else if(xz->tcp_conn != -1) {
1160d3fecca9Ssthen if(!ssl_printf(ssl, " transfer: \"TCP connected to %s\"\n",
1161d3fecca9Ssthen xz->master->ip_address_spec))
1162d3fecca9Ssthen return 0;
1163d3fecca9Ssthen }
1164d3fecca9Ssthen
1165d3fecca9Ssthen return 1;
1166d3fecca9Ssthen }
1167d3fecca9Ssthen
1168d3fecca9Ssthen /** do the zonestatus command */
1169d3fecca9Ssthen static void
do_zonestatus(RES * ssl,xfrd_state_type * xfrd,char * arg)117018e77612Sflorian do_zonestatus(RES* ssl, xfrd_state_type* xfrd, char* arg)
1171d3fecca9Ssthen {
1172fe5fe5f6Sflorian struct zone_options* zo;
1173d3fecca9Ssthen if(!get_zone_arg(ssl, xfrd, arg, &zo))
1174d3fecca9Ssthen return;
1175d3fecca9Ssthen if(zo) (void)print_zonestatus(ssl, xfrd, zo);
1176d3fecca9Ssthen else {
1177fe5fe5f6Sflorian RBTREE_FOR(zo, struct zone_options*,
1178d3fecca9Ssthen xfrd->nsd->options->zone_options) {
1179d3fecca9Ssthen if(!print_zonestatus(ssl, xfrd, zo))
1180d3fecca9Ssthen return;
1181d3fecca9Ssthen }
1182d3fecca9Ssthen }
1183d3fecca9Ssthen }
1184d3fecca9Ssthen
1185d3fecca9Ssthen /** do the verbosity command */
1186d3fecca9Ssthen static void
do_verbosity(RES * ssl,char * str)118718e77612Sflorian do_verbosity(RES* ssl, char* str)
1188d3fecca9Ssthen {
1189d3fecca9Ssthen int val = atoi(str);
1190d3fecca9Ssthen if(strcmp(str, "") == 0) {
1191308d2509Sflorian (void)ssl_printf(ssl, "verbosity %d\n", verbosity);
1192d3fecca9Ssthen return;
1193d3fecca9Ssthen }
1194d3fecca9Ssthen if(val == 0 && strcmp(str, "0") != 0) {
1195308d2509Sflorian (void)ssl_printf(ssl, "error in verbosity number syntax: %s\n", str);
1196d3fecca9Ssthen return;
1197d3fecca9Ssthen }
1198d3fecca9Ssthen verbosity = val;
1199d3fecca9Ssthen task_new_set_verbosity(xfrd->nsd->task[xfrd->nsd->mytask],
1200d3fecca9Ssthen xfrd->last_task, val);
1201d3fecca9Ssthen xfrd_set_reload_now(xfrd);
1202d3fecca9Ssthen send_ok(ssl);
1203d3fecca9Ssthen }
1204d3fecca9Ssthen
1205d3fecca9Ssthen /** find second argument, modifies string */
1206d3fecca9Ssthen static int
find_arg2(RES * ssl,char * arg,char ** arg2)120718e77612Sflorian find_arg2(RES* ssl, char* arg, char** arg2)
1208d3fecca9Ssthen {
1209d3fecca9Ssthen char* as = strrchr(arg, ' ');
1210d3fecca9Ssthen if(as) {
1211d3fecca9Ssthen as[0]=0;
1212d3fecca9Ssthen *arg2 = as+1;
121382cafdebSmillert while(isspace((unsigned char)*as) && as > arg)
1214d3fecca9Ssthen as--;
1215d3fecca9Ssthen as[0]=0;
1216d3fecca9Ssthen return 1;
1217d3fecca9Ssthen }
1218a1bac035Sflorian *arg2 = NULL;
1219308d2509Sflorian (void)ssl_printf(ssl, "error could not find next argument "
1220d3fecca9Ssthen "after %s\n", arg);
1221d3fecca9Ssthen return 0;
1222d3fecca9Ssthen }
1223d3fecca9Ssthen
1224a1bac035Sflorian /** find second and third arguments, modifies string,
1225a1bac035Sflorian * does not print error for missing arg3 so that if it does not find an
1226a1bac035Sflorian * arg3, the caller can use two arguments. */
1227a1bac035Sflorian static int
find_arg3(RES * ssl,char * arg,char ** arg2,char ** arg3)1228a1bac035Sflorian find_arg3(RES* ssl, char* arg, char** arg2, char** arg3)
1229a1bac035Sflorian {
1230a1bac035Sflorian if(find_arg2(ssl, arg, arg2)) {
1231a1bac035Sflorian char* as;
1232a1bac035Sflorian *arg3 = *arg2;
1233a1bac035Sflorian as = strrchr(arg, ' ');
1234a1bac035Sflorian if(as) {
1235a1bac035Sflorian as[0]=0;
1236a1bac035Sflorian *arg2 = as+1;
1237a1bac035Sflorian while(isspace((unsigned char)*as) && as > arg)
1238a1bac035Sflorian as--;
1239a1bac035Sflorian as[0]=0;
1240a1bac035Sflorian return 1;
1241a1bac035Sflorian }
1242a1bac035Sflorian }
1243a1bac035Sflorian *arg3 = NULL;
1244a1bac035Sflorian return 0;
1245a1bac035Sflorian }
1246a1bac035Sflorian
1247d3fecca9Ssthen /** do the status command */
1248d3fecca9Ssthen static void
do_status(RES * ssl,xfrd_state_type * xfrd)124918e77612Sflorian do_status(RES* ssl, xfrd_state_type* xfrd)
1250d3fecca9Ssthen {
1251d3fecca9Ssthen if(!ssl_printf(ssl, "version: %s\n", PACKAGE_VERSION))
1252d3fecca9Ssthen return;
1253d3fecca9Ssthen if(!ssl_printf(ssl, "verbosity: %d\n", verbosity))
1254d3fecca9Ssthen return;
1255d3fecca9Ssthen #ifdef RATELIMIT
1256d3fecca9Ssthen if(!ssl_printf(ssl, "ratelimit: %d\n",
1257d3fecca9Ssthen (int)xfrd->nsd->options->rrl_ratelimit))
1258d3fecca9Ssthen return;
1259d3fecca9Ssthen #else
1260d3fecca9Ssthen (void)xfrd;
1261d3fecca9Ssthen #endif
1262d3fecca9Ssthen }
1263d3fecca9Ssthen
1264d3fecca9Ssthen /** do the stats command */
1265d3fecca9Ssthen static void
do_stats(RES * ssl,xfrd_state_type * xfrd,int peek)1266b71395eaSflorian do_stats(RES* ssl, xfrd_state_type* xfrd, int peek)
1267d3fecca9Ssthen {
1268d3fecca9Ssthen #ifdef BIND8_STATS
1269b71395eaSflorian process_stats(ssl, xfrd, peek);
1270d3fecca9Ssthen #else
1271b71395eaSflorian (void)xfrd; (void)peek;
1272b71395eaSflorian (void)ssl_printf(ssl, "error no stats enabled at compile time\n");
1273d3fecca9Ssthen #endif /* BIND8_STATS */
1274d3fecca9Ssthen }
1275d3fecca9Ssthen
1276c1404d4fSbrad /** see if we have more zonestatistics entries and it has to be incremented */
1277c1404d4fSbrad static void
zonestat_inc_ifneeded(xfrd_state_type * xfrd)1278fe5fe5f6Sflorian zonestat_inc_ifneeded(xfrd_state_type* xfrd)
1279c1404d4fSbrad {
1280c1404d4fSbrad #ifdef USE_ZONE_STATS
1281c1404d4fSbrad if(xfrd->nsd->options->zonestatnames->count != xfrd->zonestat_safe)
1282c1404d4fSbrad task_new_zonestat_inc(xfrd->nsd->task[xfrd->nsd->mytask],
1283c1404d4fSbrad xfrd->last_task,
1284c1404d4fSbrad xfrd->nsd->options->zonestatnames->count);
1285c1404d4fSbrad #else
1286c1404d4fSbrad (void)xfrd;
1287c1404d4fSbrad #endif /* USE_ZONE_STATS */
1288c1404d4fSbrad }
1289c1404d4fSbrad
1290e02bc0dfSflorian /** perform the changezone command for one zone */
1291e02bc0dfSflorian static int
perform_changezone(RES * ssl,xfrd_state_type * xfrd,char * arg)1292e02bc0dfSflorian perform_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg)
1293e02bc0dfSflorian {
1294e02bc0dfSflorian const dname_type* dname;
1295e02bc0dfSflorian struct zone_options* zopt;
1296e02bc0dfSflorian char* arg2 = NULL;
1297e02bc0dfSflorian if(!find_arg2(ssl, arg, &arg2))
1298e02bc0dfSflorian return 0;
1299e02bc0dfSflorian
1300e02bc0dfSflorian /* if we add it to the xfrd now, then xfrd could download AXFR and
1301e02bc0dfSflorian * store it and the NSD-reload would see it in the difffile before
1302e02bc0dfSflorian * it sees the add-config task.
1303e02bc0dfSflorian */
1304e02bc0dfSflorian /* thus: AXFRs and IXFRs must store the pattern name in the
1305e02bc0dfSflorian * difffile, so that it can be added when the AXFR or IXFR is seen.
1306e02bc0dfSflorian */
1307e02bc0dfSflorian
1308e02bc0dfSflorian /* check that the pattern exists */
1309e02bc0dfSflorian if(!rbtree_search(xfrd->nsd->options->patterns, arg2)) {
1310e02bc0dfSflorian (void)ssl_printf(ssl, "error pattern %s does not exist\n",
1311e02bc0dfSflorian arg2);
1312e02bc0dfSflorian return 0;
1313e02bc0dfSflorian }
1314e02bc0dfSflorian
1315e02bc0dfSflorian dname = dname_parse(xfrd->region, arg);
1316e02bc0dfSflorian if(!dname) {
1317e02bc0dfSflorian (void)ssl_printf(ssl, "error cannot parse zone name\n");
1318e02bc0dfSflorian return 0;
1319e02bc0dfSflorian }
1320e02bc0dfSflorian
1321e02bc0dfSflorian /* see if zone is a duplicate */
1322e02bc0dfSflorian if( (zopt=zone_options_find(xfrd->nsd->options, dname)) ) {
1323e02bc0dfSflorian if(zopt->part_of_config) {
1324e02bc0dfSflorian (void)ssl_printf(ssl, "error zone defined in nsd.conf, "
1325e02bc0dfSflorian "cannot delete it in this manner: remove it from "
1326e02bc0dfSflorian "nsd.conf yourself and repattern\n");
1327e02bc0dfSflorian region_recycle(xfrd->region, (void*)dname, dname_total_size(dname));
1328e02bc0dfSflorian dname = NULL;
1329e02bc0dfSflorian return 0;
1330e02bc0dfSflorian }
1331*bf87c3c0Sflorian if(zone_is_catalog_consumer_member(zopt)) {
1332*bf87c3c0Sflorian (void)ssl_printf(ssl, "Error: Zone is a catalog "
1333*bf87c3c0Sflorian "consumer member zone with id %s\nRepattern in the "
1334*bf87c3c0Sflorian "catalog with a group property.\n", dname_to_string(
1335*bf87c3c0Sflorian as_catalog_member_zone(zopt)->member_id, NULL));
1336*bf87c3c0Sflorian region_recycle(xfrd->region, (void*)dname, dname_total_size(dname));
1337*bf87c3c0Sflorian dname = NULL;
1338*bf87c3c0Sflorian return 0;
1339*bf87c3c0Sflorian }
1340e02bc0dfSflorian /* found the zone, now delete it */
1341e02bc0dfSflorian /* create deletion task */
1342e02bc0dfSflorian /* this deletion task is processed before the addition task,
1343e02bc0dfSflorian * that is created below, in the same reload process, causing
1344e02bc0dfSflorian * a seamless change from one to the other, with no downtime
1345e02bc0dfSflorian * for the zone. */
1346e02bc0dfSflorian task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask],
1347e02bc0dfSflorian xfrd->last_task, dname);
1348e02bc0dfSflorian xfrd_set_reload_now(xfrd);
1349e02bc0dfSflorian /* delete it in xfrd */
1350e02bc0dfSflorian if(zone_is_slave(zopt)) {
1351e02bc0dfSflorian xfrd_del_slave_zone(xfrd, dname);
1352e02bc0dfSflorian }
1353e02bc0dfSflorian xfrd_del_notify(xfrd, dname);
1354*bf87c3c0Sflorian /* delete it in xfrd's catalog consumers list */
1355*bf87c3c0Sflorian if(zone_is_catalog_consumer(zopt)) {
1356*bf87c3c0Sflorian xfrd_deinit_catalog_consumer_zone(xfrd, dname);
1357*bf87c3c0Sflorian }
1358e02bc0dfSflorian /* delete from config */
1359e02bc0dfSflorian zone_list_del(xfrd->nsd->options, zopt);
1360e02bc0dfSflorian } else {
1361e02bc0dfSflorian (void)ssl_printf(ssl, "zone %s did not exist, creating", arg);
1362e02bc0dfSflorian }
1363e02bc0dfSflorian region_recycle(xfrd->region, (void*)dname, dname_total_size(dname));
1364e02bc0dfSflorian dname = NULL;
1365e02bc0dfSflorian
1366e02bc0dfSflorian /* add to zonelist and adds to config in memory */
1367*bf87c3c0Sflorian zopt = zone_list_add_or_cat(xfrd->nsd->options, arg, arg2,
1368*bf87c3c0Sflorian xfrd_add_catalog_producer_member);
1369e02bc0dfSflorian if(!zopt) {
1370e02bc0dfSflorian /* also dname parse error here */
1371e02bc0dfSflorian (void)ssl_printf(ssl, "error could not add zonelist entry\n");
1372e02bc0dfSflorian return 0;
1373e02bc0dfSflorian }
1374e02bc0dfSflorian /* make addzone task and schedule reload */
1375e02bc0dfSflorian task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask],
1376e02bc0dfSflorian xfrd->last_task, arg, arg2,
1377e02bc0dfSflorian getzonestatid(xfrd->nsd->options, zopt));
1378e02bc0dfSflorian zonestat_inc_ifneeded(xfrd);
1379e02bc0dfSflorian xfrd_set_reload_now(xfrd);
1380*bf87c3c0Sflorian /* add to xfrd - catalog consumer zones */
1381*bf87c3c0Sflorian if (zone_is_catalog_consumer(zopt)) {
1382*bf87c3c0Sflorian xfrd_init_catalog_consumer_zone(xfrd, zopt);
1383*bf87c3c0Sflorian }
1384e02bc0dfSflorian /* add to xfrd - notify (for master and slaves) */
1385e02bc0dfSflorian init_notify_send(xfrd->notify_zones, xfrd->region, zopt);
1386e02bc0dfSflorian /* add to xfrd - slave */
1387e02bc0dfSflorian if(zone_is_slave(zopt)) {
1388e02bc0dfSflorian xfrd_init_slave_zone(xfrd, zopt);
1389e02bc0dfSflorian }
1390e02bc0dfSflorian return 1;
1391e02bc0dfSflorian }
1392e02bc0dfSflorian
13938d8f1862Ssthen /** perform the addzone command for one zone */
13948d8f1862Ssthen static int
perform_addzone(RES * ssl,xfrd_state_type * xfrd,char * arg)139518e77612Sflorian perform_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg)
1396d3fecca9Ssthen {
139715ed76cbSbrad const dname_type* dname;
1398fe5fe5f6Sflorian struct zone_options* zopt;
1399d3fecca9Ssthen char* arg2 = NULL;
1400d3fecca9Ssthen if(!find_arg2(ssl, arg, &arg2))
14018d8f1862Ssthen return 0;
1402d3fecca9Ssthen
1403d3fecca9Ssthen /* if we add it to the xfrd now, then xfrd could download AXFR and
1404d3fecca9Ssthen * store it and the NSD-reload would see it in the difffile before
1405d3fecca9Ssthen * it sees the add-config task.
1406d3fecca9Ssthen */
1407d3fecca9Ssthen /* thus: AXFRs and IXFRs must store the pattern name in the
1408d3fecca9Ssthen * difffile, so that it can be added when the AXFR or IXFR is seen.
1409d3fecca9Ssthen */
1410d3fecca9Ssthen
1411d3fecca9Ssthen /* check that the pattern exists */
1412d3fecca9Ssthen if(!rbtree_search(xfrd->nsd->options->patterns, arg2)) {
141315ed76cbSbrad (void)ssl_printf(ssl, "error pattern %s does not exist\n",
141415ed76cbSbrad arg2);
14158d8f1862Ssthen return 0;
1416d3fecca9Ssthen }
1417d3fecca9Ssthen
141815ed76cbSbrad dname = dname_parse(xfrd->region, arg);
141915ed76cbSbrad if(!dname) {
142015ed76cbSbrad (void)ssl_printf(ssl, "error cannot parse zone name\n");
14218d8f1862Ssthen return 0;
142215ed76cbSbrad }
142315ed76cbSbrad
142415ed76cbSbrad /* see if zone is a duplicate */
1425308d2509Sflorian if( zone_options_find(xfrd->nsd->options, dname) ) {
142615ed76cbSbrad region_recycle(xfrd->region, (void*)dname,
142715ed76cbSbrad dname_total_size(dname));
142815ed76cbSbrad (void)ssl_printf(ssl, "zone %s already exists\n", arg);
14298d8f1862Ssthen return 1;
143015ed76cbSbrad }
143115ed76cbSbrad region_recycle(xfrd->region, (void*)dname, dname_total_size(dname));
143215ed76cbSbrad dname = NULL;
143315ed76cbSbrad
1434d3fecca9Ssthen /* add to zonelist and adds to config in memory */
1435*bf87c3c0Sflorian zopt = zone_list_add_or_cat(xfrd->nsd->options, arg, arg2,
1436*bf87c3c0Sflorian xfrd_add_catalog_producer_member);
1437d3fecca9Ssthen if(!zopt) {
1438d3fecca9Ssthen /* also dname parse error here */
1439d3fecca9Ssthen (void)ssl_printf(ssl, "error could not add zonelist entry\n");
14408d8f1862Ssthen return 0;
1441d3fecca9Ssthen }
1442d3fecca9Ssthen /* make addzone task and schedule reload */
1443d3fecca9Ssthen task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask],
1444c1404d4fSbrad xfrd->last_task, arg, arg2,
1445c1404d4fSbrad getzonestatid(xfrd->nsd->options, zopt));
1446c1404d4fSbrad zonestat_inc_ifneeded(xfrd);
1447d3fecca9Ssthen xfrd_set_reload_now(xfrd);
1448*bf87c3c0Sflorian /* add to xfrd - catalog consumer zones */
1449*bf87c3c0Sflorian if (zone_is_catalog_consumer(zopt)) {
1450*bf87c3c0Sflorian xfrd_init_catalog_consumer_zone(xfrd, zopt);
1451*bf87c3c0Sflorian }
1452d3fecca9Ssthen /* add to xfrd - notify (for master and slaves) */
1453d3fecca9Ssthen init_notify_send(xfrd->notify_zones, xfrd->region, zopt);
1454d3fecca9Ssthen /* add to xfrd - slave */
1455d3fecca9Ssthen if(zone_is_slave(zopt)) {
1456d3fecca9Ssthen xfrd_init_slave_zone(xfrd, zopt);
1457d3fecca9Ssthen }
14588d8f1862Ssthen return 1;
1459d3fecca9Ssthen }
1460d3fecca9Ssthen
14618d8f1862Ssthen /** perform the delzone command for one zone */
14628d8f1862Ssthen static int
perform_delzone(RES * ssl,xfrd_state_type * xfrd,char * arg)146318e77612Sflorian perform_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg)
1464d3fecca9Ssthen {
1465d3fecca9Ssthen const dname_type* dname;
1466fe5fe5f6Sflorian struct zone_options* zopt;
1467*bf87c3c0Sflorian /* dont recycle dname when it becomes part of a xfrd_producer_member */
1468*bf87c3c0Sflorian int recycle_dname = 1;
1469d3fecca9Ssthen
1470d3fecca9Ssthen dname = dname_parse(xfrd->region, arg);
1471d3fecca9Ssthen if(!dname) {
1472d3fecca9Ssthen (void)ssl_printf(ssl, "error cannot parse zone name\n");
14738d8f1862Ssthen return 0;
1474d3fecca9Ssthen }
1475d3fecca9Ssthen
1476d3fecca9Ssthen /* see if we have the zone in question */
1477d3fecca9Ssthen zopt = zone_options_find(xfrd->nsd->options, dname);
1478d3fecca9Ssthen if(!zopt) {
1479d3fecca9Ssthen region_recycle(xfrd->region, (void*)dname,
1480d3fecca9Ssthen dname_total_size(dname));
1481d3fecca9Ssthen /* nothing to do */
1482308d2509Sflorian (void)ssl_printf(ssl, "warning zone %s not present\n", arg);
1483e02bc0dfSflorian return 0;
1484d3fecca9Ssthen }
1485d3fecca9Ssthen
1486d3fecca9Ssthen /* see if it can be deleted */
1487d3fecca9Ssthen if(zopt->part_of_config) {
1488d3fecca9Ssthen region_recycle(xfrd->region, (void*)dname,
1489d3fecca9Ssthen dname_total_size(dname));
1490d3fecca9Ssthen (void)ssl_printf(ssl, "error zone defined in nsd.conf, "
1491d3fecca9Ssthen "cannot delete it in this manner: remove it from "
1492d3fecca9Ssthen "nsd.conf yourself and repattern\n");
14938d8f1862Ssthen return 0;
1494d3fecca9Ssthen }
1495*bf87c3c0Sflorian if(zone_is_catalog_consumer_member(zopt)
1496*bf87c3c0Sflorian && as_catalog_member_zone(zopt)->member_id) {
1497*bf87c3c0Sflorian (void)ssl_printf(ssl, "Error: Zone is a catalog consumer "
1498*bf87c3c0Sflorian "member zone with id %s\nRemove the member id from the "
1499*bf87c3c0Sflorian "catalog to delete this zone.\n", dname_to_string(
1500*bf87c3c0Sflorian as_catalog_member_zone(zopt)->member_id, NULL));
1501*bf87c3c0Sflorian region_recycle(xfrd->region, (void*)dname, dname_total_size(dname));
1502*bf87c3c0Sflorian dname = NULL;
1503*bf87c3c0Sflorian return 0;
1504d3fecca9Ssthen
1505*bf87c3c0Sflorian }
1506d3fecca9Ssthen /* create deletion task */
1507d3fecca9Ssthen task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask],
1508d3fecca9Ssthen xfrd->last_task, dname);
1509d3fecca9Ssthen xfrd_set_reload_now(xfrd);
1510d3fecca9Ssthen /* delete it in xfrd */
1511d3fecca9Ssthen if(zone_is_slave(zopt)) {
1512d3fecca9Ssthen xfrd_del_slave_zone(xfrd, dname);
1513d3fecca9Ssthen }
1514d3fecca9Ssthen xfrd_del_notify(xfrd, dname);
1515*bf87c3c0Sflorian /* delete it in xfrd's catalog consumers list */
1516*bf87c3c0Sflorian if(zone_is_catalog_consumer(zopt)) {
1517*bf87c3c0Sflorian xfrd_deinit_catalog_consumer_zone(xfrd, dname);
1518*bf87c3c0Sflorian } else {
1519*bf87c3c0Sflorian recycle_dname = !xfrd_del_catalog_producer_member(xfrd, dname);
1520*bf87c3c0Sflorian }
1521d3fecca9Ssthen /* delete from config */
1522d3fecca9Ssthen zone_list_del(xfrd->nsd->options, zopt);
1523d3fecca9Ssthen
1524*bf87c3c0Sflorian if(recycle_dname)
1525*bf87c3c0Sflorian region_recycle(xfrd->region,
1526*bf87c3c0Sflorian (void*)dname, dname_total_size(dname));
15278d8f1862Ssthen return 1;
15288d8f1862Ssthen }
15298d8f1862Ssthen
15308d8f1862Ssthen /** do the addzone command */
15318d8f1862Ssthen static void
do_addzone(RES * ssl,xfrd_state_type * xfrd,char * arg)153218e77612Sflorian do_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg)
15338d8f1862Ssthen {
15348d8f1862Ssthen if(!perform_addzone(ssl, xfrd, arg))
15358d8f1862Ssthen return;
1536d3fecca9Ssthen send_ok(ssl);
1537d3fecca9Ssthen }
1538d3fecca9Ssthen
15398d8f1862Ssthen /** do the delzone command */
15408d8f1862Ssthen static void
do_delzone(RES * ssl,xfrd_state_type * xfrd,char * arg)154118e77612Sflorian do_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg)
15428d8f1862Ssthen {
15438d8f1862Ssthen if(!perform_delzone(ssl, xfrd, arg))
15448d8f1862Ssthen return;
15458d8f1862Ssthen send_ok(ssl);
15468d8f1862Ssthen }
15478d8f1862Ssthen
1548e02bc0dfSflorian /** do the changezone command */
1549e02bc0dfSflorian static void
do_changezone(RES * ssl,xfrd_state_type * xfrd,char * arg)1550e02bc0dfSflorian do_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg)
1551e02bc0dfSflorian {
1552e02bc0dfSflorian if(!perform_changezone(ssl, xfrd, arg))
1553e02bc0dfSflorian return;
1554e02bc0dfSflorian send_ok(ssl);
1555e02bc0dfSflorian }
1556e02bc0dfSflorian
15578d8f1862Ssthen /** do the addzones command */
15588d8f1862Ssthen static void
do_addzones(RES * ssl,xfrd_state_type * xfrd)155918e77612Sflorian do_addzones(RES* ssl, xfrd_state_type* xfrd)
15608d8f1862Ssthen {
15618d8f1862Ssthen char buf[2048];
15628d8f1862Ssthen int num = 0;
15638d8f1862Ssthen while(ssl_read_line(ssl, buf, sizeof(buf))) {
15648d8f1862Ssthen if(buf[0] == 0x04 && buf[1] == 0)
15658d8f1862Ssthen break; /* end of transmission */
15668d8f1862Ssthen if(!perform_addzone(ssl, xfrd, buf)) {
15678d8f1862Ssthen if(!ssl_printf(ssl, "error for input line '%s'\n",
15688d8f1862Ssthen buf))
15698d8f1862Ssthen return;
15708d8f1862Ssthen } else {
15718d8f1862Ssthen if(!ssl_printf(ssl, "added: %s\n", buf))
15728d8f1862Ssthen return;
15738d8f1862Ssthen num++;
15748d8f1862Ssthen }
15758d8f1862Ssthen }
15768d8f1862Ssthen (void)ssl_printf(ssl, "added %d zones\n", num);
15778d8f1862Ssthen }
15788d8f1862Ssthen
15798d8f1862Ssthen /** do the delzones command */
15808d8f1862Ssthen static void
do_delzones(RES * ssl,xfrd_state_type * xfrd)158118e77612Sflorian do_delzones(RES* ssl, xfrd_state_type* xfrd)
15828d8f1862Ssthen {
15838d8f1862Ssthen char buf[2048];
15848d8f1862Ssthen int num = 0;
15858d8f1862Ssthen while(ssl_read_line(ssl, buf, sizeof(buf))) {
15868d8f1862Ssthen if(buf[0] == 0x04 && buf[1] == 0)
15878d8f1862Ssthen break; /* end of transmission */
15888d8f1862Ssthen if(!perform_delzone(ssl, xfrd, buf)) {
15898d8f1862Ssthen if(!ssl_printf(ssl, "error for input line '%s'\n",
15908d8f1862Ssthen buf))
15918d8f1862Ssthen return;
15928d8f1862Ssthen } else {
15938d8f1862Ssthen if(!ssl_printf(ssl, "removed: %s\n", buf))
15948d8f1862Ssthen return;
15958d8f1862Ssthen num++;
15968d8f1862Ssthen }
15978d8f1862Ssthen }
15988d8f1862Ssthen (void)ssl_printf(ssl, "deleted %d zones\n", num);
15998d8f1862Ssthen }
16008d8f1862Ssthen
16018d8f1862Ssthen
1602d3fecca9Ssthen /** remove TSIG key from config and add task so that reload does too */
remove_key(xfrd_state_type * xfrd,const char * kname)1603fe5fe5f6Sflorian static void remove_key(xfrd_state_type* xfrd, const char* kname)
1604d3fecca9Ssthen {
1605d3fecca9Ssthen /* add task before deletion because the name string could be deleted */
1606d3fecca9Ssthen task_new_del_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task,
1607d3fecca9Ssthen kname);
1608d3fecca9Ssthen key_options_remove(xfrd->nsd->options, kname);
1609d3fecca9Ssthen xfrd_set_reload_now(xfrd); /* this is executed when the current control
1610d3fecca9Ssthen command ends, thus the entire config changes are bunched up */
1611d3fecca9Ssthen }
1612d3fecca9Ssthen
1613d3fecca9Ssthen /** add TSIG key to config and add task so that reload does too */
add_key(xfrd_state_type * xfrd,struct key_options * k)1614fe5fe5f6Sflorian static void add_key(xfrd_state_type* xfrd, struct key_options* k)
1615d3fecca9Ssthen {
1616d3fecca9Ssthen key_options_add_modify(xfrd->nsd->options, k);
1617d3fecca9Ssthen task_new_add_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task,
1618d3fecca9Ssthen k);
1619d3fecca9Ssthen xfrd_set_reload_now(xfrd);
1620d3fecca9Ssthen }
1621d3fecca9Ssthen
1622d3fecca9Ssthen /** check if keys have changed */
repat_keys(xfrd_state_type * xfrd,struct nsd_options * newopt)1623fe5fe5f6Sflorian static void repat_keys(xfrd_state_type* xfrd, struct nsd_options* newopt)
1624d3fecca9Ssthen {
1625fe5fe5f6Sflorian struct nsd_options* oldopt = xfrd->nsd->options;
1626fe5fe5f6Sflorian struct key_options* k;
1627d3fecca9Ssthen /* find deleted keys */
1628fe5fe5f6Sflorian k = (struct key_options*)rbtree_first(oldopt->keys);
1629fe5fe5f6Sflorian while((rbnode_type*)k != RBTREE_NULL) {
1630fe5fe5f6Sflorian struct key_options* next = (struct key_options*)rbtree_next(
1631fe5fe5f6Sflorian (rbnode_type*)k);
1632d3fecca9Ssthen if(!key_options_find(newopt, k->name))
1633d3fecca9Ssthen remove_key(xfrd, k->name);
1634d3fecca9Ssthen k = next;
1635d3fecca9Ssthen }
1636d3fecca9Ssthen /* find added or changed keys */
1637fe5fe5f6Sflorian RBTREE_FOR(k, struct key_options*, newopt->keys) {
1638fe5fe5f6Sflorian struct key_options* origk = key_options_find(oldopt, k->name);
1639d3fecca9Ssthen if(!origk)
1640d3fecca9Ssthen add_key(xfrd, k);
1641d3fecca9Ssthen else if(!key_options_equal(k, origk))
1642d3fecca9Ssthen add_key(xfrd, k);
1643d3fecca9Ssthen }
1644d3fecca9Ssthen }
1645d3fecca9Ssthen
1646d3fecca9Ssthen /** find zone given the implicit pattern */
1647d3fecca9Ssthen static const dname_type*
parse_implicit_name(xfrd_state_type * xfrd,const char * pname)1648fe5fe5f6Sflorian parse_implicit_name(xfrd_state_type* xfrd,const char* pname)
1649d3fecca9Ssthen {
1650d3fecca9Ssthen if(strncmp(pname, PATTERN_IMPLICIT_MARKER,
1651d3fecca9Ssthen strlen(PATTERN_IMPLICIT_MARKER)) != 0)
1652d3fecca9Ssthen return NULL;
1653d3fecca9Ssthen return dname_parse(xfrd->region, pname +
1654d3fecca9Ssthen strlen(PATTERN_IMPLICIT_MARKER));
1655d3fecca9Ssthen }
1656d3fecca9Ssthen
1657d3fecca9Ssthen /** remove cfgzone and add task so that reload does too */
1658d3fecca9Ssthen static void
remove_cfgzone(xfrd_state_type * xfrd,const char * pname)1659fe5fe5f6Sflorian remove_cfgzone(xfrd_state_type* xfrd, const char* pname)
1660d3fecca9Ssthen {
1661d3fecca9Ssthen /* dname and find the zone for the implicit pattern */
1662fe5fe5f6Sflorian struct zone_options* zopt = NULL;
1663d3fecca9Ssthen const dname_type* dname = parse_implicit_name(xfrd, pname);
1664d3fecca9Ssthen if(!dname) {
1665d3fecca9Ssthen /* should have a parseable name, but it did not */
1666d3fecca9Ssthen return;
1667d3fecca9Ssthen }
1668d3fecca9Ssthen
1669d3fecca9Ssthen /* find the zone entry for the implicit pattern */
1670d3fecca9Ssthen zopt = zone_options_find(xfrd->nsd->options, dname);
1671d3fecca9Ssthen if(!zopt) {
1672d3fecca9Ssthen /* this should not happen; implicit pattern has zone entry */
1673d3fecca9Ssthen region_recycle(xfrd->region, (void*)dname,
1674d3fecca9Ssthen dname_total_size(dname));
1675d3fecca9Ssthen return;
1676d3fecca9Ssthen }
1677d3fecca9Ssthen
1678d3fecca9Ssthen /* create deletion task */
1679d3fecca9Ssthen task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask],
1680d3fecca9Ssthen xfrd->last_task, dname);
1681d3fecca9Ssthen xfrd_set_reload_now(xfrd);
1682d3fecca9Ssthen /* delete it in xfrd */
1683d3fecca9Ssthen if(zone_is_slave(zopt)) {
1684d3fecca9Ssthen xfrd_del_slave_zone(xfrd, dname);
1685d3fecca9Ssthen }
1686d3fecca9Ssthen xfrd_del_notify(xfrd, dname);
1687*bf87c3c0Sflorian /* delete it in xfrd's catalog consumers list */
1688*bf87c3c0Sflorian if(zone_is_catalog_consumer(zopt)) {
1689*bf87c3c0Sflorian xfrd_deinit_catalog_consumer_zone(xfrd, dname);
1690*bf87c3c0Sflorian }
1691d3fecca9Ssthen
1692d3fecca9Ssthen /* delete from zoneoptions */
1693d3fecca9Ssthen zone_options_delete(xfrd->nsd->options, zopt);
1694d3fecca9Ssthen
1695d3fecca9Ssthen /* recycle parsed dname */
1696d3fecca9Ssthen region_recycle(xfrd->region, (void*)dname, dname_total_size(dname));
1697d3fecca9Ssthen }
1698d3fecca9Ssthen
1699d3fecca9Ssthen /** add cfgzone and add task so that reload does too */
1700d3fecca9Ssthen static void
add_cfgzone(xfrd_state_type * xfrd,const char * pname)1701fe5fe5f6Sflorian add_cfgzone(xfrd_state_type* xfrd, const char* pname)
1702d3fecca9Ssthen {
1703d3fecca9Ssthen /* add to our zonelist */
1704fe5fe5f6Sflorian struct zone_options* zopt = zone_options_create(
1705fe5fe5f6Sflorian xfrd->nsd->options->region);
1706d3fecca9Ssthen if(!zopt)
1707d3fecca9Ssthen return;
1708d3fecca9Ssthen zopt->part_of_config = 1;
1709d3fecca9Ssthen zopt->name = region_strdup(xfrd->nsd->options->region,
1710d3fecca9Ssthen pname + strlen(PATTERN_IMPLICIT_MARKER));
1711d3fecca9Ssthen zopt->pattern = pattern_options_find(xfrd->nsd->options, pname);
1712d3fecca9Ssthen if(!zopt->name || !zopt->pattern)
1713d3fecca9Ssthen return;
1714d3fecca9Ssthen if(!nsd_options_insert_zone(xfrd->nsd->options, zopt)) {
1715d3fecca9Ssthen log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' "
1716d3fecca9Ssthen "pattern %s", zopt->name, pname);
1717d3fecca9Ssthen }
1718d3fecca9Ssthen
1719d3fecca9Ssthen /* make addzone task and schedule reload */
1720d3fecca9Ssthen task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask],
1721c1404d4fSbrad xfrd->last_task, zopt->name, pname,
1722c1404d4fSbrad getzonestatid(xfrd->nsd->options, zopt));
1723c1404d4fSbrad /* zonestat_inc is done after the entire config file has been done */
1724d3fecca9Ssthen xfrd_set_reload_now(xfrd);
1725*bf87c3c0Sflorian /* add to xfrd - catalog consumer zones */
1726*bf87c3c0Sflorian if (zone_is_catalog_consumer(zopt)) {
1727*bf87c3c0Sflorian xfrd_init_catalog_consumer_zone(xfrd, zopt);
1728*bf87c3c0Sflorian }
1729d3fecca9Ssthen /* add to xfrd - notify (for master and slaves) */
1730d3fecca9Ssthen init_notify_send(xfrd->notify_zones, xfrd->region, zopt);
1731d3fecca9Ssthen /* add to xfrd - slave */
1732d3fecca9Ssthen if(zone_is_slave(zopt)) {
1733d3fecca9Ssthen xfrd_init_slave_zone(xfrd, zopt);
1734d3fecca9Ssthen }
1735d3fecca9Ssthen }
1736d3fecca9Ssthen
1737d3fecca9Ssthen /** remove pattern and add task so that reload does too */
1738d3fecca9Ssthen static void
remove_pat(xfrd_state_type * xfrd,const char * name)1739fe5fe5f6Sflorian remove_pat(xfrd_state_type* xfrd, const char* name)
1740d3fecca9Ssthen {
1741d3fecca9Ssthen /* add task before deletion, because name-string could be deleted */
1742d3fecca9Ssthen task_new_del_pattern(xfrd->nsd->task[xfrd->nsd->mytask],
1743d3fecca9Ssthen xfrd->last_task, name);
1744d3fecca9Ssthen pattern_options_remove(xfrd->nsd->options, name);
1745d3fecca9Ssthen xfrd_set_reload_now(xfrd);
1746d3fecca9Ssthen }
1747d3fecca9Ssthen
1748d3fecca9Ssthen /** add pattern and add task so that reload does too */
1749d3fecca9Ssthen static void
add_pat(xfrd_state_type * xfrd,struct pattern_options * p)1750fe5fe5f6Sflorian add_pat(xfrd_state_type* xfrd, struct pattern_options* p)
1751d3fecca9Ssthen {
1752d3fecca9Ssthen pattern_options_add_modify(xfrd->nsd->options, p);
1753d3fecca9Ssthen task_new_add_pattern(xfrd->nsd->task[xfrd->nsd->mytask],
1754d3fecca9Ssthen xfrd->last_task, p);
1755d3fecca9Ssthen xfrd_set_reload_now(xfrd);
1756d3fecca9Ssthen }
1757d3fecca9Ssthen
1758d3fecca9Ssthen /** interrupt zones that are using changed or removed patterns */
1759d3fecca9Ssthen static void
repat_interrupt_zones(xfrd_state_type * xfrd,struct nsd_options * newopt)1760fe5fe5f6Sflorian repat_interrupt_zones(xfrd_state_type* xfrd, struct nsd_options* newopt)
1761d3fecca9Ssthen {
1762d3fecca9Ssthen /* if masterlist changed:
1763d3fecca9Ssthen * interrupt slave zone (UDP or TCP) transfers.
1764d3fecca9Ssthen * slave zones reset master to start of list.
1765d3fecca9Ssthen */
1766fe5fe5f6Sflorian xfrd_zone_type* xz;
1767fe5fe5f6Sflorian struct notify_zone* nz;
1768fe5fe5f6Sflorian RBTREE_FOR(xz, xfrd_zone_type*, xfrd->zones) {
1769fe5fe5f6Sflorian struct pattern_options* oldp = xz->zone_options->pattern;
1770fe5fe5f6Sflorian struct pattern_options* newp = pattern_options_find(newopt,
1771d3fecca9Ssthen oldp->pname);
1772d3fecca9Ssthen if(!newp || !acl_list_equal(oldp->request_xfr,
1773d3fecca9Ssthen newp->request_xfr)) {
1774d3fecca9Ssthen /* interrupt transfer */
1775d3fecca9Ssthen if(xz->tcp_conn != -1) {
1776d3fecca9Ssthen xfrd_tcp_release(xfrd->tcp_set, xz);
1777d3fecca9Ssthen xfrd_set_refresh_now(xz);
1778d3fecca9Ssthen } else if(xz->zone_handler.ev_fd != -1) {
1779d3fecca9Ssthen xfrd_udp_release(xz);
1780d3fecca9Ssthen xfrd_set_refresh_now(xz);
1781d3fecca9Ssthen }
1782d3fecca9Ssthen xz->master = 0;
1783d3fecca9Ssthen xz->master_num = 0;
1784d3fecca9Ssthen xz->next_master = -1;
17856a6b9a23Sflorian xz->round_num = -1; /* fresh set of retries */
1786d3fecca9Ssthen }
1787d3fecca9Ssthen }
1788d3fecca9Ssthen /* if notify list changed:
1789d3fecca9Ssthen * interrupt notify that is busy.
1790d3fecca9Ssthen * reset notify to start of list. (clear all other reset_notify)
1791d3fecca9Ssthen */
1792fe5fe5f6Sflorian RBTREE_FOR(nz, struct notify_zone*, xfrd->notify_zones) {
1793fe5fe5f6Sflorian struct pattern_options* oldp = nz->options->pattern;
1794fe5fe5f6Sflorian struct pattern_options* newp = pattern_options_find(newopt,
1795d3fecca9Ssthen oldp->pname);
1796d3fecca9Ssthen if(!newp || !acl_list_equal(oldp->notify, newp->notify)) {
1797d3fecca9Ssthen /* interrupt notify */
1798d3fecca9Ssthen if(nz->notify_send_enable) {
1799d3fecca9Ssthen notify_disable(nz);
1800d3fecca9Ssthen /* set to restart the notify after the
1801d3fecca9Ssthen * pattern has been changed. */
1802d3fecca9Ssthen nz->notify_restart = 2;
1803d3fecca9Ssthen } else {
1804d3fecca9Ssthen nz->notify_restart = 1;
1805d3fecca9Ssthen }
1806d3fecca9Ssthen } else {
1807d3fecca9Ssthen nz->notify_restart = 0;
1808d3fecca9Ssthen }
1809d3fecca9Ssthen }
1810d3fecca9Ssthen }
1811d3fecca9Ssthen
1812d3fecca9Ssthen /** for notify, after the pattern changes, restart the affected notifies */
1813d3fecca9Ssthen static void
repat_interrupt_notify_start(xfrd_state_type * xfrd)1814fe5fe5f6Sflorian repat_interrupt_notify_start(xfrd_state_type* xfrd)
1815d3fecca9Ssthen {
1816fe5fe5f6Sflorian struct notify_zone* nz;
1817fe5fe5f6Sflorian RBTREE_FOR(nz, struct notify_zone*, xfrd->notify_zones) {
1818d3fecca9Ssthen if(nz->notify_restart) {
1819d3fecca9Ssthen if(nz->notify_current)
1820d3fecca9Ssthen nz->notify_current = nz->options->pattern->notify;
1821d3fecca9Ssthen if(nz->notify_restart == 2) {
1822d3fecca9Ssthen if(nz->notify_restart)
1823e3d8a0a5Ssthen xfrd_notify_start(nz, xfrd);
1824d3fecca9Ssthen }
1825d3fecca9Ssthen }
1826d3fecca9Ssthen }
1827d3fecca9Ssthen }
1828d3fecca9Ssthen
1829d3fecca9Ssthen /** check if patterns have changed */
1830d3fecca9Ssthen static void
repat_patterns(xfrd_state_type * xfrd,struct nsd_options * newopt)1831fe5fe5f6Sflorian repat_patterns(xfrd_state_type* xfrd, struct nsd_options* newopt)
1832d3fecca9Ssthen {
1833d3fecca9Ssthen /* zones that use changed patterns must have:
1834d3fecca9Ssthen * - their AXFR/IXFR interrupted: try again, acl may have changed.
1835d3fecca9Ssthen * if the old master/key still exists, OK, fix master-numptrs and
1836d3fecca9Ssthen * keep going. Otherwise, stop xfer and reset TSIG.
1837d3fecca9Ssthen * - send NOTIFY reset to start of NOTIFY list (and TSIG reset).
1838d3fecca9Ssthen */
1839fe5fe5f6Sflorian struct nsd_options* oldopt = xfrd->nsd->options;
1840fe5fe5f6Sflorian struct pattern_options* p;
1841d3fecca9Ssthen int search_zones = 0;
1842d3fecca9Ssthen
1843d3fecca9Ssthen repat_interrupt_zones(xfrd, newopt);
1844d3fecca9Ssthen /* find deleted patterns */
1845fe5fe5f6Sflorian p = (struct pattern_options*)rbtree_first(oldopt->patterns);
1846fe5fe5f6Sflorian while((rbnode_type*)p != RBTREE_NULL) {
1847fe5fe5f6Sflorian struct pattern_options* next = (struct pattern_options*)
1848fe5fe5f6Sflorian rbtree_next((rbnode_type*)p);
1849d3fecca9Ssthen if(!pattern_options_find(newopt, p->pname)) {
1850d3fecca9Ssthen if(p->implicit) {
1851d3fecca9Ssthen /* first remove its zone */
1852d3fecca9Ssthen VERBOSITY(1, (LOG_INFO, "zone removed from config: %s", p->pname + strlen(PATTERN_IMPLICIT_MARKER)));
1853d3fecca9Ssthen remove_cfgzone(xfrd, p->pname);
1854d3fecca9Ssthen }
1855d3fecca9Ssthen remove_pat(xfrd, p->pname);
1856d3fecca9Ssthen }
1857d3fecca9Ssthen p = next;
1858d3fecca9Ssthen }
1859d3fecca9Ssthen /* find added or changed patterns */
1860fe5fe5f6Sflorian RBTREE_FOR(p, struct pattern_options*, newopt->patterns) {
1861fe5fe5f6Sflorian struct pattern_options* origp = pattern_options_find(oldopt,
1862d3fecca9Ssthen p->pname);
1863d3fecca9Ssthen if(!origp) {
1864d3fecca9Ssthen /* no zones can use it, no zone_interrupt needed */
1865d3fecca9Ssthen add_pat(xfrd, p);
1866d3fecca9Ssthen if(p->implicit) {
1867d3fecca9Ssthen VERBOSITY(1, (LOG_INFO, "zone added to config: %s", p->pname + strlen(PATTERN_IMPLICIT_MARKER)));
1868d3fecca9Ssthen add_cfgzone(xfrd, p->pname);
1869d3fecca9Ssthen }
1870d3fecca9Ssthen } else if(!pattern_options_equal(p, origp)) {
1871d3fecca9Ssthen uint8_t newstate = 0;
1872d3fecca9Ssthen if (p->request_xfr && !origp->request_xfr) {
1873d3fecca9Ssthen newstate = REPAT_SLAVE;
1874d3fecca9Ssthen } else if (!p->request_xfr && origp->request_xfr) {
1875d3fecca9Ssthen newstate = REPAT_MASTER;
1876d3fecca9Ssthen }
1877*bf87c3c0Sflorian if ( p->catalog_role == CATALOG_ROLE_CONSUMER
1878*bf87c3c0Sflorian && origp->catalog_role != CATALOG_ROLE_CONSUMER) {
1879*bf87c3c0Sflorian newstate |= REPAT_CATALOG_CONSUMER;
1880*bf87c3c0Sflorian } else if (p->catalog_role != CATALOG_ROLE_CONSUMER
1881*bf87c3c0Sflorian && origp->catalog_role == CATALOG_ROLE_CONSUMER) {
1882*bf87c3c0Sflorian newstate |= REPAT_CATALOG_CONSUMER_DEINIT;
1883*bf87c3c0Sflorian }
1884d3fecca9Ssthen add_pat(xfrd, p);
1885d3fecca9Ssthen if (p->implicit && newstate) {
1886d3fecca9Ssthen const dname_type* dname =
1887d3fecca9Ssthen parse_implicit_name(xfrd, p->pname);
1888d3fecca9Ssthen if (dname) {
1889*bf87c3c0Sflorian if (newstate & REPAT_SLAVE) {
1890fe5fe5f6Sflorian struct zone_options* zopt =
1891d3fecca9Ssthen zone_options_find(
1892d3fecca9Ssthen oldopt, dname);
1893d3fecca9Ssthen if (zopt) {
1894d3fecca9Ssthen xfrd_init_slave_zone(
1895d3fecca9Ssthen xfrd, zopt);
1896d3fecca9Ssthen }
1897*bf87c3c0Sflorian } else if (newstate & REPAT_MASTER) {
1898d3fecca9Ssthen xfrd_del_slave_zone(xfrd,
1899d3fecca9Ssthen dname);
1900d3fecca9Ssthen }
1901*bf87c3c0Sflorian if (newstate & REPAT_CATALOG_CONSUMER) {
1902*bf87c3c0Sflorian struct zone_options* zopt =
1903*bf87c3c0Sflorian zone_options_find(
1904*bf87c3c0Sflorian oldopt, dname);
1905*bf87c3c0Sflorian if (zopt) {
1906*bf87c3c0Sflorian xfrd_init_catalog_consumer_zone(
1907*bf87c3c0Sflorian xfrd, zopt);
1908*bf87c3c0Sflorian }
1909*bf87c3c0Sflorian } else if (newstate & REPAT_CATALOG_CONSUMER_DEINIT) {
1910*bf87c3c0Sflorian xfrd_deinit_catalog_consumer_zone(
1911*bf87c3c0Sflorian xfrd, dname);
1912*bf87c3c0Sflorian }
1913d3fecca9Ssthen region_recycle(xfrd->region,
1914d3fecca9Ssthen (void*)dname,
1915d3fecca9Ssthen dname_total_size(dname));
1916d3fecca9Ssthen }
1917d3fecca9Ssthen } else if(!p->implicit && newstate) {
1918d3fecca9Ssthen /* search all zones with this pattern */
1919d3fecca9Ssthen search_zones = 1;
1920d3fecca9Ssthen origp->xfrd_flags = newstate;
1921d3fecca9Ssthen }
1922d3fecca9Ssthen }
1923d3fecca9Ssthen }
1924d3fecca9Ssthen if (search_zones) {
1925fe5fe5f6Sflorian struct zone_options* zone_opt;
1926d3fecca9Ssthen /* search in oldopt because 1) it contains zonelist zones,
1927d3fecca9Ssthen * and 2) you need oldopt(existing) to call xfrd_init */
1928fe5fe5f6Sflorian RBTREE_FOR(zone_opt, struct zone_options*, oldopt->zone_options) {
1929fe5fe5f6Sflorian struct pattern_options* oldp = zone_opt->pattern;
1930d3fecca9Ssthen if (!oldp->implicit) {
1931*bf87c3c0Sflorian if (oldp->xfrd_flags & REPAT_SLAVE) {
1932d3fecca9Ssthen /* xfrd needs stable reference so get
1933d3fecca9Ssthen * it from the oldopt(modified) tree */
1934d3fecca9Ssthen xfrd_init_slave_zone(xfrd, zone_opt);
1935*bf87c3c0Sflorian } else if (oldp->xfrd_flags & REPAT_MASTER) {
1936d3fecca9Ssthen xfrd_del_slave_zone(xfrd,
1937d3fecca9Ssthen (const dname_type*)
1938d3fecca9Ssthen zone_opt->node.key);
1939d3fecca9Ssthen }
1940*bf87c3c0Sflorian if (oldp->xfrd_flags & REPAT_CATALOG_CONSUMER) {
1941*bf87c3c0Sflorian xfrd_init_catalog_consumer_zone(xfrd,
1942*bf87c3c0Sflorian zone_opt);
1943*bf87c3c0Sflorian } else if (oldp->xfrd_flags & REPAT_CATALOG_CONSUMER_DEINIT) {
1944*bf87c3c0Sflorian xfrd_deinit_catalog_consumer_zone(xfrd,
1945*bf87c3c0Sflorian (const dname_type*)
1946*bf87c3c0Sflorian zone_opt->node.key);
1947*bf87c3c0Sflorian }
1948d3fecca9Ssthen oldp->xfrd_flags = 0;
1949d3fecca9Ssthen }
1950d3fecca9Ssthen }
1951d3fecca9Ssthen }
1952d3fecca9Ssthen repat_interrupt_notify_start(xfrd);
1953d3fecca9Ssthen }
1954d3fecca9Ssthen
1955d3fecca9Ssthen /** true if options are different that can be set via repat. */
1956d3fecca9Ssthen static int
repat_options_changed(xfrd_state_type * xfrd,struct nsd_options * newopt)1957fe5fe5f6Sflorian repat_options_changed(xfrd_state_type* xfrd, struct nsd_options* newopt)
1958d3fecca9Ssthen {
1959d3fecca9Ssthen #ifdef RATELIMIT
1960d3fecca9Ssthen if(xfrd->nsd->options->rrl_ratelimit != newopt->rrl_ratelimit)
1961d3fecca9Ssthen return 1;
1962d3fecca9Ssthen if(xfrd->nsd->options->rrl_whitelist_ratelimit != newopt->rrl_whitelist_ratelimit)
1963d3fecca9Ssthen return 1;
1964d3fecca9Ssthen if(xfrd->nsd->options->rrl_slip != newopt->rrl_slip)
1965d3fecca9Ssthen return 1;
1966d3fecca9Ssthen #else
1967d3fecca9Ssthen (void)xfrd; (void)newopt;
1968d3fecca9Ssthen #endif
1969d3fecca9Ssthen return 0;
1970d3fecca9Ssthen }
1971d3fecca9Ssthen
1972d3fecca9Ssthen /** check if global options have changed */
1973d3fecca9Ssthen static void
repat_options(xfrd_state_type * xfrd,struct nsd_options * newopt)1974fe5fe5f6Sflorian repat_options(xfrd_state_type* xfrd, struct nsd_options* newopt)
1975d3fecca9Ssthen {
1976d3fecca9Ssthen if(repat_options_changed(xfrd, newopt)) {
1977d3fecca9Ssthen /* update our options */
1978d3fecca9Ssthen #ifdef RATELIMIT
1979d3fecca9Ssthen xfrd->nsd->options->rrl_ratelimit = newopt->rrl_ratelimit;
1980d3fecca9Ssthen xfrd->nsd->options->rrl_whitelist_ratelimit = newopt->rrl_whitelist_ratelimit;
1981d3fecca9Ssthen xfrd->nsd->options->rrl_slip = newopt->rrl_slip;
1982d3fecca9Ssthen #endif
1983d3fecca9Ssthen task_new_opt_change(xfrd->nsd->task[xfrd->nsd->mytask],
1984d3fecca9Ssthen xfrd->last_task, newopt);
1985d3fecca9Ssthen xfrd_set_reload_now(xfrd);
1986d3fecca9Ssthen }
1987d3fecca9Ssthen }
1988d3fecca9Ssthen
1989d3fecca9Ssthen /** print errors over ssl, gets pointer-to-pointer to ssl, so it can set
1990d3fecca9Ssthen * the pointer to NULL on failure and stop printing */
1991d3fecca9Ssthen static void
print_ssl_cfg_err(void * arg,const char * str)1992d3fecca9Ssthen print_ssl_cfg_err(void* arg, const char* str)
1993d3fecca9Ssthen {
199418e77612Sflorian RES** ssl = (RES**)arg;
1995d3fecca9Ssthen if(!*ssl) return;
1996d3fecca9Ssthen if(!ssl_printf(*ssl, "%s", str))
1997d3fecca9Ssthen *ssl = NULL; /* failed, stop printing */
1998d3fecca9Ssthen }
1999d3fecca9Ssthen
2000d3fecca9Ssthen /** do the repattern command: reread config file and apply keys, patterns */
2001d3fecca9Ssthen static void
do_repattern(RES * ssl,xfrd_state_type * xfrd)200218e77612Sflorian do_repattern(RES* ssl, xfrd_state_type* xfrd)
2003d3fecca9Ssthen {
2004d3fecca9Ssthen region_type* region = region_create(xalloc, free);
2005fe5fe5f6Sflorian struct nsd_options* opt;
2006d3fecca9Ssthen const char* cfgfile = xfrd->nsd->options->configfile;
2007d3fecca9Ssthen
2008d3fecca9Ssthen /* check chroot and configfile, if possible to reread */
2009d3fecca9Ssthen if(xfrd->nsd->chrootdir) {
2010d3fecca9Ssthen size_t l = strlen(xfrd->nsd->chrootdir);
2011d3fecca9Ssthen while(l>0 && xfrd->nsd->chrootdir[l-1] == '/')
2012d3fecca9Ssthen --l;
2013d3fecca9Ssthen if(strncmp(xfrd->nsd->chrootdir, cfgfile, l) != 0) {
2014308d2509Sflorian (void)ssl_printf(ssl, "error %s is not relative to %s: "
2015d3fecca9Ssthen "chroot prevents reread of config\n",
2016d3fecca9Ssthen cfgfile, xfrd->nsd->chrootdir);
2017d3fecca9Ssthen region_destroy(region);
2018d3fecca9Ssthen return;
2019d3fecca9Ssthen }
2020d3fecca9Ssthen cfgfile += l;
2021d3fecca9Ssthen }
2022d3fecca9Ssthen
2023308d2509Sflorian (void)ssl_printf(ssl, "reconfig start, read %s\n", cfgfile);
2024d3fecca9Ssthen opt = nsd_options_create(region);
2025*bf87c3c0Sflorian if(!parse_options_file(opt, cfgfile, &print_ssl_cfg_err, &ssl,
2026*bf87c3c0Sflorian xfrd->nsd->options)) {
2027d3fecca9Ssthen /* error already printed */
2028d3fecca9Ssthen region_destroy(region);
2029d3fecca9Ssthen return;
2030d3fecca9Ssthen }
2031d3fecca9Ssthen /* check for differences in TSIG keys and patterns, and apply,
2032d3fecca9Ssthen * first the keys, so that pattern->keyptr can be set right. */
2033d3fecca9Ssthen repat_keys(xfrd, opt);
2034d3fecca9Ssthen repat_patterns(xfrd, opt);
2035d3fecca9Ssthen repat_options(xfrd, opt);
2036c1404d4fSbrad zonestat_inc_ifneeded(xfrd);
2037d3fecca9Ssthen send_ok(ssl);
2038d3fecca9Ssthen region_destroy(region);
2039d3fecca9Ssthen }
2040d3fecca9Ssthen
2041d3fecca9Ssthen /** do the serverpid command: printout pid of server process */
2042d3fecca9Ssthen static void
do_serverpid(RES * ssl,xfrd_state_type * xfrd)204318e77612Sflorian do_serverpid(RES* ssl, xfrd_state_type* xfrd)
2044d3fecca9Ssthen {
2045d3fecca9Ssthen (void)ssl_printf(ssl, "%u\n", (unsigned)xfrd->reload_pid);
2046d3fecca9Ssthen }
2047d3fecca9Ssthen
2048a1bac035Sflorian /** do the print_tsig command: printout tsig info */
2049a1bac035Sflorian static void
do_print_tsig(RES * ssl,xfrd_state_type * xfrd,char * arg)2050a1bac035Sflorian do_print_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg)
2051a1bac035Sflorian {
2052a1bac035Sflorian if(*arg == '\0') {
2053a1bac035Sflorian struct key_options* key;
2054a1bac035Sflorian RBTREE_FOR(key, struct key_options*, xfrd->nsd->options->keys) {
2055a1bac035Sflorian if(!ssl_printf(ssl, "key: name: \"%s\" secret: \"%s\" algorithm: %s\n", key->name, key->secret, key->algorithm))
2056a1bac035Sflorian return;
2057a1bac035Sflorian }
2058a1bac035Sflorian return;
2059a1bac035Sflorian } else {
2060a1bac035Sflorian struct key_options* key_opts = key_options_find(xfrd->nsd->options, arg);
2061a1bac035Sflorian if(!key_opts) {
2062308d2509Sflorian (void)ssl_printf(ssl, "error: no such key with name: %s\n", arg);
2063a1bac035Sflorian return;
2064a1bac035Sflorian } else {
2065308d2509Sflorian (void)ssl_printf(ssl, "key: name: \"%s\" secret: \"%s\" algorithm: %s\n", arg, key_opts->secret, key_opts->algorithm);
2066a1bac035Sflorian }
2067a1bac035Sflorian }
2068a1bac035Sflorian }
2069a1bac035Sflorian
2070a1bac035Sflorian /** do the update_tsig command: change existing tsig to new secret */
2071a1bac035Sflorian static void
do_update_tsig(RES * ssl,xfrd_state_type * xfrd,char * arg)2072a1bac035Sflorian do_update_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg)
2073a1bac035Sflorian {
2074a1bac035Sflorian struct region* region = xfrd->nsd->options->region;
2075a1bac035Sflorian char* arg2 = NULL;
2076a1bac035Sflorian uint8_t data[65536]; /* 64K */
2077a1bac035Sflorian struct key_options* key_opt;
2078a1bac035Sflorian
2079a1bac035Sflorian if(*arg == '\0') {
2080308d2509Sflorian (void)ssl_printf(ssl, "error: missing argument (keyname)\n");
2081a1bac035Sflorian return;
2082a1bac035Sflorian }
2083a1bac035Sflorian if(!find_arg2(ssl, arg, &arg2)) {
2084308d2509Sflorian (void)ssl_printf(ssl, "error: missing argument (secret)\n");
2085a1bac035Sflorian return;
2086a1bac035Sflorian }
2087a1bac035Sflorian key_opt = key_options_find(xfrd->nsd->options, arg);
2088a1bac035Sflorian if(!key_opt) {
2089308d2509Sflorian (void)ssl_printf(ssl, "error: no such key with name: %s\n", arg);
2090a1bac035Sflorian memset(arg2, 0xdd, strlen(arg2));
2091a1bac035Sflorian return;
2092a1bac035Sflorian }
2093a1bac035Sflorian if(__b64_pton(arg2, data, sizeof(data)) == -1) {
2094308d2509Sflorian (void)ssl_printf(ssl, "error: the secret: %s is not in b64 format\n", arg2);
2095a1bac035Sflorian memset(data, 0xdd, sizeof(data)); /* wipe secret */
2096a1bac035Sflorian memset(arg2, 0xdd, strlen(arg2));
2097a1bac035Sflorian return;
2098a1bac035Sflorian }
2099a1bac035Sflorian log_msg(LOG_INFO, "changing secret provided with the key: %s with old secret %s and algo: %s\n", arg, key_opt->secret, key_opt->algorithm);
2100a1bac035Sflorian if(key_opt->secret) {
2101a1bac035Sflorian /* wipe old secret */
2102a1bac035Sflorian memset(key_opt->secret, 0xdd, strlen(key_opt->secret));
2103a1bac035Sflorian region_recycle(region, key_opt->secret,
2104a1bac035Sflorian strlen(key_opt->secret)+1);
2105a1bac035Sflorian }
2106a1bac035Sflorian key_opt->secret = region_strdup(region, arg2);
2107a1bac035Sflorian log_msg(LOG_INFO, "the key: %s has new secret %s and algorithm: %s\n", arg, key_opt->secret, key_opt->algorithm);
2108a1bac035Sflorian /* wipe secret from temp parse buffer */
2109a1bac035Sflorian memset(arg2, 0xdd, strlen(arg2));
2110a1bac035Sflorian memset(data, 0xdd, sizeof(data));
2111a1bac035Sflorian
2112a1bac035Sflorian key_options_desetup(region, key_opt);
2113a1bac035Sflorian key_options_setup(region, key_opt);
2114a1bac035Sflorian task_new_add_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task,
2115a1bac035Sflorian key_opt);
2116a1bac035Sflorian xfrd_set_reload_now(xfrd);
2117a1bac035Sflorian
2118a1bac035Sflorian send_ok(ssl);
2119a1bac035Sflorian }
2120a1bac035Sflorian
2121a1bac035Sflorian /** do the add tsig command, add new key with name, secret and algo given */
2122a1bac035Sflorian static void
do_add_tsig(RES * ssl,xfrd_state_type * xfrd,char * arg)2123a1bac035Sflorian do_add_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg)
2124a1bac035Sflorian {
2125a1bac035Sflorian char* arg2 = NULL;
2126a1bac035Sflorian char* arg3 = NULL;
2127a1bac035Sflorian uint8_t data[65536]; /* 64KB */
2128a1bac035Sflorian uint8_t dname[MAXDOMAINLEN+1];
2129a1bac035Sflorian char algo[256];
2130a1bac035Sflorian region_type* region = xfrd->nsd->options->region;
2131a1bac035Sflorian struct key_options* new_key_opt;
2132a1bac035Sflorian
2133a1bac035Sflorian if(*arg == '\0') {
2134308d2509Sflorian (void)ssl_printf(ssl, "error: missing argument (keyname)\n");
2135a1bac035Sflorian return;
2136a1bac035Sflorian }
2137a1bac035Sflorian if(!find_arg3(ssl, arg, &arg2, &arg3)) {
2138a1bac035Sflorian strlcpy(algo, "hmac-sha256", sizeof(algo));
2139a1bac035Sflorian } else {
2140a1bac035Sflorian strlcpy(algo, arg3, sizeof(algo));
2141a1bac035Sflorian }
2142a1bac035Sflorian if(!arg2) {
2143308d2509Sflorian (void)ssl_printf(ssl, "error: missing argument (secret)\n");
2144a1bac035Sflorian return;
2145a1bac035Sflorian }
2146a1bac035Sflorian if(key_options_find(xfrd->nsd->options, arg)) {
2147308d2509Sflorian (void)ssl_printf(ssl, "error: key %s already exists\n", arg);
2148a1bac035Sflorian memset(arg2, 0xdd, strlen(arg2));
2149a1bac035Sflorian return;
2150a1bac035Sflorian }
2151a1bac035Sflorian if(__b64_pton(arg2, data, sizeof(data)) == -1) {
2152308d2509Sflorian (void)ssl_printf(ssl, "error: the secret: %s is not in b64 format\n", arg2);
2153a1bac035Sflorian memset(data, 0xdd, sizeof(data)); /* wipe secret */
2154a1bac035Sflorian memset(arg2, 0xdd, strlen(arg2));
2155a1bac035Sflorian return;
2156a1bac035Sflorian }
2157a1bac035Sflorian memset(data, 0xdd, sizeof(data)); /* wipe secret from temp buffer */
2158a1bac035Sflorian if(!dname_parse_wire(dname, arg)) {
2159308d2509Sflorian (void)ssl_printf(ssl, "error: could not parse key name: %s\n", arg);
2160a1bac035Sflorian memset(arg2, 0xdd, strlen(arg2));
2161a1bac035Sflorian return;
2162a1bac035Sflorian }
2163a1bac035Sflorian if(tsig_get_algorithm_by_name(algo) == NULL) {
2164308d2509Sflorian (void)ssl_printf(ssl, "error: unknown algorithm: %s\n", algo);
2165a1bac035Sflorian memset(arg2, 0xdd, strlen(arg2));
2166a1bac035Sflorian return;
2167a1bac035Sflorian }
2168a1bac035Sflorian log_msg(LOG_INFO, "adding key with name: %s and secret: %s with algo: %s\n", arg, arg2, algo);
2169a1bac035Sflorian new_key_opt = key_options_create(region);
2170a1bac035Sflorian new_key_opt->name = region_strdup(region, arg);
2171a1bac035Sflorian new_key_opt->secret = region_strdup(region, arg2);
2172a1bac035Sflorian new_key_opt->algorithm = region_strdup(region, algo);
2173a1bac035Sflorian add_key(xfrd, new_key_opt);
2174a1bac035Sflorian
2175a1bac035Sflorian /* wipe secret from temp buffer */
2176a1bac035Sflorian memset(arg2, 0xdd, strlen(arg2));
2177a1bac035Sflorian send_ok(ssl);
2178a1bac035Sflorian }
2179a1bac035Sflorian
2180a1bac035Sflorian /** set acl entries to use the given TSIG key */
2181a1bac035Sflorian static void
zopt_set_acl_to_tsig(struct acl_options * acl,struct region * region,const char * key_name,struct key_options * key_opt)2182a1bac035Sflorian zopt_set_acl_to_tsig(struct acl_options* acl, struct region* region,
2183a1bac035Sflorian const char* key_name, struct key_options* key_opt)
2184a1bac035Sflorian {
2185a1bac035Sflorian while(acl) {
2186a1bac035Sflorian if(acl->blocked) {
2187a1bac035Sflorian acl = acl->next;
2188a1bac035Sflorian continue;
2189a1bac035Sflorian }
2190a1bac035Sflorian acl->nokey = 0;
2191a1bac035Sflorian if(acl->key_name)
2192a1bac035Sflorian region_recycle(region, (void*)acl->key_name,
2193a1bac035Sflorian strlen(acl->key_name)+1);
2194a1bac035Sflorian acl->key_name = region_strdup(region, key_name);
2195a1bac035Sflorian acl->key_options = key_opt;
2196a1bac035Sflorian acl = acl->next;
2197a1bac035Sflorian }
2198a1bac035Sflorian }
2199a1bac035Sflorian
2200a1bac035Sflorian /** do the assoc_tsig command: associate the zone to use the tsig name */
2201a1bac035Sflorian static void
do_assoc_tsig(RES * ssl,xfrd_state_type * xfrd,char * arg)2202a1bac035Sflorian do_assoc_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg)
2203a1bac035Sflorian {
2204a1bac035Sflorian region_type* region = xfrd->nsd->options->region;
2205a1bac035Sflorian char* arg2 = NULL;
2206a1bac035Sflorian struct zone_options* zone;
2207a1bac035Sflorian struct key_options* key_opt;
2208a1bac035Sflorian
2209a1bac035Sflorian if(*arg == '\0') {
2210308d2509Sflorian (void)ssl_printf(ssl, "error: missing argument (zonename)\n");
2211a1bac035Sflorian return;
2212a1bac035Sflorian }
2213a1bac035Sflorian if(!find_arg2(ssl, arg, &arg2)) {
2214308d2509Sflorian (void)ssl_printf(ssl, "error: missing argument (keyname)\n");
2215a1bac035Sflorian return;
2216a1bac035Sflorian }
2217a1bac035Sflorian
2218a1bac035Sflorian if(!get_zone_arg(ssl, xfrd, arg, &zone))
2219a1bac035Sflorian return;
2220a1bac035Sflorian if(!zone) {
2221308d2509Sflorian (void)ssl_printf(ssl, "error: missing argument (zone)\n");
2222a1bac035Sflorian return;
2223a1bac035Sflorian }
2224a1bac035Sflorian key_opt = key_options_find(xfrd->nsd->options, arg2);
2225a1bac035Sflorian if(!key_opt) {
2226308d2509Sflorian (void)ssl_printf(ssl, "error: key: %s does not exist\n", arg2);
2227a1bac035Sflorian return;
2228a1bac035Sflorian }
2229a1bac035Sflorian
2230a1bac035Sflorian zopt_set_acl_to_tsig(zone->pattern->allow_notify, region, arg2,
2231a1bac035Sflorian key_opt);
2232a1bac035Sflorian zopt_set_acl_to_tsig(zone->pattern->notify, region, arg2, key_opt);
2233a1bac035Sflorian zopt_set_acl_to_tsig(zone->pattern->request_xfr, region, arg2,
2234a1bac035Sflorian key_opt);
2235a1bac035Sflorian zopt_set_acl_to_tsig(zone->pattern->provide_xfr, region, arg2,
2236a1bac035Sflorian key_opt);
22378d298c9fSsthen zopt_set_acl_to_tsig(zone->pattern->allow_query, region, arg2,
22388d298c9fSsthen key_opt);
2239a1bac035Sflorian
2240a1bac035Sflorian task_new_add_pattern(xfrd->nsd->task[xfrd->nsd->mytask],
2241a1bac035Sflorian xfrd->last_task, zone->pattern);
2242a1bac035Sflorian xfrd_set_reload_now(xfrd);
2243a1bac035Sflorian
2244a1bac035Sflorian send_ok(ssl);
2245a1bac035Sflorian }
2246a1bac035Sflorian
2247a1bac035Sflorian /** see if TSIG key is used in the acl */
2248a1bac035Sflorian static int
acl_contains_tsig_key(struct acl_options * acl,const char * name)2249a1bac035Sflorian acl_contains_tsig_key(struct acl_options* acl, const char* name)
2250a1bac035Sflorian {
2251a1bac035Sflorian while(acl) {
2252a1bac035Sflorian if(acl->key_name && strcmp(acl->key_name, name) == 0)
2253a1bac035Sflorian return 1;
2254a1bac035Sflorian acl = acl->next;
2255a1bac035Sflorian }
2256a1bac035Sflorian return 0;
2257a1bac035Sflorian }
2258a1bac035Sflorian
2259a1bac035Sflorian /** do the del_tsig command, remove an (unused) tsig */
2260a1bac035Sflorian static void
do_del_tsig(RES * ssl,xfrd_state_type * xfrd,char * arg)2261a1bac035Sflorian do_del_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) {
2262a1bac035Sflorian int used_key = 0;
2263a1bac035Sflorian struct zone_options* zone;
2264a1bac035Sflorian struct key_options* key_opt;
2265a1bac035Sflorian
2266a1bac035Sflorian if(*arg == '\0') {
2267308d2509Sflorian (void)ssl_printf(ssl, "error: missing argument (keyname)\n");
2268a1bac035Sflorian return;
2269a1bac035Sflorian }
2270a1bac035Sflorian key_opt = key_options_find(xfrd->nsd->options, arg);
2271a1bac035Sflorian if(!key_opt) {
2272308d2509Sflorian (void)ssl_printf(ssl, "key %s does not exist, nothing to be deleted\n", arg);
2273a1bac035Sflorian return;
2274a1bac035Sflorian }
2275a1bac035Sflorian RBTREE_FOR(zone, struct zone_options*, xfrd->nsd->options->zone_options)
2276a1bac035Sflorian {
2277a1bac035Sflorian if(acl_contains_tsig_key(zone->pattern->allow_notify, arg) ||
2278a1bac035Sflorian acl_contains_tsig_key(zone->pattern->notify, arg) ||
2279a1bac035Sflorian acl_contains_tsig_key(zone->pattern->request_xfr, arg) ||
22808d298c9fSsthen acl_contains_tsig_key(zone->pattern->provide_xfr, arg) ||
22818d298c9fSsthen acl_contains_tsig_key(zone->pattern->allow_query, arg)) {
2282a1bac035Sflorian if(!ssl_printf(ssl, "zone %s uses key %s\n",
2283a1bac035Sflorian zone->name, arg))
2284a1bac035Sflorian return;
2285a1bac035Sflorian used_key = 1;
2286a1bac035Sflorian break;
2287a1bac035Sflorian }
2288a1bac035Sflorian }
2289a1bac035Sflorian
2290a1bac035Sflorian if(used_key) {
2291308d2509Sflorian (void)ssl_printf(ssl, "error: key: %s is in use and cannot be deleted\n", arg);
2292a1bac035Sflorian return;
2293a1bac035Sflorian } else {
2294a1bac035Sflorian remove_key(xfrd, arg);
2295a1bac035Sflorian log_msg(LOG_INFO, "key: %s is successfully deleted\n", arg);
2296a1bac035Sflorian }
2297a1bac035Sflorian
2298a1bac035Sflorian send_ok(ssl);
2299a1bac035Sflorian }
2300a1bac035Sflorian
2301063644e9Sflorian /* returns `0` on failure */
2302063644e9Sflorian static int
cookie_secret_file_dump(RES * ssl,nsd_type const * nsd)2303063644e9Sflorian cookie_secret_file_dump(RES* ssl, nsd_type const* nsd) {
2304063644e9Sflorian char const* secret_file = nsd->options->cookie_secret_file;
2305063644e9Sflorian char secret_hex[NSD_COOKIE_SECRET_SIZE * 2 + 1];
2306063644e9Sflorian FILE* f;
2307063644e9Sflorian size_t i;
2308063644e9Sflorian assert( secret_file != NULL );
2309063644e9Sflorian
2310063644e9Sflorian /* open write only and truncate */
2311063644e9Sflorian if((f = fopen(secret_file, "w")) == NULL ) {
2312063644e9Sflorian (void)ssl_printf(ssl, "unable to open cookie secret file %s: %s",
2313063644e9Sflorian secret_file, strerror(errno));
2314063644e9Sflorian return 0;
2315063644e9Sflorian }
2316063644e9Sflorian for(i = 0; i < nsd->cookie_count; i++) {
2317063644e9Sflorian struct cookie_secret const* cs = &nsd->cookie_secrets[i];
2318063644e9Sflorian ssize_t const len = hex_ntop(cs->cookie_secret, NSD_COOKIE_SECRET_SIZE,
2319063644e9Sflorian secret_hex, sizeof(secret_hex));
2320063644e9Sflorian (void)len; /* silence unused variable warning with -DNDEBUG */
2321063644e9Sflorian assert( len == NSD_COOKIE_SECRET_SIZE * 2 );
2322063644e9Sflorian secret_hex[NSD_COOKIE_SECRET_SIZE * 2] = '\0';
2323063644e9Sflorian fprintf(f, "%s\n", secret_hex);
2324063644e9Sflorian }
2325063644e9Sflorian explicit_bzero(secret_hex, sizeof(secret_hex));
2326063644e9Sflorian fclose(f);
2327063644e9Sflorian return 1;
2328063644e9Sflorian }
2329063644e9Sflorian
2330063644e9Sflorian static void
do_activate_cookie_secret(RES * ssl,xfrd_state_type * xrfd,char * arg)2331063644e9Sflorian do_activate_cookie_secret(RES* ssl, xfrd_state_type* xrfd, char* arg) {
2332063644e9Sflorian nsd_type* nsd = xrfd->nsd;
2333063644e9Sflorian (void)arg;
2334063644e9Sflorian
2335063644e9Sflorian if(nsd->cookie_count <= 1 ) {
2336063644e9Sflorian (void)ssl_printf(ssl, "error: no staging cookie secret to activate\n");
2337063644e9Sflorian return;
2338063644e9Sflorian }
2339063644e9Sflorian if(!nsd->options->cookie_secret_file || !nsd->options->cookie_secret_file[0]) {
2340063644e9Sflorian (void)ssl_printf(ssl, "error: no cookie secret file configured\n");
2341063644e9Sflorian return;
2342063644e9Sflorian }
2343063644e9Sflorian if(!cookie_secret_file_dump(ssl, nsd)) {
2344063644e9Sflorian (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n",
2345063644e9Sflorian nsd->options->cookie_secret_file);
2346063644e9Sflorian return;
2347063644e9Sflorian }
2348063644e9Sflorian activate_cookie_secret(nsd);
2349063644e9Sflorian (void)cookie_secret_file_dump(ssl, nsd);
2350063644e9Sflorian task_new_activate_cookie_secret(xfrd->nsd->task[xfrd->nsd->mytask],
2351063644e9Sflorian xfrd->last_task);
2352063644e9Sflorian xfrd_set_reload_now(xfrd);
2353063644e9Sflorian send_ok(ssl);
2354063644e9Sflorian }
2355063644e9Sflorian
2356063644e9Sflorian static void
do_drop_cookie_secret(RES * ssl,xfrd_state_type * xrfd,char * arg)2357063644e9Sflorian do_drop_cookie_secret(RES* ssl, xfrd_state_type* xrfd, char* arg) {
2358063644e9Sflorian nsd_type* nsd = xrfd->nsd;
2359063644e9Sflorian (void)arg;
2360063644e9Sflorian
2361063644e9Sflorian if(nsd->cookie_count <= 1 ) {
2362063644e9Sflorian (void)ssl_printf(ssl, "error: can not drop the currently active cookie secret\n");
2363063644e9Sflorian return;
2364063644e9Sflorian }
2365063644e9Sflorian if(!nsd->options->cookie_secret_file || !nsd->options->cookie_secret_file[0]) {
2366063644e9Sflorian (void)ssl_printf(ssl, "error: no cookie secret file configured\n");
2367063644e9Sflorian return;
2368063644e9Sflorian }
2369063644e9Sflorian if(!cookie_secret_file_dump(ssl, nsd)) {
2370063644e9Sflorian (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n",
2371063644e9Sflorian nsd->options->cookie_secret_file);
2372063644e9Sflorian return;
2373063644e9Sflorian }
2374063644e9Sflorian drop_cookie_secret(nsd);
2375063644e9Sflorian (void)cookie_secret_file_dump(ssl, nsd);
2376063644e9Sflorian task_new_drop_cookie_secret(xfrd->nsd->task[xfrd->nsd->mytask],
2377063644e9Sflorian xfrd->last_task);
2378063644e9Sflorian xfrd_set_reload_now(xfrd);
2379063644e9Sflorian send_ok(ssl);
2380063644e9Sflorian }
2381063644e9Sflorian
2382063644e9Sflorian static void
do_add_cookie_secret(RES * ssl,xfrd_state_type * xrfd,char * arg)2383063644e9Sflorian do_add_cookie_secret(RES* ssl, xfrd_state_type* xrfd, char* arg) {
2384063644e9Sflorian nsd_type* nsd = xrfd->nsd;
2385063644e9Sflorian uint8_t secret[NSD_COOKIE_SECRET_SIZE];
2386063644e9Sflorian
2387063644e9Sflorian if(*arg == '\0') {
2388063644e9Sflorian (void)ssl_printf(ssl, "error: missing argument (cookie_secret)\n");
2389063644e9Sflorian return;
2390063644e9Sflorian }
2391063644e9Sflorian if(strlen(arg) != 32) {
2392063644e9Sflorian explicit_bzero(arg, strlen(arg));
2393063644e9Sflorian (void)ssl_printf(ssl, "invalid cookie secret: invalid argument length\n");
2394063644e9Sflorian (void)ssl_printf(ssl, "please provide a 128bit hex encoded secret\n");
2395063644e9Sflorian return;
2396063644e9Sflorian }
2397063644e9Sflorian if(hex_pton(arg, secret, NSD_COOKIE_SECRET_SIZE) != NSD_COOKIE_SECRET_SIZE ) {
2398063644e9Sflorian explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE);
2399063644e9Sflorian explicit_bzero(arg, strlen(arg));
2400063644e9Sflorian (void)ssl_printf(ssl, "invalid cookie secret: parse error\n");
2401063644e9Sflorian (void)ssl_printf(ssl, "please provide a 128bit hex encoded secret\n");
2402063644e9Sflorian return;
2403063644e9Sflorian }
2404063644e9Sflorian if(!nsd->options->cookie_secret_file || !nsd->options->cookie_secret_file[0]) {
2405063644e9Sflorian explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE);
2406063644e9Sflorian explicit_bzero(arg, strlen(arg));
2407063644e9Sflorian (void)ssl_printf(ssl, "error: no cookie secret file configured\n");
2408063644e9Sflorian return;
2409063644e9Sflorian }
2410063644e9Sflorian if(!cookie_secret_file_dump(ssl, nsd)) {
2411063644e9Sflorian explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE);
2412063644e9Sflorian explicit_bzero(arg, strlen(arg));
2413063644e9Sflorian (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n",
2414063644e9Sflorian nsd->options->cookie_secret_file);
2415063644e9Sflorian return;
2416063644e9Sflorian }
2417063644e9Sflorian add_cookie_secret(nsd, secret);
2418063644e9Sflorian explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE);
2419063644e9Sflorian (void)cookie_secret_file_dump(ssl, nsd);
2420063644e9Sflorian task_new_add_cookie_secret(xfrd->nsd->task[xfrd->nsd->mytask],
2421063644e9Sflorian xfrd->last_task, arg);
2422063644e9Sflorian explicit_bzero(arg, strlen(arg));
2423063644e9Sflorian xfrd_set_reload_now(xfrd);
2424063644e9Sflorian send_ok(ssl);
2425063644e9Sflorian }
2426063644e9Sflorian
2427063644e9Sflorian static void
do_print_cookie_secrets(RES * ssl,xfrd_state_type * xrfd,char * arg)2428063644e9Sflorian do_print_cookie_secrets(RES* ssl, xfrd_state_type* xrfd, char* arg) {
2429063644e9Sflorian nsd_type* nsd = xrfd->nsd;
2430063644e9Sflorian char secret_hex[NSD_COOKIE_SECRET_SIZE * 2 + 1];
2431063644e9Sflorian int i;
2432063644e9Sflorian (void)arg;
2433063644e9Sflorian
2434063644e9Sflorian /* (void)ssl_printf(ssl, "cookie_secret_count=%zu\n", nsd->cookie_count); */
2435063644e9Sflorian for(i = 0; (size_t)i < nsd->cookie_count; i++) {
2436063644e9Sflorian struct cookie_secret const* cs = &nsd->cookie_secrets[i];
2437063644e9Sflorian ssize_t const len = hex_ntop(cs->cookie_secret, NSD_COOKIE_SECRET_SIZE,
2438063644e9Sflorian secret_hex, sizeof(secret_hex));
2439063644e9Sflorian (void)len; /* silence unused variable warning with -DNDEBUG */
2440063644e9Sflorian assert( len == NSD_COOKIE_SECRET_SIZE * 2 );
2441063644e9Sflorian secret_hex[NSD_COOKIE_SECRET_SIZE * 2] = '\0';
2442063644e9Sflorian if (i == 0)
2443063644e9Sflorian (void)ssl_printf(ssl, "active : %s\n", secret_hex);
2444063644e9Sflorian else if (nsd->cookie_count == 2)
2445063644e9Sflorian (void)ssl_printf(ssl, "staging: %s\n", secret_hex);
2446063644e9Sflorian else
2447063644e9Sflorian (void)ssl_printf(ssl, "staging[%d]: %s\n", i, secret_hex);
2448063644e9Sflorian }
2449063644e9Sflorian explicit_bzero(secret_hex, sizeof(secret_hex));
2450063644e9Sflorian }
2451063644e9Sflorian
2452d3fecca9Ssthen /** check for name with end-of-string, space or tab after it */
2453d3fecca9Ssthen static int
cmdcmp(char * p,const char * cmd,size_t len)2454d3fecca9Ssthen cmdcmp(char* p, const char* cmd, size_t len)
2455d3fecca9Ssthen {
2456d3fecca9Ssthen return strncmp(p,cmd,len)==0 && (p[len]==0||p[len]==' '||p[len]=='\t');
2457d3fecca9Ssthen }
2458d3fecca9Ssthen
2459d3fecca9Ssthen /** execute a remote control command */
2460d3fecca9Ssthen static void
execute_cmd(struct daemon_remote * rc,RES * ssl,char * cmd)2461b71395eaSflorian execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd)
2462d3fecca9Ssthen {
2463d3fecca9Ssthen char* p = skipwhite(cmd);
2464d3fecca9Ssthen /* compare command */
2465d3fecca9Ssthen if(cmdcmp(p, "stop", 4)) {
2466d3fecca9Ssthen do_stop(ssl, rc->xfrd);
2467d3fecca9Ssthen } else if(cmdcmp(p, "reload", 6)) {
2468d3fecca9Ssthen do_reload(ssl, rc->xfrd, skipwhite(p+6));
2469d3fecca9Ssthen } else if(cmdcmp(p, "write", 5)) {
2470d3fecca9Ssthen do_write(ssl, rc->xfrd, skipwhite(p+5));
2471d3fecca9Ssthen } else if(cmdcmp(p, "status", 6)) {
2472d3fecca9Ssthen do_status(ssl, rc->xfrd);
2473d3fecca9Ssthen } else if(cmdcmp(p, "stats_noreset", 13)) {
2474b71395eaSflorian do_stats(ssl, rc->xfrd, 1);
2475d3fecca9Ssthen } else if(cmdcmp(p, "stats", 5)) {
2476b71395eaSflorian do_stats(ssl, rc->xfrd, 0);
2477d3fecca9Ssthen } else if(cmdcmp(p, "log_reopen", 10)) {
2478d3fecca9Ssthen do_log_reopen(ssl, rc->xfrd);
2479d3fecca9Ssthen } else if(cmdcmp(p, "addzone", 7)) {
2480d3fecca9Ssthen do_addzone(ssl, rc->xfrd, skipwhite(p+7));
2481d3fecca9Ssthen } else if(cmdcmp(p, "delzone", 7)) {
2482d3fecca9Ssthen do_delzone(ssl, rc->xfrd, skipwhite(p+7));
2483e02bc0dfSflorian } else if(cmdcmp(p, "changezone", 10)) {
2484e02bc0dfSflorian do_changezone(ssl, rc->xfrd, skipwhite(p+10));
24858d8f1862Ssthen } else if(cmdcmp(p, "addzones", 8)) {
24868d8f1862Ssthen do_addzones(ssl, rc->xfrd);
24878d8f1862Ssthen } else if(cmdcmp(p, "delzones", 8)) {
24888d8f1862Ssthen do_delzones(ssl, rc->xfrd);
2489d3fecca9Ssthen } else if(cmdcmp(p, "notify", 6)) {
2490d3fecca9Ssthen do_notify(ssl, rc->xfrd, skipwhite(p+6));
2491d3fecca9Ssthen } else if(cmdcmp(p, "transfer", 8)) {
2492d3fecca9Ssthen do_transfer(ssl, rc->xfrd, skipwhite(p+8));
2493d3fecca9Ssthen } else if(cmdcmp(p, "force_transfer", 14)) {
2494d3fecca9Ssthen do_force_transfer(ssl, rc->xfrd, skipwhite(p+14));
2495d3fecca9Ssthen } else if(cmdcmp(p, "zonestatus", 10)) {
2496d3fecca9Ssthen do_zonestatus(ssl, rc->xfrd, skipwhite(p+10));
2497d3fecca9Ssthen } else if(cmdcmp(p, "verbosity", 9)) {
2498d3fecca9Ssthen do_verbosity(ssl, skipwhite(p+9));
2499d3fecca9Ssthen } else if(cmdcmp(p, "repattern", 9)) {
2500d3fecca9Ssthen do_repattern(ssl, rc->xfrd);
2501d3fecca9Ssthen } else if(cmdcmp(p, "reconfig", 8)) {
2502d3fecca9Ssthen do_repattern(ssl, rc->xfrd);
2503d3fecca9Ssthen } else if(cmdcmp(p, "serverpid", 9)) {
2504d3fecca9Ssthen do_serverpid(ssl, rc->xfrd);
2505a1bac035Sflorian } else if(cmdcmp(p, "print_tsig", 10)) {
2506a1bac035Sflorian do_print_tsig(ssl, rc->xfrd, skipwhite(p+10));
2507a1bac035Sflorian } else if(cmdcmp(p, "update_tsig", 11)) {
2508a1bac035Sflorian do_update_tsig(ssl, rc->xfrd, skipwhite(p+11));
2509a1bac035Sflorian } else if(cmdcmp(p, "add_tsig", 8)) {
2510a1bac035Sflorian do_add_tsig(ssl, rc->xfrd, skipwhite(p+8));
2511a1bac035Sflorian } else if(cmdcmp(p, "assoc_tsig", 10)) {
2512a1bac035Sflorian do_assoc_tsig(ssl, rc->xfrd, skipwhite(p+10));
2513a1bac035Sflorian } else if(cmdcmp(p, "del_tsig", 8)) {
2514a1bac035Sflorian do_del_tsig(ssl, rc->xfrd, skipwhite(p+8));
2515063644e9Sflorian } else if(cmdcmp(p, "add_cookie_secret", 17)) {
2516063644e9Sflorian do_add_cookie_secret(ssl, rc->xfrd, skipwhite(p+17));
2517063644e9Sflorian } else if(cmdcmp(p, "drop_cookie_secret", 18)) {
2518063644e9Sflorian do_drop_cookie_secret(ssl, rc->xfrd, skipwhite(p+18));
2519063644e9Sflorian } else if(cmdcmp(p, "print_cookie_secrets", 20)) {
2520063644e9Sflorian do_print_cookie_secrets(ssl, rc->xfrd, skipwhite(p+20));
2521063644e9Sflorian } else if(cmdcmp(p, "activate_cookie_secret", 22)) {
2522063644e9Sflorian do_activate_cookie_secret(ssl, rc->xfrd, skipwhite(p+22));
2523d3fecca9Ssthen } else {
2524d3fecca9Ssthen (void)ssl_printf(ssl, "error unknown command '%s'\n", p);
2525d3fecca9Ssthen }
2526d3fecca9Ssthen }
2527d3fecca9Ssthen
2528d3fecca9Ssthen /** handle remote control request */
2529d3fecca9Ssthen static void
handle_req(struct daemon_remote * rc,struct rc_state * s,RES * res)253018e77612Sflorian handle_req(struct daemon_remote* rc, struct rc_state* s, RES* res)
2531d3fecca9Ssthen {
2532d3fecca9Ssthen int r;
2533d3fecca9Ssthen char pre[10];
2534d3fecca9Ssthen char magic[8];
2535d3fecca9Ssthen char buf[1024];
2536d3fecca9Ssthen if (fcntl(s->c.ev_fd, F_SETFL, 0) == -1) { /* set blocking */
2537d3fecca9Ssthen log_msg(LOG_ERR, "cannot fcntl rc: %s", strerror(errno));
2538d3fecca9Ssthen }
2539d3fecca9Ssthen
2540d3fecca9Ssthen /* try to read magic UBCT[version]_space_ string */
25413efee2e1Sflorian #ifdef HAVE_SSL
254218e77612Sflorian if(res->ssl) {
2543d3fecca9Ssthen ERR_clear_error();
254418e77612Sflorian if((r=SSL_read(res->ssl, magic, (int)sizeof(magic)-1)) <= 0) {
254518e77612Sflorian if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN)
2546d3fecca9Ssthen return;
2547d3fecca9Ssthen log_crypto_err("could not SSL_read");
2548d3fecca9Ssthen return;
2549d3fecca9Ssthen }
255018e77612Sflorian } else {
25513efee2e1Sflorian #endif /* HAVE_SSL */
255218e77612Sflorian while(1) {
255318e77612Sflorian ssize_t rr = read(res->fd, magic, sizeof(magic)-1);
255418e77612Sflorian if(rr <= 0) {
255518e77612Sflorian if(rr == 0) return;
255618e77612Sflorian if(errno == EINTR || errno == EAGAIN)
255718e77612Sflorian continue;
255818e77612Sflorian log_msg(LOG_ERR, "could not read: %s", strerror(errno));
255918e77612Sflorian return;
256018e77612Sflorian }
256118e77612Sflorian r = (int)rr;
256218e77612Sflorian break;
256318e77612Sflorian }
25643efee2e1Sflorian #ifdef HAVE_SSL
256518e77612Sflorian }
25663efee2e1Sflorian #endif /* HAVE_SSL */
2567d3fecca9Ssthen magic[7] = 0;
2568d3fecca9Ssthen if( r != 7 || strncmp(magic, "NSDCT", 5) != 0) {
2569d3fecca9Ssthen VERBOSITY(2, (LOG_INFO, "control connection has bad header"));
2570d3fecca9Ssthen /* probably wrong tool connected, ignore it completely */
2571d3fecca9Ssthen return;
2572d3fecca9Ssthen }
2573d3fecca9Ssthen
2574d3fecca9Ssthen /* read the command line */
257518e77612Sflorian if(!ssl_read_line(res, buf, sizeof(buf))) {
2576d3fecca9Ssthen return;
2577d3fecca9Ssthen }
2578d3fecca9Ssthen snprintf(pre, sizeof(pre), "NSDCT%d ", NSD_CONTROL_VERSION);
2579d3fecca9Ssthen if(strcmp(magic, pre) != 0) {
2580d3fecca9Ssthen VERBOSITY(2, (LOG_INFO, "control connection had bad "
2581d3fecca9Ssthen "version %s, cmd: %s", magic, buf));
2582308d2509Sflorian (void)ssl_printf(res, "error version mismatch\n");
2583d3fecca9Ssthen return;
2584d3fecca9Ssthen }
2585de04d855Ssthen /* always log control commands */
2586de04d855Ssthen VERBOSITY(0, (LOG_INFO, "control cmd: %s", buf));
2587d3fecca9Ssthen
2588d3fecca9Ssthen /* figure out what to do */
2589b71395eaSflorian execute_cmd(rc, res, buf);
2590d3fecca9Ssthen }
2591d3fecca9Ssthen
25923efee2e1Sflorian #ifdef HAVE_SSL
259318e77612Sflorian /** handle SSL_do_handshake changes to the file descriptor to wait for later */
2594d3fecca9Ssthen static void
remote_handshake_later(struct daemon_remote * rc,struct rc_state * s,int fd,int r,int r2)259518e77612Sflorian remote_handshake_later(struct daemon_remote* rc, struct rc_state* s, int fd,
259618e77612Sflorian int r, int r2)
2597d3fecca9Ssthen {
2598d3fecca9Ssthen if(r2 == SSL_ERROR_WANT_READ) {
2599d3fecca9Ssthen if(s->shake_state == rc_hs_read) {
2600d3fecca9Ssthen /* try again later */
2601d3fecca9Ssthen return;
2602d3fecca9Ssthen }
2603d3fecca9Ssthen s->shake_state = rc_hs_read;
2604*bf87c3c0Sflorian if(s->event_added)
2605d3fecca9Ssthen event_del(&s->c);
2606eab1363eSsthen memset(&s->c, 0, sizeof(s->c));
2607d3fecca9Ssthen event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_READ,
2608d3fecca9Ssthen remote_control_callback, s);
2609d3fecca9Ssthen if(event_base_set(xfrd->event_base, &s->c) != 0)
2610d3fecca9Ssthen log_msg(LOG_ERR, "remote_accept: cannot set event_base");
2611d3fecca9Ssthen if(event_add(&s->c, &s->tval) != 0)
2612d3fecca9Ssthen log_msg(LOG_ERR, "remote_accept: cannot add event");
2613*bf87c3c0Sflorian s->event_added = 1;
2614d3fecca9Ssthen return;
2615d3fecca9Ssthen } else if(r2 == SSL_ERROR_WANT_WRITE) {
2616d3fecca9Ssthen if(s->shake_state == rc_hs_write) {
2617d3fecca9Ssthen /* try again later */
2618d3fecca9Ssthen return;
2619d3fecca9Ssthen }
2620d3fecca9Ssthen s->shake_state = rc_hs_write;
2621*bf87c3c0Sflorian if(s->event_added)
2622d3fecca9Ssthen event_del(&s->c);
2623eab1363eSsthen memset(&s->c, 0, sizeof(s->c));
2624d3fecca9Ssthen event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE,
2625d3fecca9Ssthen remote_control_callback, s);
2626d3fecca9Ssthen if(event_base_set(xfrd->event_base, &s->c) != 0)
2627d3fecca9Ssthen log_msg(LOG_ERR, "remote_accept: cannot set event_base");
2628d3fecca9Ssthen if(event_add(&s->c, &s->tval) != 0)
2629d3fecca9Ssthen log_msg(LOG_ERR, "remote_accept: cannot add event");
2630*bf87c3c0Sflorian s->event_added = 1;
2631d3fecca9Ssthen return;
2632d3fecca9Ssthen } else {
2633d3fecca9Ssthen if(r == 0)
2634d3fecca9Ssthen log_msg(LOG_ERR, "remote control connection closed prematurely");
2635d3fecca9Ssthen log_crypto_err("remote control failed ssl");
2636d3fecca9Ssthen clean_point(rc, s);
263718e77612Sflorian }
263818e77612Sflorian }
26393efee2e1Sflorian #endif /* HAVE_SSL */
264018e77612Sflorian
264118e77612Sflorian static void
remote_control_callback(int fd,short event,void * arg)264218e77612Sflorian remote_control_callback(int fd, short event, void* arg)
264318e77612Sflorian {
264418e77612Sflorian RES res;
264518e77612Sflorian struct rc_state* s = (struct rc_state*)arg;
264618e77612Sflorian struct daemon_remote* rc = s->rc;
264718e77612Sflorian if( (event&EV_TIMEOUT) ) {
264818e77612Sflorian log_msg(LOG_ERR, "remote control timed out");
264918e77612Sflorian clean_point(rc, s);
2650d3fecca9Ssthen return;
2651d3fecca9Ssthen }
26523efee2e1Sflorian #ifdef HAVE_SSL
265318e77612Sflorian if(s->ssl) {
265418e77612Sflorian /* (continue to) setup the SSL connection */
26553efee2e1Sflorian int r;
265618e77612Sflorian ERR_clear_error();
265718e77612Sflorian r = SSL_do_handshake(s->ssl);
265818e77612Sflorian if(r != 1) {
265918e77612Sflorian int r2 = SSL_get_error(s->ssl, r);
266018e77612Sflorian remote_handshake_later(rc, s, fd, r, r2);
266118e77612Sflorian return;
2662d3fecca9Ssthen }
2663d3fecca9Ssthen s->shake_state = rc_none;
266418e77612Sflorian }
26653efee2e1Sflorian #endif /* HAVE_SSL */
2666d3fecca9Ssthen
2667d3fecca9Ssthen /* once handshake has completed, check authentication */
266818e77612Sflorian if (!rc->use_cert) {
266918e77612Sflorian VERBOSITY(3, (LOG_INFO, "unauthenticated remote control connection"));
26703efee2e1Sflorian #ifdef HAVE_SSL
267118e77612Sflorian } else if(SSL_get_verify_result(s->ssl) == X509_V_OK) {
2672d3fecca9Ssthen X509* x = SSL_get_peer_certificate(s->ssl);
2673d3fecca9Ssthen if(!x) {
2674d3fecca9Ssthen VERBOSITY(2, (LOG_INFO, "remote control connection "
2675d3fecca9Ssthen "provided no client certificate"));
2676d3fecca9Ssthen clean_point(rc, s);
2677d3fecca9Ssthen return;
2678d3fecca9Ssthen }
2679d3fecca9Ssthen VERBOSITY(3, (LOG_INFO, "remote control connection authenticated"));
2680d3fecca9Ssthen X509_free(x);
26813efee2e1Sflorian #endif /* HAVE_SSL */
2682d3fecca9Ssthen } else {
2683d3fecca9Ssthen VERBOSITY(2, (LOG_INFO, "remote control connection failed to "
2684d3fecca9Ssthen "authenticate with client certificate"));
2685d3fecca9Ssthen clean_point(rc, s);
2686d3fecca9Ssthen return;
2687d3fecca9Ssthen }
2688d3fecca9Ssthen
2689d3fecca9Ssthen /* if OK start to actually handle the request */
26903efee2e1Sflorian #ifdef HAVE_SSL
269118e77612Sflorian res.ssl = s->ssl;
26923efee2e1Sflorian #endif /* HAVE_SSL */
269318e77612Sflorian res.fd = fd;
269418e77612Sflorian handle_req(rc, s, &res);
2695d3fecca9Ssthen
2696d3fecca9Ssthen VERBOSITY(3, (LOG_INFO, "remote control operation completed"));
2697d3fecca9Ssthen clean_point(rc, s);
2698d3fecca9Ssthen }
2699d3fecca9Ssthen
2700d3fecca9Ssthen #ifdef BIND8_STATS
2701d3fecca9Ssthen static const char*
opcode2str(int o)2702d3fecca9Ssthen opcode2str(int o)
2703d3fecca9Ssthen {
2704d3fecca9Ssthen switch(o) {
2705d3fecca9Ssthen case OPCODE_QUERY: return "QUERY";
2706d3fecca9Ssthen case OPCODE_IQUERY: return "IQUERY";
2707d3fecca9Ssthen case OPCODE_STATUS: return "STATUS";
2708d3fecca9Ssthen case OPCODE_NOTIFY: return "NOTIFY";
2709d3fecca9Ssthen case OPCODE_UPDATE: return "UPDATE";
2710d3fecca9Ssthen default: return "OTHER";
2711d3fecca9Ssthen }
2712d3fecca9Ssthen }
2713d3fecca9Ssthen
2714d3fecca9Ssthen /** print long number */
2715d3fecca9Ssthen static int
print_longnum(RES * ssl,char * desc,uint64_t x)271618e77612Sflorian print_longnum(RES* ssl, char* desc, uint64_t x)
2717d3fecca9Ssthen {
2718d3fecca9Ssthen if(x > (uint64_t)1024*1024*1024) {
2719d3fecca9Ssthen /* more than a Gb */
2720d3fecca9Ssthen size_t front = (size_t)(x / (uint64_t)1000000);
2721d3fecca9Ssthen size_t back = (size_t)(x % (uint64_t)1000000);
272218e77612Sflorian return ssl_printf(ssl, "%s%lu%6.6lu\n", desc,
272318e77612Sflorian (unsigned long)front, (unsigned long)back);
2724d3fecca9Ssthen } else {
272518e77612Sflorian return ssl_printf(ssl, "%s%lu\n", desc, (unsigned long)x);
2726d3fecca9Ssthen }
2727d3fecca9Ssthen }
2728d3fecca9Ssthen
2729c1404d4fSbrad /* print one block of statistics. n is name and d is delimiter */
2730d3fecca9Ssthen static void
print_stat_block(RES * ssl,char * n,char * d,struct nsdst * st)273118e77612Sflorian print_stat_block(RES* ssl, char* n, char* d, struct nsdst* st)
2732d3fecca9Ssthen {
2733d3fecca9Ssthen const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN",
2734d3fecca9Ssthen "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH",
2735d3fecca9Ssthen "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15",
2736d3fecca9Ssthen "BADVERS"
2737d3fecca9Ssthen };
2738d3fecca9Ssthen size_t i;
2739c1404d4fSbrad for(i=0; i<= 255; i++) {
2740c1404d4fSbrad if(inhibit_zero && st->qtype[i] == 0 &&
2741c1404d4fSbrad strncmp(rrtype_to_string(i), "TYPE", 4) == 0)
2742c1404d4fSbrad continue;
274318e77612Sflorian if(!ssl_printf(ssl, "%s%snum.type.%s=%lu\n", n, d,
274418e77612Sflorian rrtype_to_string(i), (unsigned long)st->qtype[i]))
2745c1404d4fSbrad return;
2746c1404d4fSbrad }
2747c1404d4fSbrad
2748c1404d4fSbrad /* opcode */
2749c1404d4fSbrad for(i=0; i<6; i++) {
2750c1404d4fSbrad if(inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY)
2751c1404d4fSbrad continue;
275218e77612Sflorian if(!ssl_printf(ssl, "%s%snum.opcode.%s=%lu\n", n, d,
275318e77612Sflorian opcode2str(i), (unsigned long)st->opcode[i]))
2754c1404d4fSbrad return;
2755c1404d4fSbrad }
2756c1404d4fSbrad
2757c1404d4fSbrad /* qclass */
2758c1404d4fSbrad for(i=0; i<4; i++) {
2759c1404d4fSbrad if(inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN)
2760c1404d4fSbrad continue;
276118e77612Sflorian if(!ssl_printf(ssl, "%s%snum.class.%s=%lu\n", n, d,
276218e77612Sflorian rrclass_to_string(i), (unsigned long)st->qclass[i]))
2763c1404d4fSbrad return;
2764c1404d4fSbrad }
2765c1404d4fSbrad
2766c1404d4fSbrad /* rcode */
2767c1404d4fSbrad for(i=0; i<17; i++) {
2768c1404d4fSbrad if(inhibit_zero && st->rcode[i] == 0 &&
2769c1404d4fSbrad i > RCODE_YXDOMAIN) /* NSD does not use larger */
2770c1404d4fSbrad continue;
277118e77612Sflorian if(!ssl_printf(ssl, "%s%snum.rcode.%s=%lu\n", n, d, rcstr[i],
277218e77612Sflorian (unsigned long)st->rcode[i]))
2773c1404d4fSbrad return;
2774c1404d4fSbrad }
2775c1404d4fSbrad
2776c1404d4fSbrad /* edns */
277718e77612Sflorian if(!ssl_printf(ssl, "%s%snum.edns=%lu\n", n, d, (unsigned long)st->edns))
2778c1404d4fSbrad return;
2779c1404d4fSbrad
2780c1404d4fSbrad /* ednserr */
278118e77612Sflorian if(!ssl_printf(ssl, "%s%snum.ednserr=%lu\n", n, d,
278218e77612Sflorian (unsigned long)st->ednserr))
2783c1404d4fSbrad return;
2784c1404d4fSbrad
2785c1404d4fSbrad /* qudp */
278618e77612Sflorian if(!ssl_printf(ssl, "%s%snum.udp=%lu\n", n, d, (unsigned long)st->qudp))
2787c1404d4fSbrad return;
2788c1404d4fSbrad /* qudp6 */
278918e77612Sflorian if(!ssl_printf(ssl, "%s%snum.udp6=%lu\n", n, d, (unsigned long)st->qudp6))
2790c1404d4fSbrad return;
2791c1404d4fSbrad /* ctcp */
279218e77612Sflorian if(!ssl_printf(ssl, "%s%snum.tcp=%lu\n", n, d, (unsigned long)st->ctcp))
2793c1404d4fSbrad return;
2794c1404d4fSbrad /* ctcp6 */
279518e77612Sflorian if(!ssl_printf(ssl, "%s%snum.tcp6=%lu\n", n, d, (unsigned long)st->ctcp6))
2796c1404d4fSbrad return;
2797eab1363eSsthen /* ctls */
2798eab1363eSsthen if(!ssl_printf(ssl, "%s%snum.tls=%lu\n", n, d, (unsigned long)st->ctls))
2799eab1363eSsthen return;
2800eab1363eSsthen /* ctls6 */
2801eab1363eSsthen if(!ssl_printf(ssl, "%s%snum.tls6=%lu\n", n, d, (unsigned long)st->ctls6))
2802eab1363eSsthen return;
2803c1404d4fSbrad
2804c1404d4fSbrad /* nona */
280518e77612Sflorian if(!ssl_printf(ssl, "%s%snum.answer_wo_aa=%lu\n", n, d,
280618e77612Sflorian (unsigned long)st->nona))
2807c1404d4fSbrad return;
2808c1404d4fSbrad
2809c1404d4fSbrad /* rxerr */
281018e77612Sflorian if(!ssl_printf(ssl, "%s%snum.rxerr=%lu\n", n, d, (unsigned long)st->rxerr))
2811c1404d4fSbrad return;
2812c1404d4fSbrad
2813c1404d4fSbrad /* txerr */
281418e77612Sflorian if(!ssl_printf(ssl, "%s%snum.txerr=%lu\n", n, d, (unsigned long)st->txerr))
2815c1404d4fSbrad return;
2816c1404d4fSbrad
2817c1404d4fSbrad /* number of requested-axfr, number of times axfr served to clients */
281818e77612Sflorian if(!ssl_printf(ssl, "%s%snum.raxfr=%lu\n", n, d, (unsigned long)st->raxfr))
2819c1404d4fSbrad return;
2820c1404d4fSbrad
28214564029fSflorian /* number of requested-ixfr, number of times ixfr served to clients */
28224564029fSflorian if(!ssl_printf(ssl, "%s%snum.rixfr=%lu\n", n, d, (unsigned long)st->rixfr))
28234564029fSflorian return;
28244564029fSflorian
2825c1404d4fSbrad /* truncated */
282618e77612Sflorian if(!ssl_printf(ssl, "%s%snum.truncated=%lu\n", n, d,
282718e77612Sflorian (unsigned long)st->truncated))
2828c1404d4fSbrad return;
2829c1404d4fSbrad
2830c1404d4fSbrad /* dropped */
283118e77612Sflorian if(!ssl_printf(ssl, "%s%snum.dropped=%lu\n", n, d,
283218e77612Sflorian (unsigned long)st->dropped))
2833c1404d4fSbrad return;
2834c1404d4fSbrad }
2835c1404d4fSbrad
2836c1404d4fSbrad #ifdef USE_ZONE_STATS
2837c1404d4fSbrad static void
resize_zonestat(xfrd_state_type * xfrd,size_t num)2838fe5fe5f6Sflorian resize_zonestat(xfrd_state_type* xfrd, size_t num)
2839c1404d4fSbrad {
28408d8f1862Ssthen struct nsdst** a = xalloc_array_zero(num, sizeof(struct nsdst*));
2841c1404d4fSbrad if(xfrd->zonestat_clear_num != 0)
2842c1404d4fSbrad memcpy(a, xfrd->zonestat_clear, xfrd->zonestat_clear_num
2843c1404d4fSbrad * sizeof(struct nsdst*));
2844c1404d4fSbrad free(xfrd->zonestat_clear);
2845c1404d4fSbrad xfrd->zonestat_clear = a;
2846c1404d4fSbrad xfrd->zonestat_clear_num = num;
2847c1404d4fSbrad }
2848c1404d4fSbrad
2849c1404d4fSbrad static void
zonestat_print(RES * ssl,xfrd_state_type * xfrd,int clear,struct nsdst ** zonestats)2850b71395eaSflorian zonestat_print(RES* ssl, xfrd_state_type* xfrd, int clear,
2851b71395eaSflorian struct nsdst** zonestats)
2852c1404d4fSbrad {
2853c1404d4fSbrad struct zonestatname* n;
2854c1404d4fSbrad struct nsdst stat0, stat1;
2855c1404d4fSbrad RBTREE_FOR(n, struct zonestatname*, xfrd->nsd->options->zonestatnames){
2856c1404d4fSbrad char* name = (char*)n->node.key;
2857c1404d4fSbrad if(n->id >= xfrd->zonestat_safe)
2858c1404d4fSbrad continue; /* newly allocated and reload has not yet
2859c1404d4fSbrad done and replied with new size */
2860c1404d4fSbrad if(name == NULL || name[0]==0)
2861c1404d4fSbrad continue; /* empty name, do not output */
2862c1404d4fSbrad /* the statistics are stored in two blocks, during reload
2863c1404d4fSbrad * the newly forked processes get the other block to use,
2864c1404d4fSbrad * these blocks are mmapped and are currently in use to
2865c1404d4fSbrad * add statistics to */
2866b71395eaSflorian memcpy(&stat0, &zonestats[0][n->id], sizeof(stat0));
2867b71395eaSflorian memcpy(&stat1, &zonestats[1][n->id], sizeof(stat1));
2868c1404d4fSbrad stats_add(&stat0, &stat1);
2869c1404d4fSbrad
2870c1404d4fSbrad /* save a copy of current (cumulative) stats in stat1 */
2871c1404d4fSbrad memcpy(&stat1, &stat0, sizeof(stat1));
2872c1404d4fSbrad /* subtract last total of stats that was 'cleared' */
2873c1404d4fSbrad if(n->id < xfrd->zonestat_clear_num &&
2874c1404d4fSbrad xfrd->zonestat_clear[n->id])
2875c1404d4fSbrad stats_subtract(&stat0, xfrd->zonestat_clear[n->id]);
2876c1404d4fSbrad if(clear) {
2877c1404d4fSbrad /* extend storage array if needed */
2878c1404d4fSbrad if(n->id >= xfrd->zonestat_clear_num) {
2879c1404d4fSbrad if(n->id+1 < xfrd->nsd->options->zonestatnames->count)
2880c1404d4fSbrad resize_zonestat(xfrd, xfrd->nsd->options->zonestatnames->count);
2881c1404d4fSbrad else
2882c1404d4fSbrad resize_zonestat(xfrd, n->id+1);
2883c1404d4fSbrad }
2884c1404d4fSbrad if(!xfrd->zonestat_clear[n->id])
2885c1404d4fSbrad xfrd->zonestat_clear[n->id] = xalloc(
2886c1404d4fSbrad sizeof(struct nsdst));
2887c1404d4fSbrad /* store last total of stats */
2888c1404d4fSbrad memcpy(xfrd->zonestat_clear[n->id], &stat1,
2889c1404d4fSbrad sizeof(struct nsdst));
2890c1404d4fSbrad }
2891c1404d4fSbrad
2892c1404d4fSbrad /* stat0 contains the details that we want to print */
289318e77612Sflorian if(!ssl_printf(ssl, "%s%snum.queries=%lu\n", name, ".",
289418e77612Sflorian (unsigned long)(stat0.qudp + stat0.qudp6 + stat0.ctcp +
2895eab1363eSsthen stat0.ctcp6 + stat0.ctls + stat0.ctls6)))
2896c1404d4fSbrad return;
2897c1404d4fSbrad print_stat_block(ssl, name, ".", &stat0);
2898c1404d4fSbrad }
2899c1404d4fSbrad }
2900c1404d4fSbrad #endif /* USE_ZONE_STATS */
2901c1404d4fSbrad
2902c1404d4fSbrad static void
print_stats(RES * ssl,xfrd_state_type * xfrd,struct timeval * now,int clear,struct nsdst * st,struct nsdst ** zonestats)2903b71395eaSflorian print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear,
2904b71395eaSflorian struct nsdst* st, struct nsdst** zonestats)
2905c1404d4fSbrad {
2906c1404d4fSbrad size_t i;
2907fe5fe5f6Sflorian stc_type total = 0;
2908d3fecca9Ssthen struct timeval elapsed, uptime;
2909d3fecca9Ssthen
2910d3fecca9Ssthen /* per CPU and total */
2911d3fecca9Ssthen for(i=0; i<xfrd->nsd->child_count; i++) {
291218e77612Sflorian if(!ssl_printf(ssl, "server%d.queries=%lu\n", (int)i,
291318e77612Sflorian (unsigned long)xfrd->nsd->children[i].query_count))
2914d3fecca9Ssthen return;
2915d3fecca9Ssthen total += xfrd->nsd->children[i].query_count;
2916d3fecca9Ssthen }
291718e77612Sflorian if(!ssl_printf(ssl, "num.queries=%lu\n", (unsigned long)total))
2918d3fecca9Ssthen return;
2919d3fecca9Ssthen
2920d3fecca9Ssthen /* time elapsed and uptime (in seconds) */
2921d3fecca9Ssthen timeval_subtract(&uptime, now, &xfrd->nsd->rc->boot_time);
2922d3fecca9Ssthen timeval_subtract(&elapsed, now, &xfrd->nsd->rc->stats_time);
292318e77612Sflorian if(!ssl_printf(ssl, "time.boot=%lu.%6.6lu\n",
292418e77612Sflorian (unsigned long)uptime.tv_sec, (unsigned long)uptime.tv_usec))
2925d3fecca9Ssthen return;
292618e77612Sflorian if(!ssl_printf(ssl, "time.elapsed=%lu.%6.6lu\n",
292718e77612Sflorian (unsigned long)elapsed.tv_sec, (unsigned long)elapsed.tv_usec))
2928d3fecca9Ssthen return;
2929d3fecca9Ssthen
2930d3fecca9Ssthen /* mem info, database on disksize */
2931b71395eaSflorian if(!print_longnum(ssl, "size.db.disk=", st->db_disk))
2932d3fecca9Ssthen return;
2933b71395eaSflorian if(!print_longnum(ssl, "size.db.mem=", st->db_mem))
2934d3fecca9Ssthen return;
2935d3fecca9Ssthen if(!print_longnum(ssl, "size.xfrd.mem=", region_get_mem(xfrd->region)))
2936d3fecca9Ssthen return;
2937d3fecca9Ssthen if(!print_longnum(ssl, "size.config.disk=",
2938d3fecca9Ssthen xfrd->nsd->options->zonelist_off))
2939d3fecca9Ssthen return;
2940d3fecca9Ssthen if(!print_longnum(ssl, "size.config.mem=", region_get_mem(
2941d3fecca9Ssthen xfrd->nsd->options->region)))
2942d3fecca9Ssthen return;
2943b71395eaSflorian print_stat_block(ssl, "", "", st);
2944d3fecca9Ssthen
2945d3fecca9Ssthen /* zone statistics */
2946*bf87c3c0Sflorian if(!ssl_printf(ssl, "zone.primary=%lu\n",
2947*bf87c3c0Sflorian (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count)))
2948*bf87c3c0Sflorian return;
2949*bf87c3c0Sflorian if(!ssl_printf(ssl, "zone.secondary=%lu\n", (unsigned long)xfrd->zones->count))
2950*bf87c3c0Sflorian return;
295118e77612Sflorian if(!ssl_printf(ssl, "zone.master=%lu\n",
295218e77612Sflorian (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count)))
2953d3fecca9Ssthen return;
295418e77612Sflorian if(!ssl_printf(ssl, "zone.slave=%lu\n", (unsigned long)xfrd->zones->count))
2955d3fecca9Ssthen return;
2956c1404d4fSbrad #ifdef USE_ZONE_STATS
2957b71395eaSflorian zonestat_print(ssl, xfrd, clear, zonestats); /* per-zone statistics */
2958c1404d4fSbrad #else
2959b71395eaSflorian (void)clear; (void)zonestats;
2960c1404d4fSbrad #endif
2961d3fecca9Ssthen }
2962d3fecca9Ssthen
2963b71395eaSflorian /* allocate stats temp arrays, for taking a coherent snapshot of the
2964b71395eaSflorian * statistics values at that time. */
2965d3fecca9Ssthen static void
process_stats_alloc(xfrd_state_type * xfrd,struct nsdst ** stats,struct nsdst ** zonestats)2966b71395eaSflorian process_stats_alloc(xfrd_state_type* xfrd, struct nsdst** stats,
2967b71395eaSflorian struct nsdst** zonestats)
2968b71395eaSflorian {
2969b71395eaSflorian *stats = xmallocarray(xfrd->nsd->child_count*2, sizeof(struct nsdst));
2970b71395eaSflorian #ifdef USE_ZONE_STATS
2971b71395eaSflorian zonestats[0] = xmallocarray(xfrd->zonestat_safe, sizeof(struct nsdst));
2972b71395eaSflorian zonestats[1] = xmallocarray(xfrd->zonestat_safe, sizeof(struct nsdst));
2973b71395eaSflorian #else
2974b71395eaSflorian (void)zonestats;
2975b71395eaSflorian #endif
2976b71395eaSflorian }
2977b71395eaSflorian
2978b71395eaSflorian /* grab a copy of the statistics, at this particular time. */
2979b71395eaSflorian static void
process_stats_grab(xfrd_state_type * xfrd,struct timeval * stattime,struct nsdst * stats,struct nsdst ** zonestats)2980b71395eaSflorian process_stats_grab(xfrd_state_type* xfrd, struct timeval* stattime,
2981b71395eaSflorian struct nsdst* stats, struct nsdst** zonestats)
2982b71395eaSflorian {
2983b71395eaSflorian if(gettimeofday(stattime, NULL) == -1)
2984b71395eaSflorian log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno));
2985b71395eaSflorian memcpy(stats, xfrd->nsd->stat_map,
2986b71395eaSflorian xfrd->nsd->child_count*2*sizeof(struct nsdst));
2987b71395eaSflorian #ifdef USE_ZONE_STATS
2988b71395eaSflorian memcpy(zonestats[0], xfrd->nsd->zonestat[0],
2989b71395eaSflorian xfrd->zonestat_safe*sizeof(struct nsdst));
2990b71395eaSflorian memcpy(zonestats[1], xfrd->nsd->zonestat[1],
2991b71395eaSflorian xfrd->zonestat_safe*sizeof(struct nsdst));
2992b71395eaSflorian #else
2993b71395eaSflorian (void)zonestats;
2994b71395eaSflorian #endif
2995b71395eaSflorian }
2996b71395eaSflorian
2997b71395eaSflorian /* add the old and new processes stat values into the first part of the
2998b71395eaSflorian * array of stats */
2999b71395eaSflorian static void
process_stats_add_old_new(xfrd_state_type * xfrd,struct nsdst * stats)3000b71395eaSflorian process_stats_add_old_new(xfrd_state_type* xfrd, struct nsdst* stats)
3001d3fecca9Ssthen {
3002d3fecca9Ssthen size_t i;
3003b71395eaSflorian uint64_t dbd = stats[0].db_disk;
3004b71395eaSflorian uint64_t dbm = stats[0].db_mem;
3005b71395eaSflorian /* The old and new server processes have separate stat blocks,
3006b71395eaSflorian * and these are added up together. This results in the statistics
3007b71395eaSflorian * values per server-child. The reload task briefly forks both
3008b71395eaSflorian * old and new server processes. */
3009d3fecca9Ssthen for(i=0; i<xfrd->nsd->child_count; i++) {
3010b71395eaSflorian stats_add(&stats[i], &stats[xfrd->nsd->child_count+i]);
3011d3fecca9Ssthen }
3012b71395eaSflorian stats[0].db_disk = dbd;
3013b71395eaSflorian stats[0].db_mem = dbm;
3014d3fecca9Ssthen }
3015d3fecca9Ssthen
3016b71395eaSflorian /* manage clearing of stats, a cumulative count of cleared statistics */
3017b71395eaSflorian static void
process_stats_manage_clear(xfrd_state_type * xfrd,struct nsdst * stats,int peek)3018b71395eaSflorian process_stats_manage_clear(xfrd_state_type* xfrd, struct nsdst* stats,
3019b71395eaSflorian int peek)
3020d3fecca9Ssthen {
3021b71395eaSflorian struct nsdst st;
3022b71395eaSflorian size_t i;
3023b71395eaSflorian if(peek) {
3024b71395eaSflorian /* Subtract the earlier resetted values from the numbers,
3025b71395eaSflorian * but do not reset the values that are retrieved now. */
3026b71395eaSflorian if(!xfrd->stat_clear)
3027b71395eaSflorian return; /* nothing to subtract */
3028b71395eaSflorian for(i=0; i<xfrd->nsd->child_count; i++) {
3029b71395eaSflorian /* subtract cumulative count that has been reset */
3030b71395eaSflorian stats_subtract(&stats[i], &xfrd->stat_clear[i]);
3031b71395eaSflorian }
3032b71395eaSflorian return;
3033b71395eaSflorian }
3034b71395eaSflorian if(!xfrd->stat_clear)
3035b71395eaSflorian xfrd->stat_clear = region_alloc_zero(xfrd->region,
3036b71395eaSflorian sizeof(struct nsdst)*xfrd->nsd->child_count);
3037b71395eaSflorian for(i=0; i<xfrd->nsd->child_count; i++) {
3038b71395eaSflorian /* store cumulative count copy */
3039b71395eaSflorian memcpy(&st, &stats[i], sizeof(st));
3040b71395eaSflorian /* subtract cumulative count that has been reset */
3041b71395eaSflorian stats_subtract(&stats[i], &xfrd->stat_clear[i]);
3042b71395eaSflorian /* store cumulative count in the cleared value array */
3043b71395eaSflorian memcpy(&xfrd->stat_clear[i], &st, sizeof(st));
3044b71395eaSflorian }
3045b71395eaSflorian }
3046b71395eaSflorian
3047b71395eaSflorian /* add up the statistics to get the total over the server children. */
3048b71395eaSflorian static void
process_stats_add_total(xfrd_state_type * xfrd,struct nsdst * total,struct nsdst * stats)3049b71395eaSflorian process_stats_add_total(xfrd_state_type* xfrd, struct nsdst* total,
3050b71395eaSflorian struct nsdst* stats)
3051b71395eaSflorian {
3052b71395eaSflorian size_t i;
3053b71395eaSflorian /* copy over the first one, with also the nonadded values. */
3054b71395eaSflorian memcpy(total, &stats[0], sizeof(*total));
3055b71395eaSflorian xfrd->nsd->children[0].query_count = stats[0].qudp + stats[0].qudp6
3056b71395eaSflorian + stats[0].ctcp + stats[0].ctcp6 + stats[0].ctls
3057b71395eaSflorian + stats[0].ctls6;
3058b71395eaSflorian for(i=1; i<xfrd->nsd->child_count; i++) {
3059b71395eaSflorian stats_add(total, &stats[i]);
3060b71395eaSflorian xfrd->nsd->children[i].query_count = stats[i].qudp
3061b71395eaSflorian + stats[i].qudp6 + stats[i].ctcp + stats[i].ctcp6
3062b71395eaSflorian + stats[i].ctls + stats[i].ctls6;
3063b71395eaSflorian }
3064b71395eaSflorian }
3065b71395eaSflorian
3066b71395eaSflorian /* process the statistics and output them */
3067b71395eaSflorian static void
process_stats(RES * ssl,xfrd_state_type * xfrd,int peek)3068b71395eaSflorian process_stats(RES* ssl, xfrd_state_type* xfrd, int peek)
3069b71395eaSflorian {
3070b71395eaSflorian struct timeval stattime;
3071b71395eaSflorian struct nsdst* stats, *zonestats[2], total;
3072b71395eaSflorian
3073b71395eaSflorian process_stats_alloc(xfrd, &stats, zonestats);
3074b71395eaSflorian process_stats_grab(xfrd, &stattime, stats, zonestats);
3075b71395eaSflorian process_stats_add_old_new(xfrd, stats);
3076b71395eaSflorian process_stats_manage_clear(xfrd, stats, peek);
3077b71395eaSflorian process_stats_add_total(xfrd, &total, stats);
3078b71395eaSflorian print_stats(ssl, xfrd, &stattime, !peek, &total, zonestats);
3079*bf87c3c0Sflorian if(!peek) {
3080b71395eaSflorian xfrd->nsd->rc->stats_time = stattime;
3081*bf87c3c0Sflorian }
3082b71395eaSflorian
3083b71395eaSflorian free(stats);
3084b71395eaSflorian #ifdef USE_ZONE_STATS
3085b71395eaSflorian free(zonestats[0]);
3086b71395eaSflorian free(zonestats[1]);
30873efee2e1Sflorian #endif
3088b71395eaSflorian
3089d3fecca9Ssthen VERBOSITY(3, (LOG_INFO, "remote control stats printed"));
3090d3fecca9Ssthen }
3091d3fecca9Ssthen #endif /* BIND8_STATS */
3092d3fecca9Ssthen
309318e77612Sflorian int
create_local_accept_sock(const char * path,int * noproto)309418e77612Sflorian create_local_accept_sock(const char *path, int* noproto)
309518e77612Sflorian {
309618e77612Sflorian #ifdef HAVE_SYS_UN_H
309718e77612Sflorian int s;
309818e77612Sflorian struct sockaddr_un usock;
309918e77612Sflorian
310018e77612Sflorian VERBOSITY(3, (LOG_INFO, "creating unix socket %s", path));
310118e77612Sflorian #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
310218e77612Sflorian /* this member exists on BSDs, not Linux */
310318e77612Sflorian usock.sun_len = (unsigned)sizeof(usock);
310418e77612Sflorian #endif
310518e77612Sflorian usock.sun_family = AF_LOCAL;
310618e77612Sflorian /* length is 92-108, 104 on FreeBSD */
310718e77612Sflorian (void)strlcpy(usock.sun_path, path, sizeof(usock.sun_path));
310818e77612Sflorian
310918e77612Sflorian if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
311018e77612Sflorian log_msg(LOG_ERR, "Cannot create local socket %s (%s)",
311118e77612Sflorian path, strerror(errno));
311218e77612Sflorian return -1;
311318e77612Sflorian }
311418e77612Sflorian
311518e77612Sflorian if (unlink(path) && errno != ENOENT) {
311618e77612Sflorian /* The socket already exists and cannot be removed */
311718e77612Sflorian log_msg(LOG_ERR, "Cannot remove old local socket %s (%s)",
311818e77612Sflorian path, strerror(errno));
311918e77612Sflorian goto err;
312018e77612Sflorian }
312118e77612Sflorian
312218e77612Sflorian if (bind(s, (struct sockaddr *)&usock,
312318e77612Sflorian (socklen_t)sizeof(struct sockaddr_un)) == -1) {
312418e77612Sflorian log_msg(LOG_ERR, "Cannot bind local socket %s (%s)",
312518e77612Sflorian path, strerror(errno));
312618e77612Sflorian goto err;
312718e77612Sflorian }
312818e77612Sflorian
312918e77612Sflorian if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
313018e77612Sflorian log_msg(LOG_ERR, "Cannot set non-blocking mode");
313118e77612Sflorian goto err;
313218e77612Sflorian }
313318e77612Sflorian
313418e77612Sflorian if (listen(s, TCP_BACKLOG) == -1) {
313518e77612Sflorian log_msg(LOG_ERR, "can't listen: %s", strerror(errno));
313618e77612Sflorian goto err;
313718e77612Sflorian }
313818e77612Sflorian
313918e77612Sflorian (void)noproto; /*unused*/
314018e77612Sflorian return s;
314118e77612Sflorian
314218e77612Sflorian err:
314318e77612Sflorian close(s);
314418e77612Sflorian return -1;
314518e77612Sflorian
314618e77612Sflorian #else
314718e77612Sflorian (void)path;
314818e77612Sflorian log_msg(LOG_ERR, "Local sockets are not supported");
314918e77612Sflorian *noproto = 1;
315018e77612Sflorian return -1;
315118e77612Sflorian #endif
315218e77612Sflorian }
3153