1*b7579f77SDag-Erling Smørgrav /* 2*b7579f77SDag-Erling Smørgrav * checkconf/unbound-control.c - remote control utility for unbound. 3*b7579f77SDag-Erling Smørgrav * 4*b7579f77SDag-Erling Smørgrav * Copyright (c) 2008, NLnet Labs. All rights reserved. 5*b7579f77SDag-Erling Smørgrav * 6*b7579f77SDag-Erling Smørgrav * This software is open source. 7*b7579f77SDag-Erling Smørgrav * 8*b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9*b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10*b7579f77SDag-Erling Smørgrav * are met: 11*b7579f77SDag-Erling Smørgrav * 12*b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14*b7579f77SDag-Erling Smørgrav * 15*b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17*b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18*b7579f77SDag-Erling Smørgrav * 19*b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20*b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21*b7579f77SDag-Erling Smørgrav * specific prior written permission. 22*b7579f77SDag-Erling Smørgrav * 23*b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24*b7579f77SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25*b7579f77SDag-Erling Smørgrav * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26*b7579f77SDag-Erling Smørgrav * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27*b7579f77SDag-Erling Smørgrav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28*b7579f77SDag-Erling Smørgrav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29*b7579f77SDag-Erling Smørgrav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30*b7579f77SDag-Erling Smørgrav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31*b7579f77SDag-Erling Smørgrav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32*b7579f77SDag-Erling Smørgrav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33*b7579f77SDag-Erling Smørgrav * POSSIBILITY OF SUCH DAMAGE. 34*b7579f77SDag-Erling Smørgrav */ 35*b7579f77SDag-Erling Smørgrav 36*b7579f77SDag-Erling Smørgrav /** 37*b7579f77SDag-Erling Smørgrav * \file 38*b7579f77SDag-Erling Smørgrav * 39*b7579f77SDag-Erling Smørgrav * The remote control utility contacts the unbound server over ssl and 40*b7579f77SDag-Erling Smørgrav * sends the command, receives the answer, and displays the result 41*b7579f77SDag-Erling Smørgrav * from the commandline. 42*b7579f77SDag-Erling Smørgrav */ 43*b7579f77SDag-Erling Smørgrav 44*b7579f77SDag-Erling Smørgrav #include "config.h" 45*b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETOPT_H 46*b7579f77SDag-Erling Smørgrav #include <getopt.h> 47*b7579f77SDag-Erling Smørgrav #endif 48*b7579f77SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_SSL_H 49*b7579f77SDag-Erling Smørgrav #include <openssl/ssl.h> 50*b7579f77SDag-Erling Smørgrav #endif 51*b7579f77SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_ERR_H 52*b7579f77SDag-Erling Smørgrav #include <openssl/err.h> 53*b7579f77SDag-Erling Smørgrav #endif 54*b7579f77SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_RAND_H 55*b7579f77SDag-Erling Smørgrav #include <openssl/rand.h> 56*b7579f77SDag-Erling Smørgrav #endif 57*b7579f77SDag-Erling Smørgrav #include "util/log.h" 58*b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 59*b7579f77SDag-Erling Smørgrav #include "util/locks.h" 60*b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 61*b7579f77SDag-Erling Smørgrav 62*b7579f77SDag-Erling Smørgrav /** Give unbound-control usage, and exit (1). */ 63*b7579f77SDag-Erling Smørgrav static void 64*b7579f77SDag-Erling Smørgrav usage() 65*b7579f77SDag-Erling Smørgrav { 66*b7579f77SDag-Erling Smørgrav printf("Usage: unbound-control [options] command\n"); 67*b7579f77SDag-Erling Smørgrav printf(" Remote control utility for unbound server.\n"); 68*b7579f77SDag-Erling Smørgrav printf("Options:\n"); 69*b7579f77SDag-Erling Smørgrav printf(" -c file config file, default is %s\n", CONFIGFILE); 70*b7579f77SDag-Erling Smørgrav printf(" -s ip[@port] server address, if omitted config is used.\n"); 71*b7579f77SDag-Erling Smørgrav printf(" -h show this usage help.\n"); 72*b7579f77SDag-Erling Smørgrav printf("Commands:\n"); 73*b7579f77SDag-Erling Smørgrav printf(" start start server; runs unbound(8)\n"); 74*b7579f77SDag-Erling Smørgrav printf(" stop stops the server\n"); 75*b7579f77SDag-Erling Smørgrav printf(" reload reloads the server\n"); 76*b7579f77SDag-Erling Smørgrav printf(" (this flushes data, stats, requestlist)\n"); 77*b7579f77SDag-Erling Smørgrav printf(" stats print statistics\n"); 78*b7579f77SDag-Erling Smørgrav printf(" stats_noreset peek at statistics\n"); 79*b7579f77SDag-Erling Smørgrav printf(" status display status of server\n"); 80*b7579f77SDag-Erling Smørgrav printf(" verbosity <number> change logging detail\n"); 81*b7579f77SDag-Erling Smørgrav printf(" log_reopen close and open the logfile\n"); 82*b7579f77SDag-Erling Smørgrav printf(" local_zone <name> <type> add new local zone\n"); 83*b7579f77SDag-Erling Smørgrav printf(" local_zone_remove <name> remove local zone and its contents\n"); 84*b7579f77SDag-Erling Smørgrav printf(" local_data <RR data...> add local data, for example\n"); 85*b7579f77SDag-Erling Smørgrav printf(" local_data www.example.com A 192.0.2.1\n"); 86*b7579f77SDag-Erling Smørgrav printf(" local_data_remove <name> remove local RR data from name\n"); 87*b7579f77SDag-Erling Smørgrav printf(" dump_cache print cache to stdout\n"); 88*b7579f77SDag-Erling Smørgrav printf(" load_cache load cache from stdin\n"); 89*b7579f77SDag-Erling Smørgrav printf(" lookup <name> print nameservers for name\n"); 90*b7579f77SDag-Erling Smørgrav printf(" flush <name> flushes common types for name from cache\n"); 91*b7579f77SDag-Erling Smørgrav printf(" types: A, AAAA, MX, PTR, NS,\n"); 92*b7579f77SDag-Erling Smørgrav printf(" SOA, CNAME, DNAME, SRV, NAPTR\n"); 93*b7579f77SDag-Erling Smørgrav printf(" flush_type <name> <type> flush name, type from cache\n"); 94*b7579f77SDag-Erling Smørgrav printf(" flush_zone <name> flush everything at or under name\n"); 95*b7579f77SDag-Erling Smørgrav printf(" from rr and dnssec caches\n"); 96*b7579f77SDag-Erling Smørgrav printf(" flush_stats flush statistics, make zero\n"); 97*b7579f77SDag-Erling Smørgrav printf(" flush_requestlist drop queries that are worked on\n"); 98*b7579f77SDag-Erling Smørgrav printf(" dump_requestlist show what is worked on\n"); 99*b7579f77SDag-Erling Smørgrav printf(" flush_infra [all | ip] remove ping, edns for one IP or all\n"); 100*b7579f77SDag-Erling Smørgrav printf(" dump_infra show ping and edns entries\n"); 101*b7579f77SDag-Erling Smørgrav printf(" set_option opt: val set option to value, no reload\n"); 102*b7579f77SDag-Erling Smørgrav printf(" get_option opt get option value\n"); 103*b7579f77SDag-Erling Smørgrav printf(" list_stubs list stub-zones and root hints in use\n"); 104*b7579f77SDag-Erling Smørgrav printf(" list_forwards list forward-zones in use\n"); 105*b7579f77SDag-Erling Smørgrav printf(" list_local_zones list local-zones in use\n"); 106*b7579f77SDag-Erling Smørgrav printf(" list_local_data list local-data RRs in use\n"); 107*b7579f77SDag-Erling Smørgrav printf(" forward_add [+i] zone addr.. add forward-zone with servers\n"); 108*b7579f77SDag-Erling Smørgrav printf(" forward_remove [+i] zone remove forward zone\n"); 109*b7579f77SDag-Erling Smørgrav printf(" stub_add [+ip] zone addr.. add stub-zone with servers\n"); 110*b7579f77SDag-Erling Smørgrav printf(" stub_remove [+i] zone remove stub zone\n"); 111*b7579f77SDag-Erling Smørgrav printf(" +i also do dnssec insecure point\n"); 112*b7579f77SDag-Erling Smørgrav printf(" +p set stub to use priming\n"); 113*b7579f77SDag-Erling Smørgrav printf(" forward [off | addr ...] without arg show forward setup\n"); 114*b7579f77SDag-Erling Smørgrav printf(" or off to turn off root forwarding\n"); 115*b7579f77SDag-Erling Smørgrav printf(" or give list of ip addresses\n"); 116*b7579f77SDag-Erling Smørgrav printf("Version %s\n", PACKAGE_VERSION); 117*b7579f77SDag-Erling Smørgrav printf("BSD licensed, see LICENSE in source package for details.\n"); 118*b7579f77SDag-Erling Smørgrav printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 119*b7579f77SDag-Erling Smørgrav exit(1); 120*b7579f77SDag-Erling Smørgrav } 121*b7579f77SDag-Erling Smørgrav 122*b7579f77SDag-Erling Smørgrav /** exit with ssl error */ 123*b7579f77SDag-Erling Smørgrav static void ssl_err(const char* s) 124*b7579f77SDag-Erling Smørgrav { 125*b7579f77SDag-Erling Smørgrav fprintf(stderr, "error: %s\n", s); 126*b7579f77SDag-Erling Smørgrav ERR_print_errors_fp(stderr); 127*b7579f77SDag-Erling Smørgrav exit(1); 128*b7579f77SDag-Erling Smørgrav } 129*b7579f77SDag-Erling Smørgrav 130*b7579f77SDag-Erling Smørgrav /** setup SSL context */ 131*b7579f77SDag-Erling Smørgrav static SSL_CTX* 132*b7579f77SDag-Erling Smørgrav setup_ctx(struct config_file* cfg) 133*b7579f77SDag-Erling Smørgrav { 134*b7579f77SDag-Erling Smørgrav char* s_cert, *c_key, *c_cert; 135*b7579f77SDag-Erling Smørgrav SSL_CTX* ctx; 136*b7579f77SDag-Erling Smørgrav 137*b7579f77SDag-Erling Smørgrav s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); 138*b7579f77SDag-Erling Smørgrav c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); 139*b7579f77SDag-Erling Smørgrav c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); 140*b7579f77SDag-Erling Smørgrav if(!s_cert || !c_key || !c_cert) 141*b7579f77SDag-Erling Smørgrav fatal_exit("out of memory"); 142*b7579f77SDag-Erling Smørgrav ctx = SSL_CTX_new(SSLv23_client_method()); 143*b7579f77SDag-Erling Smørgrav if(!ctx) 144*b7579f77SDag-Erling Smørgrav ssl_err("could not allocate SSL_CTX pointer"); 145*b7579f77SDag-Erling Smørgrav if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)) 146*b7579f77SDag-Erling Smørgrav ssl_err("could not set SSL_OP_NO_SSLv2"); 147*b7579f77SDag-Erling Smørgrav if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) || 148*b7579f77SDag-Erling Smørgrav !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) 149*b7579f77SDag-Erling Smørgrav || !SSL_CTX_check_private_key(ctx)) 150*b7579f77SDag-Erling Smørgrav ssl_err("Error setting up SSL_CTX client key and cert"); 151*b7579f77SDag-Erling Smørgrav if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) 152*b7579f77SDag-Erling Smørgrav ssl_err("Error setting up SSL_CTX verify, server cert"); 153*b7579f77SDag-Erling Smørgrav SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 154*b7579f77SDag-Erling Smørgrav 155*b7579f77SDag-Erling Smørgrav free(s_cert); 156*b7579f77SDag-Erling Smørgrav free(c_key); 157*b7579f77SDag-Erling Smørgrav free(c_cert); 158*b7579f77SDag-Erling Smørgrav return ctx; 159*b7579f77SDag-Erling Smørgrav } 160*b7579f77SDag-Erling Smørgrav 161*b7579f77SDag-Erling Smørgrav /** contact the server with TCP connect */ 162*b7579f77SDag-Erling Smørgrav static int 163*b7579f77SDag-Erling Smørgrav contact_server(const char* svr, struct config_file* cfg, int statuscmd) 164*b7579f77SDag-Erling Smørgrav { 165*b7579f77SDag-Erling Smørgrav struct sockaddr_storage addr; 166*b7579f77SDag-Erling Smørgrav socklen_t addrlen; 167*b7579f77SDag-Erling Smørgrav int fd; 168*b7579f77SDag-Erling Smørgrav /* use svr or the first config entry */ 169*b7579f77SDag-Erling Smørgrav if(!svr) { 170*b7579f77SDag-Erling Smørgrav if(cfg->control_ifs) 171*b7579f77SDag-Erling Smørgrav svr = cfg->control_ifs->str; 172*b7579f77SDag-Erling Smørgrav else svr = "127.0.0.1"; 173*b7579f77SDag-Erling Smørgrav /* config 0 addr (everything), means ask localhost */ 174*b7579f77SDag-Erling Smørgrav if(strcmp(svr, "0.0.0.0") == 0) 175*b7579f77SDag-Erling Smørgrav svr = "127.0.0.1"; 176*b7579f77SDag-Erling Smørgrav else if(strcmp(svr, "::0") == 0 || 177*b7579f77SDag-Erling Smørgrav strcmp(svr, "0::0") == 0 || 178*b7579f77SDag-Erling Smørgrav strcmp(svr, "0::") == 0 || 179*b7579f77SDag-Erling Smørgrav strcmp(svr, "::") == 0) 180*b7579f77SDag-Erling Smørgrav svr = "::1"; 181*b7579f77SDag-Erling Smørgrav } 182*b7579f77SDag-Erling Smørgrav if(strchr(svr, '@')) { 183*b7579f77SDag-Erling Smørgrav if(!extstrtoaddr(svr, &addr, &addrlen)) 184*b7579f77SDag-Erling Smørgrav fatal_exit("could not parse IP@port: %s", svr); 185*b7579f77SDag-Erling Smørgrav } else { 186*b7579f77SDag-Erling Smørgrav if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) 187*b7579f77SDag-Erling Smørgrav fatal_exit("could not parse IP: %s", svr); 188*b7579f77SDag-Erling Smørgrav } 189*b7579f77SDag-Erling Smørgrav fd = socket(addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET, 190*b7579f77SDag-Erling Smørgrav SOCK_STREAM, 0); 191*b7579f77SDag-Erling Smørgrav if(fd == -1) { 192*b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 193*b7579f77SDag-Erling Smørgrav fatal_exit("socket: %s", strerror(errno)); 194*b7579f77SDag-Erling Smørgrav #else 195*b7579f77SDag-Erling Smørgrav fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); 196*b7579f77SDag-Erling Smørgrav #endif 197*b7579f77SDag-Erling Smørgrav } 198*b7579f77SDag-Erling Smørgrav if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { 199*b7579f77SDag-Erling Smørgrav log_addr(0, "address", &addr, addrlen); 200*b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 201*b7579f77SDag-Erling Smørgrav log_err("connect: %s", strerror(errno)); 202*b7579f77SDag-Erling Smørgrav if(errno == ECONNREFUSED && statuscmd) { 203*b7579f77SDag-Erling Smørgrav printf("unbound is stopped\n"); 204*b7579f77SDag-Erling Smørgrav exit(3); 205*b7579f77SDag-Erling Smørgrav } 206*b7579f77SDag-Erling Smørgrav #else 207*b7579f77SDag-Erling Smørgrav log_err("connect: %s", wsa_strerror(WSAGetLastError())); 208*b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) { 209*b7579f77SDag-Erling Smørgrav printf("unbound is stopped\n"); 210*b7579f77SDag-Erling Smørgrav exit(3); 211*b7579f77SDag-Erling Smørgrav } 212*b7579f77SDag-Erling Smørgrav #endif 213*b7579f77SDag-Erling Smørgrav exit(1); 214*b7579f77SDag-Erling Smørgrav } 215*b7579f77SDag-Erling Smørgrav return fd; 216*b7579f77SDag-Erling Smørgrav } 217*b7579f77SDag-Erling Smørgrav 218*b7579f77SDag-Erling Smørgrav /** setup SSL on the connection */ 219*b7579f77SDag-Erling Smørgrav static SSL* 220*b7579f77SDag-Erling Smørgrav setup_ssl(SSL_CTX* ctx, int fd) 221*b7579f77SDag-Erling Smørgrav { 222*b7579f77SDag-Erling Smørgrav SSL* ssl; 223*b7579f77SDag-Erling Smørgrav X509* x; 224*b7579f77SDag-Erling Smørgrav int r; 225*b7579f77SDag-Erling Smørgrav 226*b7579f77SDag-Erling Smørgrav ssl = SSL_new(ctx); 227*b7579f77SDag-Erling Smørgrav if(!ssl) 228*b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_new"); 229*b7579f77SDag-Erling Smørgrav SSL_set_connect_state(ssl); 230*b7579f77SDag-Erling Smørgrav (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); 231*b7579f77SDag-Erling Smørgrav if(!SSL_set_fd(ssl, fd)) 232*b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_set_fd"); 233*b7579f77SDag-Erling Smørgrav while(1) { 234*b7579f77SDag-Erling Smørgrav ERR_clear_error(); 235*b7579f77SDag-Erling Smørgrav if( (r=SSL_do_handshake(ssl)) == 1) 236*b7579f77SDag-Erling Smørgrav break; 237*b7579f77SDag-Erling Smørgrav r = SSL_get_error(ssl, r); 238*b7579f77SDag-Erling Smørgrav if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) 239*b7579f77SDag-Erling Smørgrav ssl_err("SSL handshake failed"); 240*b7579f77SDag-Erling Smørgrav /* wants to be called again */ 241*b7579f77SDag-Erling Smørgrav } 242*b7579f77SDag-Erling Smørgrav 243*b7579f77SDag-Erling Smørgrav /* check authenticity of server */ 244*b7579f77SDag-Erling Smørgrav if(SSL_get_verify_result(ssl) != X509_V_OK) 245*b7579f77SDag-Erling Smørgrav ssl_err("SSL verification failed"); 246*b7579f77SDag-Erling Smørgrav x = SSL_get_peer_certificate(ssl); 247*b7579f77SDag-Erling Smørgrav if(!x) 248*b7579f77SDag-Erling Smørgrav ssl_err("Server presented no peer certificate"); 249*b7579f77SDag-Erling Smørgrav X509_free(x); 250*b7579f77SDag-Erling Smørgrav return ssl; 251*b7579f77SDag-Erling Smørgrav } 252*b7579f77SDag-Erling Smørgrav 253*b7579f77SDag-Erling Smørgrav /** send stdin to server */ 254*b7579f77SDag-Erling Smørgrav static void 255*b7579f77SDag-Erling Smørgrav send_file(SSL* ssl, FILE* in, char* buf, size_t sz) 256*b7579f77SDag-Erling Smørgrav { 257*b7579f77SDag-Erling Smørgrav while(fgets(buf, (int)sz, in)) { 258*b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) 259*b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write contents"); 260*b7579f77SDag-Erling Smørgrav } 261*b7579f77SDag-Erling Smørgrav } 262*b7579f77SDag-Erling Smørgrav 263*b7579f77SDag-Erling Smørgrav /** send command and display result */ 264*b7579f77SDag-Erling Smørgrav static int 265*b7579f77SDag-Erling Smørgrav go_cmd(SSL* ssl, int argc, char* argv[]) 266*b7579f77SDag-Erling Smørgrav { 267*b7579f77SDag-Erling Smørgrav char pre[10]; 268*b7579f77SDag-Erling Smørgrav const char* space=" "; 269*b7579f77SDag-Erling Smørgrav const char* newline="\n"; 270*b7579f77SDag-Erling Smørgrav int was_error = 0, first_line = 1; 271*b7579f77SDag-Erling Smørgrav int r, i; 272*b7579f77SDag-Erling Smørgrav char buf[1024]; 273*b7579f77SDag-Erling Smørgrav snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); 274*b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, pre, (int)strlen(pre)) <= 0) 275*b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write"); 276*b7579f77SDag-Erling Smørgrav for(i=0; i<argc; i++) { 277*b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, space, (int)strlen(space)) <= 0) 278*b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write"); 279*b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, argv[i], (int)strlen(argv[i])) <= 0) 280*b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write"); 281*b7579f77SDag-Erling Smørgrav } 282*b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, newline, (int)strlen(newline)) <= 0) 283*b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_write"); 284*b7579f77SDag-Erling Smørgrav 285*b7579f77SDag-Erling Smørgrav if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { 286*b7579f77SDag-Erling Smørgrav send_file(ssl, stdin, buf, sizeof(buf)); 287*b7579f77SDag-Erling Smørgrav } 288*b7579f77SDag-Erling Smørgrav 289*b7579f77SDag-Erling Smørgrav while(1) { 290*b7579f77SDag-Erling Smørgrav ERR_clear_error(); 291*b7579f77SDag-Erling Smørgrav if((r = SSL_read(ssl, buf, (int)sizeof(buf)-1)) <= 0) { 292*b7579f77SDag-Erling Smørgrav if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 293*b7579f77SDag-Erling Smørgrav /* EOF */ 294*b7579f77SDag-Erling Smørgrav break; 295*b7579f77SDag-Erling Smørgrav } 296*b7579f77SDag-Erling Smørgrav ssl_err("could not SSL_read"); 297*b7579f77SDag-Erling Smørgrav } 298*b7579f77SDag-Erling Smørgrav buf[r] = 0; 299*b7579f77SDag-Erling Smørgrav printf("%s", buf); 300*b7579f77SDag-Erling Smørgrav if(first_line && strncmp(buf, "error", 5) == 0) 301*b7579f77SDag-Erling Smørgrav was_error = 1; 302*b7579f77SDag-Erling Smørgrav first_line = 0; 303*b7579f77SDag-Erling Smørgrav } 304*b7579f77SDag-Erling Smørgrav return was_error; 305*b7579f77SDag-Erling Smørgrav } 306*b7579f77SDag-Erling Smørgrav 307*b7579f77SDag-Erling Smørgrav /** go ahead and read config, contact server and perform command and display */ 308*b7579f77SDag-Erling Smørgrav static int 309*b7579f77SDag-Erling Smørgrav go(const char* cfgfile, char* svr, int argc, char* argv[]) 310*b7579f77SDag-Erling Smørgrav { 311*b7579f77SDag-Erling Smørgrav struct config_file* cfg; 312*b7579f77SDag-Erling Smørgrav int fd, ret; 313*b7579f77SDag-Erling Smørgrav SSL_CTX* ctx; 314*b7579f77SDag-Erling Smørgrav SSL* ssl; 315*b7579f77SDag-Erling Smørgrav 316*b7579f77SDag-Erling Smørgrav /* read config */ 317*b7579f77SDag-Erling Smørgrav if(!(cfg = config_create())) 318*b7579f77SDag-Erling Smørgrav fatal_exit("out of memory"); 319*b7579f77SDag-Erling Smørgrav if(!config_read(cfg, cfgfile, NULL)) 320*b7579f77SDag-Erling Smørgrav fatal_exit("could not read config file"); 321*b7579f77SDag-Erling Smørgrav if(!cfg->remote_control_enable) 322*b7579f77SDag-Erling Smørgrav log_warn("control-enable is 'no' in the config file."); 323*b7579f77SDag-Erling Smørgrav ctx = setup_ctx(cfg); 324*b7579f77SDag-Erling Smørgrav 325*b7579f77SDag-Erling Smørgrav /* contact server */ 326*b7579f77SDag-Erling Smørgrav fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0); 327*b7579f77SDag-Erling Smørgrav ssl = setup_ssl(ctx, fd); 328*b7579f77SDag-Erling Smørgrav 329*b7579f77SDag-Erling Smørgrav /* send command */ 330*b7579f77SDag-Erling Smørgrav ret = go_cmd(ssl, argc, argv); 331*b7579f77SDag-Erling Smørgrav 332*b7579f77SDag-Erling Smørgrav SSL_free(ssl); 333*b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 334*b7579f77SDag-Erling Smørgrav close(fd); 335*b7579f77SDag-Erling Smørgrav #else 336*b7579f77SDag-Erling Smørgrav closesocket(fd); 337*b7579f77SDag-Erling Smørgrav #endif 338*b7579f77SDag-Erling Smørgrav SSL_CTX_free(ctx); 339*b7579f77SDag-Erling Smørgrav config_delete(cfg); 340*b7579f77SDag-Erling Smørgrav return ret; 341*b7579f77SDag-Erling Smørgrav } 342*b7579f77SDag-Erling Smørgrav 343*b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 344*b7579f77SDag-Erling Smørgrav extern int optind; 345*b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 346*b7579f77SDag-Erling Smørgrav extern char* optarg; 347*b7579f77SDag-Erling Smørgrav 348*b7579f77SDag-Erling Smørgrav /** Main routine for unbound-control */ 349*b7579f77SDag-Erling Smørgrav int main(int argc, char* argv[]) 350*b7579f77SDag-Erling Smørgrav { 351*b7579f77SDag-Erling Smørgrav int c, ret; 352*b7579f77SDag-Erling Smørgrav const char* cfgfile = CONFIGFILE; 353*b7579f77SDag-Erling Smørgrav char* svr = NULL; 354*b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 355*b7579f77SDag-Erling Smørgrav int r; 356*b7579f77SDag-Erling Smørgrav WSADATA wsa_data; 357*b7579f77SDag-Erling Smørgrav #endif 358*b7579f77SDag-Erling Smørgrav #ifdef USE_THREAD_DEBUG 359*b7579f77SDag-Erling Smørgrav /* stop the file output from unbound-control, overwites the servers */ 360*b7579f77SDag-Erling Smørgrav extern int check_locking_order; 361*b7579f77SDag-Erling Smørgrav check_locking_order = 0; 362*b7579f77SDag-Erling Smørgrav #endif /* USE_THREAD_DEBUG */ 363*b7579f77SDag-Erling Smørgrav log_ident_set("unbound-control"); 364*b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); 365*b7579f77SDag-Erling Smørgrav checklock_start(); 366*b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 367*b7579f77SDag-Erling Smørgrav if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) 368*b7579f77SDag-Erling Smørgrav fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); 369*b7579f77SDag-Erling Smørgrav /* use registry config file in preference to compiletime location */ 370*b7579f77SDag-Erling Smørgrav if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) 371*b7579f77SDag-Erling Smørgrav cfgfile = CONFIGFILE; 372*b7579f77SDag-Erling Smørgrav #endif 373*b7579f77SDag-Erling Smørgrav 374*b7579f77SDag-Erling Smørgrav ERR_load_crypto_strings(); 375*b7579f77SDag-Erling Smørgrav ERR_load_SSL_strings(); 376*b7579f77SDag-Erling Smørgrav OpenSSL_add_all_algorithms(); 377*b7579f77SDag-Erling Smørgrav (void)SSL_library_init(); 378*b7579f77SDag-Erling Smørgrav 379*b7579f77SDag-Erling Smørgrav if(!RAND_status()) { 380*b7579f77SDag-Erling Smørgrav /* try to seed it */ 381*b7579f77SDag-Erling Smørgrav unsigned char buf[256]; 382*b7579f77SDag-Erling Smørgrav unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid(); 383*b7579f77SDag-Erling Smørgrav size_t i; 384*b7579f77SDag-Erling Smørgrav for(i=0; i<256/sizeof(v); i++) { 385*b7579f77SDag-Erling Smørgrav memmove(buf+i*sizeof(v), &v, sizeof(v)); 386*b7579f77SDag-Erling Smørgrav v = v*seed + (unsigned int)i; 387*b7579f77SDag-Erling Smørgrav } 388*b7579f77SDag-Erling Smørgrav RAND_seed(buf, 256); 389*b7579f77SDag-Erling Smørgrav log_warn("no entropy, seeding openssl PRNG with time\n"); 390*b7579f77SDag-Erling Smørgrav } 391*b7579f77SDag-Erling Smørgrav 392*b7579f77SDag-Erling Smørgrav /* parse the options */ 393*b7579f77SDag-Erling Smørgrav while( (c=getopt(argc, argv, "c:s:h")) != -1) { 394*b7579f77SDag-Erling Smørgrav switch(c) { 395*b7579f77SDag-Erling Smørgrav case 'c': 396*b7579f77SDag-Erling Smørgrav cfgfile = optarg; 397*b7579f77SDag-Erling Smørgrav break; 398*b7579f77SDag-Erling Smørgrav case 's': 399*b7579f77SDag-Erling Smørgrav svr = optarg; 400*b7579f77SDag-Erling Smørgrav break; 401*b7579f77SDag-Erling Smørgrav case '?': 402*b7579f77SDag-Erling Smørgrav case 'h': 403*b7579f77SDag-Erling Smørgrav default: 404*b7579f77SDag-Erling Smørgrav usage(); 405*b7579f77SDag-Erling Smørgrav } 406*b7579f77SDag-Erling Smørgrav } 407*b7579f77SDag-Erling Smørgrav argc -= optind; 408*b7579f77SDag-Erling Smørgrav argv += optind; 409*b7579f77SDag-Erling Smørgrav if(argc == 0) 410*b7579f77SDag-Erling Smørgrav usage(); 411*b7579f77SDag-Erling Smørgrav if(argc >= 1 && strcmp(argv[0], "start")==0) { 412*b7579f77SDag-Erling Smørgrav if(execlp("unbound", "unbound", "-c", cfgfile, 413*b7579f77SDag-Erling Smørgrav (char*)NULL) < 0) { 414*b7579f77SDag-Erling Smørgrav fatal_exit("could not exec unbound: %s", 415*b7579f77SDag-Erling Smørgrav strerror(errno)); 416*b7579f77SDag-Erling Smørgrav } 417*b7579f77SDag-Erling Smørgrav } 418*b7579f77SDag-Erling Smørgrav 419*b7579f77SDag-Erling Smørgrav ret = go(cfgfile, svr, argc, argv); 420*b7579f77SDag-Erling Smørgrav 421*b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 422*b7579f77SDag-Erling Smørgrav WSACleanup(); 423*b7579f77SDag-Erling Smørgrav #endif 424*b7579f77SDag-Erling Smørgrav checklock_stop(); 425*b7579f77SDag-Erling Smørgrav return ret; 426*b7579f77SDag-Erling Smørgrav } 427