unbound-control.c revision 249141
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 24238106Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25238106Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26238106Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27238106Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28238106Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29238106Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30238106Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31238106Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32238106Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33238106Sdes * 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"); 109238106Sdes printf(" forward_add [+i] zone addr.. add forward-zone with servers\n"); 110238106Sdes printf(" forward_remove [+i] zone remove forward zone\n"); 111238106Sdes printf(" stub_add [+ip] zone addr.. add stub-zone with servers\n"); 112238106Sdes printf(" stub_remove [+i] zone remove stub zone\n"); 113238106Sdes printf(" +i also do dnssec insecure point\n"); 114238106Sdes printf(" +p set stub to use priming\n"); 115238106Sdes printf(" forward [off | addr ...] without arg show forward setup\n"); 116238106Sdes printf(" or off to turn off root forwarding\n"); 117238106Sdes printf(" or give list of ip addresses\n"); 118238106Sdes printf("Version %s\n", PACKAGE_VERSION); 119238106Sdes printf("BSD licensed, see LICENSE in source package for details.\n"); 120238106Sdes printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 121238106Sdes exit(1); 122238106Sdes} 123238106Sdes 124238106Sdes/** exit with ssl error */ 125238106Sdesstatic void ssl_err(const char* s) 126238106Sdes{ 127238106Sdes fprintf(stderr, "error: %s\n", s); 128238106Sdes ERR_print_errors_fp(stderr); 129238106Sdes exit(1); 130238106Sdes} 131238106Sdes 132238106Sdes/** setup SSL context */ 133238106Sdesstatic SSL_CTX* 134238106Sdessetup_ctx(struct config_file* cfg) 135238106Sdes{ 136238106Sdes char* s_cert, *c_key, *c_cert; 137238106Sdes SSL_CTX* ctx; 138238106Sdes 139238106Sdes s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); 140238106Sdes c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); 141238106Sdes c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); 142238106Sdes if(!s_cert || !c_key || !c_cert) 143238106Sdes fatal_exit("out of memory"); 144238106Sdes ctx = SSL_CTX_new(SSLv23_client_method()); 145238106Sdes if(!ctx) 146238106Sdes ssl_err("could not allocate SSL_CTX pointer"); 147238106Sdes if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)) 148238106Sdes ssl_err("could not set SSL_OP_NO_SSLv2"); 149238106Sdes if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) || 150238106Sdes !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) 151238106Sdes || !SSL_CTX_check_private_key(ctx)) 152238106Sdes ssl_err("Error setting up SSL_CTX client key and cert"); 153238106Sdes if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) 154238106Sdes ssl_err("Error setting up SSL_CTX verify, server cert"); 155238106Sdes SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 156238106Sdes 157238106Sdes free(s_cert); 158238106Sdes free(c_key); 159238106Sdes free(c_cert); 160238106Sdes return ctx; 161238106Sdes} 162238106Sdes 163238106Sdes/** contact the server with TCP connect */ 164238106Sdesstatic int 165238106Sdescontact_server(const char* svr, struct config_file* cfg, int statuscmd) 166238106Sdes{ 167238106Sdes struct sockaddr_storage addr; 168238106Sdes socklen_t addrlen; 169238106Sdes int fd; 170238106Sdes /* use svr or the first config entry */ 171238106Sdes if(!svr) { 172238106Sdes if(cfg->control_ifs) 173238106Sdes svr = cfg->control_ifs->str; 174238106Sdes else svr = "127.0.0.1"; 175238106Sdes /* config 0 addr (everything), means ask localhost */ 176238106Sdes if(strcmp(svr, "0.0.0.0") == 0) 177238106Sdes svr = "127.0.0.1"; 178238106Sdes else if(strcmp(svr, "::0") == 0 || 179238106Sdes strcmp(svr, "0::0") == 0 || 180238106Sdes strcmp(svr, "0::") == 0 || 181238106Sdes strcmp(svr, "::") == 0) 182238106Sdes svr = "::1"; 183238106Sdes } 184238106Sdes if(strchr(svr, '@')) { 185238106Sdes if(!extstrtoaddr(svr, &addr, &addrlen)) 186238106Sdes fatal_exit("could not parse IP@port: %s", svr); 187238106Sdes } else { 188238106Sdes if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) 189238106Sdes fatal_exit("could not parse IP: %s", svr); 190238106Sdes } 191238106Sdes fd = socket(addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET, 192238106Sdes SOCK_STREAM, 0); 193238106Sdes if(fd == -1) { 194238106Sdes#ifndef USE_WINSOCK 195238106Sdes fatal_exit("socket: %s", strerror(errno)); 196238106Sdes#else 197238106Sdes fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); 198238106Sdes#endif 199238106Sdes } 200238106Sdes if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { 201238106Sdes log_addr(0, "address", &addr, addrlen); 202238106Sdes#ifndef USE_WINSOCK 203238106Sdes log_err("connect: %s", strerror(errno)); 204238106Sdes if(errno == ECONNREFUSED && statuscmd) { 205238106Sdes printf("unbound is stopped\n"); 206238106Sdes exit(3); 207238106Sdes } 208238106Sdes#else 209238106Sdes log_err("connect: %s", wsa_strerror(WSAGetLastError())); 210238106Sdes if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) { 211238106Sdes printf("unbound is stopped\n"); 212238106Sdes exit(3); 213238106Sdes } 214238106Sdes#endif 215238106Sdes exit(1); 216238106Sdes } 217238106Sdes return fd; 218238106Sdes} 219238106Sdes 220238106Sdes/** setup SSL on the connection */ 221238106Sdesstatic SSL* 222238106Sdessetup_ssl(SSL_CTX* ctx, int fd) 223238106Sdes{ 224238106Sdes SSL* ssl; 225238106Sdes X509* x; 226238106Sdes int r; 227238106Sdes 228238106Sdes ssl = SSL_new(ctx); 229238106Sdes if(!ssl) 230238106Sdes ssl_err("could not SSL_new"); 231238106Sdes SSL_set_connect_state(ssl); 232238106Sdes (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); 233238106Sdes if(!SSL_set_fd(ssl, fd)) 234238106Sdes ssl_err("could not SSL_set_fd"); 235238106Sdes while(1) { 236238106Sdes ERR_clear_error(); 237238106Sdes if( (r=SSL_do_handshake(ssl)) == 1) 238238106Sdes break; 239238106Sdes r = SSL_get_error(ssl, r); 240238106Sdes if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) 241238106Sdes ssl_err("SSL handshake failed"); 242238106Sdes /* wants to be called again */ 243238106Sdes } 244238106Sdes 245238106Sdes /* check authenticity of server */ 246238106Sdes if(SSL_get_verify_result(ssl) != X509_V_OK) 247238106Sdes ssl_err("SSL verification failed"); 248238106Sdes x = SSL_get_peer_certificate(ssl); 249238106Sdes if(!x) 250238106Sdes ssl_err("Server presented no peer certificate"); 251238106Sdes X509_free(x); 252238106Sdes return ssl; 253238106Sdes} 254238106Sdes 255238106Sdes/** send stdin to server */ 256238106Sdesstatic void 257238106Sdessend_file(SSL* ssl, FILE* in, char* buf, size_t sz) 258238106Sdes{ 259238106Sdes while(fgets(buf, (int)sz, in)) { 260238106Sdes if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) 261238106Sdes ssl_err("could not SSL_write contents"); 262238106Sdes } 263238106Sdes} 264238106Sdes 265238106Sdes/** send command and display result */ 266238106Sdesstatic int 267249141Sdesgo_cmd(SSL* ssl, int quiet, int argc, char* argv[]) 268238106Sdes{ 269238106Sdes char pre[10]; 270238106Sdes const char* space=" "; 271238106Sdes const char* newline="\n"; 272238106Sdes int was_error = 0, first_line = 1; 273238106Sdes int r, i; 274238106Sdes char buf[1024]; 275238106Sdes snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); 276238106Sdes if(SSL_write(ssl, pre, (int)strlen(pre)) <= 0) 277238106Sdes ssl_err("could not SSL_write"); 278238106Sdes for(i=0; i<argc; i++) { 279238106Sdes if(SSL_write(ssl, space, (int)strlen(space)) <= 0) 280238106Sdes ssl_err("could not SSL_write"); 281238106Sdes if(SSL_write(ssl, argv[i], (int)strlen(argv[i])) <= 0) 282238106Sdes ssl_err("could not SSL_write"); 283238106Sdes } 284238106Sdes if(SSL_write(ssl, newline, (int)strlen(newline)) <= 0) 285238106Sdes ssl_err("could not SSL_write"); 286238106Sdes 287238106Sdes if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { 288238106Sdes send_file(ssl, stdin, buf, sizeof(buf)); 289238106Sdes } 290238106Sdes 291238106Sdes while(1) { 292238106Sdes ERR_clear_error(); 293238106Sdes if((r = SSL_read(ssl, buf, (int)sizeof(buf)-1)) <= 0) { 294238106Sdes if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 295238106Sdes /* EOF */ 296238106Sdes break; 297238106Sdes } 298238106Sdes ssl_err("could not SSL_read"); 299238106Sdes } 300238106Sdes buf[r] = 0; 301249141Sdes if(first_line && strncmp(buf, "error", 5) == 0) { 302249141Sdes printf("%s", buf); 303238106Sdes was_error = 1; 304249141Sdes } else if (!quiet) 305249141Sdes printf("%s", buf); 306249141Sdes 307238106Sdes first_line = 0; 308238106Sdes } 309238106Sdes return was_error; 310238106Sdes} 311238106Sdes 312238106Sdes/** go ahead and read config, contact server and perform command and display */ 313238106Sdesstatic int 314249141Sdesgo(const char* cfgfile, char* svr, int quiet, int argc, char* argv[]) 315238106Sdes{ 316238106Sdes struct config_file* cfg; 317238106Sdes int fd, ret; 318238106Sdes SSL_CTX* ctx; 319238106Sdes SSL* ssl; 320238106Sdes 321238106Sdes /* read config */ 322238106Sdes if(!(cfg = config_create())) 323238106Sdes fatal_exit("out of memory"); 324238106Sdes if(!config_read(cfg, cfgfile, NULL)) 325238106Sdes fatal_exit("could not read config file"); 326238106Sdes if(!cfg->remote_control_enable) 327238106Sdes log_warn("control-enable is 'no' in the config file."); 328238106Sdes ctx = setup_ctx(cfg); 329238106Sdes 330238106Sdes /* contact server */ 331238106Sdes fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0); 332238106Sdes ssl = setup_ssl(ctx, fd); 333238106Sdes 334238106Sdes /* send command */ 335249141Sdes ret = go_cmd(ssl, quiet, argc, argv); 336238106Sdes 337238106Sdes SSL_free(ssl); 338238106Sdes#ifndef USE_WINSOCK 339238106Sdes close(fd); 340238106Sdes#else 341238106Sdes closesocket(fd); 342238106Sdes#endif 343238106Sdes SSL_CTX_free(ctx); 344238106Sdes config_delete(cfg); 345238106Sdes return ret; 346238106Sdes} 347238106Sdes 348238106Sdes/** getopt global, in case header files fail to declare it. */ 349238106Sdesextern int optind; 350238106Sdes/** getopt global, in case header files fail to declare it. */ 351238106Sdesextern char* optarg; 352238106Sdes 353238106Sdes/** Main routine for unbound-control */ 354238106Sdesint main(int argc, char* argv[]) 355238106Sdes{ 356238106Sdes int c, ret; 357249141Sdes int quiet = 0; 358238106Sdes const char* cfgfile = CONFIGFILE; 359238106Sdes char* svr = NULL; 360238106Sdes#ifdef USE_WINSOCK 361238106Sdes int r; 362238106Sdes WSADATA wsa_data; 363238106Sdes#endif 364238106Sdes#ifdef USE_THREAD_DEBUG 365238106Sdes /* stop the file output from unbound-control, overwites the servers */ 366238106Sdes extern int check_locking_order; 367238106Sdes check_locking_order = 0; 368238106Sdes#endif /* USE_THREAD_DEBUG */ 369238106Sdes log_ident_set("unbound-control"); 370238106Sdes log_init(NULL, 0, NULL); 371238106Sdes checklock_start(); 372238106Sdes#ifdef USE_WINSOCK 373238106Sdes if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) 374238106Sdes fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); 375238106Sdes /* use registry config file in preference to compiletime location */ 376238106Sdes if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) 377238106Sdes cfgfile = CONFIGFILE; 378238106Sdes#endif 379238106Sdes 380238106Sdes ERR_load_crypto_strings(); 381238106Sdes ERR_load_SSL_strings(); 382238106Sdes OpenSSL_add_all_algorithms(); 383238106Sdes (void)SSL_library_init(); 384238106Sdes 385238106Sdes if(!RAND_status()) { 386238106Sdes /* try to seed it */ 387238106Sdes unsigned char buf[256]; 388249141Sdes unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid(); 389249141Sdes unsigned int v = seed; 390238106Sdes size_t i; 391238106Sdes for(i=0; i<256/sizeof(v); i++) { 392238106Sdes memmove(buf+i*sizeof(v), &v, sizeof(v)); 393238106Sdes v = v*seed + (unsigned int)i; 394238106Sdes } 395238106Sdes RAND_seed(buf, 256); 396238106Sdes log_warn("no entropy, seeding openssl PRNG with time\n"); 397238106Sdes } 398238106Sdes 399238106Sdes /* parse the options */ 400249141Sdes while( (c=getopt(argc, argv, "c:s:qh")) != -1) { 401238106Sdes switch(c) { 402238106Sdes case 'c': 403238106Sdes cfgfile = optarg; 404238106Sdes break; 405238106Sdes case 's': 406238106Sdes svr = optarg; 407238106Sdes break; 408249141Sdes case 'q': 409249141Sdes quiet = 1; 410249141Sdes break; 411238106Sdes case '?': 412238106Sdes case 'h': 413238106Sdes default: 414238106Sdes usage(); 415238106Sdes } 416238106Sdes } 417238106Sdes argc -= optind; 418238106Sdes argv += optind; 419238106Sdes if(argc == 0) 420238106Sdes usage(); 421238106Sdes if(argc >= 1 && strcmp(argv[0], "start")==0) { 422238106Sdes if(execlp("unbound", "unbound", "-c", cfgfile, 423238106Sdes (char*)NULL) < 0) { 424238106Sdes fatal_exit("could not exec unbound: %s", 425238106Sdes strerror(errno)); 426238106Sdes } 427238106Sdes } 428238106Sdes 429249141Sdes ret = go(cfgfile, svr, quiet, argc, argv); 430238106Sdes 431238106Sdes#ifdef USE_WINSOCK 432238106Sdes WSACleanup(); 433238106Sdes#endif 434238106Sdes checklock_stop(); 435238106Sdes return ret; 436238106Sdes} 437