1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * checkconf/unbound-control.c - remote control utility for unbound. 3b7579f77SDag-Erling Smørgrav * 4b7579f77SDag-Erling Smørgrav * Copyright (c) 2008, NLnet Labs. All rights reserved. 5b7579f77SDag-Erling Smørgrav * 6b7579f77SDag-Erling Smørgrav * This software is open source. 7b7579f77SDag-Erling Smørgrav * 8b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10b7579f77SDag-Erling Smørgrav * are met: 11b7579f77SDag-Erling Smørgrav * 12b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14b7579f77SDag-Erling Smørgrav * 15b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18b7579f77SDag-Erling Smørgrav * 19b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21b7579f77SDag-Erling Smørgrav * specific prior written permission. 22b7579f77SDag-Erling Smørgrav * 23b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2417d15b25SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2517d15b25SDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2617d15b25SDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2717d15b25SDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2817d15b25SDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2917d15b25SDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 3017d15b25SDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3117d15b25SDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3217d15b25SDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3317d15b25SDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34b7579f77SDag-Erling Smørgrav */ 35b7579f77SDag-Erling Smørgrav 36b7579f77SDag-Erling Smørgrav /** 37b7579f77SDag-Erling Smørgrav * \file 38b7579f77SDag-Erling Smørgrav * 39b7579f77SDag-Erling Smørgrav * The remote control utility contacts the unbound server over ssl and 40b7579f77SDag-Erling Smørgrav * sends the command, receives the answer, and displays the result 41b7579f77SDag-Erling Smørgrav * from the commandline. 42b7579f77SDag-Erling Smørgrav */ 43b7579f77SDag-Erling Smørgrav 44b7579f77SDag-Erling Smørgrav #include "config.h" 45b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETOPT_H 46b7579f77SDag-Erling Smørgrav #include <getopt.h> 47b7579f77SDag-Erling Smørgrav #endif 48b7579f77SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_SSL_H 49b7579f77SDag-Erling Smørgrav #include <openssl/ssl.h> 50b7579f77SDag-Erling Smørgrav #endif 51b7579f77SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_ERR_H 52b7579f77SDag-Erling Smørgrav #include <openssl/err.h> 53b7579f77SDag-Erling Smørgrav #endif 54b7579f77SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_RAND_H 55b7579f77SDag-Erling Smørgrav #include <openssl/rand.h> 56b7579f77SDag-Erling Smørgrav #endif 57b7579f77SDag-Erling Smørgrav #include "util/log.h" 58b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 59b7579f77SDag-Erling Smørgrav #include "util/locks.h" 60b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 61b7579f77SDag-Erling Smørgrav 6231099b50SDag-Erling Smørgrav #ifdef HAVE_SYS_UN_H 6331099b50SDag-Erling Smørgrav #include <sys/un.h> 6431099b50SDag-Erling Smørgrav #endif 6531099b50SDag-Erling Smørgrav 66b7579f77SDag-Erling Smørgrav /** Give unbound-control usage, and exit (1). */ 67b7579f77SDag-Erling Smørgrav static void 68b5663de9SDag-Erling Smørgrav usage(void) 69b7579f77SDag-Erling Smørgrav { 70b7579f77SDag-Erling Smørgrav printf("Usage: unbound-control [options] command\n"); 71b7579f77SDag-Erling Smørgrav printf(" Remote control utility for unbound server.\n"); 72b7579f77SDag-Erling Smørgrav printf("Options:\n"); 73b7579f77SDag-Erling Smørgrav printf(" -c file config file, default is %s\n", CONFIGFILE); 74b7579f77SDag-Erling Smørgrav printf(" -s ip[@port] server address, if omitted config is used.\n"); 758ed2b524SDag-Erling Smørgrav printf(" -q quiet (don't print anything if it works ok).\n"); 76b7579f77SDag-Erling Smørgrav printf(" -h show this usage help.\n"); 77b7579f77SDag-Erling Smørgrav printf("Commands:\n"); 78b7579f77SDag-Erling Smørgrav printf(" start start server; runs unbound(8)\n"); 79b7579f77SDag-Erling Smørgrav printf(" stop stops the server\n"); 80b7579f77SDag-Erling Smørgrav printf(" reload reloads the server\n"); 81b7579f77SDag-Erling Smørgrav printf(" (this flushes data, stats, requestlist)\n"); 82b7579f77SDag-Erling Smørgrav printf(" stats print statistics\n"); 83b7579f77SDag-Erling Smørgrav printf(" stats_noreset peek at statistics\n"); 84b7579f77SDag-Erling Smørgrav printf(" status display status of server\n"); 85b7579f77SDag-Erling Smørgrav printf(" verbosity <number> change logging detail\n"); 86b7579f77SDag-Erling Smørgrav printf(" log_reopen close and open the logfile\n"); 87b7579f77SDag-Erling Smørgrav printf(" local_zone <name> <type> add new local zone\n"); 88b7579f77SDag-Erling Smørgrav printf(" local_zone_remove <name> remove local zone and its contents\n"); 89b7579f77SDag-Erling Smørgrav printf(" local_data <RR data...> add local data, for example\n"); 90b7579f77SDag-Erling Smørgrav printf(" local_data www.example.com A 192.0.2.1\n"); 91b7579f77SDag-Erling Smørgrav printf(" local_data_remove <name> remove local RR data from name\n"); 92b7579f77SDag-Erling Smørgrav printf(" dump_cache print cache to stdout\n"); 93b7579f77SDag-Erling Smørgrav printf(" load_cache load cache from stdin\n"); 94b7579f77SDag-Erling Smørgrav printf(" lookup <name> print nameservers for name\n"); 95b7579f77SDag-Erling Smørgrav printf(" flush <name> flushes common types for name from cache\n"); 96b7579f77SDag-Erling Smørgrav printf(" types: A, AAAA, MX, PTR, NS,\n"); 97b7579f77SDag-Erling Smørgrav printf(" SOA, CNAME, DNAME, SRV, NAPTR\n"); 98b7579f77SDag-Erling Smørgrav printf(" flush_type <name> <type> flush name, type from cache\n"); 99b7579f77SDag-Erling Smørgrav printf(" flush_zone <name> flush everything at or under name\n"); 100b7579f77SDag-Erling Smørgrav printf(" from rr and dnssec caches\n"); 1018ed2b524SDag-Erling Smørgrav printf(" flush_bogus flush all bogus data\n"); 102ff825849SDag-Erling Smørgrav printf(" flush_negative flush all negative data\n"); 103b7579f77SDag-Erling Smørgrav printf(" flush_stats flush statistics, make zero\n"); 104b7579f77SDag-Erling Smørgrav printf(" flush_requestlist drop queries that are worked on\n"); 105e2d15004SDag-Erling Smørgrav printf(" dump_requestlist show what is worked on by first thread\n"); 106b7579f77SDag-Erling Smørgrav printf(" flush_infra [all | ip] remove ping, edns for one IP or all\n"); 107b7579f77SDag-Erling Smørgrav printf(" dump_infra show ping and edns entries\n"); 108b7579f77SDag-Erling Smørgrav printf(" set_option opt: val set option to value, no reload\n"); 109b7579f77SDag-Erling Smørgrav printf(" get_option opt get option value\n"); 110b7579f77SDag-Erling Smørgrav printf(" list_stubs list stub-zones and root hints in use\n"); 111b7579f77SDag-Erling Smørgrav printf(" list_forwards list forward-zones in use\n"); 11209a3aaf3SDag-Erling Smørgrav printf(" list_insecure list domain-insecure zones\n"); 113b7579f77SDag-Erling Smørgrav printf(" list_local_zones list local-zones in use\n"); 114b7579f77SDag-Erling Smørgrav printf(" list_local_data list local-data RRs in use\n"); 11517d15b25SDag-Erling Smørgrav printf(" insecure_add zone add domain-insecure zone\n"); 11617d15b25SDag-Erling Smørgrav printf(" insecure_remove zone remove domain-insecure zone\n"); 117b7579f77SDag-Erling Smørgrav printf(" forward_add [+i] zone addr.. add forward-zone with servers\n"); 118b7579f77SDag-Erling Smørgrav printf(" forward_remove [+i] zone remove forward zone\n"); 119b7579f77SDag-Erling Smørgrav printf(" stub_add [+ip] zone addr.. add stub-zone with servers\n"); 120b7579f77SDag-Erling Smørgrav printf(" stub_remove [+i] zone remove stub zone\n"); 121b7579f77SDag-Erling Smørgrav printf(" +i also do dnssec insecure point\n"); 122b7579f77SDag-Erling Smørgrav printf(" +p set stub to use priming\n"); 123b7579f77SDag-Erling Smørgrav printf(" forward [off | addr ...] without arg show forward setup\n"); 124b7579f77SDag-Erling Smørgrav printf(" or off to turn off root forwarding\n"); 125b7579f77SDag-Erling Smørgrav printf(" or give list of ip addresses\n"); 12609a3aaf3SDag-Erling Smørgrav printf(" ratelimit_list [+a] list ratelimited domains\n"); 12709a3aaf3SDag-Erling Smørgrav printf(" +a list all, also not ratelimited\n"); 128b7579f77SDag-Erling Smørgrav printf("Version %s\n", PACKAGE_VERSION); 129b7579f77SDag-Erling Smørgrav printf("BSD licensed, see LICENSE in source package for details.\n"); 130b7579f77SDag-Erling Smørgrav printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 131b7579f77SDag-Erling Smørgrav exit(1); 132b7579f77SDag-Erling Smørgrav } 133b7579f77SDag-Erling Smørgrav 134b7579f77SDag-Erling Smørgrav /** exit with ssl error */ 135b7579f77SDag-Erling Smørgrav static void ssl_err(const char* s) 136b7579f77SDag-Erling Smørgrav { 137b7579f77SDag-Erling Smørgrav fprintf(stderr, "error: %s\n", s); 138b7579f77SDag-Erling Smørgrav ERR_print_errors_fp(stderr); 139b7579f77SDag-Erling Smørgrav exit(1); 140b7579f77SDag-Erling Smørgrav } 141b7579f77SDag-Erling Smørgrav 142b7579f77SDag-Erling Smørgrav /** setup SSL context */ 143b7579f77SDag-Erling Smørgrav static SSL_CTX* 144b7579f77SDag-Erling Smørgrav setup_ctx(struct config_file* cfg) 145b7579f77SDag-Erling Smørgrav { 146748bd829SDag-Erling Smørgrav char* s_cert=NULL, *c_key=NULL, *c_cert=NULL; 147b7579f77SDag-Erling Smørgrav SSL_CTX* ctx; 148b7579f77SDag-Erling Smørgrav 14931099b50SDag-Erling Smørgrav if(cfg->remote_control_use_cert) { 150b7579f77SDag-Erling Smørgrav s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); 151b7579f77SDag-Erling Smørgrav c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); 152b7579f77SDag-Erling Smørgrav c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); 153b7579f77SDag-Erling Smørgrav if(!s_cert || !c_key || !c_cert) 154b7579f77SDag-Erling Smørgrav fatal_exit("out of memory"); 15531099b50SDag-Erling Smørgrav } 156b7579f77SDag-Erling Smørgrav ctx = SSL_CTX_new(SSLv23_client_method()); 157b7579f77SDag-Erling Smørgrav if(!ctx) 158b7579f77SDag-Erling Smørgrav ssl_err("could not allocate SSL_CTX pointer"); 15905ab2901SDag-Erling Smørgrav if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) 16005ab2901SDag-Erling Smørgrav != SSL_OP_NO_SSLv2) 161b7579f77SDag-Erling Smørgrav ssl_err("could not set SSL_OP_NO_SSLv2"); 16231099b50SDag-Erling Smørgrav if(cfg->remote_control_use_cert) { 16305ab2901SDag-Erling Smørgrav if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) 16405ab2901SDag-Erling Smørgrav != SSL_OP_NO_SSLv3) 165ff825849SDag-Erling Smørgrav ssl_err("could not set SSL_OP_NO_SSLv3"); 166b75612f8SDag-Erling Smørgrav if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert) || 167b7579f77SDag-Erling Smørgrav !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) 168b7579f77SDag-Erling Smørgrav || !SSL_CTX_check_private_key(ctx)) 169b7579f77SDag-Erling Smørgrav ssl_err("Error setting up SSL_CTX client key and cert"); 170b7579f77SDag-Erling Smørgrav if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) 171b7579f77SDag-Erling Smørgrav ssl_err("Error setting up SSL_CTX verify, server cert"); 172b7579f77SDag-Erling Smørgrav SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 173b7579f77SDag-Erling Smørgrav 174b7579f77SDag-Erling Smørgrav free(s_cert); 175b7579f77SDag-Erling Smørgrav free(c_key); 176b7579f77SDag-Erling Smørgrav free(c_cert); 17731099b50SDag-Erling Smørgrav } else { 17831099b50SDag-Erling Smørgrav /* Use ciphers that don't require authentication */ 179*bc892140SDag-Erling Smørgrav #ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL 180*bc892140SDag-Erling Smørgrav SSL_CTX_set_security_level(ctx, 0); 181*bc892140SDag-Erling Smørgrav #endif 182*bc892140SDag-Erling Smørgrav if(!SSL_CTX_set_cipher_list(ctx, "aNULL, eNULL")) 18331099b50SDag-Erling Smørgrav ssl_err("Error setting NULL cipher!"); 18431099b50SDag-Erling Smørgrav } 185b7579f77SDag-Erling Smørgrav return ctx; 186b7579f77SDag-Erling Smørgrav } 187b7579f77SDag-Erling Smørgrav 188b7579f77SDag-Erling Smørgrav /** contact the server with TCP connect */ 189b7579f77SDag-Erling Smørgrav static int 190b7579f77SDag-Erling Smørgrav contact_server(const char* svr, struct config_file* cfg, int statuscmd) 191b7579f77SDag-Erling Smørgrav { 192b7579f77SDag-Erling Smørgrav struct sockaddr_storage addr; 193b7579f77SDag-Erling Smørgrav socklen_t addrlen; 19431099b50SDag-Erling Smørgrav int addrfamily = 0; 195b7579f77SDag-Erling Smørgrav int fd; 196b7579f77SDag-Erling Smørgrav /* use svr or the first config entry */ 197b7579f77SDag-Erling Smørgrav if(!svr) { 198b7579f77SDag-Erling Smørgrav if(cfg->control_ifs) 199b7579f77SDag-Erling Smørgrav svr = cfg->control_ifs->str; 200b7579f77SDag-Erling Smørgrav else svr = "127.0.0.1"; 201b7579f77SDag-Erling Smørgrav /* config 0 addr (everything), means ask localhost */ 202b7579f77SDag-Erling Smørgrav if(strcmp(svr, "0.0.0.0") == 0) 203b7579f77SDag-Erling Smørgrav svr = "127.0.0.1"; 204b7579f77SDag-Erling Smørgrav else if(strcmp(svr, "::0") == 0 || 205b7579f77SDag-Erling Smørgrav strcmp(svr, "0::0") == 0 || 206b7579f77SDag-Erling Smørgrav strcmp(svr, "0::") == 0 || 207b7579f77SDag-Erling Smørgrav strcmp(svr, "::") == 0) 208b7579f77SDag-Erling Smørgrav svr = "::1"; 209b7579f77SDag-Erling Smørgrav } 210b7579f77SDag-Erling Smørgrav if(strchr(svr, '@')) { 211b7579f77SDag-Erling Smørgrav if(!extstrtoaddr(svr, &addr, &addrlen)) 212b7579f77SDag-Erling Smørgrav fatal_exit("could not parse IP@port: %s", svr); 21331099b50SDag-Erling Smørgrav #ifdef HAVE_SYS_UN_H 21431099b50SDag-Erling Smørgrav } else if(svr[0] == '/') { 2156480faa8SDag-Erling Smørgrav struct sockaddr_un* usock = (struct sockaddr_un *) &addr; 2166480faa8SDag-Erling Smørgrav usock->sun_family = AF_LOCAL; 217748bd829SDag-Erling Smørgrav #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 218b5663de9SDag-Erling Smørgrav usock->sun_len = (unsigned)sizeof(usock); 219748bd829SDag-Erling Smørgrav #endif 2206480faa8SDag-Erling Smørgrav (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path)); 221748bd829SDag-Erling Smørgrav addrlen = (socklen_t)sizeof(struct sockaddr_un); 22231099b50SDag-Erling Smørgrav addrfamily = AF_LOCAL; 22331099b50SDag-Erling Smørgrav #endif 224b7579f77SDag-Erling Smørgrav } else { 225b7579f77SDag-Erling Smørgrav if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) 226b7579f77SDag-Erling Smørgrav fatal_exit("could not parse IP: %s", svr); 227b7579f77SDag-Erling Smørgrav } 22831099b50SDag-Erling Smørgrav 22931099b50SDag-Erling Smørgrav if(addrfamily == 0) 23031099b50SDag-Erling Smørgrav addrfamily = addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET; 23131099b50SDag-Erling Smørgrav fd = socket(addrfamily, SOCK_STREAM, 0); 232b7579f77SDag-Erling Smørgrav if(fd == -1) { 233b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 234b7579f77SDag-Erling Smørgrav fatal_exit("socket: %s", strerror(errno)); 235b7579f77SDag-Erling Smørgrav #else 236b7579f77SDag-Erling Smørgrav fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); 237b7579f77SDag-Erling Smørgrav #endif 238b7579f77SDag-Erling Smørgrav } 239b7579f77SDag-Erling Smørgrav if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { 240b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 241ff825849SDag-Erling Smørgrav log_err_addr("connect", strerror(errno), &addr, addrlen); 242b7579f77SDag-Erling Smørgrav if(errno == ECONNREFUSED && statuscmd) { 243b7579f77SDag-Erling Smørgrav printf("unbound is stopped\n"); 244b7579f77SDag-Erling Smørgrav exit(3); 245b7579f77SDag-Erling Smørgrav } 246b7579f77SDag-Erling Smørgrav #else 247ff825849SDag-Erling Smørgrav log_err_addr("connect", wsa_strerror(WSAGetLastError()), &addr, addrlen); 248b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) { 249b7579f77SDag-Erling Smørgrav printf("unbound is stopped\n"); 250b7579f77SDag-Erling Smørgrav exit(3); 251b7579f77SDag-Erling Smørgrav } 252b7579f77SDag-Erling Smørgrav #endif 253b7579f77SDag-Erling Smørgrav exit(1); 254b7579f77SDag-Erling Smørgrav } 255b7579f77SDag-Erling Smørgrav return fd; 256b7579f77SDag-Erling Smørgrav } 257b7579f77SDag-Erling Smørgrav 258b7579f77SDag-Erling Smørgrav /** setup SSL on the connection */ 259b7579f77SDag-Erling Smørgrav static SSL* 26031099b50SDag-Erling Smørgrav setup_ssl(SSL_CTX* ctx, int fd, struct config_file* cfg) 261b7579f77SDag-Erling Smørgrav { 262b7579f77SDag-Erling Smørgrav SSL* ssl; 263b7579f77SDag-Erling Smørgrav X509* x; 264b7579f77SDag-Erling Smørgrav int r; 265b7579f77SDag-Erling Smørgrav 266b7579f77SDag-Erling Smørgrav ssl = SSL_new(ctx); 267b7579f77SDag-Erling Smørgrav if(!ssl) 268b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_new"); 269b7579f77SDag-Erling Smørgrav SSL_set_connect_state(ssl); 270b7579f77SDag-Erling Smørgrav (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); 271b7579f77SDag-Erling Smørgrav if(!SSL_set_fd(ssl, fd)) 272b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_set_fd"); 273b7579f77SDag-Erling Smørgrav while(1) { 274b7579f77SDag-Erling Smørgrav ERR_clear_error(); 275b7579f77SDag-Erling Smørgrav if( (r=SSL_do_handshake(ssl)) == 1) 276b7579f77SDag-Erling Smørgrav break; 277b7579f77SDag-Erling Smørgrav r = SSL_get_error(ssl, r); 278b7579f77SDag-Erling Smørgrav if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) 279b7579f77SDag-Erling Smørgrav ssl_err("SSL handshake failed"); 280b7579f77SDag-Erling Smørgrav /* wants to be called again */ 281b7579f77SDag-Erling Smørgrav } 282b7579f77SDag-Erling Smørgrav 283b7579f77SDag-Erling Smørgrav /* check authenticity of server */ 284b7579f77SDag-Erling Smørgrav if(SSL_get_verify_result(ssl) != X509_V_OK) 285b7579f77SDag-Erling Smørgrav ssl_err("SSL verification failed"); 28631099b50SDag-Erling Smørgrav if(cfg->remote_control_use_cert) { 287b7579f77SDag-Erling Smørgrav x = SSL_get_peer_certificate(ssl); 288b7579f77SDag-Erling Smørgrav if(!x) 289b7579f77SDag-Erling Smørgrav ssl_err("Server presented no peer certificate"); 290b7579f77SDag-Erling Smørgrav X509_free(x); 29131099b50SDag-Erling Smørgrav } 29231099b50SDag-Erling Smørgrav 293b7579f77SDag-Erling Smørgrav return ssl; 294b7579f77SDag-Erling Smørgrav } 295b7579f77SDag-Erling Smørgrav 296b7579f77SDag-Erling Smørgrav /** send stdin to server */ 297b7579f77SDag-Erling Smørgrav static void 298b7579f77SDag-Erling Smørgrav send_file(SSL* ssl, FILE* in, char* buf, size_t sz) 299b7579f77SDag-Erling Smørgrav { 300b7579f77SDag-Erling Smørgrav while(fgets(buf, (int)sz, in)) { 301b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) 302b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write contents"); 303b7579f77SDag-Erling Smørgrav } 304b7579f77SDag-Erling Smørgrav } 305b7579f77SDag-Erling Smørgrav 306*bc892140SDag-Erling Smørgrav /** send end-of-file marker to server */ 307*bc892140SDag-Erling Smørgrav static void 308*bc892140SDag-Erling Smørgrav send_eof(SSL* ssl) 309*bc892140SDag-Erling Smørgrav { 310*bc892140SDag-Erling Smørgrav char e[] = {0x04, 0x0a}; 311*bc892140SDag-Erling Smørgrav if(SSL_write(ssl, e, (int)sizeof(e)) <= 0) 312*bc892140SDag-Erling Smørgrav ssl_err("could not SSL_write end-of-file marker"); 313*bc892140SDag-Erling Smørgrav } 314*bc892140SDag-Erling Smørgrav 315b7579f77SDag-Erling Smørgrav /** send command and display result */ 316b7579f77SDag-Erling Smørgrav static int 3178ed2b524SDag-Erling Smørgrav go_cmd(SSL* ssl, int quiet, int argc, char* argv[]) 318b7579f77SDag-Erling Smørgrav { 319b7579f77SDag-Erling Smørgrav char pre[10]; 320b7579f77SDag-Erling Smørgrav const char* space=" "; 321b7579f77SDag-Erling Smørgrav const char* newline="\n"; 322b7579f77SDag-Erling Smørgrav int was_error = 0, first_line = 1; 323b7579f77SDag-Erling Smørgrav int r, i; 324b7579f77SDag-Erling Smørgrav char buf[1024]; 325b7579f77SDag-Erling Smørgrav snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); 326b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, pre, (int)strlen(pre)) <= 0) 327b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write"); 328b7579f77SDag-Erling Smørgrav for(i=0; i<argc; i++) { 329b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, space, (int)strlen(space)) <= 0) 330b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write"); 331b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, argv[i], (int)strlen(argv[i])) <= 0) 332b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write"); 333b7579f77SDag-Erling Smørgrav } 334b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, newline, (int)strlen(newline)) <= 0) 335b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write"); 336b7579f77SDag-Erling Smørgrav 337b7579f77SDag-Erling Smørgrav if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { 338b7579f77SDag-Erling Smørgrav send_file(ssl, stdin, buf, sizeof(buf)); 339b7579f77SDag-Erling Smørgrav } 340*bc892140SDag-Erling Smørgrav else if(argc == 1 && (strcmp(argv[0], "local_zones") == 0 || 341*bc892140SDag-Erling Smørgrav strcmp(argv[0], "local_zones_remove") == 0 || 342*bc892140SDag-Erling Smørgrav strcmp(argv[0], "local_datas") == 0 || 343*bc892140SDag-Erling Smørgrav strcmp(argv[0], "local_datas_remove") == 0)) { 344*bc892140SDag-Erling Smørgrav send_file(ssl, stdin, buf, sizeof(buf)); 345*bc892140SDag-Erling Smørgrav send_eof(ssl); 346*bc892140SDag-Erling Smørgrav } 347b7579f77SDag-Erling Smørgrav 348b7579f77SDag-Erling Smørgrav while(1) { 349b7579f77SDag-Erling Smørgrav ERR_clear_error(); 350b7579f77SDag-Erling Smørgrav if((r = SSL_read(ssl, buf, (int)sizeof(buf)-1)) <= 0) { 351b7579f77SDag-Erling Smørgrav if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 352b7579f77SDag-Erling Smørgrav /* EOF */ 353b7579f77SDag-Erling Smørgrav break; 354b7579f77SDag-Erling Smørgrav } 355b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_read"); 356b7579f77SDag-Erling Smørgrav } 357b7579f77SDag-Erling Smørgrav buf[r] = 0; 3588ed2b524SDag-Erling Smørgrav if(first_line && strncmp(buf, "error", 5) == 0) { 359b7579f77SDag-Erling Smørgrav printf("%s", buf); 360b7579f77SDag-Erling Smørgrav was_error = 1; 3618ed2b524SDag-Erling Smørgrav } else if (!quiet) 3628ed2b524SDag-Erling Smørgrav printf("%s", buf); 3638ed2b524SDag-Erling Smørgrav 364b7579f77SDag-Erling Smørgrav first_line = 0; 365b7579f77SDag-Erling Smørgrav } 366b7579f77SDag-Erling Smørgrav return was_error; 367b7579f77SDag-Erling Smørgrav } 368b7579f77SDag-Erling Smørgrav 369b7579f77SDag-Erling Smørgrav /** go ahead and read config, contact server and perform command and display */ 370b7579f77SDag-Erling Smørgrav static int 3718ed2b524SDag-Erling Smørgrav go(const char* cfgfile, char* svr, int quiet, int argc, char* argv[]) 372b7579f77SDag-Erling Smørgrav { 373b7579f77SDag-Erling Smørgrav struct config_file* cfg; 374b7579f77SDag-Erling Smørgrav int fd, ret; 375b7579f77SDag-Erling Smørgrav SSL_CTX* ctx; 376b7579f77SDag-Erling Smørgrav SSL* ssl; 377b7579f77SDag-Erling Smørgrav 378b7579f77SDag-Erling Smørgrav /* read config */ 379b7579f77SDag-Erling Smørgrav if(!(cfg = config_create())) 380b7579f77SDag-Erling Smørgrav fatal_exit("out of memory"); 381b7579f77SDag-Erling Smørgrav if(!config_read(cfg, cfgfile, NULL)) 382b7579f77SDag-Erling Smørgrav fatal_exit("could not read config file"); 383b7579f77SDag-Erling Smørgrav if(!cfg->remote_control_enable) 384b7579f77SDag-Erling Smørgrav log_warn("control-enable is 'no' in the config file."); 38505ab2901SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 38605ab2901SDag-Erling Smørgrav w_config_adjust_directory(cfg); 38705ab2901SDag-Erling Smørgrav #endif 388b7579f77SDag-Erling Smørgrav ctx = setup_ctx(cfg); 389b7579f77SDag-Erling Smørgrav 390b7579f77SDag-Erling Smørgrav /* contact server */ 391b7579f77SDag-Erling Smørgrav fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0); 39231099b50SDag-Erling Smørgrav ssl = setup_ssl(ctx, fd, cfg); 393b7579f77SDag-Erling Smørgrav 394b7579f77SDag-Erling Smørgrav /* send command */ 3958ed2b524SDag-Erling Smørgrav ret = go_cmd(ssl, quiet, argc, argv); 396b7579f77SDag-Erling Smørgrav 397b7579f77SDag-Erling Smørgrav SSL_free(ssl); 398b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 399b7579f77SDag-Erling Smørgrav close(fd); 400b7579f77SDag-Erling Smørgrav #else 401b7579f77SDag-Erling Smørgrav closesocket(fd); 402b7579f77SDag-Erling Smørgrav #endif 403b7579f77SDag-Erling Smørgrav SSL_CTX_free(ctx); 404b7579f77SDag-Erling Smørgrav config_delete(cfg); 405b7579f77SDag-Erling Smørgrav return ret; 406b7579f77SDag-Erling Smørgrav } 407b7579f77SDag-Erling Smørgrav 408b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 409b7579f77SDag-Erling Smørgrav extern int optind; 410b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 411b7579f77SDag-Erling Smørgrav extern char* optarg; 412b7579f77SDag-Erling Smørgrav 413b7579f77SDag-Erling Smørgrav /** Main routine for unbound-control */ 414b7579f77SDag-Erling Smørgrav int main(int argc, char* argv[]) 415b7579f77SDag-Erling Smørgrav { 416b7579f77SDag-Erling Smørgrav int c, ret; 4178ed2b524SDag-Erling Smørgrav int quiet = 0; 418b7579f77SDag-Erling Smørgrav const char* cfgfile = CONFIGFILE; 419b7579f77SDag-Erling Smørgrav char* svr = NULL; 420b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 421b7579f77SDag-Erling Smørgrav int r; 422b7579f77SDag-Erling Smørgrav WSADATA wsa_data; 423b7579f77SDag-Erling Smørgrav #endif 424b7579f77SDag-Erling Smørgrav #ifdef USE_THREAD_DEBUG 425b7579f77SDag-Erling Smørgrav /* stop the file output from unbound-control, overwites the servers */ 426b7579f77SDag-Erling Smørgrav extern int check_locking_order; 427b7579f77SDag-Erling Smørgrav check_locking_order = 0; 428b7579f77SDag-Erling Smørgrav #endif /* USE_THREAD_DEBUG */ 429b7579f77SDag-Erling Smørgrav log_ident_set("unbound-control"); 430b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); 431b7579f77SDag-Erling Smørgrav checklock_start(); 432b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 433b7579f77SDag-Erling Smørgrav if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) 434b7579f77SDag-Erling Smørgrav fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); 435b7579f77SDag-Erling Smørgrav /* use registry config file in preference to compiletime location */ 436b7579f77SDag-Erling Smørgrav if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) 437b7579f77SDag-Erling Smørgrav cfgfile = CONFIGFILE; 438b7579f77SDag-Erling Smørgrav #endif 439b7579f77SDag-Erling Smørgrav 440b5663de9SDag-Erling Smørgrav #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS 441b7579f77SDag-Erling Smørgrav ERR_load_crypto_strings(); 442b5663de9SDag-Erling Smørgrav #endif 443b7579f77SDag-Erling Smørgrav ERR_load_SSL_strings(); 444b5663de9SDag-Erling Smørgrav #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) 445b7579f77SDag-Erling Smørgrav OpenSSL_add_all_algorithms(); 446b5663de9SDag-Erling Smørgrav #else 447b5663de9SDag-Erling Smørgrav OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS 448b5663de9SDag-Erling Smørgrav | OPENSSL_INIT_ADD_ALL_DIGESTS 449b5663de9SDag-Erling Smørgrav | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); 450b5663de9SDag-Erling Smørgrav #endif 451b5663de9SDag-Erling Smørgrav #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 452b7579f77SDag-Erling Smørgrav (void)SSL_library_init(); 453b5663de9SDag-Erling Smørgrav #else 454b5663de9SDag-Erling Smørgrav (void)OPENSSL_init_ssl(0, NULL); 455b5663de9SDag-Erling Smørgrav #endif 456b7579f77SDag-Erling Smørgrav 457b7579f77SDag-Erling Smørgrav if(!RAND_status()) { 458b7579f77SDag-Erling Smørgrav /* try to seed it */ 459b7579f77SDag-Erling Smørgrav unsigned char buf[256]; 4608ed2b524SDag-Erling Smørgrav unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid(); 4618ed2b524SDag-Erling Smørgrav unsigned int v = seed; 462b7579f77SDag-Erling Smørgrav size_t i; 463b7579f77SDag-Erling Smørgrav for(i=0; i<256/sizeof(v); i++) { 464b7579f77SDag-Erling Smørgrav memmove(buf+i*sizeof(v), &v, sizeof(v)); 465b7579f77SDag-Erling Smørgrav v = v*seed + (unsigned int)i; 466b7579f77SDag-Erling Smørgrav } 467b7579f77SDag-Erling Smørgrav RAND_seed(buf, 256); 468b7579f77SDag-Erling Smørgrav log_warn("no entropy, seeding openssl PRNG with time\n"); 469b7579f77SDag-Erling Smørgrav } 470b7579f77SDag-Erling Smørgrav 471b7579f77SDag-Erling Smørgrav /* parse the options */ 4728ed2b524SDag-Erling Smørgrav while( (c=getopt(argc, argv, "c:s:qh")) != -1) { 473b7579f77SDag-Erling Smørgrav switch(c) { 474b7579f77SDag-Erling Smørgrav case 'c': 475b7579f77SDag-Erling Smørgrav cfgfile = optarg; 476b7579f77SDag-Erling Smørgrav break; 477b7579f77SDag-Erling Smørgrav case 's': 478b7579f77SDag-Erling Smørgrav svr = optarg; 479b7579f77SDag-Erling Smørgrav break; 4808ed2b524SDag-Erling Smørgrav case 'q': 4818ed2b524SDag-Erling Smørgrav quiet = 1; 4828ed2b524SDag-Erling Smørgrav break; 483b7579f77SDag-Erling Smørgrav case '?': 484b7579f77SDag-Erling Smørgrav case 'h': 485b7579f77SDag-Erling Smørgrav default: 486b7579f77SDag-Erling Smørgrav usage(); 487b7579f77SDag-Erling Smørgrav } 488b7579f77SDag-Erling Smørgrav } 489b7579f77SDag-Erling Smørgrav argc -= optind; 490b7579f77SDag-Erling Smørgrav argv += optind; 491b7579f77SDag-Erling Smørgrav if(argc == 0) 492b7579f77SDag-Erling Smørgrav usage(); 493b7579f77SDag-Erling Smørgrav if(argc >= 1 && strcmp(argv[0], "start")==0) { 494b7579f77SDag-Erling Smørgrav if(execlp("unbound", "unbound", "-c", cfgfile, 495b7579f77SDag-Erling Smørgrav (char*)NULL) < 0) { 496b7579f77SDag-Erling Smørgrav fatal_exit("could not exec unbound: %s", 497b7579f77SDag-Erling Smørgrav strerror(errno)); 498b7579f77SDag-Erling Smørgrav } 499b7579f77SDag-Erling Smørgrav } 500b7579f77SDag-Erling Smørgrav 5018ed2b524SDag-Erling Smørgrav ret = go(cfgfile, svr, quiet, argc, argv); 502b7579f77SDag-Erling Smørgrav 503b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 504b7579f77SDag-Erling Smørgrav WSACleanup(); 505b7579f77SDag-Erling Smørgrav #endif 506b7579f77SDag-Erling Smørgrav checklock_stop(); 507b7579f77SDag-Erling Smørgrav return ret; 508b7579f77SDag-Erling Smørgrav } 509