1238106Sdes/* 2238106Sdes * checkconf/unbound-control.c - remote control utility for unbound. 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 * The remote control utility contacts the unbound server over ssl and 40238106Sdes * sends the command, receives the answer, and displays the result 41238106Sdes * from the commandline. 42238106Sdes */ 43238106Sdes 44238106Sdes#include "config.h" 45238106Sdes#ifdef HAVE_GETOPT_H 46238106Sdes#include <getopt.h> 47238106Sdes#endif 48238106Sdes#ifdef HAVE_OPENSSL_SSL_H 49238106Sdes#include <openssl/ssl.h> 50238106Sdes#endif 51238106Sdes#ifdef HAVE_OPENSSL_ERR_H 52238106Sdes#include <openssl/err.h> 53238106Sdes#endif 54238106Sdes#ifdef HAVE_OPENSSL_RAND_H 55238106Sdes#include <openssl/rand.h> 56238106Sdes#endif 57238106Sdes#include "util/log.h" 58238106Sdes#include "util/config_file.h" 59238106Sdes#include "util/locks.h" 60238106Sdes#include "util/net_help.h" 61238106Sdes 62238106Sdes/** Give unbound-control usage, and exit (1). */ 63238106Sdesstatic void 64238106Sdesusage() 65238106Sdes{ 66238106Sdes printf("Usage: unbound-control [options] command\n"); 67238106Sdes printf(" Remote control utility for unbound server.\n"); 68238106Sdes printf("Options:\n"); 69238106Sdes printf(" -c file config file, default is %s\n", CONFIGFILE); 70238106Sdes printf(" -s ip[@port] server address, if omitted config is used.\n"); 71249141Sdes printf(" -q quiet (don't print anything if it works ok).\n"); 72238106Sdes printf(" -h show this usage help.\n"); 73238106Sdes printf("Commands:\n"); 74238106Sdes printf(" start start server; runs unbound(8)\n"); 75238106Sdes printf(" stop stops the server\n"); 76238106Sdes printf(" reload reloads the server\n"); 77238106Sdes printf(" (this flushes data, stats, requestlist)\n"); 78238106Sdes printf(" stats print statistics\n"); 79238106Sdes printf(" stats_noreset peek at statistics\n"); 80238106Sdes printf(" status display status of server\n"); 81238106Sdes printf(" verbosity <number> change logging detail\n"); 82238106Sdes printf(" log_reopen close and open the logfile\n"); 83238106Sdes printf(" local_zone <name> <type> add new local zone\n"); 84238106Sdes printf(" local_zone_remove <name> remove local zone and its contents\n"); 85238106Sdes printf(" local_data <RR data...> add local data, for example\n"); 86238106Sdes printf(" local_data www.example.com A 192.0.2.1\n"); 87238106Sdes printf(" local_data_remove <name> remove local RR data from name\n"); 88238106Sdes printf(" dump_cache print cache to stdout\n"); 89238106Sdes printf(" load_cache load cache from stdin\n"); 90238106Sdes printf(" lookup <name> print nameservers for name\n"); 91238106Sdes printf(" flush <name> flushes common types for name from cache\n"); 92238106Sdes printf(" types: A, AAAA, MX, PTR, NS,\n"); 93238106Sdes printf(" SOA, CNAME, DNAME, SRV, NAPTR\n"); 94238106Sdes printf(" flush_type <name> <type> flush name, type from cache\n"); 95238106Sdes printf(" flush_zone <name> flush everything at or under name\n"); 96238106Sdes printf(" from rr and dnssec caches\n"); 97249141Sdes printf(" flush_bogus flush all bogus data\n"); 98238106Sdes printf(" flush_stats flush statistics, make zero\n"); 99238106Sdes printf(" flush_requestlist drop queries that are worked on\n"); 100238106Sdes printf(" dump_requestlist show what is worked on\n"); 101238106Sdes printf(" flush_infra [all | ip] remove ping, edns for one IP or all\n"); 102238106Sdes printf(" dump_infra show ping and edns entries\n"); 103238106Sdes printf(" set_option opt: val set option to value, no reload\n"); 104238106Sdes printf(" get_option opt get option value\n"); 105238106Sdes printf(" list_stubs list stub-zones and root hints in use\n"); 106238106Sdes printf(" list_forwards list forward-zones in use\n"); 107238106Sdes printf(" list_local_zones list local-zones in use\n"); 108238106Sdes printf(" list_local_data list local-data RRs in use\n"); 109269257Sdes printf(" insecure_add zone add domain-insecure zone\n"); 110269257Sdes printf(" insecure_remove zone remove domain-insecure zone\n"); 111238106Sdes printf(" forward_add [+i] zone addr.. add forward-zone with servers\n"); 112238106Sdes printf(" forward_remove [+i] zone remove forward zone\n"); 113238106Sdes printf(" stub_add [+ip] zone addr.. add stub-zone with servers\n"); 114238106Sdes printf(" stub_remove [+i] zone remove stub zone\n"); 115238106Sdes printf(" +i also do dnssec insecure point\n"); 116238106Sdes printf(" +p set stub to use priming\n"); 117238106Sdes printf(" forward [off | addr ...] without arg show forward setup\n"); 118238106Sdes printf(" or off to turn off root forwarding\n"); 119238106Sdes printf(" or give list of ip addresses\n"); 120238106Sdes printf("Version %s\n", PACKAGE_VERSION); 121238106Sdes printf("BSD licensed, see LICENSE in source package for details.\n"); 122238106Sdes printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 123238106Sdes exit(1); 124238106Sdes} 125238106Sdes 126238106Sdes/** exit with ssl error */ 127238106Sdesstatic void ssl_err(const char* s) 128238106Sdes{ 129238106Sdes fprintf(stderr, "error: %s\n", s); 130238106Sdes ERR_print_errors_fp(stderr); 131238106Sdes exit(1); 132238106Sdes} 133238106Sdes 134238106Sdes/** setup SSL context */ 135238106Sdesstatic SSL_CTX* 136238106Sdessetup_ctx(struct config_file* cfg) 137238106Sdes{ 138238106Sdes char* s_cert, *c_key, *c_cert; 139238106Sdes SSL_CTX* ctx; 140238106Sdes 141238106Sdes s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); 142238106Sdes c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); 143238106Sdes c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); 144238106Sdes if(!s_cert || !c_key || !c_cert) 145238106Sdes fatal_exit("out of memory"); 146238106Sdes ctx = SSL_CTX_new(SSLv23_client_method()); 147238106Sdes if(!ctx) 148238106Sdes ssl_err("could not allocate SSL_CTX pointer"); 149238106Sdes if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)) 150238106Sdes ssl_err("could not set SSL_OP_NO_SSLv2"); 151238106Sdes if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) || 152238106Sdes !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) 153238106Sdes || !SSL_CTX_check_private_key(ctx)) 154238106Sdes ssl_err("Error setting up SSL_CTX client key and cert"); 155238106Sdes if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) 156238106Sdes ssl_err("Error setting up SSL_CTX verify, server cert"); 157238106Sdes SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 158238106Sdes 159238106Sdes free(s_cert); 160238106Sdes free(c_key); 161238106Sdes free(c_cert); 162238106Sdes return ctx; 163238106Sdes} 164238106Sdes 165238106Sdes/** contact the server with TCP connect */ 166238106Sdesstatic int 167238106Sdescontact_server(const char* svr, struct config_file* cfg, int statuscmd) 168238106Sdes{ 169238106Sdes struct sockaddr_storage addr; 170238106Sdes socklen_t addrlen; 171238106Sdes int fd; 172238106Sdes /* use svr or the first config entry */ 173238106Sdes if(!svr) { 174238106Sdes if(cfg->control_ifs) 175238106Sdes svr = cfg->control_ifs->str; 176238106Sdes else svr = "127.0.0.1"; 177238106Sdes /* config 0 addr (everything), means ask localhost */ 178238106Sdes if(strcmp(svr, "0.0.0.0") == 0) 179238106Sdes svr = "127.0.0.1"; 180238106Sdes else if(strcmp(svr, "::0") == 0 || 181238106Sdes strcmp(svr, "0::0") == 0 || 182238106Sdes strcmp(svr, "0::") == 0 || 183238106Sdes strcmp(svr, "::") == 0) 184238106Sdes svr = "::1"; 185238106Sdes } 186238106Sdes if(strchr(svr, '@')) { 187238106Sdes if(!extstrtoaddr(svr, &addr, &addrlen)) 188238106Sdes fatal_exit("could not parse IP@port: %s", svr); 189238106Sdes } else { 190238106Sdes if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) 191238106Sdes fatal_exit("could not parse IP: %s", svr); 192238106Sdes } 193238106Sdes fd = socket(addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET, 194238106Sdes SOCK_STREAM, 0); 195238106Sdes if(fd == -1) { 196238106Sdes#ifndef USE_WINSOCK 197238106Sdes fatal_exit("socket: %s", strerror(errno)); 198238106Sdes#else 199238106Sdes fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); 200238106Sdes#endif 201238106Sdes } 202238106Sdes if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { 203238106Sdes log_addr(0, "address", &addr, addrlen); 204238106Sdes#ifndef USE_WINSOCK 205238106Sdes log_err("connect: %s", strerror(errno)); 206238106Sdes if(errno == ECONNREFUSED && statuscmd) { 207238106Sdes printf("unbound is stopped\n"); 208238106Sdes exit(3); 209238106Sdes } 210238106Sdes#else 211238106Sdes log_err("connect: %s", wsa_strerror(WSAGetLastError())); 212238106Sdes if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) { 213238106Sdes printf("unbound is stopped\n"); 214238106Sdes exit(3); 215238106Sdes } 216238106Sdes#endif 217238106Sdes exit(1); 218238106Sdes } 219238106Sdes return fd; 220238106Sdes} 221238106Sdes 222238106Sdes/** setup SSL on the connection */ 223238106Sdesstatic SSL* 224238106Sdessetup_ssl(SSL_CTX* ctx, int fd) 225238106Sdes{ 226238106Sdes SSL* ssl; 227238106Sdes X509* x; 228238106Sdes int r; 229238106Sdes 230238106Sdes ssl = SSL_new(ctx); 231238106Sdes if(!ssl) 232238106Sdes ssl_err("could not SSL_new"); 233238106Sdes SSL_set_connect_state(ssl); 234238106Sdes (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); 235238106Sdes if(!SSL_set_fd(ssl, fd)) 236238106Sdes ssl_err("could not SSL_set_fd"); 237238106Sdes while(1) { 238238106Sdes ERR_clear_error(); 239238106Sdes if( (r=SSL_do_handshake(ssl)) == 1) 240238106Sdes break; 241238106Sdes r = SSL_get_error(ssl, r); 242238106Sdes if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) 243238106Sdes ssl_err("SSL handshake failed"); 244238106Sdes /* wants to be called again */ 245238106Sdes } 246238106Sdes 247238106Sdes /* check authenticity of server */ 248238106Sdes if(SSL_get_verify_result(ssl) != X509_V_OK) 249238106Sdes ssl_err("SSL verification failed"); 250238106Sdes x = SSL_get_peer_certificate(ssl); 251238106Sdes if(!x) 252238106Sdes ssl_err("Server presented no peer certificate"); 253238106Sdes X509_free(x); 254238106Sdes return ssl; 255238106Sdes} 256238106Sdes 257238106Sdes/** send stdin to server */ 258238106Sdesstatic void 259238106Sdessend_file(SSL* ssl, FILE* in, char* buf, size_t sz) 260238106Sdes{ 261238106Sdes while(fgets(buf, (int)sz, in)) { 262238106Sdes if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) 263238106Sdes ssl_err("could not SSL_write contents"); 264238106Sdes } 265238106Sdes} 266238106Sdes 267238106Sdes/** send command and display result */ 268238106Sdesstatic int 269249141Sdesgo_cmd(SSL* ssl, int quiet, int argc, char* argv[]) 270238106Sdes{ 271238106Sdes char pre[10]; 272238106Sdes const char* space=" "; 273238106Sdes const char* newline="\n"; 274238106Sdes int was_error = 0, first_line = 1; 275238106Sdes int r, i; 276238106Sdes char buf[1024]; 277238106Sdes snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); 278238106Sdes if(SSL_write(ssl, pre, (int)strlen(pre)) <= 0) 279238106Sdes ssl_err("could not SSL_write"); 280238106Sdes for(i=0; i<argc; i++) { 281238106Sdes if(SSL_write(ssl, space, (int)strlen(space)) <= 0) 282238106Sdes ssl_err("could not SSL_write"); 283238106Sdes if(SSL_write(ssl, argv[i], (int)strlen(argv[i])) <= 0) 284238106Sdes ssl_err("could not SSL_write"); 285238106Sdes } 286238106Sdes if(SSL_write(ssl, newline, (int)strlen(newline)) <= 0) 287238106Sdes ssl_err("could not SSL_write"); 288238106Sdes 289238106Sdes if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { 290238106Sdes send_file(ssl, stdin, buf, sizeof(buf)); 291238106Sdes } 292238106Sdes 293238106Sdes while(1) { 294238106Sdes ERR_clear_error(); 295238106Sdes if((r = SSL_read(ssl, buf, (int)sizeof(buf)-1)) <= 0) { 296238106Sdes if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 297238106Sdes /* EOF */ 298238106Sdes break; 299238106Sdes } 300238106Sdes ssl_err("could not SSL_read"); 301238106Sdes } 302238106Sdes buf[r] = 0; 303249141Sdes if(first_line && strncmp(buf, "error", 5) == 0) { 304249141Sdes printf("%s", buf); 305238106Sdes was_error = 1; 306249141Sdes } else if (!quiet) 307249141Sdes printf("%s", buf); 308249141Sdes 309238106Sdes first_line = 0; 310238106Sdes } 311238106Sdes return was_error; 312238106Sdes} 313238106Sdes 314238106Sdes/** go ahead and read config, contact server and perform command and display */ 315238106Sdesstatic int 316249141Sdesgo(const char* cfgfile, char* svr, int quiet, int argc, char* argv[]) 317238106Sdes{ 318238106Sdes struct config_file* cfg; 319238106Sdes int fd, ret; 320238106Sdes SSL_CTX* ctx; 321238106Sdes SSL* ssl; 322238106Sdes 323238106Sdes /* read config */ 324238106Sdes if(!(cfg = config_create())) 325238106Sdes fatal_exit("out of memory"); 326238106Sdes if(!config_read(cfg, cfgfile, NULL)) 327238106Sdes fatal_exit("could not read config file"); 328238106Sdes if(!cfg->remote_control_enable) 329238106Sdes log_warn("control-enable is 'no' in the config file."); 330238106Sdes ctx = setup_ctx(cfg); 331238106Sdes 332238106Sdes /* contact server */ 333238106Sdes fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0); 334238106Sdes ssl = setup_ssl(ctx, fd); 335238106Sdes 336238106Sdes /* send command */ 337249141Sdes ret = go_cmd(ssl, quiet, argc, argv); 338238106Sdes 339238106Sdes SSL_free(ssl); 340238106Sdes#ifndef USE_WINSOCK 341238106Sdes close(fd); 342238106Sdes#else 343238106Sdes closesocket(fd); 344238106Sdes#endif 345238106Sdes SSL_CTX_free(ctx); 346238106Sdes config_delete(cfg); 347238106Sdes return ret; 348238106Sdes} 349238106Sdes 350238106Sdes/** getopt global, in case header files fail to declare it. */ 351238106Sdesextern int optind; 352238106Sdes/** getopt global, in case header files fail to declare it. */ 353238106Sdesextern char* optarg; 354238106Sdes 355238106Sdes/** Main routine for unbound-control */ 356238106Sdesint main(int argc, char* argv[]) 357238106Sdes{ 358238106Sdes int c, ret; 359249141Sdes int quiet = 0; 360238106Sdes const char* cfgfile = CONFIGFILE; 361238106Sdes char* svr = NULL; 362238106Sdes#ifdef USE_WINSOCK 363238106Sdes int r; 364238106Sdes WSADATA wsa_data; 365238106Sdes#endif 366238106Sdes#ifdef USE_THREAD_DEBUG 367238106Sdes /* stop the file output from unbound-control, overwites the servers */ 368238106Sdes extern int check_locking_order; 369238106Sdes check_locking_order = 0; 370238106Sdes#endif /* USE_THREAD_DEBUG */ 371238106Sdes log_ident_set("unbound-control"); 372238106Sdes log_init(NULL, 0, NULL); 373238106Sdes checklock_start(); 374238106Sdes#ifdef USE_WINSOCK 375238106Sdes if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) 376238106Sdes fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); 377238106Sdes /* use registry config file in preference to compiletime location */ 378238106Sdes if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) 379238106Sdes cfgfile = CONFIGFILE; 380238106Sdes#endif 381238106Sdes 382238106Sdes ERR_load_crypto_strings(); 383238106Sdes ERR_load_SSL_strings(); 384238106Sdes OpenSSL_add_all_algorithms(); 385238106Sdes (void)SSL_library_init(); 386238106Sdes 387238106Sdes if(!RAND_status()) { 388238106Sdes /* try to seed it */ 389238106Sdes unsigned char buf[256]; 390249141Sdes unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid(); 391249141Sdes unsigned int v = seed; 392238106Sdes size_t i; 393238106Sdes for(i=0; i<256/sizeof(v); i++) { 394238106Sdes memmove(buf+i*sizeof(v), &v, sizeof(v)); 395238106Sdes v = v*seed + (unsigned int)i; 396238106Sdes } 397238106Sdes RAND_seed(buf, 256); 398238106Sdes log_warn("no entropy, seeding openssl PRNG with time\n"); 399238106Sdes } 400238106Sdes 401238106Sdes /* parse the options */ 402249141Sdes while( (c=getopt(argc, argv, "c:s:qh")) != -1) { 403238106Sdes switch(c) { 404238106Sdes case 'c': 405238106Sdes cfgfile = optarg; 406238106Sdes break; 407238106Sdes case 's': 408238106Sdes svr = optarg; 409238106Sdes break; 410249141Sdes case 'q': 411249141Sdes quiet = 1; 412249141Sdes break; 413238106Sdes case '?': 414238106Sdes case 'h': 415238106Sdes default: 416238106Sdes usage(); 417238106Sdes } 418238106Sdes } 419238106Sdes argc -= optind; 420238106Sdes argv += optind; 421238106Sdes if(argc == 0) 422238106Sdes usage(); 423238106Sdes if(argc >= 1 && strcmp(argv[0], "start")==0) { 424238106Sdes if(execlp("unbound", "unbound", "-c", cfgfile, 425238106Sdes (char*)NULL) < 0) { 426238106Sdes fatal_exit("could not exec unbound: %s", 427238106Sdes strerror(errno)); 428238106Sdes } 429238106Sdes } 430238106Sdes 431249141Sdes ret = go(cfgfile, svr, quiet, argc, argv); 432238106Sdes 433238106Sdes#ifdef USE_WINSOCK 434238106Sdes WSACleanup(); 435238106Sdes#endif 436238106Sdes checklock_stop(); 437238106Sdes return ret; 438238106Sdes} 439