1238106Sdes/* 2238106Sdes * daemon/remote.c - remote control for the unbound daemon. 3238106Sdes * 4238106Sdes * Copyright (c) 2008, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains the remote control functionality for the daemon. 40238106Sdes * The remote control can be performed using either the commandline 41238106Sdes * unbound-control tool, or a SSLv3/TLS capable web browser. 42238106Sdes * The channel is secured using SSLv3 or TLSv1, and certificates. 43238106Sdes * Both the server and the client(control tool) have their own keys. 44238106Sdes */ 45238106Sdes#include "config.h" 46238106Sdes#ifdef HAVE_OPENSSL_ERR_H 47238106Sdes#include <openssl/err.h> 48238106Sdes#endif 49238106Sdes#include <ctype.h> 50238106Sdes#include "daemon/remote.h" 51238106Sdes#include "daemon/worker.h" 52238106Sdes#include "daemon/daemon.h" 53238106Sdes#include "daemon/stats.h" 54238106Sdes#include "daemon/cachedump.h" 55238106Sdes#include "util/log.h" 56238106Sdes#include "util/config_file.h" 57238106Sdes#include "util/net_help.h" 58238106Sdes#include "util/module.h" 59238106Sdes#include "services/listen_dnsport.h" 60238106Sdes#include "services/cache/rrset.h" 61238106Sdes#include "services/cache/infra.h" 62238106Sdes#include "services/mesh.h" 63238106Sdes#include "services/localzone.h" 64238106Sdes#include "util/storage/slabhash.h" 65238106Sdes#include "util/fptr_wlist.h" 66238106Sdes#include "util/data/dname.h" 67238106Sdes#include "validator/validator.h" 68238106Sdes#include "validator/val_kcache.h" 69238106Sdes#include "validator/val_kentry.h" 70238106Sdes#include "validator/val_anchor.h" 71238106Sdes#include "iterator/iterator.h" 72238106Sdes#include "iterator/iter_fwd.h" 73238106Sdes#include "iterator/iter_hints.h" 74238106Sdes#include "iterator/iter_delegpt.h" 75238106Sdes#include "services/outbound_list.h" 76238106Sdes#include "services/outside_network.h" 77269257Sdes#include "ldns/str2wire.h" 78269257Sdes#include "ldns/parseutil.h" 79269257Sdes#include "ldns/wire2str.h" 80269257Sdes#include "ldns/sbuffer.h" 81238106Sdes 82238106Sdes#ifdef HAVE_SYS_TYPES_H 83238106Sdes# include <sys/types.h> 84238106Sdes#endif 85238106Sdes#ifdef HAVE_NETDB_H 86238106Sdes#include <netdb.h> 87238106Sdes#endif 88238106Sdes 89238106Sdes/* just for portability */ 90238106Sdes#ifdef SQ 91238106Sdes#undef SQ 92238106Sdes#endif 93238106Sdes 94238106Sdes/** what to put on statistics lines between var and value, ": " or "=" */ 95238106Sdes#define SQ "=" 96238106Sdes/** if true, inhibits a lot of =0 lines from the stats output */ 97238106Sdesstatic const int inhibit_zero = 1; 98238106Sdes 99238106Sdes/** subtract timers and the values do not overflow or become negative */ 100238106Sdesstatic void 101238106Sdestimeval_subtract(struct timeval* d, const struct timeval* end, 102238106Sdes const struct timeval* start) 103238106Sdes{ 104238106Sdes#ifndef S_SPLINT_S 105238106Sdes time_t end_usec = end->tv_usec; 106238106Sdes d->tv_sec = end->tv_sec - start->tv_sec; 107238106Sdes if(end_usec < start->tv_usec) { 108238106Sdes end_usec += 1000000; 109238106Sdes d->tv_sec--; 110238106Sdes } 111238106Sdes d->tv_usec = end_usec - start->tv_usec; 112238106Sdes#endif 113238106Sdes} 114238106Sdes 115238106Sdes/** divide sum of timers to get average */ 116238106Sdesstatic void 117238106Sdestimeval_divide(struct timeval* avg, const struct timeval* sum, size_t d) 118238106Sdes{ 119238106Sdes#ifndef S_SPLINT_S 120238106Sdes size_t leftover; 121238106Sdes if(d == 0) { 122238106Sdes avg->tv_sec = 0; 123238106Sdes avg->tv_usec = 0; 124238106Sdes return; 125238106Sdes } 126238106Sdes avg->tv_sec = sum->tv_sec / d; 127238106Sdes avg->tv_usec = sum->tv_usec / d; 128238106Sdes /* handle fraction from seconds divide */ 129238106Sdes leftover = sum->tv_sec - avg->tv_sec*d; 130238106Sdes avg->tv_usec += (leftover*1000000)/d; 131238106Sdes#endif 132238106Sdes} 133238106Sdes 134238106Sdesstruct daemon_remote* 135238106Sdesdaemon_remote_create(struct config_file* cfg) 136238106Sdes{ 137238106Sdes char* s_cert; 138238106Sdes char* s_key; 139238106Sdes struct daemon_remote* rc = (struct daemon_remote*)calloc(1, 140238106Sdes sizeof(*rc)); 141238106Sdes if(!rc) { 142238106Sdes log_err("out of memory in daemon_remote_create"); 143238106Sdes return NULL; 144238106Sdes } 145238106Sdes rc->max_active = 10; 146238106Sdes 147238106Sdes if(!cfg->remote_control_enable) { 148238106Sdes rc->ctx = NULL; 149238106Sdes return rc; 150238106Sdes } 151238106Sdes rc->ctx = SSL_CTX_new(SSLv23_server_method()); 152238106Sdes if(!rc->ctx) { 153238106Sdes log_crypto_err("could not SSL_CTX_new"); 154238106Sdes free(rc); 155238106Sdes return NULL; 156238106Sdes } 157238106Sdes /* no SSLv2 because has defects */ 158238106Sdes if(!(SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)){ 159238106Sdes log_crypto_err("could not set SSL_OP_NO_SSLv2"); 160238106Sdes daemon_remote_delete(rc); 161238106Sdes return NULL; 162238106Sdes } 163238106Sdes s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); 164238106Sdes s_key = fname_after_chroot(cfg->server_key_file, cfg, 1); 165238106Sdes if(!s_cert || !s_key) { 166238106Sdes log_err("out of memory in remote control fname"); 167238106Sdes goto setup_error; 168238106Sdes } 169238106Sdes verbose(VERB_ALGO, "setup SSL certificates"); 170238106Sdes if (!SSL_CTX_use_certificate_file(rc->ctx,s_cert,SSL_FILETYPE_PEM)) { 171238106Sdes log_err("Error for server-cert-file: %s", s_cert); 172238106Sdes log_crypto_err("Error in SSL_CTX use_certificate_file"); 173238106Sdes goto setup_error; 174238106Sdes } 175238106Sdes if(!SSL_CTX_use_PrivateKey_file(rc->ctx,s_key,SSL_FILETYPE_PEM)) { 176238106Sdes log_err("Error for server-key-file: %s", s_key); 177238106Sdes log_crypto_err("Error in SSL_CTX use_PrivateKey_file"); 178238106Sdes goto setup_error; 179238106Sdes } 180238106Sdes if(!SSL_CTX_check_private_key(rc->ctx)) { 181238106Sdes log_err("Error for server-key-file: %s", s_key); 182238106Sdes log_crypto_err("Error in SSL_CTX check_private_key"); 183238106Sdes goto setup_error; 184238106Sdes } 185238106Sdes if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) { 186238106Sdes log_crypto_err("Error setting up SSL_CTX verify locations"); 187238106Sdes setup_error: 188238106Sdes free(s_cert); 189238106Sdes free(s_key); 190238106Sdes daemon_remote_delete(rc); 191238106Sdes return NULL; 192238106Sdes } 193238106Sdes SSL_CTX_set_client_CA_list(rc->ctx, SSL_load_client_CA_file(s_cert)); 194238106Sdes SSL_CTX_set_verify(rc->ctx, SSL_VERIFY_PEER, NULL); 195238106Sdes free(s_cert); 196238106Sdes free(s_key); 197238106Sdes 198238106Sdes return rc; 199238106Sdes} 200238106Sdes 201238106Sdesvoid daemon_remote_clear(struct daemon_remote* rc) 202238106Sdes{ 203238106Sdes struct rc_state* p, *np; 204238106Sdes if(!rc) return; 205238106Sdes /* but do not close the ports */ 206238106Sdes listen_list_delete(rc->accept_list); 207238106Sdes rc->accept_list = NULL; 208238106Sdes /* do close these sockets */ 209238106Sdes p = rc->busy_list; 210238106Sdes while(p) { 211238106Sdes np = p->next; 212238106Sdes if(p->ssl) 213238106Sdes SSL_free(p->ssl); 214238106Sdes comm_point_delete(p->c); 215238106Sdes free(p); 216238106Sdes p = np; 217238106Sdes } 218238106Sdes rc->busy_list = NULL; 219238106Sdes rc->active = 0; 220238106Sdes rc->worker = NULL; 221238106Sdes} 222238106Sdes 223238106Sdesvoid daemon_remote_delete(struct daemon_remote* rc) 224238106Sdes{ 225238106Sdes if(!rc) return; 226238106Sdes daemon_remote_clear(rc); 227238106Sdes if(rc->ctx) { 228238106Sdes SSL_CTX_free(rc->ctx); 229238106Sdes } 230238106Sdes free(rc); 231238106Sdes} 232238106Sdes 233238106Sdes/** 234238106Sdes * Add and open a new control port 235238106Sdes * @param ip: ip str 236238106Sdes * @param nr: port nr 237238106Sdes * @param list: list head 238238106Sdes * @param noproto_is_err: if lack of protocol support is an error. 239238106Sdes * @return false on failure. 240238106Sdes */ 241238106Sdesstatic int 242238106Sdesadd_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err) 243238106Sdes{ 244238106Sdes struct addrinfo hints; 245238106Sdes struct addrinfo* res; 246238106Sdes struct listen_port* n; 247238106Sdes int noproto; 248238106Sdes int fd, r; 249238106Sdes char port[15]; 250238106Sdes snprintf(port, sizeof(port), "%d", nr); 251238106Sdes port[sizeof(port)-1]=0; 252238106Sdes memset(&hints, 0, sizeof(hints)); 253238106Sdes hints.ai_socktype = SOCK_STREAM; 254238106Sdes hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 255238106Sdes if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) { 256238106Sdes#ifdef USE_WINSOCK 257238106Sdes if(!noproto_is_err && r == EAI_NONAME) { 258238106Sdes /* tried to lookup the address as name */ 259238106Sdes return 1; /* return success, but do nothing */ 260238106Sdes } 261238106Sdes#endif /* USE_WINSOCK */ 262238106Sdes log_err("control interface %s:%s getaddrinfo: %s %s", 263238106Sdes ip?ip:"default", port, gai_strerror(r), 264238106Sdes#ifdef EAI_SYSTEM 265238106Sdes r==EAI_SYSTEM?(char*)strerror(errno):"" 266238106Sdes#else 267238106Sdes "" 268238106Sdes#endif 269238106Sdes ); 270238106Sdes return 0; 271238106Sdes } 272238106Sdes 273238106Sdes /* open fd */ 274269257Sdes fd = create_tcp_accept_sock(res, 1, &noproto, 0); 275238106Sdes freeaddrinfo(res); 276238106Sdes if(fd == -1 && noproto) { 277238106Sdes if(!noproto_is_err) 278238106Sdes return 1; /* return success, but do nothing */ 279238106Sdes log_err("cannot open control interface %s %d : " 280238106Sdes "protocol not supported", ip, nr); 281238106Sdes return 0; 282238106Sdes } 283238106Sdes if(fd == -1) { 284238106Sdes log_err("cannot open control interface %s %d", ip, nr); 285238106Sdes return 0; 286238106Sdes } 287238106Sdes 288238106Sdes /* alloc */ 289238106Sdes n = (struct listen_port*)calloc(1, sizeof(*n)); 290238106Sdes if(!n) { 291238106Sdes#ifndef USE_WINSOCK 292238106Sdes close(fd); 293238106Sdes#else 294238106Sdes closesocket(fd); 295238106Sdes#endif 296238106Sdes log_err("out of memory"); 297238106Sdes return 0; 298238106Sdes } 299238106Sdes n->next = *list; 300238106Sdes *list = n; 301238106Sdes n->fd = fd; 302238106Sdes return 1; 303238106Sdes} 304238106Sdes 305238106Sdesstruct listen_port* daemon_remote_open_ports(struct config_file* cfg) 306238106Sdes{ 307238106Sdes struct listen_port* l = NULL; 308238106Sdes log_assert(cfg->remote_control_enable && cfg->control_port); 309238106Sdes if(cfg->control_ifs) { 310238106Sdes struct config_strlist* p; 311238106Sdes for(p = cfg->control_ifs; p; p = p->next) { 312238106Sdes if(!add_open(p->str, cfg->control_port, &l, 1)) { 313238106Sdes listening_ports_free(l); 314238106Sdes return NULL; 315238106Sdes } 316238106Sdes } 317238106Sdes } else { 318238106Sdes /* defaults */ 319238106Sdes if(cfg->do_ip6 && 320238106Sdes !add_open("::1", cfg->control_port, &l, 0)) { 321238106Sdes listening_ports_free(l); 322238106Sdes return NULL; 323238106Sdes } 324238106Sdes if(cfg->do_ip4 && 325238106Sdes !add_open("127.0.0.1", cfg->control_port, &l, 1)) { 326238106Sdes listening_ports_free(l); 327238106Sdes return NULL; 328238106Sdes } 329238106Sdes } 330238106Sdes return l; 331238106Sdes} 332238106Sdes 333238106Sdes/** open accept commpoint */ 334238106Sdesstatic int 335238106Sdesaccept_open(struct daemon_remote* rc, int fd) 336238106Sdes{ 337238106Sdes struct listen_list* n = (struct listen_list*)malloc(sizeof(*n)); 338238106Sdes if(!n) { 339238106Sdes log_err("out of memory"); 340238106Sdes return 0; 341238106Sdes } 342238106Sdes n->next = rc->accept_list; 343238106Sdes rc->accept_list = n; 344238106Sdes /* open commpt */ 345238106Sdes n->com = comm_point_create_raw(rc->worker->base, fd, 0, 346238106Sdes &remote_accept_callback, rc); 347238106Sdes if(!n->com) 348238106Sdes return 0; 349238106Sdes /* keep this port open, its fd is kept in the rc portlist */ 350238106Sdes n->com->do_not_close = 1; 351238106Sdes return 1; 352238106Sdes} 353238106Sdes 354238106Sdesint daemon_remote_open_accept(struct daemon_remote* rc, 355238106Sdes struct listen_port* ports, struct worker* worker) 356238106Sdes{ 357238106Sdes struct listen_port* p; 358238106Sdes rc->worker = worker; 359238106Sdes for(p = ports; p; p = p->next) { 360238106Sdes if(!accept_open(rc, p->fd)) { 361238106Sdes log_err("could not create accept comm point"); 362238106Sdes return 0; 363238106Sdes } 364238106Sdes } 365238106Sdes return 1; 366238106Sdes} 367238106Sdes 368238106Sdesvoid daemon_remote_stop_accept(struct daemon_remote* rc) 369238106Sdes{ 370238106Sdes struct listen_list* p; 371238106Sdes for(p=rc->accept_list; p; p=p->next) { 372238106Sdes comm_point_stop_listening(p->com); 373238106Sdes } 374238106Sdes} 375238106Sdes 376238106Sdesvoid daemon_remote_start_accept(struct daemon_remote* rc) 377238106Sdes{ 378238106Sdes struct listen_list* p; 379238106Sdes for(p=rc->accept_list; p; p=p->next) { 380238106Sdes comm_point_start_listening(p->com, -1, -1); 381238106Sdes } 382238106Sdes} 383238106Sdes 384238106Sdesint remote_accept_callback(struct comm_point* c, void* arg, int err, 385238106Sdes struct comm_reply* ATTR_UNUSED(rep)) 386238106Sdes{ 387238106Sdes struct daemon_remote* rc = (struct daemon_remote*)arg; 388238106Sdes struct sockaddr_storage addr; 389238106Sdes socklen_t addrlen; 390238106Sdes int newfd; 391238106Sdes struct rc_state* n; 392238106Sdes if(err != NETEVENT_NOERROR) { 393238106Sdes log_err("error %d on remote_accept_callback", err); 394238106Sdes return 0; 395238106Sdes } 396238106Sdes /* perform the accept */ 397238106Sdes newfd = comm_point_perform_accept(c, &addr, &addrlen); 398238106Sdes if(newfd == -1) 399238106Sdes return 0; 400238106Sdes /* create new commpoint unless we are servicing already */ 401238106Sdes if(rc->active >= rc->max_active) { 402238106Sdes log_warn("drop incoming remote control: too many connections"); 403238106Sdes close_exit: 404238106Sdes#ifndef USE_WINSOCK 405238106Sdes close(newfd); 406238106Sdes#else 407238106Sdes closesocket(newfd); 408238106Sdes#endif 409238106Sdes return 0; 410238106Sdes } 411238106Sdes 412238106Sdes /* setup commpoint to service the remote control command */ 413238106Sdes n = (struct rc_state*)calloc(1, sizeof(*n)); 414238106Sdes if(!n) { 415238106Sdes log_err("out of memory"); 416238106Sdes goto close_exit; 417238106Sdes } 418238106Sdes /* start in reading state */ 419238106Sdes n->c = comm_point_create_raw(rc->worker->base, newfd, 0, 420238106Sdes &remote_control_callback, n); 421238106Sdes if(!n->c) { 422238106Sdes log_err("out of memory"); 423238106Sdes free(n); 424238106Sdes goto close_exit; 425238106Sdes } 426238106Sdes log_addr(VERB_QUERY, "new control connection from", &addr, addrlen); 427238106Sdes n->c->do_not_close = 0; 428238106Sdes comm_point_stop_listening(n->c); 429238106Sdes comm_point_start_listening(n->c, -1, REMOTE_CONTROL_TCP_TIMEOUT); 430238106Sdes memcpy(&n->c->repinfo.addr, &addr, addrlen); 431238106Sdes n->c->repinfo.addrlen = addrlen; 432238106Sdes n->shake_state = rc_hs_read; 433238106Sdes n->ssl = SSL_new(rc->ctx); 434238106Sdes if(!n->ssl) { 435238106Sdes log_crypto_err("could not SSL_new"); 436238106Sdes comm_point_delete(n->c); 437238106Sdes free(n); 438238106Sdes goto close_exit; 439238106Sdes } 440238106Sdes SSL_set_accept_state(n->ssl); 441238106Sdes (void)SSL_set_mode(n->ssl, SSL_MODE_AUTO_RETRY); 442238106Sdes if(!SSL_set_fd(n->ssl, newfd)) { 443238106Sdes log_crypto_err("could not SSL_set_fd"); 444238106Sdes SSL_free(n->ssl); 445238106Sdes comm_point_delete(n->c); 446238106Sdes free(n); 447238106Sdes goto close_exit; 448238106Sdes } 449238106Sdes 450238106Sdes n->rc = rc; 451238106Sdes n->next = rc->busy_list; 452238106Sdes rc->busy_list = n; 453238106Sdes rc->active ++; 454238106Sdes 455238106Sdes /* perform the first nonblocking read already, for windows, 456238106Sdes * so it can return wouldblock. could be faster too. */ 457238106Sdes (void)remote_control_callback(n->c, n, NETEVENT_NOERROR, NULL); 458238106Sdes return 0; 459238106Sdes} 460238106Sdes 461238106Sdes/** delete from list */ 462238106Sdesstatic void 463238106Sdesstate_list_remove_elem(struct rc_state** list, struct comm_point* c) 464238106Sdes{ 465238106Sdes while(*list) { 466238106Sdes if( (*list)->c == c) { 467238106Sdes *list = (*list)->next; 468238106Sdes return; 469238106Sdes } 470238106Sdes list = &(*list)->next; 471238106Sdes } 472238106Sdes} 473238106Sdes 474238106Sdes/** decrease active count and remove commpoint from busy list */ 475238106Sdesstatic void 476238106Sdesclean_point(struct daemon_remote* rc, struct rc_state* s) 477238106Sdes{ 478238106Sdes state_list_remove_elem(&rc->busy_list, s->c); 479238106Sdes rc->active --; 480238106Sdes if(s->ssl) { 481238106Sdes SSL_shutdown(s->ssl); 482238106Sdes SSL_free(s->ssl); 483238106Sdes } 484238106Sdes comm_point_delete(s->c); 485238106Sdes free(s); 486238106Sdes} 487238106Sdes 488238106Sdesint 489238106Sdesssl_print_text(SSL* ssl, const char* text) 490238106Sdes{ 491238106Sdes int r; 492238106Sdes if(!ssl) 493238106Sdes return 0; 494238106Sdes ERR_clear_error(); 495238106Sdes if((r=SSL_write(ssl, text, (int)strlen(text))) <= 0) { 496238106Sdes if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 497238106Sdes verbose(VERB_QUERY, "warning, in SSL_write, peer " 498238106Sdes "closed connection"); 499238106Sdes return 0; 500238106Sdes } 501238106Sdes log_crypto_err("could not SSL_write"); 502238106Sdes return 0; 503238106Sdes } 504238106Sdes return 1; 505238106Sdes} 506238106Sdes 507238106Sdes/** print text over the ssl connection */ 508238106Sdesstatic int 509238106Sdesssl_print_vmsg(SSL* ssl, const char* format, va_list args) 510238106Sdes{ 511238106Sdes char msg[1024]; 512238106Sdes vsnprintf(msg, sizeof(msg), format, args); 513238106Sdes return ssl_print_text(ssl, msg); 514238106Sdes} 515238106Sdes 516238106Sdes/** printf style printing to the ssl connection */ 517238106Sdesint ssl_printf(SSL* ssl, const char* format, ...) 518238106Sdes{ 519238106Sdes va_list args; 520238106Sdes int ret; 521238106Sdes va_start(args, format); 522238106Sdes ret = ssl_print_vmsg(ssl, format, args); 523238106Sdes va_end(args); 524238106Sdes return ret; 525238106Sdes} 526238106Sdes 527238106Sdesint 528238106Sdesssl_read_line(SSL* ssl, char* buf, size_t max) 529238106Sdes{ 530238106Sdes int r; 531238106Sdes size_t len = 0; 532238106Sdes if(!ssl) 533238106Sdes return 0; 534238106Sdes while(len < max) { 535238106Sdes ERR_clear_error(); 536238106Sdes if((r=SSL_read(ssl, buf+len, 1)) <= 0) { 537238106Sdes if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 538238106Sdes buf[len] = 0; 539238106Sdes return 1; 540238106Sdes } 541238106Sdes log_crypto_err("could not SSL_read"); 542238106Sdes return 0; 543238106Sdes } 544238106Sdes if(buf[len] == '\n') { 545238106Sdes /* return string without \n */ 546238106Sdes buf[len] = 0; 547238106Sdes return 1; 548238106Sdes } 549238106Sdes len++; 550238106Sdes } 551238106Sdes buf[max-1] = 0; 552238106Sdes log_err("control line too long (%d): %s", (int)max, buf); 553238106Sdes return 0; 554238106Sdes} 555238106Sdes 556238106Sdes/** skip whitespace, return new pointer into string */ 557238106Sdesstatic char* 558238106Sdesskipwhite(char* str) 559238106Sdes{ 560238106Sdes /* EOS \0 is not a space */ 561238106Sdes while( isspace(*str) ) 562238106Sdes str++; 563238106Sdes return str; 564238106Sdes} 565238106Sdes 566238106Sdes/** send the OK to the control client */ 567238106Sdesstatic void send_ok(SSL* ssl) 568238106Sdes{ 569238106Sdes (void)ssl_printf(ssl, "ok\n"); 570238106Sdes} 571238106Sdes 572238106Sdes/** do the stop command */ 573238106Sdesstatic void 574238106Sdesdo_stop(SSL* ssl, struct daemon_remote* rc) 575238106Sdes{ 576238106Sdes rc->worker->need_to_exit = 1; 577238106Sdes comm_base_exit(rc->worker->base); 578238106Sdes send_ok(ssl); 579238106Sdes} 580238106Sdes 581238106Sdes/** do the reload command */ 582238106Sdesstatic void 583238106Sdesdo_reload(SSL* ssl, struct daemon_remote* rc) 584238106Sdes{ 585238106Sdes rc->worker->need_to_exit = 0; 586238106Sdes comm_base_exit(rc->worker->base); 587238106Sdes send_ok(ssl); 588238106Sdes} 589238106Sdes 590238106Sdes/** do the verbosity command */ 591238106Sdesstatic void 592238106Sdesdo_verbosity(SSL* ssl, char* str) 593238106Sdes{ 594238106Sdes int val = atoi(str); 595238106Sdes if(val == 0 && strcmp(str, "0") != 0) { 596238106Sdes ssl_printf(ssl, "error in verbosity number syntax: %s\n", str); 597238106Sdes return; 598238106Sdes } 599238106Sdes verbosity = val; 600238106Sdes send_ok(ssl); 601238106Sdes} 602238106Sdes 603238106Sdes/** print stats from statinfo */ 604238106Sdesstatic int 605238106Sdesprint_stats(SSL* ssl, const char* nm, struct stats_info* s) 606238106Sdes{ 607238106Sdes struct timeval avg; 608238106Sdes if(!ssl_printf(ssl, "%s.num.queries"SQ"%u\n", nm, 609238106Sdes (unsigned)s->svr.num_queries)) return 0; 610238106Sdes if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%u\n", nm, 611238106Sdes (unsigned)(s->svr.num_queries 612238106Sdes - s->svr.num_queries_missed_cache))) return 0; 613238106Sdes if(!ssl_printf(ssl, "%s.num.cachemiss"SQ"%u\n", nm, 614238106Sdes (unsigned)s->svr.num_queries_missed_cache)) return 0; 615238106Sdes if(!ssl_printf(ssl, "%s.num.prefetch"SQ"%u\n", nm, 616238106Sdes (unsigned)s->svr.num_queries_prefetch)) return 0; 617238106Sdes if(!ssl_printf(ssl, "%s.num.recursivereplies"SQ"%u\n", nm, 618238106Sdes (unsigned)s->mesh_replies_sent)) return 0; 619238106Sdes if(!ssl_printf(ssl, "%s.requestlist.avg"SQ"%g\n", nm, 620238106Sdes (s->svr.num_queries_missed_cache+s->svr.num_queries_prefetch)? 621238106Sdes (double)s->svr.sum_query_list_size/ 622238106Sdes (s->svr.num_queries_missed_cache+ 623238106Sdes s->svr.num_queries_prefetch) : 0.0)) return 0; 624238106Sdes if(!ssl_printf(ssl, "%s.requestlist.max"SQ"%u\n", nm, 625238106Sdes (unsigned)s->svr.max_query_list_size)) return 0; 626238106Sdes if(!ssl_printf(ssl, "%s.requestlist.overwritten"SQ"%u\n", nm, 627238106Sdes (unsigned)s->mesh_jostled)) return 0; 628238106Sdes if(!ssl_printf(ssl, "%s.requestlist.exceeded"SQ"%u\n", nm, 629238106Sdes (unsigned)s->mesh_dropped)) return 0; 630238106Sdes if(!ssl_printf(ssl, "%s.requestlist.current.all"SQ"%u\n", nm, 631238106Sdes (unsigned)s->mesh_num_states)) return 0; 632238106Sdes if(!ssl_printf(ssl, "%s.requestlist.current.user"SQ"%u\n", nm, 633238106Sdes (unsigned)s->mesh_num_reply_states)) return 0; 634238106Sdes timeval_divide(&avg, &s->mesh_replies_sum_wait, s->mesh_replies_sent); 635269257Sdes if(!ssl_printf(ssl, "%s.recursion.time.avg"SQ ARG_LL "d.%6.6d\n", nm, 636269257Sdes (long long)avg.tv_sec, (int)avg.tv_usec)) return 0; 637238106Sdes if(!ssl_printf(ssl, "%s.recursion.time.median"SQ"%g\n", nm, 638238106Sdes s->mesh_time_median)) return 0; 639238106Sdes return 1; 640238106Sdes} 641238106Sdes 642238106Sdes/** print stats for one thread */ 643238106Sdesstatic int 644238106Sdesprint_thread_stats(SSL* ssl, int i, struct stats_info* s) 645238106Sdes{ 646238106Sdes char nm[16]; 647238106Sdes snprintf(nm, sizeof(nm), "thread%d", i); 648238106Sdes nm[sizeof(nm)-1]=0; 649238106Sdes return print_stats(ssl, nm, s); 650238106Sdes} 651238106Sdes 652238106Sdes/** print long number */ 653238106Sdesstatic int 654255579Sdesprint_longnum(SSL* ssl, const char* desc, size_t x) 655238106Sdes{ 656238106Sdes if(x > 1024*1024*1024) { 657238106Sdes /* more than a Gb */ 658238106Sdes size_t front = x / (size_t)1000000; 659238106Sdes size_t back = x % (size_t)1000000; 660238106Sdes return ssl_printf(ssl, "%s%u%6.6u\n", desc, 661238106Sdes (unsigned)front, (unsigned)back); 662238106Sdes } else { 663238106Sdes return ssl_printf(ssl, "%s%u\n", desc, (unsigned)x); 664238106Sdes } 665238106Sdes} 666238106Sdes 667238106Sdes/** print mem stats */ 668238106Sdesstatic int 669238106Sdesprint_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) 670238106Sdes{ 671238106Sdes int m; 672238106Sdes size_t msg, rrset, val, iter; 673238106Sdes#ifdef HAVE_SBRK 674238106Sdes extern void* unbound_start_brk; 675238106Sdes void* cur = sbrk(0); 676238106Sdes if(!print_longnum(ssl, "mem.total.sbrk"SQ, 677238106Sdes (size_t)((char*)cur - (char*)unbound_start_brk))) return 0; 678238106Sdes#endif /* HAVE_SBRK */ 679238106Sdes msg = slabhash_get_mem(daemon->env->msg_cache); 680238106Sdes rrset = slabhash_get_mem(&daemon->env->rrset_cache->table); 681238106Sdes val=0; 682238106Sdes iter=0; 683238106Sdes m = modstack_find(&worker->env.mesh->mods, "validator"); 684238106Sdes if(m != -1) { 685238106Sdes fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> 686238106Sdes mods.mod[m]->get_mem)); 687238106Sdes val = (*worker->env.mesh->mods.mod[m]->get_mem) 688238106Sdes (&worker->env, m); 689238106Sdes } 690238106Sdes m = modstack_find(&worker->env.mesh->mods, "iterator"); 691238106Sdes if(m != -1) { 692238106Sdes fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> 693238106Sdes mods.mod[m]->get_mem)); 694238106Sdes iter = (*worker->env.mesh->mods.mod[m]->get_mem) 695238106Sdes (&worker->env, m); 696238106Sdes } 697238106Sdes 698238106Sdes if(!print_longnum(ssl, "mem.cache.rrset"SQ, rrset)) 699238106Sdes return 0; 700238106Sdes if(!print_longnum(ssl, "mem.cache.message"SQ, msg)) 701238106Sdes return 0; 702238106Sdes if(!print_longnum(ssl, "mem.mod.iterator"SQ, iter)) 703238106Sdes return 0; 704238106Sdes if(!print_longnum(ssl, "mem.mod.validator"SQ, val)) 705238106Sdes return 0; 706238106Sdes return 1; 707238106Sdes} 708238106Sdes 709238106Sdes/** print uptime stats */ 710238106Sdesstatic int 711238106Sdesprint_uptime(SSL* ssl, struct worker* worker, int reset) 712238106Sdes{ 713238106Sdes struct timeval now = *worker->env.now_tv; 714238106Sdes struct timeval up, dt; 715238106Sdes timeval_subtract(&up, &now, &worker->daemon->time_boot); 716238106Sdes timeval_subtract(&dt, &now, &worker->daemon->time_last_stat); 717238106Sdes if(reset) 718238106Sdes worker->daemon->time_last_stat = now; 719269257Sdes if(!ssl_printf(ssl, "time.now"SQ ARG_LL "d.%6.6d\n", 720269257Sdes (long long)now.tv_sec, (unsigned)now.tv_usec)) return 0; 721269257Sdes if(!ssl_printf(ssl, "time.up"SQ ARG_LL "d.%6.6d\n", 722269257Sdes (long long)up.tv_sec, (unsigned)up.tv_usec)) return 0; 723269257Sdes if(!ssl_printf(ssl, "time.elapsed"SQ ARG_LL "d.%6.6d\n", 724269257Sdes (long long)dt.tv_sec, (unsigned)dt.tv_usec)) return 0; 725238106Sdes return 1; 726238106Sdes} 727238106Sdes 728238106Sdes/** print extended histogram */ 729238106Sdesstatic int 730238106Sdesprint_hist(SSL* ssl, struct stats_info* s) 731238106Sdes{ 732238106Sdes struct timehist* hist; 733238106Sdes size_t i; 734238106Sdes hist = timehist_setup(); 735238106Sdes if(!hist) { 736238106Sdes log_err("out of memory"); 737238106Sdes return 0; 738238106Sdes } 739238106Sdes timehist_import(hist, s->svr.hist, NUM_BUCKETS_HIST); 740238106Sdes for(i=0; i<hist->num; i++) { 741238106Sdes if(!ssl_printf(ssl, 742238106Sdes "histogram.%6.6d.%6.6d.to.%6.6d.%6.6d=%u\n", 743238106Sdes (int)hist->buckets[i].lower.tv_sec, 744238106Sdes (int)hist->buckets[i].lower.tv_usec, 745238106Sdes (int)hist->buckets[i].upper.tv_sec, 746238106Sdes (int)hist->buckets[i].upper.tv_usec, 747238106Sdes (unsigned)hist->buckets[i].count)) { 748238106Sdes timehist_delete(hist); 749238106Sdes return 0; 750238106Sdes } 751238106Sdes } 752238106Sdes timehist_delete(hist); 753238106Sdes return 1; 754238106Sdes} 755238106Sdes 756238106Sdes/** print extended stats */ 757238106Sdesstatic int 758238106Sdesprint_ext(SSL* ssl, struct stats_info* s) 759238106Sdes{ 760238106Sdes int i; 761238106Sdes char nm[16]; 762269257Sdes const sldns_rr_descriptor* desc; 763269257Sdes const sldns_lookup_table* lt; 764238106Sdes /* TYPE */ 765238106Sdes for(i=0; i<STATS_QTYPE_NUM; i++) { 766238106Sdes if(inhibit_zero && s->svr.qtype[i] == 0) 767238106Sdes continue; 768269257Sdes desc = sldns_rr_descript((uint16_t)i); 769238106Sdes if(desc && desc->_name) { 770238106Sdes snprintf(nm, sizeof(nm), "%s", desc->_name); 771238106Sdes } else if (i == LDNS_RR_TYPE_IXFR) { 772238106Sdes snprintf(nm, sizeof(nm), "IXFR"); 773238106Sdes } else if (i == LDNS_RR_TYPE_AXFR) { 774238106Sdes snprintf(nm, sizeof(nm), "AXFR"); 775238106Sdes } else if (i == LDNS_RR_TYPE_MAILA) { 776238106Sdes snprintf(nm, sizeof(nm), "MAILA"); 777238106Sdes } else if (i == LDNS_RR_TYPE_MAILB) { 778238106Sdes snprintf(nm, sizeof(nm), "MAILB"); 779238106Sdes } else if (i == LDNS_RR_TYPE_ANY) { 780238106Sdes snprintf(nm, sizeof(nm), "ANY"); 781238106Sdes } else { 782238106Sdes snprintf(nm, sizeof(nm), "TYPE%d", i); 783238106Sdes } 784238106Sdes if(!ssl_printf(ssl, "num.query.type.%s"SQ"%u\n", 785238106Sdes nm, (unsigned)s->svr.qtype[i])) return 0; 786238106Sdes } 787238106Sdes if(!inhibit_zero || s->svr.qtype_big) { 788238106Sdes if(!ssl_printf(ssl, "num.query.type.other"SQ"%u\n", 789238106Sdes (unsigned)s->svr.qtype_big)) return 0; 790238106Sdes } 791238106Sdes /* CLASS */ 792238106Sdes for(i=0; i<STATS_QCLASS_NUM; i++) { 793238106Sdes if(inhibit_zero && s->svr.qclass[i] == 0) 794238106Sdes continue; 795269257Sdes lt = sldns_lookup_by_id(sldns_rr_classes, i); 796238106Sdes if(lt && lt->name) { 797238106Sdes snprintf(nm, sizeof(nm), "%s", lt->name); 798238106Sdes } else { 799238106Sdes snprintf(nm, sizeof(nm), "CLASS%d", i); 800238106Sdes } 801238106Sdes if(!ssl_printf(ssl, "num.query.class.%s"SQ"%u\n", 802238106Sdes nm, (unsigned)s->svr.qclass[i])) return 0; 803238106Sdes } 804238106Sdes if(!inhibit_zero || s->svr.qclass_big) { 805238106Sdes if(!ssl_printf(ssl, "num.query.class.other"SQ"%u\n", 806238106Sdes (unsigned)s->svr.qclass_big)) return 0; 807238106Sdes } 808238106Sdes /* OPCODE */ 809238106Sdes for(i=0; i<STATS_OPCODE_NUM; i++) { 810238106Sdes if(inhibit_zero && s->svr.qopcode[i] == 0) 811238106Sdes continue; 812269257Sdes lt = sldns_lookup_by_id(sldns_opcodes, i); 813238106Sdes if(lt && lt->name) { 814238106Sdes snprintf(nm, sizeof(nm), "%s", lt->name); 815238106Sdes } else { 816238106Sdes snprintf(nm, sizeof(nm), "OPCODE%d", i); 817238106Sdes } 818238106Sdes if(!ssl_printf(ssl, "num.query.opcode.%s"SQ"%u\n", 819238106Sdes nm, (unsigned)s->svr.qopcode[i])) return 0; 820238106Sdes } 821238106Sdes /* transport */ 822238106Sdes if(!ssl_printf(ssl, "num.query.tcp"SQ"%u\n", 823238106Sdes (unsigned)s->svr.qtcp)) return 0; 824238106Sdes if(!ssl_printf(ssl, "num.query.ipv6"SQ"%u\n", 825238106Sdes (unsigned)s->svr.qipv6)) return 0; 826238106Sdes /* flags */ 827238106Sdes if(!ssl_printf(ssl, "num.query.flags.QR"SQ"%u\n", 828238106Sdes (unsigned)s->svr.qbit_QR)) return 0; 829238106Sdes if(!ssl_printf(ssl, "num.query.flags.AA"SQ"%u\n", 830238106Sdes (unsigned)s->svr.qbit_AA)) return 0; 831238106Sdes if(!ssl_printf(ssl, "num.query.flags.TC"SQ"%u\n", 832238106Sdes (unsigned)s->svr.qbit_TC)) return 0; 833238106Sdes if(!ssl_printf(ssl, "num.query.flags.RD"SQ"%u\n", 834238106Sdes (unsigned)s->svr.qbit_RD)) return 0; 835238106Sdes if(!ssl_printf(ssl, "num.query.flags.RA"SQ"%u\n", 836238106Sdes (unsigned)s->svr.qbit_RA)) return 0; 837238106Sdes if(!ssl_printf(ssl, "num.query.flags.Z"SQ"%u\n", 838238106Sdes (unsigned)s->svr.qbit_Z)) return 0; 839238106Sdes if(!ssl_printf(ssl, "num.query.flags.AD"SQ"%u\n", 840238106Sdes (unsigned)s->svr.qbit_AD)) return 0; 841238106Sdes if(!ssl_printf(ssl, "num.query.flags.CD"SQ"%u\n", 842238106Sdes (unsigned)s->svr.qbit_CD)) return 0; 843238106Sdes if(!ssl_printf(ssl, "num.query.edns.present"SQ"%u\n", 844238106Sdes (unsigned)s->svr.qEDNS)) return 0; 845238106Sdes if(!ssl_printf(ssl, "num.query.edns.DO"SQ"%u\n", 846238106Sdes (unsigned)s->svr.qEDNS_DO)) return 0; 847238106Sdes 848238106Sdes /* RCODE */ 849238106Sdes for(i=0; i<STATS_RCODE_NUM; i++) { 850238106Sdes if(inhibit_zero && s->svr.ans_rcode[i] == 0) 851238106Sdes continue; 852269257Sdes lt = sldns_lookup_by_id(sldns_rcodes, i); 853238106Sdes if(lt && lt->name) { 854238106Sdes snprintf(nm, sizeof(nm), "%s", lt->name); 855238106Sdes } else { 856238106Sdes snprintf(nm, sizeof(nm), "RCODE%d", i); 857238106Sdes } 858238106Sdes if(!ssl_printf(ssl, "num.answer.rcode.%s"SQ"%u\n", 859238106Sdes nm, (unsigned)s->svr.ans_rcode[i])) return 0; 860238106Sdes } 861238106Sdes if(!inhibit_zero || s->svr.ans_rcode_nodata) { 862238106Sdes if(!ssl_printf(ssl, "num.answer.rcode.nodata"SQ"%u\n", 863238106Sdes (unsigned)s->svr.ans_rcode_nodata)) return 0; 864238106Sdes } 865238106Sdes /* validation */ 866238106Sdes if(!ssl_printf(ssl, "num.answer.secure"SQ"%u\n", 867238106Sdes (unsigned)s->svr.ans_secure)) return 0; 868238106Sdes if(!ssl_printf(ssl, "num.answer.bogus"SQ"%u\n", 869238106Sdes (unsigned)s->svr.ans_bogus)) return 0; 870238106Sdes if(!ssl_printf(ssl, "num.rrset.bogus"SQ"%u\n", 871238106Sdes (unsigned)s->svr.rrset_bogus)) return 0; 872238106Sdes /* threat detection */ 873238106Sdes if(!ssl_printf(ssl, "unwanted.queries"SQ"%u\n", 874238106Sdes (unsigned)s->svr.unwanted_queries)) return 0; 875238106Sdes if(!ssl_printf(ssl, "unwanted.replies"SQ"%u\n", 876238106Sdes (unsigned)s->svr.unwanted_replies)) return 0; 877238106Sdes return 1; 878238106Sdes} 879238106Sdes 880238106Sdes/** do the stats command */ 881238106Sdesstatic void 882238106Sdesdo_stats(SSL* ssl, struct daemon_remote* rc, int reset) 883238106Sdes{ 884238106Sdes struct daemon* daemon = rc->worker->daemon; 885238106Sdes struct stats_info total; 886238106Sdes struct stats_info s; 887238106Sdes int i; 888238106Sdes log_assert(daemon->num > 0); 889238106Sdes /* gather all thread statistics in one place */ 890238106Sdes for(i=0; i<daemon->num; i++) { 891238106Sdes server_stats_obtain(rc->worker, daemon->workers[i], &s, reset); 892238106Sdes if(!print_thread_stats(ssl, i, &s)) 893238106Sdes return; 894238106Sdes if(i == 0) 895238106Sdes total = s; 896238106Sdes else server_stats_add(&total, &s); 897238106Sdes } 898238106Sdes /* print the thread statistics */ 899238106Sdes total.mesh_time_median /= (double)daemon->num; 900238106Sdes if(!print_stats(ssl, "total", &total)) 901238106Sdes return; 902238106Sdes if(!print_uptime(ssl, rc->worker, reset)) 903238106Sdes return; 904238106Sdes if(daemon->cfg->stat_extended) { 905238106Sdes if(!print_mem(ssl, rc->worker, daemon)) 906238106Sdes return; 907238106Sdes if(!print_hist(ssl, &total)) 908238106Sdes return; 909238106Sdes if(!print_ext(ssl, &total)) 910238106Sdes return; 911238106Sdes } 912238106Sdes} 913238106Sdes 914238106Sdes/** parse commandline argument domain name */ 915238106Sdesstatic int 916238106Sdesparse_arg_name(SSL* ssl, char* str, uint8_t** res, size_t* len, int* labs) 917238106Sdes{ 918269257Sdes uint8_t nm[LDNS_MAX_DOMAINLEN+1]; 919269257Sdes size_t nmlen = sizeof(nm); 920269257Sdes int status; 921238106Sdes *res = NULL; 922238106Sdes *len = 0; 923238106Sdes *labs = 0; 924269257Sdes status = sldns_str2wire_dname_buf(str, nm, &nmlen); 925269257Sdes if(status != 0) { 926269257Sdes ssl_printf(ssl, "error cannot parse name %s at %d: %s\n", str, 927269257Sdes LDNS_WIREPARSE_OFFSET(status), 928269257Sdes sldns_get_errorstr_parse(status)); 929238106Sdes return 0; 930238106Sdes } 931269257Sdes *res = memdup(nm, nmlen); 932238106Sdes if(!*res) { 933238106Sdes ssl_printf(ssl, "error out of memory\n"); 934238106Sdes return 0; 935238106Sdes } 936238106Sdes *labs = dname_count_size_labels(*res, len); 937238106Sdes return 1; 938238106Sdes} 939238106Sdes 940238106Sdes/** find second argument, modifies string */ 941238106Sdesstatic int 942238106Sdesfind_arg2(SSL* ssl, char* arg, char** arg2) 943238106Sdes{ 944238106Sdes char* as = strchr(arg, ' '); 945238106Sdes char* at = strchr(arg, '\t'); 946238106Sdes if(as && at) { 947238106Sdes if(at < as) 948238106Sdes as = at; 949238106Sdes as[0]=0; 950238106Sdes *arg2 = skipwhite(as+1); 951238106Sdes } else if(as) { 952238106Sdes as[0]=0; 953238106Sdes *arg2 = skipwhite(as+1); 954238106Sdes } else if(at) { 955238106Sdes at[0]=0; 956238106Sdes *arg2 = skipwhite(at+1); 957238106Sdes } else { 958238106Sdes ssl_printf(ssl, "error could not find next argument " 959238106Sdes "after %s\n", arg); 960238106Sdes return 0; 961238106Sdes } 962238106Sdes return 1; 963238106Sdes} 964238106Sdes 965238106Sdes/** Add a new zone */ 966238106Sdesstatic void 967238106Sdesdo_zone_add(SSL* ssl, struct worker* worker, char* arg) 968238106Sdes{ 969238106Sdes uint8_t* nm; 970238106Sdes int nmlabs; 971238106Sdes size_t nmlen; 972238106Sdes char* arg2; 973238106Sdes enum localzone_type t; 974238106Sdes struct local_zone* z; 975238106Sdes if(!find_arg2(ssl, arg, &arg2)) 976238106Sdes return; 977238106Sdes if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) 978238106Sdes return; 979238106Sdes if(!local_zone_str2type(arg2, &t)) { 980238106Sdes ssl_printf(ssl, "error not a zone type. %s\n", arg2); 981238106Sdes free(nm); 982238106Sdes return; 983238106Sdes } 984269257Sdes lock_rw_wrlock(&worker->daemon->local_zones->lock); 985238106Sdes if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen, 986238106Sdes nmlabs, LDNS_RR_CLASS_IN))) { 987238106Sdes /* already present in tree */ 988238106Sdes lock_rw_wrlock(&z->lock); 989238106Sdes z->type = t; /* update type anyway */ 990238106Sdes lock_rw_unlock(&z->lock); 991238106Sdes free(nm); 992269257Sdes lock_rw_unlock(&worker->daemon->local_zones->lock); 993238106Sdes send_ok(ssl); 994238106Sdes return; 995238106Sdes } 996238106Sdes if(!local_zones_add_zone(worker->daemon->local_zones, nm, nmlen, 997238106Sdes nmlabs, LDNS_RR_CLASS_IN, t)) { 998269257Sdes lock_rw_unlock(&worker->daemon->local_zones->lock); 999238106Sdes ssl_printf(ssl, "error out of memory\n"); 1000238106Sdes return; 1001238106Sdes } 1002269257Sdes lock_rw_unlock(&worker->daemon->local_zones->lock); 1003238106Sdes send_ok(ssl); 1004238106Sdes} 1005238106Sdes 1006238106Sdes/** Remove a zone */ 1007238106Sdesstatic void 1008238106Sdesdo_zone_remove(SSL* ssl, struct worker* worker, char* arg) 1009238106Sdes{ 1010238106Sdes uint8_t* nm; 1011238106Sdes int nmlabs; 1012238106Sdes size_t nmlen; 1013238106Sdes struct local_zone* z; 1014238106Sdes if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) 1015238106Sdes return; 1016269257Sdes lock_rw_wrlock(&worker->daemon->local_zones->lock); 1017238106Sdes if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen, 1018238106Sdes nmlabs, LDNS_RR_CLASS_IN))) { 1019238106Sdes /* present in tree */ 1020238106Sdes local_zones_del_zone(worker->daemon->local_zones, z); 1021238106Sdes } 1022269257Sdes lock_rw_unlock(&worker->daemon->local_zones->lock); 1023238106Sdes free(nm); 1024238106Sdes send_ok(ssl); 1025238106Sdes} 1026238106Sdes 1027238106Sdes/** Add new RR data */ 1028238106Sdesstatic void 1029238106Sdesdo_data_add(SSL* ssl, struct worker* worker, char* arg) 1030238106Sdes{ 1031269257Sdes if(!local_zones_add_RR(worker->daemon->local_zones, arg)) { 1032238106Sdes ssl_printf(ssl,"error in syntax or out of memory, %s\n", arg); 1033238106Sdes return; 1034238106Sdes } 1035238106Sdes send_ok(ssl); 1036238106Sdes} 1037238106Sdes 1038238106Sdes/** Remove RR data */ 1039238106Sdesstatic void 1040238106Sdesdo_data_remove(SSL* ssl, struct worker* worker, char* arg) 1041238106Sdes{ 1042238106Sdes uint8_t* nm; 1043238106Sdes int nmlabs; 1044238106Sdes size_t nmlen; 1045238106Sdes if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) 1046238106Sdes return; 1047238106Sdes local_zones_del_data(worker->daemon->local_zones, nm, 1048238106Sdes nmlen, nmlabs, LDNS_RR_CLASS_IN); 1049238106Sdes free(nm); 1050238106Sdes send_ok(ssl); 1051238106Sdes} 1052238106Sdes 1053238106Sdes/** cache lookup of nameservers */ 1054238106Sdesstatic void 1055238106Sdesdo_lookup(SSL* ssl, struct worker* worker, char* arg) 1056238106Sdes{ 1057238106Sdes uint8_t* nm; 1058238106Sdes int nmlabs; 1059238106Sdes size_t nmlen; 1060238106Sdes if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) 1061238106Sdes return; 1062238106Sdes (void)print_deleg_lookup(ssl, worker, nm, nmlen, nmlabs); 1063238106Sdes free(nm); 1064238106Sdes} 1065238106Sdes 1066238106Sdes/** flush something from rrset and msg caches */ 1067238106Sdesstatic void 1068238106Sdesdo_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen, 1069238106Sdes uint16_t t, uint16_t c) 1070238106Sdes{ 1071238106Sdes hashvalue_t h; 1072238106Sdes struct query_info k; 1073238106Sdes rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, t, c, 0); 1074238106Sdes if(t == LDNS_RR_TYPE_SOA) 1075238106Sdes rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, t, c, 1076238106Sdes PACKED_RRSET_SOA_NEG); 1077238106Sdes k.qname = nm; 1078238106Sdes k.qname_len = nmlen; 1079238106Sdes k.qtype = t; 1080238106Sdes k.qclass = c; 1081238106Sdes h = query_info_hash(&k); 1082238106Sdes slabhash_remove(worker->env.msg_cache, h, &k); 1083238106Sdes} 1084238106Sdes 1085238106Sdes/** flush a type */ 1086238106Sdesstatic void 1087238106Sdesdo_flush_type(SSL* ssl, struct worker* worker, char* arg) 1088238106Sdes{ 1089238106Sdes uint8_t* nm; 1090238106Sdes int nmlabs; 1091238106Sdes size_t nmlen; 1092238106Sdes char* arg2; 1093238106Sdes uint16_t t; 1094238106Sdes if(!find_arg2(ssl, arg, &arg2)) 1095238106Sdes return; 1096238106Sdes if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) 1097238106Sdes return; 1098269257Sdes t = sldns_get_rr_type_by_name(arg2); 1099238106Sdes do_cache_remove(worker, nm, nmlen, t, LDNS_RR_CLASS_IN); 1100238106Sdes 1101238106Sdes free(nm); 1102238106Sdes send_ok(ssl); 1103238106Sdes} 1104238106Sdes 1105238106Sdes/** flush statistics */ 1106238106Sdesstatic void 1107238106Sdesdo_flush_stats(SSL* ssl, struct worker* worker) 1108238106Sdes{ 1109238106Sdes worker_stats_clear(worker); 1110238106Sdes send_ok(ssl); 1111238106Sdes} 1112238106Sdes 1113238106Sdes/** 1114238106Sdes * Local info for deletion functions 1115238106Sdes */ 1116238106Sdesstruct del_info { 1117238106Sdes /** worker */ 1118238106Sdes struct worker* worker; 1119238106Sdes /** name to delete */ 1120238106Sdes uint8_t* name; 1121238106Sdes /** length */ 1122238106Sdes size_t len; 1123238106Sdes /** labels */ 1124238106Sdes int labs; 1125238106Sdes /** now */ 1126269257Sdes time_t now; 1127238106Sdes /** time to invalidate to */ 1128269257Sdes time_t expired; 1129238106Sdes /** number of rrsets removed */ 1130238106Sdes size_t num_rrsets; 1131238106Sdes /** number of msgs removed */ 1132238106Sdes size_t num_msgs; 1133238106Sdes /** number of key entries removed */ 1134238106Sdes size_t num_keys; 1135238106Sdes /** length of addr */ 1136238106Sdes socklen_t addrlen; 1137238106Sdes /** socket address for host deletion */ 1138238106Sdes struct sockaddr_storage addr; 1139238106Sdes}; 1140238106Sdes 1141238106Sdes/** callback to delete hosts in infra cache */ 1142238106Sdesstatic void 1143238106Sdesinfra_del_host(struct lruhash_entry* e, void* arg) 1144238106Sdes{ 1145238106Sdes /* entry is locked */ 1146238106Sdes struct del_info* inf = (struct del_info*)arg; 1147238106Sdes struct infra_key* k = (struct infra_key*)e->key; 1148238106Sdes if(sockaddr_cmp(&inf->addr, inf->addrlen, &k->addr, k->addrlen) == 0) { 1149238106Sdes struct infra_data* d = (struct infra_data*)e->data; 1150238106Sdes d->probedelay = 0; 1151238106Sdes d->timeout_A = 0; 1152238106Sdes d->timeout_AAAA = 0; 1153238106Sdes d->timeout_other = 0; 1154238106Sdes rtt_init(&d->rtt); 1155238106Sdes if(d->ttl >= inf->now) { 1156238106Sdes d->ttl = inf->expired; 1157238106Sdes inf->num_keys++; 1158238106Sdes } 1159238106Sdes } 1160238106Sdes} 1161238106Sdes 1162238106Sdes/** flush infra cache */ 1163238106Sdesstatic void 1164238106Sdesdo_flush_infra(SSL* ssl, struct worker* worker, char* arg) 1165238106Sdes{ 1166238106Sdes struct sockaddr_storage addr; 1167238106Sdes socklen_t len; 1168238106Sdes struct del_info inf; 1169238106Sdes if(strcmp(arg, "all") == 0) { 1170238106Sdes slabhash_clear(worker->env.infra_cache->hosts); 1171238106Sdes send_ok(ssl); 1172238106Sdes return; 1173238106Sdes } 1174238106Sdes if(!ipstrtoaddr(arg, UNBOUND_DNS_PORT, &addr, &len)) { 1175238106Sdes (void)ssl_printf(ssl, "error parsing ip addr: '%s'\n", arg); 1176238106Sdes return; 1177238106Sdes } 1178238106Sdes /* delete all entries from cache */ 1179238106Sdes /* what we do is to set them all expired */ 1180238106Sdes inf.worker = worker; 1181238106Sdes inf.name = 0; 1182238106Sdes inf.len = 0; 1183238106Sdes inf.labs = 0; 1184238106Sdes inf.now = *worker->env.now; 1185238106Sdes inf.expired = *worker->env.now; 1186238106Sdes inf.expired -= 3; /* handle 3 seconds skew between threads */ 1187238106Sdes inf.num_rrsets = 0; 1188238106Sdes inf.num_msgs = 0; 1189238106Sdes inf.num_keys = 0; 1190238106Sdes inf.addrlen = len; 1191238106Sdes memmove(&inf.addr, &addr, len); 1192238106Sdes slabhash_traverse(worker->env.infra_cache->hosts, 1, &infra_del_host, 1193238106Sdes &inf); 1194238106Sdes send_ok(ssl); 1195238106Sdes} 1196238106Sdes 1197238106Sdes/** flush requestlist */ 1198238106Sdesstatic void 1199238106Sdesdo_flush_requestlist(SSL* ssl, struct worker* worker) 1200238106Sdes{ 1201238106Sdes mesh_delete_all(worker->env.mesh); 1202238106Sdes send_ok(ssl); 1203238106Sdes} 1204238106Sdes 1205238106Sdes/** callback to delete rrsets in a zone */ 1206238106Sdesstatic void 1207238106Sdeszone_del_rrset(struct lruhash_entry* e, void* arg) 1208238106Sdes{ 1209238106Sdes /* entry is locked */ 1210238106Sdes struct del_info* inf = (struct del_info*)arg; 1211238106Sdes struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key; 1212238106Sdes if(dname_subdomain_c(k->rk.dname, inf->name)) { 1213238106Sdes struct packed_rrset_data* d = 1214238106Sdes (struct packed_rrset_data*)e->data; 1215238106Sdes if(d->ttl >= inf->now) { 1216238106Sdes d->ttl = inf->expired; 1217238106Sdes inf->num_rrsets++; 1218238106Sdes } 1219238106Sdes } 1220238106Sdes} 1221238106Sdes 1222238106Sdes/** callback to delete messages in a zone */ 1223238106Sdesstatic void 1224238106Sdeszone_del_msg(struct lruhash_entry* e, void* arg) 1225238106Sdes{ 1226238106Sdes /* entry is locked */ 1227238106Sdes struct del_info* inf = (struct del_info*)arg; 1228238106Sdes struct msgreply_entry* k = (struct msgreply_entry*)e->key; 1229238106Sdes if(dname_subdomain_c(k->key.qname, inf->name)) { 1230238106Sdes struct reply_info* d = (struct reply_info*)e->data; 1231238106Sdes if(d->ttl >= inf->now) { 1232238106Sdes d->ttl = inf->expired; 1233238106Sdes inf->num_msgs++; 1234238106Sdes } 1235238106Sdes } 1236238106Sdes} 1237238106Sdes 1238238106Sdes/** callback to delete keys in zone */ 1239238106Sdesstatic void 1240238106Sdeszone_del_kcache(struct lruhash_entry* e, void* arg) 1241238106Sdes{ 1242238106Sdes /* entry is locked */ 1243238106Sdes struct del_info* inf = (struct del_info*)arg; 1244238106Sdes struct key_entry_key* k = (struct key_entry_key*)e->key; 1245238106Sdes if(dname_subdomain_c(k->name, inf->name)) { 1246238106Sdes struct key_entry_data* d = (struct key_entry_data*)e->data; 1247238106Sdes if(d->ttl >= inf->now) { 1248238106Sdes d->ttl = inf->expired; 1249238106Sdes inf->num_keys++; 1250238106Sdes } 1251238106Sdes } 1252238106Sdes} 1253238106Sdes 1254238106Sdes/** remove all rrsets and keys from zone from cache */ 1255238106Sdesstatic void 1256238106Sdesdo_flush_zone(SSL* ssl, struct worker* worker, char* arg) 1257238106Sdes{ 1258238106Sdes uint8_t* nm; 1259238106Sdes int nmlabs; 1260238106Sdes size_t nmlen; 1261238106Sdes struct del_info inf; 1262238106Sdes if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) 1263238106Sdes return; 1264238106Sdes /* delete all RRs and key entries from zone */ 1265238106Sdes /* what we do is to set them all expired */ 1266238106Sdes inf.worker = worker; 1267238106Sdes inf.name = nm; 1268238106Sdes inf.len = nmlen; 1269238106Sdes inf.labs = nmlabs; 1270238106Sdes inf.now = *worker->env.now; 1271238106Sdes inf.expired = *worker->env.now; 1272238106Sdes inf.expired -= 3; /* handle 3 seconds skew between threads */ 1273238106Sdes inf.num_rrsets = 0; 1274238106Sdes inf.num_msgs = 0; 1275238106Sdes inf.num_keys = 0; 1276238106Sdes slabhash_traverse(&worker->env.rrset_cache->table, 1, 1277238106Sdes &zone_del_rrset, &inf); 1278238106Sdes 1279238106Sdes slabhash_traverse(worker->env.msg_cache, 1, &zone_del_msg, &inf); 1280238106Sdes 1281238106Sdes /* and validator cache */ 1282238106Sdes if(worker->env.key_cache) { 1283238106Sdes slabhash_traverse(worker->env.key_cache->slab, 1, 1284238106Sdes &zone_del_kcache, &inf); 1285238106Sdes } 1286238106Sdes 1287238106Sdes free(nm); 1288238106Sdes 1289238106Sdes (void)ssl_printf(ssl, "ok removed %u rrsets, %u messages " 1290238106Sdes "and %u key entries\n", (unsigned)inf.num_rrsets, 1291238106Sdes (unsigned)inf.num_msgs, (unsigned)inf.num_keys); 1292238106Sdes} 1293238106Sdes 1294249141Sdes/** callback to delete bogus rrsets */ 1295249141Sdesstatic void 1296249141Sdesbogus_del_rrset(struct lruhash_entry* e, void* arg) 1297249141Sdes{ 1298249141Sdes /* entry is locked */ 1299249141Sdes struct del_info* inf = (struct del_info*)arg; 1300249141Sdes struct packed_rrset_data* d = (struct packed_rrset_data*)e->data; 1301249141Sdes if(d->security == sec_status_bogus) { 1302249141Sdes d->ttl = inf->expired; 1303249141Sdes inf->num_rrsets++; 1304249141Sdes } 1305249141Sdes} 1306249141Sdes 1307249141Sdes/** callback to delete bogus messages */ 1308249141Sdesstatic void 1309249141Sdesbogus_del_msg(struct lruhash_entry* e, void* arg) 1310249141Sdes{ 1311249141Sdes /* entry is locked */ 1312249141Sdes struct del_info* inf = (struct del_info*)arg; 1313249141Sdes struct reply_info* d = (struct reply_info*)e->data; 1314249141Sdes if(d->security == sec_status_bogus) { 1315249141Sdes d->ttl = inf->expired; 1316249141Sdes inf->num_msgs++; 1317249141Sdes } 1318249141Sdes} 1319249141Sdes 1320249141Sdes/** callback to delete bogus keys */ 1321249141Sdesstatic void 1322249141Sdesbogus_del_kcache(struct lruhash_entry* e, void* arg) 1323249141Sdes{ 1324249141Sdes /* entry is locked */ 1325249141Sdes struct del_info* inf = (struct del_info*)arg; 1326249141Sdes struct key_entry_data* d = (struct key_entry_data*)e->data; 1327249141Sdes if(d->isbad) { 1328249141Sdes d->ttl = inf->expired; 1329249141Sdes inf->num_keys++; 1330249141Sdes } 1331249141Sdes} 1332249141Sdes 1333249141Sdes/** remove all rrsets and keys from zone from cache */ 1334249141Sdesstatic void 1335249141Sdesdo_flush_bogus(SSL* ssl, struct worker* worker) 1336249141Sdes{ 1337249141Sdes struct del_info inf; 1338249141Sdes /* what we do is to set them all expired */ 1339249141Sdes inf.worker = worker; 1340249141Sdes inf.now = *worker->env.now; 1341249141Sdes inf.expired = *worker->env.now; 1342249141Sdes inf.expired -= 3; /* handle 3 seconds skew between threads */ 1343249141Sdes inf.num_rrsets = 0; 1344249141Sdes inf.num_msgs = 0; 1345249141Sdes inf.num_keys = 0; 1346249141Sdes slabhash_traverse(&worker->env.rrset_cache->table, 1, 1347249141Sdes &bogus_del_rrset, &inf); 1348249141Sdes 1349249141Sdes slabhash_traverse(worker->env.msg_cache, 1, &bogus_del_msg, &inf); 1350249141Sdes 1351249141Sdes /* and validator cache */ 1352249141Sdes if(worker->env.key_cache) { 1353249141Sdes slabhash_traverse(worker->env.key_cache->slab, 1, 1354249141Sdes &bogus_del_kcache, &inf); 1355249141Sdes } 1356249141Sdes 1357249141Sdes (void)ssl_printf(ssl, "ok removed %u rrsets, %u messages " 1358249141Sdes "and %u key entries\n", (unsigned)inf.num_rrsets, 1359249141Sdes (unsigned)inf.num_msgs, (unsigned)inf.num_keys); 1360249141Sdes} 1361249141Sdes 1362238106Sdes/** remove name rrset from cache */ 1363238106Sdesstatic void 1364238106Sdesdo_flush_name(SSL* ssl, struct worker* w, char* arg) 1365238106Sdes{ 1366238106Sdes uint8_t* nm; 1367238106Sdes int nmlabs; 1368238106Sdes size_t nmlen; 1369238106Sdes if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) 1370238106Sdes return; 1371238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN); 1372238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN); 1373238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN); 1374238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN); 1375238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN); 1376238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN); 1377238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN); 1378238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN); 1379238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN); 1380238106Sdes do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN); 1381238106Sdes 1382238106Sdes free(nm); 1383238106Sdes send_ok(ssl); 1384238106Sdes} 1385238106Sdes 1386238106Sdes/** printout a delegation point info */ 1387238106Sdesstatic int 1388255579Sdesssl_print_name_dp(SSL* ssl, const char* str, uint8_t* nm, uint16_t dclass, 1389238106Sdes struct delegpt* dp) 1390238106Sdes{ 1391238106Sdes char buf[257]; 1392238106Sdes struct delegpt_ns* ns; 1393238106Sdes struct delegpt_addr* a; 1394238106Sdes int f = 0; 1395238106Sdes if(str) { /* print header for forward, stub */ 1396269257Sdes char* c = sldns_wire2str_class(dclass); 1397238106Sdes dname_str(nm, buf); 1398269257Sdes if(!ssl_printf(ssl, "%s %s %s: ", buf, (c?c:"CLASS??"), str)) { 1399238106Sdes free(c); 1400238106Sdes return 0; 1401238106Sdes } 1402238106Sdes free(c); 1403238106Sdes } 1404238106Sdes for(ns = dp->nslist; ns; ns = ns->next) { 1405238106Sdes dname_str(ns->name, buf); 1406238106Sdes if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf)) 1407238106Sdes return 0; 1408238106Sdes f = 1; 1409238106Sdes } 1410238106Sdes for(a = dp->target_list; a; a = a->next_target) { 1411238106Sdes addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf)); 1412238106Sdes if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf)) 1413238106Sdes return 0; 1414238106Sdes f = 1; 1415238106Sdes } 1416238106Sdes return ssl_printf(ssl, "\n"); 1417238106Sdes} 1418238106Sdes 1419238106Sdes 1420238106Sdes/** print root forwards */ 1421238106Sdesstatic int 1422238106Sdesprint_root_fwds(SSL* ssl, struct iter_forwards* fwds, uint8_t* root) 1423238106Sdes{ 1424238106Sdes struct delegpt* dp; 1425238106Sdes dp = forwards_lookup(fwds, root, LDNS_RR_CLASS_IN); 1426238106Sdes if(!dp) 1427238106Sdes return ssl_printf(ssl, "off (using root hints)\n"); 1428238106Sdes /* if dp is returned it must be the root */ 1429238106Sdes log_assert(query_dname_compare(dp->name, root)==0); 1430238106Sdes return ssl_print_name_dp(ssl, NULL, root, LDNS_RR_CLASS_IN, dp); 1431238106Sdes} 1432238106Sdes 1433238106Sdes/** parse args into delegpt */ 1434238106Sdesstatic struct delegpt* 1435238106Sdesparse_delegpt(SSL* ssl, char* args, uint8_t* nm, int allow_names) 1436238106Sdes{ 1437238106Sdes /* parse args and add in */ 1438238106Sdes char* p = args; 1439238106Sdes char* todo; 1440238106Sdes struct delegpt* dp = delegpt_create_mlc(nm); 1441238106Sdes struct sockaddr_storage addr; 1442238106Sdes socklen_t addrlen; 1443238106Sdes if(!dp) { 1444238106Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1445238106Sdes return NULL; 1446238106Sdes } 1447238106Sdes while(p) { 1448238106Sdes todo = p; 1449238106Sdes p = strchr(p, ' '); /* find next spot, if any */ 1450238106Sdes if(p) { 1451238106Sdes *p++ = 0; /* end this spot */ 1452238106Sdes p = skipwhite(p); /* position at next spot */ 1453238106Sdes } 1454238106Sdes /* parse address */ 1455238106Sdes if(!extstrtoaddr(todo, &addr, &addrlen)) { 1456238106Sdes if(allow_names) { 1457238106Sdes uint8_t* n = NULL; 1458238106Sdes size_t ln; 1459238106Sdes int lb; 1460238106Sdes if(!parse_arg_name(ssl, todo, &n, &ln, &lb)) { 1461238106Sdes (void)ssl_printf(ssl, "error cannot " 1462238106Sdes "parse IP address or name " 1463238106Sdes "'%s'\n", todo); 1464238106Sdes delegpt_free_mlc(dp); 1465238106Sdes return NULL; 1466238106Sdes } 1467238106Sdes if(!delegpt_add_ns_mlc(dp, n, 0)) { 1468238106Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1469249141Sdes free(n); 1470238106Sdes delegpt_free_mlc(dp); 1471238106Sdes return NULL; 1472238106Sdes } 1473238106Sdes free(n); 1474238106Sdes 1475238106Sdes } else { 1476238106Sdes (void)ssl_printf(ssl, "error cannot parse" 1477238106Sdes " IP address '%s'\n", todo); 1478238106Sdes delegpt_free_mlc(dp); 1479238106Sdes return NULL; 1480238106Sdes } 1481238106Sdes } else { 1482238106Sdes /* add address */ 1483238106Sdes if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0)) { 1484238106Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1485238106Sdes delegpt_free_mlc(dp); 1486238106Sdes return NULL; 1487238106Sdes } 1488238106Sdes } 1489238106Sdes } 1490238106Sdes return dp; 1491238106Sdes} 1492238106Sdes 1493238106Sdes/** do the status command */ 1494238106Sdesstatic void 1495238106Sdesdo_forward(SSL* ssl, struct worker* worker, char* args) 1496238106Sdes{ 1497238106Sdes struct iter_forwards* fwd = worker->env.fwds; 1498238106Sdes uint8_t* root = (uint8_t*)"\000"; 1499238106Sdes if(!fwd) { 1500238106Sdes (void)ssl_printf(ssl, "error: structure not allocated\n"); 1501238106Sdes return; 1502238106Sdes } 1503238106Sdes if(args == NULL || args[0] == 0) { 1504238106Sdes (void)print_root_fwds(ssl, fwd, root); 1505238106Sdes return; 1506238106Sdes } 1507238106Sdes /* set root forwards for this thread. since we are in remote control 1508238106Sdes * the actual mesh is not running, so we can freely edit it. */ 1509238106Sdes /* delete all the existing queries first */ 1510238106Sdes mesh_delete_all(worker->env.mesh); 1511238106Sdes if(strcmp(args, "off") == 0) { 1512238106Sdes forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, root); 1513238106Sdes } else { 1514238106Sdes struct delegpt* dp; 1515238106Sdes if(!(dp = parse_delegpt(ssl, args, root, 0))) 1516238106Sdes return; 1517238106Sdes if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) { 1518238106Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1519238106Sdes return; 1520238106Sdes } 1521238106Sdes } 1522238106Sdes send_ok(ssl); 1523238106Sdes} 1524238106Sdes 1525238106Sdesstatic int 1526238106Sdesparse_fs_args(SSL* ssl, char* args, uint8_t** nm, struct delegpt** dp, 1527238106Sdes int* insecure, int* prime) 1528238106Sdes{ 1529238106Sdes char* zonename; 1530238106Sdes char* rest; 1531238106Sdes size_t nmlen; 1532238106Sdes int nmlabs; 1533238106Sdes /* parse all -x args */ 1534238106Sdes while(args[0] == '+') { 1535238106Sdes if(!find_arg2(ssl, args, &rest)) 1536238106Sdes return 0; 1537238106Sdes while(*(++args) != 0) { 1538238106Sdes if(*args == 'i' && insecure) 1539238106Sdes *insecure = 1; 1540238106Sdes else if(*args == 'p' && prime) 1541238106Sdes *prime = 1; 1542238106Sdes else { 1543238106Sdes (void)ssl_printf(ssl, "error: unknown option %s\n", args); 1544238106Sdes return 0; 1545238106Sdes } 1546238106Sdes } 1547238106Sdes args = rest; 1548238106Sdes } 1549238106Sdes /* parse name */ 1550238106Sdes if(dp) { 1551238106Sdes if(!find_arg2(ssl, args, &rest)) 1552238106Sdes return 0; 1553238106Sdes zonename = args; 1554238106Sdes args = rest; 1555238106Sdes } else zonename = args; 1556238106Sdes if(!parse_arg_name(ssl, zonename, nm, &nmlen, &nmlabs)) 1557238106Sdes return 0; 1558238106Sdes 1559238106Sdes /* parse dp */ 1560238106Sdes if(dp) { 1561238106Sdes if(!(*dp = parse_delegpt(ssl, args, *nm, 1))) { 1562238106Sdes free(*nm); 1563238106Sdes return 0; 1564238106Sdes } 1565238106Sdes } 1566238106Sdes return 1; 1567238106Sdes} 1568238106Sdes 1569238106Sdes/** do the forward_add command */ 1570238106Sdesstatic void 1571238106Sdesdo_forward_add(SSL* ssl, struct worker* worker, char* args) 1572238106Sdes{ 1573238106Sdes struct iter_forwards* fwd = worker->env.fwds; 1574238106Sdes int insecure = 0; 1575238106Sdes uint8_t* nm = NULL; 1576238106Sdes struct delegpt* dp = NULL; 1577238106Sdes if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, NULL)) 1578238106Sdes return; 1579269257Sdes if(insecure && worker->env.anchors) { 1580238106Sdes if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, 1581238106Sdes nm)) { 1582238106Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1583238106Sdes delegpt_free_mlc(dp); 1584238106Sdes free(nm); 1585238106Sdes return; 1586238106Sdes } 1587238106Sdes } 1588238106Sdes if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) { 1589238106Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1590238106Sdes free(nm); 1591238106Sdes return; 1592238106Sdes } 1593238106Sdes free(nm); 1594238106Sdes send_ok(ssl); 1595238106Sdes} 1596238106Sdes 1597238106Sdes/** do the forward_remove command */ 1598238106Sdesstatic void 1599238106Sdesdo_forward_remove(SSL* ssl, struct worker* worker, char* args) 1600238106Sdes{ 1601238106Sdes struct iter_forwards* fwd = worker->env.fwds; 1602238106Sdes int insecure = 0; 1603238106Sdes uint8_t* nm = NULL; 1604238106Sdes if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL)) 1605238106Sdes return; 1606269257Sdes if(insecure && worker->env.anchors) 1607238106Sdes anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, 1608238106Sdes nm); 1609238106Sdes forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, nm); 1610238106Sdes free(nm); 1611238106Sdes send_ok(ssl); 1612238106Sdes} 1613238106Sdes 1614238106Sdes/** do the stub_add command */ 1615238106Sdesstatic void 1616238106Sdesdo_stub_add(SSL* ssl, struct worker* worker, char* args) 1617238106Sdes{ 1618238106Sdes struct iter_forwards* fwd = worker->env.fwds; 1619238106Sdes int insecure = 0, prime = 0; 1620238106Sdes uint8_t* nm = NULL; 1621238106Sdes struct delegpt* dp = NULL; 1622238106Sdes if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, &prime)) 1623238106Sdes return; 1624269257Sdes if(insecure && worker->env.anchors) { 1625238106Sdes if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, 1626238106Sdes nm)) { 1627238106Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1628238106Sdes delegpt_free_mlc(dp); 1629238106Sdes free(nm); 1630238106Sdes return; 1631238106Sdes } 1632238106Sdes } 1633238106Sdes if(!forwards_add_stub_hole(fwd, LDNS_RR_CLASS_IN, nm)) { 1634269257Sdes if(insecure && worker->env.anchors) 1635269257Sdes anchors_delete_insecure(worker->env.anchors, 1636269257Sdes LDNS_RR_CLASS_IN, nm); 1637238106Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1638238106Sdes delegpt_free_mlc(dp); 1639238106Sdes free(nm); 1640238106Sdes return; 1641238106Sdes } 1642238106Sdes if(!hints_add_stub(worker->env.hints, LDNS_RR_CLASS_IN, dp, !prime)) { 1643238106Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1644238106Sdes forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm); 1645269257Sdes if(insecure && worker->env.anchors) 1646269257Sdes anchors_delete_insecure(worker->env.anchors, 1647269257Sdes LDNS_RR_CLASS_IN, nm); 1648238106Sdes free(nm); 1649238106Sdes return; 1650238106Sdes } 1651238106Sdes free(nm); 1652238106Sdes send_ok(ssl); 1653238106Sdes} 1654238106Sdes 1655238106Sdes/** do the stub_remove command */ 1656238106Sdesstatic void 1657238106Sdesdo_stub_remove(SSL* ssl, struct worker* worker, char* args) 1658238106Sdes{ 1659238106Sdes struct iter_forwards* fwd = worker->env.fwds; 1660238106Sdes int insecure = 0; 1661238106Sdes uint8_t* nm = NULL; 1662238106Sdes if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL)) 1663238106Sdes return; 1664269257Sdes if(insecure && worker->env.anchors) 1665238106Sdes anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, 1666238106Sdes nm); 1667238106Sdes forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm); 1668238106Sdes hints_delete_stub(worker->env.hints, LDNS_RR_CLASS_IN, nm); 1669238106Sdes free(nm); 1670238106Sdes send_ok(ssl); 1671238106Sdes} 1672238106Sdes 1673269257Sdes/** do the insecure_add command */ 1674269257Sdesstatic void 1675269257Sdesdo_insecure_add(SSL* ssl, struct worker* worker, char* arg) 1676269257Sdes{ 1677269257Sdes size_t nmlen; 1678269257Sdes int nmlabs; 1679269257Sdes uint8_t* nm = NULL; 1680269257Sdes if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) 1681269257Sdes return; 1682269257Sdes if(worker->env.anchors) { 1683269257Sdes if(!anchors_add_insecure(worker->env.anchors, 1684269257Sdes LDNS_RR_CLASS_IN, nm)) { 1685269257Sdes (void)ssl_printf(ssl, "error out of memory\n"); 1686269257Sdes free(nm); 1687269257Sdes return; 1688269257Sdes } 1689269257Sdes } 1690269257Sdes free(nm); 1691269257Sdes send_ok(ssl); 1692269257Sdes} 1693269257Sdes 1694269257Sdes/** do the insecure_remove command */ 1695269257Sdesstatic void 1696269257Sdesdo_insecure_remove(SSL* ssl, struct worker* worker, char* arg) 1697269257Sdes{ 1698269257Sdes size_t nmlen; 1699269257Sdes int nmlabs; 1700269257Sdes uint8_t* nm = NULL; 1701269257Sdes if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) 1702269257Sdes return; 1703269257Sdes if(worker->env.anchors) 1704269257Sdes anchors_delete_insecure(worker->env.anchors, 1705269257Sdes LDNS_RR_CLASS_IN, nm); 1706269257Sdes free(nm); 1707269257Sdes send_ok(ssl); 1708269257Sdes} 1709269257Sdes 1710238106Sdes/** do the status command */ 1711238106Sdesstatic void 1712238106Sdesdo_status(SSL* ssl, struct worker* worker) 1713238106Sdes{ 1714238106Sdes int i; 1715238106Sdes time_t uptime; 1716238106Sdes if(!ssl_printf(ssl, "version: %s\n", PACKAGE_VERSION)) 1717238106Sdes return; 1718238106Sdes if(!ssl_printf(ssl, "verbosity: %d\n", verbosity)) 1719238106Sdes return; 1720238106Sdes if(!ssl_printf(ssl, "threads: %d\n", worker->daemon->num)) 1721238106Sdes return; 1722238106Sdes if(!ssl_printf(ssl, "modules: %d [", worker->daemon->mods.num)) 1723238106Sdes return; 1724238106Sdes for(i=0; i<worker->daemon->mods.num; i++) { 1725238106Sdes if(!ssl_printf(ssl, " %s", worker->daemon->mods.mod[i]->name)) 1726238106Sdes return; 1727238106Sdes } 1728238106Sdes if(!ssl_printf(ssl, " ]\n")) 1729238106Sdes return; 1730238106Sdes uptime = (time_t)time(NULL) - (time_t)worker->daemon->time_boot.tv_sec; 1731269257Sdes if(!ssl_printf(ssl, "uptime: " ARG_LL "d seconds\n", (long long)uptime)) 1732238106Sdes return; 1733238106Sdes if(!ssl_printf(ssl, "unbound (pid %d) is running...\n", 1734238106Sdes (int)getpid())) 1735238106Sdes return; 1736238106Sdes} 1737238106Sdes 1738238106Sdes/** get age for the mesh state */ 1739238106Sdesstatic void 1740238106Sdesget_mesh_age(struct mesh_state* m, char* buf, size_t len, 1741238106Sdes struct module_env* env) 1742238106Sdes{ 1743238106Sdes if(m->reply_list) { 1744238106Sdes struct timeval d; 1745238106Sdes struct mesh_reply* r = m->reply_list; 1746238106Sdes /* last reply is the oldest */ 1747238106Sdes while(r && r->next) 1748238106Sdes r = r->next; 1749238106Sdes timeval_subtract(&d, env->now_tv, &r->start_time); 1750269257Sdes snprintf(buf, len, ARG_LL "d.%6.6d", 1751269257Sdes (long long)d.tv_sec, (int)d.tv_usec); 1752238106Sdes } else { 1753238106Sdes snprintf(buf, len, "-"); 1754238106Sdes } 1755238106Sdes} 1756238106Sdes 1757238106Sdes/** get status of a mesh state */ 1758238106Sdesstatic void 1759238106Sdesget_mesh_status(struct mesh_area* mesh, struct mesh_state* m, 1760238106Sdes char* buf, size_t len) 1761238106Sdes{ 1762238106Sdes enum module_ext_state s = m->s.ext_state[m->s.curmod]; 1763238106Sdes const char *modname = mesh->mods.mod[m->s.curmod]->name; 1764238106Sdes size_t l; 1765238106Sdes if(strcmp(modname, "iterator") == 0 && s == module_wait_reply && 1766238106Sdes m->s.minfo[m->s.curmod]) { 1767238106Sdes /* break into iterator to find out who its waiting for */ 1768238106Sdes struct iter_qstate* qstate = (struct iter_qstate*) 1769238106Sdes m->s.minfo[m->s.curmod]; 1770238106Sdes struct outbound_list* ol = &qstate->outlist; 1771238106Sdes struct outbound_entry* e; 1772238106Sdes snprintf(buf, len, "%s wait for", modname); 1773238106Sdes l = strlen(buf); 1774238106Sdes buf += l; len -= l; 1775238106Sdes if(ol->first == NULL) 1776238106Sdes snprintf(buf, len, " (empty_list)"); 1777238106Sdes for(e = ol->first; e; e = e->next) { 1778238106Sdes snprintf(buf, len, " "); 1779238106Sdes l = strlen(buf); 1780238106Sdes buf += l; len -= l; 1781238106Sdes addr_to_str(&e->qsent->addr, e->qsent->addrlen, 1782238106Sdes buf, len); 1783238106Sdes l = strlen(buf); 1784238106Sdes buf += l; len -= l; 1785238106Sdes } 1786238106Sdes } else if(s == module_wait_subquery) { 1787238106Sdes /* look in subs from mesh state to see what */ 1788238106Sdes char nm[257]; 1789238106Sdes struct mesh_state_ref* sub; 1790238106Sdes snprintf(buf, len, "%s wants", modname); 1791238106Sdes l = strlen(buf); 1792238106Sdes buf += l; len -= l; 1793238106Sdes if(m->sub_set.count == 0) 1794238106Sdes snprintf(buf, len, " (empty_list)"); 1795238106Sdes RBTREE_FOR(sub, struct mesh_state_ref*, &m->sub_set) { 1796269257Sdes char* t = sldns_wire2str_type(sub->s->s.qinfo.qtype); 1797269257Sdes char* c = sldns_wire2str_class(sub->s->s.qinfo.qclass); 1798238106Sdes dname_str(sub->s->s.qinfo.qname, nm); 1799269257Sdes snprintf(buf, len, " %s %s %s", (t?t:"TYPE??"), 1800269257Sdes (c?c:"CLASS??"), nm); 1801238106Sdes l = strlen(buf); 1802238106Sdes buf += l; len -= l; 1803238106Sdes free(t); 1804238106Sdes free(c); 1805238106Sdes } 1806238106Sdes } else { 1807238106Sdes snprintf(buf, len, "%s is %s", modname, strextstate(s)); 1808238106Sdes } 1809238106Sdes} 1810238106Sdes 1811238106Sdes/** do the dump_requestlist command */ 1812238106Sdesstatic void 1813238106Sdesdo_dump_requestlist(SSL* ssl, struct worker* worker) 1814238106Sdes{ 1815238106Sdes struct mesh_area* mesh; 1816238106Sdes struct mesh_state* m; 1817238106Sdes int num = 0; 1818238106Sdes char buf[257]; 1819238106Sdes char timebuf[32]; 1820238106Sdes char statbuf[10240]; 1821238106Sdes if(!ssl_printf(ssl, "thread #%d\n", worker->thread_num)) 1822238106Sdes return; 1823238106Sdes if(!ssl_printf(ssl, "# type cl name seconds module status\n")) 1824238106Sdes return; 1825238106Sdes /* show worker mesh contents */ 1826238106Sdes mesh = worker->env.mesh; 1827238106Sdes if(!mesh) return; 1828238106Sdes RBTREE_FOR(m, struct mesh_state*, &mesh->all) { 1829269257Sdes char* t = sldns_wire2str_type(m->s.qinfo.qtype); 1830269257Sdes char* c = sldns_wire2str_class(m->s.qinfo.qclass); 1831238106Sdes dname_str(m->s.qinfo.qname, buf); 1832238106Sdes get_mesh_age(m, timebuf, sizeof(timebuf), &worker->env); 1833238106Sdes get_mesh_status(mesh, m, statbuf, sizeof(statbuf)); 1834238106Sdes if(!ssl_printf(ssl, "%3d %4s %2s %s %s %s\n", 1835269257Sdes num, (t?t:"TYPE??"), (c?c:"CLASS??"), buf, timebuf, 1836269257Sdes statbuf)) { 1837238106Sdes free(t); 1838238106Sdes free(c); 1839238106Sdes return; 1840238106Sdes } 1841238106Sdes num++; 1842238106Sdes free(t); 1843238106Sdes free(c); 1844238106Sdes } 1845238106Sdes} 1846238106Sdes 1847238106Sdes/** structure for argument data for dump infra host */ 1848238106Sdesstruct infra_arg { 1849238106Sdes /** the infra cache */ 1850238106Sdes struct infra_cache* infra; 1851238106Sdes /** the SSL connection */ 1852238106Sdes SSL* ssl; 1853238106Sdes /** the time now */ 1854269257Sdes time_t now; 1855238106Sdes}; 1856238106Sdes 1857238106Sdes/** callback for every host element in the infra cache */ 1858238106Sdesstatic void 1859238106Sdesdump_infra_host(struct lruhash_entry* e, void* arg) 1860238106Sdes{ 1861238106Sdes struct infra_arg* a = (struct infra_arg*)arg; 1862238106Sdes struct infra_key* k = (struct infra_key*)e->key; 1863238106Sdes struct infra_data* d = (struct infra_data*)e->data; 1864238106Sdes char ip_str[1024]; 1865238106Sdes char name[257]; 1866238106Sdes addr_to_str(&k->addr, k->addrlen, ip_str, sizeof(ip_str)); 1867238106Sdes dname_str(k->zonename, name); 1868238106Sdes /* skip expired stuff (only backed off) */ 1869238106Sdes if(d->ttl < a->now) { 1870238106Sdes if(d->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) { 1871238106Sdes if(!ssl_printf(a->ssl, "%s %s expired rto %d\n", ip_str, 1872238106Sdes name, d->rtt.rto)) return; 1873238106Sdes } 1874238106Sdes return; 1875238106Sdes } 1876238106Sdes if(!ssl_printf(a->ssl, "%s %s ttl %d ping %d var %d rtt %d rto %d " 1877238106Sdes "tA %d tAAAA %d tother %d " 1878238106Sdes "ednsknown %d edns %d delay %d lame dnssec %d rec %d A %d " 1879238106Sdes "other %d\n", ip_str, name, (int)(d->ttl - a->now), 1880238106Sdes d->rtt.srtt, d->rtt.rttvar, rtt_notimeout(&d->rtt), d->rtt.rto, 1881238106Sdes d->timeout_A, d->timeout_AAAA, d->timeout_other, 1882238106Sdes (int)d->edns_lame_known, (int)d->edns_version, 1883238106Sdes (int)(a->now<d->probedelay?d->probedelay-a->now:0), 1884238106Sdes (int)d->isdnsseclame, (int)d->rec_lame, (int)d->lame_type_A, 1885238106Sdes (int)d->lame_other)) 1886238106Sdes return; 1887238106Sdes} 1888238106Sdes 1889238106Sdes/** do the dump_infra command */ 1890238106Sdesstatic void 1891238106Sdesdo_dump_infra(SSL* ssl, struct worker* worker) 1892238106Sdes{ 1893238106Sdes struct infra_arg arg; 1894238106Sdes arg.infra = worker->env.infra_cache; 1895238106Sdes arg.ssl = ssl; 1896238106Sdes arg.now = *worker->env.now; 1897238106Sdes slabhash_traverse(arg.infra->hosts, 0, &dump_infra_host, (void*)&arg); 1898238106Sdes} 1899238106Sdes 1900238106Sdes/** do the log_reopen command */ 1901238106Sdesstatic void 1902238106Sdesdo_log_reopen(SSL* ssl, struct worker* worker) 1903238106Sdes{ 1904238106Sdes struct config_file* cfg = worker->env.cfg; 1905238106Sdes send_ok(ssl); 1906238106Sdes log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); 1907238106Sdes} 1908238106Sdes 1909238106Sdes/** do the set_option command */ 1910238106Sdesstatic void 1911238106Sdesdo_set_option(SSL* ssl, struct worker* worker, char* arg) 1912238106Sdes{ 1913238106Sdes char* arg2; 1914238106Sdes if(!find_arg2(ssl, arg, &arg2)) 1915238106Sdes return; 1916238106Sdes if(!config_set_option(worker->env.cfg, arg, arg2)) { 1917238106Sdes (void)ssl_printf(ssl, "error setting option\n"); 1918238106Sdes return; 1919238106Sdes } 1920238106Sdes send_ok(ssl); 1921238106Sdes} 1922238106Sdes 1923238106Sdes/* routine to printout option values over SSL */ 1924238106Sdesvoid remote_get_opt_ssl(char* line, void* arg) 1925238106Sdes{ 1926238106Sdes SSL* ssl = (SSL*)arg; 1927238106Sdes (void)ssl_printf(ssl, "%s\n", line); 1928238106Sdes} 1929238106Sdes 1930238106Sdes/** do the get_option command */ 1931238106Sdesstatic void 1932238106Sdesdo_get_option(SSL* ssl, struct worker* worker, char* arg) 1933238106Sdes{ 1934238106Sdes int r; 1935238106Sdes r = config_get_option(worker->env.cfg, arg, remote_get_opt_ssl, ssl); 1936238106Sdes if(!r) { 1937238106Sdes (void)ssl_printf(ssl, "error unknown option\n"); 1938238106Sdes return; 1939238106Sdes } 1940238106Sdes} 1941238106Sdes 1942238106Sdes/** do the list_forwards command */ 1943238106Sdesstatic void 1944238106Sdesdo_list_forwards(SSL* ssl, struct worker* worker) 1945238106Sdes{ 1946238106Sdes /* since its a per-worker structure no locks needed */ 1947238106Sdes struct iter_forwards* fwds = worker->env.fwds; 1948238106Sdes struct iter_forward_zone* z; 1949238106Sdes RBTREE_FOR(z, struct iter_forward_zone*, fwds->tree) { 1950238106Sdes if(!z->dp) continue; /* skip empty marker for stub */ 1951238106Sdes if(!ssl_print_name_dp(ssl, "forward", z->name, z->dclass, 1952238106Sdes z->dp)) 1953238106Sdes return; 1954238106Sdes } 1955238106Sdes} 1956238106Sdes 1957238106Sdes/** do the list_stubs command */ 1958238106Sdesstatic void 1959238106Sdesdo_list_stubs(SSL* ssl, struct worker* worker) 1960238106Sdes{ 1961238106Sdes struct iter_hints_stub* z; 1962238106Sdes RBTREE_FOR(z, struct iter_hints_stub*, &worker->env.hints->tree) { 1963238106Sdes if(!ssl_print_name_dp(ssl, 1964238106Sdes z->noprime?"stub noprime":"stub prime", z->node.name, 1965238106Sdes z->node.dclass, z->dp)) 1966238106Sdes return; 1967238106Sdes } 1968238106Sdes} 1969238106Sdes 1970238106Sdes/** do the list_local_zones command */ 1971238106Sdesstatic void 1972238106Sdesdo_list_local_zones(SSL* ssl, struct worker* worker) 1973238106Sdes{ 1974238106Sdes struct local_zones* zones = worker->daemon->local_zones; 1975238106Sdes struct local_zone* z; 1976238106Sdes char buf[257]; 1977269257Sdes lock_rw_rdlock(&zones->lock); 1978238106Sdes RBTREE_FOR(z, struct local_zone*, &zones->ztree) { 1979238106Sdes lock_rw_rdlock(&z->lock); 1980238106Sdes dname_str(z->name, buf); 1981238106Sdes (void)ssl_printf(ssl, "%s %s\n", buf, 1982238106Sdes local_zone_type2str(z->type)); 1983238106Sdes lock_rw_unlock(&z->lock); 1984238106Sdes } 1985269257Sdes lock_rw_unlock(&zones->lock); 1986238106Sdes} 1987238106Sdes 1988238106Sdes/** do the list_local_data command */ 1989238106Sdesstatic void 1990238106Sdesdo_list_local_data(SSL* ssl, struct worker* worker) 1991238106Sdes{ 1992238106Sdes struct local_zones* zones = worker->daemon->local_zones; 1993238106Sdes struct local_zone* z; 1994238106Sdes struct local_data* d; 1995238106Sdes struct local_rrset* p; 1996269257Sdes char* s = (char*)sldns_buffer_begin(worker->env.scratch_buffer); 1997269257Sdes size_t slen = sldns_buffer_capacity(worker->env.scratch_buffer); 1998269257Sdes lock_rw_rdlock(&zones->lock); 1999238106Sdes RBTREE_FOR(z, struct local_zone*, &zones->ztree) { 2000238106Sdes lock_rw_rdlock(&z->lock); 2001238106Sdes RBTREE_FOR(d, struct local_data*, &z->data) { 2002238106Sdes for(p = d->rrsets; p; p = p->next) { 2003269257Sdes struct packed_rrset_data* d = 2004269257Sdes (struct packed_rrset_data*)p->rrset->entry.data; 2005269257Sdes size_t i; 2006269257Sdes for(i=0; i<d->count + d->rrsig_count; i++) { 2007269257Sdes if(!packed_rr_to_string(p->rrset, i, 2008269257Sdes 0, s, slen)) { 2009269257Sdes if(!ssl_printf(ssl, "BADRR\n")) 2010269257Sdes return; 2011269257Sdes } 2012269257Sdes if(!ssl_printf(ssl, "%s\n", s)) 2013269257Sdes return; 2014269257Sdes } 2015238106Sdes } 2016238106Sdes } 2017238106Sdes lock_rw_unlock(&z->lock); 2018238106Sdes } 2019269257Sdes lock_rw_unlock(&zones->lock); 2020238106Sdes} 2021238106Sdes 2022238106Sdes/** tell other processes to execute the command */ 2023238106Sdesstatic void 2024238106Sdesdistribute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd) 2025238106Sdes{ 2026238106Sdes int i; 2027238106Sdes if(!cmd || !ssl) 2028238106Sdes return; 2029238106Sdes /* skip i=0 which is me */ 2030238106Sdes for(i=1; i<rc->worker->daemon->num; i++) { 2031238106Sdes worker_send_cmd(rc->worker->daemon->workers[i], 2032238106Sdes worker_cmd_remote); 2033238106Sdes if(!tube_write_msg(rc->worker->daemon->workers[i]->cmd, 2034238106Sdes (uint8_t*)cmd, strlen(cmd)+1, 0)) { 2035238106Sdes ssl_printf(ssl, "error could not distribute cmd\n"); 2036238106Sdes return; 2037238106Sdes } 2038238106Sdes } 2039238106Sdes} 2040238106Sdes 2041238106Sdes/** check for name with end-of-string, space or tab after it */ 2042238106Sdesstatic int 2043238106Sdescmdcmp(char* p, const char* cmd, size_t len) 2044238106Sdes{ 2045238106Sdes return strncmp(p,cmd,len)==0 && (p[len]==0||p[len]==' '||p[len]=='\t'); 2046238106Sdes} 2047238106Sdes 2048238106Sdes/** execute a remote control command */ 2049238106Sdesstatic void 2050238106Sdesexecute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, 2051238106Sdes struct worker* worker) 2052238106Sdes{ 2053238106Sdes char* p = skipwhite(cmd); 2054238106Sdes /* compare command */ 2055238106Sdes if(cmdcmp(p, "stop", 4)) { 2056238106Sdes do_stop(ssl, rc); 2057238106Sdes return; 2058238106Sdes } else if(cmdcmp(p, "reload", 6)) { 2059238106Sdes do_reload(ssl, rc); 2060238106Sdes return; 2061238106Sdes } else if(cmdcmp(p, "stats_noreset", 13)) { 2062238106Sdes do_stats(ssl, rc, 0); 2063238106Sdes return; 2064238106Sdes } else if(cmdcmp(p, "stats", 5)) { 2065238106Sdes do_stats(ssl, rc, 1); 2066238106Sdes return; 2067238106Sdes } else if(cmdcmp(p, "status", 6)) { 2068238106Sdes do_status(ssl, worker); 2069238106Sdes return; 2070238106Sdes } else if(cmdcmp(p, "dump_cache", 10)) { 2071238106Sdes (void)dump_cache(ssl, worker); 2072238106Sdes return; 2073238106Sdes } else if(cmdcmp(p, "load_cache", 10)) { 2074238106Sdes if(load_cache(ssl, worker)) send_ok(ssl); 2075238106Sdes return; 2076238106Sdes } else if(cmdcmp(p, "list_forwards", 13)) { 2077238106Sdes do_list_forwards(ssl, worker); 2078238106Sdes return; 2079238106Sdes } else if(cmdcmp(p, "list_stubs", 10)) { 2080238106Sdes do_list_stubs(ssl, worker); 2081238106Sdes return; 2082238106Sdes } else if(cmdcmp(p, "list_local_zones", 16)) { 2083238106Sdes do_list_local_zones(ssl, worker); 2084238106Sdes return; 2085238106Sdes } else if(cmdcmp(p, "list_local_data", 15)) { 2086238106Sdes do_list_local_data(ssl, worker); 2087238106Sdes return; 2088238106Sdes } else if(cmdcmp(p, "stub_add", 8)) { 2089238106Sdes /* must always distribute this cmd */ 2090238106Sdes if(rc) distribute_cmd(rc, ssl, cmd); 2091238106Sdes do_stub_add(ssl, worker, skipwhite(p+8)); 2092238106Sdes return; 2093238106Sdes } else if(cmdcmp(p, "stub_remove", 11)) { 2094238106Sdes /* must always distribute this cmd */ 2095238106Sdes if(rc) distribute_cmd(rc, ssl, cmd); 2096238106Sdes do_stub_remove(ssl, worker, skipwhite(p+11)); 2097238106Sdes return; 2098238106Sdes } else if(cmdcmp(p, "forward_add", 11)) { 2099238106Sdes /* must always distribute this cmd */ 2100238106Sdes if(rc) distribute_cmd(rc, ssl, cmd); 2101238106Sdes do_forward_add(ssl, worker, skipwhite(p+11)); 2102238106Sdes return; 2103238106Sdes } else if(cmdcmp(p, "forward_remove", 14)) { 2104238106Sdes /* must always distribute this cmd */ 2105238106Sdes if(rc) distribute_cmd(rc, ssl, cmd); 2106238106Sdes do_forward_remove(ssl, worker, skipwhite(p+14)); 2107238106Sdes return; 2108269257Sdes } else if(cmdcmp(p, "insecure_add", 12)) { 2109269257Sdes /* must always distribute this cmd */ 2110269257Sdes if(rc) distribute_cmd(rc, ssl, cmd); 2111269257Sdes do_insecure_add(ssl, worker, skipwhite(p+12)); 2112269257Sdes return; 2113269257Sdes } else if(cmdcmp(p, "insecure_remove", 15)) { 2114269257Sdes /* must always distribute this cmd */ 2115269257Sdes if(rc) distribute_cmd(rc, ssl, cmd); 2116269257Sdes do_insecure_remove(ssl, worker, skipwhite(p+15)); 2117269257Sdes return; 2118238106Sdes } else if(cmdcmp(p, "forward", 7)) { 2119238106Sdes /* must always distribute this cmd */ 2120238106Sdes if(rc) distribute_cmd(rc, ssl, cmd); 2121238106Sdes do_forward(ssl, worker, skipwhite(p+7)); 2122238106Sdes return; 2123238106Sdes } else if(cmdcmp(p, "flush_stats", 11)) { 2124238106Sdes /* must always distribute this cmd */ 2125238106Sdes if(rc) distribute_cmd(rc, ssl, cmd); 2126238106Sdes do_flush_stats(ssl, worker); 2127238106Sdes return; 2128238106Sdes } else if(cmdcmp(p, "flush_requestlist", 17)) { 2129238106Sdes /* must always distribute this cmd */ 2130238106Sdes if(rc) distribute_cmd(rc, ssl, cmd); 2131238106Sdes do_flush_requestlist(ssl, worker); 2132238106Sdes return; 2133238106Sdes } else if(cmdcmp(p, "lookup", 6)) { 2134238106Sdes do_lookup(ssl, worker, skipwhite(p+6)); 2135238106Sdes return; 2136238106Sdes } 2137238106Sdes 2138238106Sdes#ifdef THREADS_DISABLED 2139238106Sdes /* other processes must execute the command as well */ 2140238106Sdes /* commands that should not be distributed, returned above. */ 2141238106Sdes if(rc) { /* only if this thread is the master (rc) thread */ 2142238106Sdes /* done before the code below, which may split the string */ 2143238106Sdes distribute_cmd(rc, ssl, cmd); 2144238106Sdes } 2145238106Sdes#endif 2146238106Sdes if(cmdcmp(p, "verbosity", 9)) { 2147238106Sdes do_verbosity(ssl, skipwhite(p+9)); 2148238106Sdes } else if(cmdcmp(p, "local_zone_remove", 17)) { 2149238106Sdes do_zone_remove(ssl, worker, skipwhite(p+17)); 2150238106Sdes } else if(cmdcmp(p, "local_zone", 10)) { 2151238106Sdes do_zone_add(ssl, worker, skipwhite(p+10)); 2152238106Sdes } else if(cmdcmp(p, "local_data_remove", 17)) { 2153238106Sdes do_data_remove(ssl, worker, skipwhite(p+17)); 2154238106Sdes } else if(cmdcmp(p, "local_data", 10)) { 2155238106Sdes do_data_add(ssl, worker, skipwhite(p+10)); 2156238106Sdes } else if(cmdcmp(p, "flush_zone", 10)) { 2157238106Sdes do_flush_zone(ssl, worker, skipwhite(p+10)); 2158238106Sdes } else if(cmdcmp(p, "flush_type", 10)) { 2159238106Sdes do_flush_type(ssl, worker, skipwhite(p+10)); 2160238106Sdes } else if(cmdcmp(p, "flush_infra", 11)) { 2161238106Sdes do_flush_infra(ssl, worker, skipwhite(p+11)); 2162238106Sdes } else if(cmdcmp(p, "flush", 5)) { 2163238106Sdes do_flush_name(ssl, worker, skipwhite(p+5)); 2164238106Sdes } else if(cmdcmp(p, "dump_requestlist", 16)) { 2165238106Sdes do_dump_requestlist(ssl, worker); 2166238106Sdes } else if(cmdcmp(p, "dump_infra", 10)) { 2167238106Sdes do_dump_infra(ssl, worker); 2168238106Sdes } else if(cmdcmp(p, "log_reopen", 10)) { 2169238106Sdes do_log_reopen(ssl, worker); 2170238106Sdes } else if(cmdcmp(p, "set_option", 10)) { 2171238106Sdes do_set_option(ssl, worker, skipwhite(p+10)); 2172238106Sdes } else if(cmdcmp(p, "get_option", 10)) { 2173238106Sdes do_get_option(ssl, worker, skipwhite(p+10)); 2174249141Sdes } else if(cmdcmp(p, "flush_bogus", 11)) { 2175249141Sdes do_flush_bogus(ssl, worker); 2176238106Sdes } else { 2177238106Sdes (void)ssl_printf(ssl, "error unknown command '%s'\n", p); 2178238106Sdes } 2179238106Sdes} 2180238106Sdes 2181238106Sdesvoid 2182238106Sdesdaemon_remote_exec(struct worker* worker) 2183238106Sdes{ 2184238106Sdes /* read the cmd string */ 2185238106Sdes uint8_t* msg = NULL; 2186238106Sdes uint32_t len = 0; 2187238106Sdes if(!tube_read_msg(worker->cmd, &msg, &len, 0)) { 2188238106Sdes log_err("daemon_remote_exec: tube_read_msg failed"); 2189238106Sdes return; 2190238106Sdes } 2191238106Sdes verbose(VERB_ALGO, "remote exec distributed: %s", (char*)msg); 2192238106Sdes execute_cmd(NULL, NULL, (char*)msg, worker); 2193238106Sdes free(msg); 2194238106Sdes} 2195238106Sdes 2196238106Sdes/** handle remote control request */ 2197238106Sdesstatic void 2198238106Sdeshandle_req(struct daemon_remote* rc, struct rc_state* s, SSL* ssl) 2199238106Sdes{ 2200238106Sdes int r; 2201238106Sdes char pre[10]; 2202238106Sdes char magic[7]; 2203238106Sdes char buf[1024]; 2204238106Sdes#ifdef USE_WINSOCK 2205238106Sdes /* makes it possible to set the socket blocking again. */ 2206238106Sdes /* basically removes it from winsock_event ... */ 2207238106Sdes WSAEventSelect(s->c->fd, NULL, 0); 2208238106Sdes#endif 2209238106Sdes fd_set_block(s->c->fd); 2210238106Sdes 2211238106Sdes /* try to read magic UBCT[version]_space_ string */ 2212238106Sdes ERR_clear_error(); 2213238106Sdes if((r=SSL_read(ssl, magic, (int)sizeof(magic)-1)) <= 0) { 2214238106Sdes if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) 2215238106Sdes return; 2216238106Sdes log_crypto_err("could not SSL_read"); 2217238106Sdes return; 2218238106Sdes } 2219238106Sdes magic[6] = 0; 2220238106Sdes if( r != 6 || strncmp(magic, "UBCT", 4) != 0) { 2221238106Sdes verbose(VERB_QUERY, "control connection has bad magic string"); 2222238106Sdes /* probably wrong tool connected, ignore it completely */ 2223238106Sdes return; 2224238106Sdes } 2225238106Sdes 2226238106Sdes /* read the command line */ 2227238106Sdes if(!ssl_read_line(ssl, buf, sizeof(buf))) { 2228238106Sdes return; 2229238106Sdes } 2230238106Sdes snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); 2231238106Sdes if(strcmp(magic, pre) != 0) { 2232238106Sdes verbose(VERB_QUERY, "control connection had bad " 2233238106Sdes "version %s, cmd: %s", magic, buf); 2234238106Sdes ssl_printf(ssl, "error version mismatch\n"); 2235238106Sdes return; 2236238106Sdes } 2237238106Sdes verbose(VERB_DETAIL, "control cmd: %s", buf); 2238238106Sdes 2239238106Sdes /* figure out what to do */ 2240238106Sdes execute_cmd(rc, ssl, buf, rc->worker); 2241238106Sdes} 2242238106Sdes 2243238106Sdesint remote_control_callback(struct comm_point* c, void* arg, int err, 2244238106Sdes struct comm_reply* ATTR_UNUSED(rep)) 2245238106Sdes{ 2246238106Sdes struct rc_state* s = (struct rc_state*)arg; 2247238106Sdes struct daemon_remote* rc = s->rc; 2248238106Sdes int r; 2249238106Sdes if(err != NETEVENT_NOERROR) { 2250238106Sdes if(err==NETEVENT_TIMEOUT) 2251238106Sdes log_err("remote control timed out"); 2252238106Sdes clean_point(rc, s); 2253238106Sdes return 0; 2254238106Sdes } 2255238106Sdes /* (continue to) setup the SSL connection */ 2256238106Sdes ERR_clear_error(); 2257238106Sdes r = SSL_do_handshake(s->ssl); 2258238106Sdes if(r != 1) { 2259238106Sdes int r2 = SSL_get_error(s->ssl, r); 2260238106Sdes if(r2 == SSL_ERROR_WANT_READ) { 2261238106Sdes if(s->shake_state == rc_hs_read) { 2262238106Sdes /* try again later */ 2263238106Sdes return 0; 2264238106Sdes } 2265238106Sdes s->shake_state = rc_hs_read; 2266238106Sdes comm_point_listen_for_rw(c, 1, 0); 2267238106Sdes return 0; 2268238106Sdes } else if(r2 == SSL_ERROR_WANT_WRITE) { 2269238106Sdes if(s->shake_state == rc_hs_write) { 2270238106Sdes /* try again later */ 2271238106Sdes return 0; 2272238106Sdes } 2273238106Sdes s->shake_state = rc_hs_write; 2274238106Sdes comm_point_listen_for_rw(c, 0, 1); 2275238106Sdes return 0; 2276238106Sdes } else { 2277238106Sdes if(r == 0) 2278238106Sdes log_err("remote control connection closed prematurely"); 2279238106Sdes log_addr(1, "failed connection from", 2280238106Sdes &s->c->repinfo.addr, s->c->repinfo.addrlen); 2281238106Sdes log_crypto_err("remote control failed ssl"); 2282238106Sdes clean_point(rc, s); 2283238106Sdes return 0; 2284238106Sdes } 2285238106Sdes } 2286238106Sdes s->shake_state = rc_none; 2287238106Sdes 2288238106Sdes /* once handshake has completed, check authentication */ 2289238106Sdes if(SSL_get_verify_result(s->ssl) == X509_V_OK) { 2290238106Sdes X509* x = SSL_get_peer_certificate(s->ssl); 2291238106Sdes if(!x) { 2292238106Sdes verbose(VERB_DETAIL, "remote control connection " 2293238106Sdes "provided no client certificate"); 2294238106Sdes clean_point(rc, s); 2295238106Sdes return 0; 2296238106Sdes } 2297238106Sdes verbose(VERB_ALGO, "remote control connection authenticated"); 2298238106Sdes X509_free(x); 2299238106Sdes } else { 2300238106Sdes verbose(VERB_DETAIL, "remote control connection failed to " 2301238106Sdes "authenticate with client certificate"); 2302238106Sdes clean_point(rc, s); 2303238106Sdes return 0; 2304238106Sdes } 2305238106Sdes 2306238106Sdes /* if OK start to actually handle the request */ 2307238106Sdes handle_req(rc, s, s->ssl); 2308238106Sdes 2309238106Sdes verbose(VERB_ALGO, "remote control operation completed"); 2310238106Sdes clean_point(rc, s); 2311238106Sdes return 0; 2312238106Sdes} 2313