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 24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33266114Sdes * 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" 61356345Scy#include "util/shm_side/shm_main.h" 62356345Scy#include "daemon/stats.h" 63356345Scy#include "sldns/wire2str.h" 64356345Scy#include "sldns/pkthdr.h" 65361435Scy#include "services/rpz.h" 66238106Sdes 67356345Scy#ifdef HAVE_SYS_IPC_H 68356345Scy#include "sys/ipc.h" 69356345Scy#endif 70356345Scy#ifdef HAVE_SYS_SHM_H 71356345Scy#include "sys/shm.h" 72356345Scy#endif 73276699Sdes#ifdef HAVE_SYS_UN_H 74276699Sdes#include <sys/un.h> 75276699Sdes#endif 76276699Sdes 77366095Scy#ifdef HAVE_TARGETCONDITIONALS_H 78366095Scy#include <TargetConditionals.h> 79366095Scy#endif 80366095Scy 81356345Scystatic void usage(void) ATTR_NORETURN; 82356345Scystatic void ssl_err(const char* s) ATTR_NORETURN; 83356345Scystatic void ssl_path_err(const char* s, const char *path) ATTR_NORETURN; 84356345Scy 85369939Sgit2svn/** timeout to wait for connection over stream, in msec */ 86369939Sgit2svn#define UNBOUND_CONTROL_CONNECT_TIMEOUT 5000 87369939Sgit2svn 88238106Sdes/** Give unbound-control usage, and exit (1). */ 89238106Sdesstatic void 90307729Sdesusage(void) 91238106Sdes{ 92356345Scy printf("Usage: local-unbound-control [options] command\n"); 93238106Sdes printf(" Remote control utility for unbound server.\n"); 94238106Sdes printf("Options:\n"); 95238106Sdes printf(" -c file config file, default is %s\n", CONFIGFILE); 96238106Sdes printf(" -s ip[@port] server address, if omitted config is used.\n"); 97249141Sdes printf(" -q quiet (don't print anything if it works ok).\n"); 98238106Sdes printf(" -h show this usage help.\n"); 99238106Sdes printf("Commands:\n"); 100238106Sdes printf(" start start server; runs unbound(8)\n"); 101238106Sdes printf(" stop stops the server\n"); 102238106Sdes printf(" reload reloads the server\n"); 103238106Sdes printf(" (this flushes data, stats, requestlist)\n"); 104238106Sdes printf(" stats print statistics\n"); 105238106Sdes printf(" stats_noreset peek at statistics\n"); 106356345Scy#ifdef HAVE_SHMGET 107356345Scy printf(" stats_shm print statistics using shm\n"); 108356345Scy#endif 109238106Sdes printf(" status display status of server\n"); 110238106Sdes printf(" verbosity <number> change logging detail\n"); 111238106Sdes printf(" log_reopen close and open the logfile\n"); 112238106Sdes printf(" local_zone <name> <type> add new local zone\n"); 113238106Sdes printf(" local_zone_remove <name> remove local zone and its contents\n"); 114238106Sdes printf(" local_data <RR data...> add local data, for example\n"); 115238106Sdes printf(" local_data www.example.com A 192.0.2.1\n"); 116238106Sdes printf(" local_data_remove <name> remove local RR data from name\n"); 117356345Scy printf(" local_zones, local_zones_remove, local_datas, local_datas_remove\n"); 118356345Scy printf(" same, but read list from stdin\n"); 119356345Scy printf(" (one entry per line).\n"); 120238106Sdes printf(" dump_cache print cache to stdout\n"); 121238106Sdes printf(" load_cache load cache from stdin\n"); 122238106Sdes printf(" lookup <name> print nameservers for name\n"); 123238106Sdes printf(" flush <name> flushes common types for name from cache\n"); 124238106Sdes printf(" types: A, AAAA, MX, PTR, NS,\n"); 125238106Sdes printf(" SOA, CNAME, DNAME, SRV, NAPTR\n"); 126238106Sdes printf(" flush_type <name> <type> flush name, type from cache\n"); 127238106Sdes printf(" flush_zone <name> flush everything at or under name\n"); 128238106Sdes printf(" from rr and dnssec caches\n"); 129249141Sdes printf(" flush_bogus flush all bogus data\n"); 130276605Sdes printf(" flush_negative flush all negative data\n"); 131238106Sdes printf(" flush_stats flush statistics, make zero\n"); 132238106Sdes printf(" flush_requestlist drop queries that are worked on\n"); 133307729Sdes printf(" dump_requestlist show what is worked on by first thread\n"); 134238106Sdes printf(" flush_infra [all | ip] remove ping, edns for one IP or all\n"); 135238106Sdes printf(" dump_infra show ping and edns entries\n"); 136238106Sdes printf(" set_option opt: val set option to value, no reload\n"); 137238106Sdes printf(" get_option opt get option value\n"); 138238106Sdes printf(" list_stubs list stub-zones and root hints in use\n"); 139238106Sdes printf(" list_forwards list forward-zones in use\n"); 140287917Sdes printf(" list_insecure list domain-insecure zones\n"); 141238106Sdes printf(" list_local_zones list local-zones in use\n"); 142238106Sdes printf(" list_local_data list local-data RRs in use\n"); 143266114Sdes printf(" insecure_add zone add domain-insecure zone\n"); 144266114Sdes printf(" insecure_remove zone remove domain-insecure zone\n"); 145238106Sdes printf(" forward_add [+i] zone addr.. add forward-zone with servers\n"); 146238106Sdes printf(" forward_remove [+i] zone remove forward zone\n"); 147238106Sdes printf(" stub_add [+ip] zone addr.. add stub-zone with servers\n"); 148238106Sdes printf(" stub_remove [+i] zone remove stub zone\n"); 149238106Sdes printf(" +i also do dnssec insecure point\n"); 150238106Sdes printf(" +p set stub to use priming\n"); 151238106Sdes printf(" forward [off | addr ...] without arg show forward setup\n"); 152238106Sdes printf(" or off to turn off root forwarding\n"); 153238106Sdes printf(" or give list of ip addresses\n"); 154287917Sdes printf(" ratelimit_list [+a] list ratelimited domains\n"); 155356345Scy printf(" ip_ratelimit_list [+a] list ratelimited ip addresses\n"); 156287917Sdes printf(" +a list all, also not ratelimited\n"); 157356345Scy printf(" list_auth_zones list auth zones\n"); 158356345Scy printf(" auth_zone_reload zone reload auth zone from zonefile\n"); 159356345Scy printf(" auth_zone_transfer zone transfer auth zone from master\n"); 160356345Scy printf(" view_list_local_zones view list local-zones in view\n"); 161356345Scy printf(" view_list_local_data view list local-data RRs in view\n"); 162356345Scy printf(" view_local_zone view name type add local-zone in view\n"); 163356345Scy printf(" view_local_zone_remove view name remove local-zone in view\n"); 164356345Scy printf(" view_local_data view RR... add local-data in view\n"); 165356345Scy printf(" view_local_datas view add list of local-data to view\n"); 166356345Scy printf(" one entry per line read from stdin\n"); 167356345Scy printf(" view_local_data_remove view name remove local-data in view\n"); 168361435Scy printf(" view_local_datas_remove view remove list of local-data from view\n"); 169361435Scy printf(" one entry per line read from stdin\n"); 170369939Sgit2svn printf(" rpz_enable zone Enable the RPZ zone if it had previously\n"); 171369939Sgit2svn printf(" been disabled\n"); 172369939Sgit2svn printf(" rpz_disable zone Disable the RPZ zone\n"); 173238106Sdes printf("Version %s\n", PACKAGE_VERSION); 174238106Sdes printf("BSD licensed, see LICENSE in source package for details.\n"); 175238106Sdes printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 176238106Sdes exit(1); 177238106Sdes} 178238106Sdes 179356345Scy#ifdef HAVE_SHMGET 180356345Scy/** what to put on statistics lines between var and value, ": " or "=" */ 181356345Scy#define SQ "=" 182356345Scy/** if true, inhibits a lot of =0 lines from the stats output */ 183356345Scystatic const int inhibit_zero = 1; 184356345Scy/** divide sum of timers to get average */ 185356345Scystatic void 186356345Scytimeval_divide(struct timeval* avg, const struct timeval* sum, long long d) 187356345Scy{ 188356345Scy#ifndef S_SPLINT_S 189356345Scy size_t leftover; 190356345Scy if(d == 0) { 191356345Scy avg->tv_sec = 0; 192356345Scy avg->tv_usec = 0; 193356345Scy return; 194356345Scy } 195356345Scy avg->tv_sec = sum->tv_sec / d; 196356345Scy avg->tv_usec = sum->tv_usec / d; 197356345Scy /* handle fraction from seconds divide */ 198356345Scy leftover = sum->tv_sec - avg->tv_sec*d; 199356345Scy avg->tv_usec += (leftover*1000000)/d; 200356345Scy#endif 201356345Scy} 202356345Scy 203356345Scy/** print unsigned long stats value */ 204356345Scy#define PR_UL_NM(str, var) printf("%s."str SQ"%lu\n", nm, (unsigned long)(var)); 205356345Scy#define PR_UL(str, var) printf(str SQ"%lu\n", (unsigned long)(var)); 206356345Scy#define PR_UL_SUB(str, nm, var) printf(str".%s"SQ"%lu\n", nm, (unsigned long)(var)); 207356345Scy#define PR_TIMEVAL(str, var) printf(str SQ ARG_LL "d.%6.6d\n", \ 208356345Scy (long long)var.tv_sec, (int)var.tv_usec); 209356345Scy#define PR_STATSTIME(str, var) printf(str SQ ARG_LL "d.%6.6d\n", \ 210356345Scy (long long)var ## _sec, (int)var ## _usec); 211356345Scy#define PR_LL(str, var) printf(str SQ ARG_LL"d\n", (long long)(var)); 212356345Scy 213356345Scy/** print stat block */ 214356345Scystatic void pr_stats(const char* nm, struct ub_stats_info* s) 215356345Scy{ 216356345Scy struct timeval sumwait, avg; 217356345Scy PR_UL_NM("num.queries", s->svr.num_queries); 218356345Scy PR_UL_NM("num.queries_ip_ratelimited", 219356345Scy s->svr.num_queries_ip_ratelimited); 220356345Scy PR_UL_NM("num.cachehits", 221356345Scy s->svr.num_queries - s->svr.num_queries_missed_cache); 222356345Scy PR_UL_NM("num.cachemiss", s->svr.num_queries_missed_cache); 223356345Scy PR_UL_NM("num.prefetch", s->svr.num_queries_prefetch); 224361435Scy PR_UL_NM("num.expired", s->svr.ans_expired); 225356345Scy PR_UL_NM("num.recursivereplies", s->mesh_replies_sent); 226356345Scy#ifdef USE_DNSCRYPT 227356345Scy PR_UL_NM("num.dnscrypt.crypted", s->svr.num_query_dnscrypt_crypted); 228356345Scy PR_UL_NM("num.dnscrypt.cert", s->svr.num_query_dnscrypt_cert); 229356345Scy PR_UL_NM("num.dnscrypt.cleartext", s->svr.num_query_dnscrypt_cleartext); 230356345Scy PR_UL_NM("num.dnscrypt.malformed", 231356345Scy s->svr.num_query_dnscrypt_crypted_malformed); 232356345Scy#endif /* USE_DNSCRYPT */ 233356345Scy printf("%s.requestlist.avg"SQ"%g\n", nm, 234356345Scy (s->svr.num_queries_missed_cache+s->svr.num_queries_prefetch)? 235356345Scy (double)s->svr.sum_query_list_size/ 236356345Scy (double)(s->svr.num_queries_missed_cache+ 237356345Scy s->svr.num_queries_prefetch) : 0.0); 238356345Scy PR_UL_NM("requestlist.max", s->svr.max_query_list_size); 239356345Scy PR_UL_NM("requestlist.overwritten", s->mesh_jostled); 240356345Scy PR_UL_NM("requestlist.exceeded", s->mesh_dropped); 241356345Scy PR_UL_NM("requestlist.current.all", s->mesh_num_states); 242356345Scy PR_UL_NM("requestlist.current.user", s->mesh_num_reply_states); 243356345Scy#ifndef S_SPLINT_S 244356345Scy sumwait.tv_sec = s->mesh_replies_sum_wait_sec; 245356345Scy sumwait.tv_usec = s->mesh_replies_sum_wait_usec; 246356345Scy#endif 247356345Scy timeval_divide(&avg, &sumwait, s->mesh_replies_sent); 248356345Scy printf("%s.", nm); 249356345Scy PR_TIMEVAL("recursion.time.avg", avg); 250356345Scy printf("%s.recursion.time.median"SQ"%g\n", nm, s->mesh_time_median); 251356345Scy PR_UL_NM("tcpusage", s->svr.tcp_accept_usage); 252356345Scy} 253356345Scy 254356345Scy/** print uptime */ 255356345Scystatic void print_uptime(struct ub_shm_stat_info* shm_stat) 256356345Scy{ 257356345Scy PR_STATSTIME("time.now", shm_stat->time.now); 258356345Scy PR_STATSTIME("time.up", shm_stat->time.up); 259356345Scy PR_STATSTIME("time.elapsed", shm_stat->time.elapsed); 260356345Scy} 261356345Scy 262356345Scy/** print memory usage */ 263356345Scystatic void print_mem(struct ub_shm_stat_info* shm_stat, 264356345Scy struct ub_stats_info* s) 265356345Scy{ 266356345Scy PR_LL("mem.cache.rrset", shm_stat->mem.rrset); 267356345Scy PR_LL("mem.cache.message", shm_stat->mem.msg); 268356345Scy PR_LL("mem.mod.iterator", shm_stat->mem.iter); 269356345Scy PR_LL("mem.mod.validator", shm_stat->mem.val); 270356345Scy PR_LL("mem.mod.respip", shm_stat->mem.respip); 271356345Scy#ifdef CLIENT_SUBNET 272356345Scy PR_LL("mem.mod.subnet", shm_stat->mem.subnet); 273356345Scy#endif 274356345Scy#ifdef USE_IPSECMOD 275356345Scy PR_LL("mem.mod.ipsecmod", shm_stat->mem.ipsecmod); 276356345Scy#endif 277366095Scy#ifdef WITH_DYNLIBMODULE 278366095Scy PR_LL("mem.mod.dynlib", shm_stat->mem.dynlib); 279366095Scy#endif 280356345Scy#ifdef USE_DNSCRYPT 281356345Scy PR_LL("mem.cache.dnscrypt_shared_secret", 282356345Scy shm_stat->mem.dnscrypt_shared_secret); 283356345Scy PR_LL("mem.cache.dnscrypt_nonce", 284356345Scy shm_stat->mem.dnscrypt_nonce); 285356345Scy#endif 286356345Scy PR_LL("mem.streamwait", s->svr.mem_stream_wait); 287368129Scy PR_LL("mem.http.query_buffer", s->svr.mem_http2_query_buffer); 288368129Scy PR_LL("mem.http.response_buffer", s->svr.mem_http2_response_buffer); 289356345Scy} 290356345Scy 291356345Scy/** print histogram */ 292356345Scystatic void print_hist(struct ub_stats_info* s) 293356345Scy{ 294356345Scy struct timehist* hist; 295356345Scy size_t i; 296356345Scy hist = timehist_setup(); 297356345Scy if(!hist) 298356345Scy fatal_exit("out of memory"); 299356345Scy timehist_import(hist, s->svr.hist, NUM_BUCKETS_HIST); 300356345Scy for(i=0; i<hist->num; i++) { 301356345Scy printf("histogram.%6.6d.%6.6d.to.%6.6d.%6.6d=%lu\n", 302356345Scy (int)hist->buckets[i].lower.tv_sec, 303356345Scy (int)hist->buckets[i].lower.tv_usec, 304356345Scy (int)hist->buckets[i].upper.tv_sec, 305356345Scy (int)hist->buckets[i].upper.tv_usec, 306356345Scy (unsigned long)hist->buckets[i].count); 307356345Scy } 308356345Scy timehist_delete(hist); 309356345Scy} 310356345Scy 311356345Scy/** print extended */ 312356345Scystatic void print_extended(struct ub_stats_info* s) 313356345Scy{ 314356345Scy int i; 315356345Scy char nm[16]; 316356345Scy 317356345Scy /* TYPE */ 318356345Scy for(i=0; i<UB_STATS_QTYPE_NUM; i++) { 319356345Scy if(inhibit_zero && s->svr.qtype[i] == 0) 320356345Scy continue; 321356345Scy sldns_wire2str_type_buf((uint16_t)i, nm, sizeof(nm)); 322356345Scy PR_UL_SUB("num.query.type", nm, s->svr.qtype[i]); 323356345Scy } 324356345Scy if(!inhibit_zero || s->svr.qtype_big) { 325356345Scy PR_UL("num.query.type.other", s->svr.qtype_big); 326356345Scy } 327356345Scy 328356345Scy /* CLASS */ 329356345Scy for(i=0; i<UB_STATS_QCLASS_NUM; i++) { 330356345Scy if(inhibit_zero && s->svr.qclass[i] == 0) 331356345Scy continue; 332356345Scy sldns_wire2str_class_buf((uint16_t)i, nm, sizeof(nm)); 333356345Scy PR_UL_SUB("num.query.class", nm, s->svr.qclass[i]); 334356345Scy } 335356345Scy if(!inhibit_zero || s->svr.qclass_big) { 336356345Scy PR_UL("num.query.class.other", s->svr.qclass_big); 337356345Scy } 338356345Scy 339356345Scy /* OPCODE */ 340356345Scy for(i=0; i<UB_STATS_OPCODE_NUM; i++) { 341356345Scy if(inhibit_zero && s->svr.qopcode[i] == 0) 342356345Scy continue; 343356345Scy sldns_wire2str_opcode_buf(i, nm, sizeof(nm)); 344356345Scy PR_UL_SUB("num.query.opcode", nm, s->svr.qopcode[i]); 345356345Scy } 346356345Scy 347356345Scy /* transport */ 348356345Scy PR_UL("num.query.tcp", s->svr.qtcp); 349356345Scy PR_UL("num.query.tcpout", s->svr.qtcp_outgoing); 350356345Scy PR_UL("num.query.tls", s->svr.qtls); 351356345Scy PR_UL("num.query.tls_resume", s->svr.qtls_resume); 352356345Scy PR_UL("num.query.ipv6", s->svr.qipv6); 353368129Scy PR_UL("num.query.https", s->svr.qhttps); 354356345Scy 355356345Scy /* flags */ 356356345Scy PR_UL("num.query.flags.QR", s->svr.qbit_QR); 357356345Scy PR_UL("num.query.flags.AA", s->svr.qbit_AA); 358356345Scy PR_UL("num.query.flags.TC", s->svr.qbit_TC); 359356345Scy PR_UL("num.query.flags.RD", s->svr.qbit_RD); 360356345Scy PR_UL("num.query.flags.RA", s->svr.qbit_RA); 361356345Scy PR_UL("num.query.flags.Z", s->svr.qbit_Z); 362356345Scy PR_UL("num.query.flags.AD", s->svr.qbit_AD); 363356345Scy PR_UL("num.query.flags.CD", s->svr.qbit_CD); 364356345Scy PR_UL("num.query.edns.present", s->svr.qEDNS); 365356345Scy PR_UL("num.query.edns.DO", s->svr.qEDNS_DO); 366356345Scy 367356345Scy /* RCODE */ 368356345Scy for(i=0; i<UB_STATS_RCODE_NUM; i++) { 369356345Scy /* Always include RCODEs 0-5 */ 370356345Scy if(inhibit_zero && i > LDNS_RCODE_REFUSED && s->svr.ans_rcode[i] == 0) 371356345Scy continue; 372356345Scy sldns_wire2str_rcode_buf(i, nm, sizeof(nm)); 373356345Scy PR_UL_SUB("num.answer.rcode", nm, s->svr.ans_rcode[i]); 374356345Scy } 375356345Scy if(!inhibit_zero || s->svr.ans_rcode_nodata) { 376356345Scy PR_UL("num.answer.rcode.nodata", s->svr.ans_rcode_nodata); 377356345Scy } 378356345Scy /* iteration */ 379356345Scy PR_UL("num.query.ratelimited", s->svr.queries_ratelimited); 380356345Scy /* validation */ 381356345Scy PR_UL("num.answer.secure", s->svr.ans_secure); 382356345Scy PR_UL("num.answer.bogus", s->svr.ans_bogus); 383356345Scy PR_UL("num.rrset.bogus", s->svr.rrset_bogus); 384356345Scy PR_UL("num.query.aggressive.NOERROR", s->svr.num_neg_cache_noerror); 385356345Scy PR_UL("num.query.aggressive.NXDOMAIN", s->svr.num_neg_cache_nxdomain); 386356345Scy /* threat detection */ 387356345Scy PR_UL("unwanted.queries", s->svr.unwanted_queries); 388356345Scy PR_UL("unwanted.replies", s->svr.unwanted_replies); 389356345Scy /* cache counts */ 390356345Scy PR_UL("msg.cache.count", s->svr.msg_cache_count); 391356345Scy PR_UL("rrset.cache.count", s->svr.rrset_cache_count); 392356345Scy PR_UL("infra.cache.count", s->svr.infra_cache_count); 393356345Scy PR_UL("key.cache.count", s->svr.key_cache_count); 394361435Scy /* applied RPZ actions */ 395361435Scy for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++) { 396361435Scy if(i == RPZ_NO_OVERRIDE_ACTION) 397361435Scy continue; 398361435Scy if(inhibit_zero && s->svr.rpz_action[i] == 0) 399361435Scy continue; 400361435Scy PR_UL_SUB("num.rpz.action", rpz_action_to_string(i), s->svr.rpz_action[i]); 401361435Scy } 402356345Scy#ifdef USE_DNSCRYPT 403356345Scy PR_UL("dnscrypt_shared_secret.cache.count", 404356345Scy s->svr.shared_secret_cache_count); 405356345Scy PR_UL("num.query.dnscrypt.shared_secret.cachemiss", 406356345Scy s->svr.num_query_dnscrypt_secret_missed_cache); 407356345Scy PR_UL("dnscrypt_nonce.cache.count", s->svr.nonce_cache_count); 408356345Scy PR_UL("num.query.dnscrypt.replay", 409356345Scy s->svr.num_query_dnscrypt_replay); 410356345Scy#endif /* USE_DNSCRYPT */ 411356345Scy PR_UL("num.query.authzone.up", s->svr.num_query_authzone_up); 412356345Scy PR_UL("num.query.authzone.down", s->svr.num_query_authzone_down); 413356345Scy#ifdef CLIENT_SUBNET 414356345Scy PR_UL("num.query.subnet", s->svr.num_query_subnet); 415356345Scy PR_UL("num.query.subnet_cache", s->svr.num_query_subnet_cache); 416356345Scy#endif 417356345Scy} 418356345Scy 419356345Scy/** print statistics out of memory structures */ 420356345Scystatic void do_stats_shm(struct config_file* cfg, struct ub_stats_info* stats, 421356345Scy struct ub_shm_stat_info* shm_stat) 422356345Scy{ 423356345Scy int i; 424356345Scy char nm[32]; 425356345Scy for(i=0; i<cfg->num_threads; i++) { 426356345Scy snprintf(nm, sizeof(nm), "thread%d", i); 427356345Scy pr_stats(nm, &stats[i+1]); 428356345Scy } 429356345Scy pr_stats("total", &stats[0]); 430356345Scy print_uptime(shm_stat); 431356345Scy if(cfg->stat_extended) { 432356345Scy print_mem(shm_stat, &stats[0]); 433356345Scy print_hist(stats); 434356345Scy print_extended(stats); 435356345Scy } 436356345Scy} 437356345Scy#endif /* HAVE_SHMGET */ 438356345Scy 439356345Scy/** print statistics from shm memory segment */ 440356345Scystatic void print_stats_shm(const char* cfgfile) 441356345Scy{ 442356345Scy#ifdef HAVE_SHMGET 443356345Scy struct config_file* cfg; 444356345Scy struct ub_stats_info* stats; 445356345Scy struct ub_shm_stat_info* shm_stat; 446356345Scy int id_ctl, id_arr; 447356345Scy /* read config */ 448356345Scy if(!(cfg = config_create())) 449356345Scy fatal_exit("out of memory"); 450356345Scy if(!config_read(cfg, cfgfile, NULL)) 451356345Scy fatal_exit("could not read config file"); 452356345Scy /* get shm segments */ 453356345Scy id_ctl = shmget(cfg->shm_key, sizeof(int), SHM_R); 454356345Scy if(id_ctl == -1) { 455356345Scy fatal_exit("shmget(%d): %s", cfg->shm_key, strerror(errno)); 456356345Scy } 457356345Scy id_arr = shmget(cfg->shm_key+1, sizeof(int), SHM_R); 458356345Scy if(id_arr == -1) { 459356345Scy fatal_exit("shmget(%d): %s", cfg->shm_key+1, strerror(errno)); 460356345Scy } 461356345Scy shm_stat = (struct ub_shm_stat_info*)shmat(id_ctl, NULL, SHM_RDONLY); 462356345Scy if(shm_stat == (void*)-1) { 463356345Scy fatal_exit("shmat(%d): %s", id_ctl, strerror(errno)); 464356345Scy } 465356345Scy stats = (struct ub_stats_info*)shmat(id_arr, NULL, SHM_RDONLY); 466356345Scy if(stats == (void*)-1) { 467356345Scy fatal_exit("shmat(%d): %s", id_arr, strerror(errno)); 468356345Scy } 469356345Scy 470356345Scy /* print the stats */ 471356345Scy do_stats_shm(cfg, stats, shm_stat); 472356345Scy 473356345Scy /* shutdown */ 474356345Scy shmdt(shm_stat); 475356345Scy shmdt(stats); 476356345Scy config_delete(cfg); 477356345Scy#else 478356345Scy (void)cfgfile; 479356345Scy#endif /* HAVE_SHMGET */ 480356345Scy} 481356345Scy 482238106Sdes/** exit with ssl error */ 483238106Sdesstatic void ssl_err(const char* s) 484238106Sdes{ 485238106Sdes fprintf(stderr, "error: %s\n", s); 486238106Sdes ERR_print_errors_fp(stderr); 487238106Sdes exit(1); 488238106Sdes} 489238106Sdes 490356345Scy/** exit with ssl error related to a file path */ 491356345Scystatic void ssl_path_err(const char* s, const char *path) 492356345Scy{ 493356345Scy unsigned long err; 494356345Scy err = ERR_peek_error(); 495356345Scy if (ERR_GET_LIB(err) == ERR_LIB_SYS && 496356345Scy (ERR_GET_FUNC(err) == SYS_F_FOPEN || 497356345Scy ERR_GET_FUNC(err) == SYS_F_FREAD) ) { 498356345Scy fprintf(stderr, "error: %s\n%s: %s\n", 499356345Scy s, path, ERR_reason_error_string(err)); 500356345Scy exit(1); 501356345Scy } else { 502356345Scy ssl_err(s); 503356345Scy } 504356345Scy} 505356345Scy 506238106Sdes/** setup SSL context */ 507238106Sdesstatic SSL_CTX* 508238106Sdessetup_ctx(struct config_file* cfg) 509238106Sdes{ 510277057Sdes char* s_cert=NULL, *c_key=NULL, *c_cert=NULL; 511238106Sdes SSL_CTX* ctx; 512238106Sdes 513356345Scy if(!(options_remote_is_address(cfg) && cfg->control_use_cert)) 514356345Scy return NULL; 515356345Scy s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); 516356345Scy c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); 517356345Scy c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); 518356345Scy if(!s_cert || !c_key || !c_cert) 519356345Scy fatal_exit("out of memory"); 520356345Scy ctx = SSL_CTX_new(SSLv23_client_method()); 521238106Sdes if(!ctx) 522238106Sdes ssl_err("could not allocate SSL_CTX pointer"); 523361435Scy#if SSL_OP_NO_SSLv2 != 0 524356345Scy if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) 525292206Sdes != SSL_OP_NO_SSLv2) 526238106Sdes ssl_err("could not set SSL_OP_NO_SSLv2"); 527361435Scy#endif 528356345Scy if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) 529356345Scy != SSL_OP_NO_SSLv3) 530356345Scy ssl_err("could not set SSL_OP_NO_SSLv3"); 531356345Scy#if defined(SSL_OP_NO_RENEGOTIATION) 532356345Scy /* disable client renegotiation */ 533356345Scy if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) & 534356345Scy SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) 535356345Scy ssl_err("could not set SSL_OP_NO_RENEGOTIATION"); 536356345Scy#endif 537356345Scy if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert)) 538356345Scy ssl_path_err("Error setting up SSL_CTX client cert", c_cert); 539356345Scy if (!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)) 540356345Scy ssl_path_err("Error setting up SSL_CTX client key", c_key); 541356345Scy if (!SSL_CTX_check_private_key(ctx)) 542356345Scy ssl_err("Error setting up SSL_CTX client key"); 543356345Scy if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) 544356345Scy ssl_path_err("Error setting up SSL_CTX verify, server cert", 545356345Scy s_cert); 546356345Scy SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 547238106Sdes 548356345Scy free(s_cert); 549356345Scy free(c_key); 550356345Scy free(c_cert); 551238106Sdes return ctx; 552238106Sdes} 553238106Sdes 554369939Sgit2svn/** check connect error */ 555369939Sgit2svnstatic void 556369939Sgit2svncheckconnecterr(int err, const char* svr, struct sockaddr_storage* addr, 557369939Sgit2svn socklen_t addrlen, int statuscmd, int useport) 558369939Sgit2svn{ 559369939Sgit2svn#ifndef USE_WINSOCK 560369939Sgit2svn if(!useport) log_err("connect: %s for %s", strerror(err), svr); 561369939Sgit2svn else log_err_addr("connect", strerror(err), addr, addrlen); 562369939Sgit2svn if(err == ECONNREFUSED && statuscmd) { 563369939Sgit2svn printf("unbound is stopped\n"); 564369939Sgit2svn exit(3); 565369939Sgit2svn } 566369939Sgit2svn#else 567369939Sgit2svn int wsaerr = err; 568369939Sgit2svn if(!useport) log_err("connect: %s for %s", wsa_strerror(wsaerr), svr); 569369939Sgit2svn else log_err_addr("connect", wsa_strerror(wsaerr), addr, addrlen); 570369939Sgit2svn if(wsaerr == WSAECONNREFUSED && statuscmd) { 571369939Sgit2svn printf("unbound is stopped\n"); 572369939Sgit2svn exit(3); 573369939Sgit2svn } 574369939Sgit2svn#endif 575369939Sgit2svn exit(1); 576369939Sgit2svn} 577369939Sgit2svn 578238106Sdes/** contact the server with TCP connect */ 579238106Sdesstatic int 580238106Sdescontact_server(const char* svr, struct config_file* cfg, int statuscmd) 581238106Sdes{ 582238106Sdes struct sockaddr_storage addr; 583238106Sdes socklen_t addrlen; 584356345Scy int addrfamily = 0, proto = IPPROTO_TCP; 585356345Scy int fd, useport = 1; 586238106Sdes /* use svr or the first config entry */ 587238106Sdes if(!svr) { 588356345Scy if(cfg->control_ifs.first) { 589356345Scy svr = cfg->control_ifs.first->str; 590356345Scy } else if(cfg->do_ip4) { 591356345Scy svr = "127.0.0.1"; 592356345Scy } else { 593356345Scy svr = "::1"; 594356345Scy } 595238106Sdes /* config 0 addr (everything), means ask localhost */ 596238106Sdes if(strcmp(svr, "0.0.0.0") == 0) 597238106Sdes svr = "127.0.0.1"; 598238106Sdes else if(strcmp(svr, "::0") == 0 || 599238106Sdes strcmp(svr, "0::0") == 0 || 600238106Sdes strcmp(svr, "0::") == 0 || 601238106Sdes strcmp(svr, "::") == 0) 602238106Sdes svr = "::1"; 603238106Sdes } 604238106Sdes if(strchr(svr, '@')) { 605238106Sdes if(!extstrtoaddr(svr, &addr, &addrlen)) 606238106Sdes fatal_exit("could not parse IP@port: %s", svr); 607276699Sdes#ifdef HAVE_SYS_UN_H 608276699Sdes } else if(svr[0] == '/') { 609282089Sdes struct sockaddr_un* usock = (struct sockaddr_un *) &addr; 610282089Sdes usock->sun_family = AF_LOCAL; 611277057Sdes#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 612307729Sdes usock->sun_len = (unsigned)sizeof(usock); 613277057Sdes#endif 614282089Sdes (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path)); 615277057Sdes addrlen = (socklen_t)sizeof(struct sockaddr_un); 616276699Sdes addrfamily = AF_LOCAL; 617356345Scy useport = 0; 618356345Scy proto = 0; 619276699Sdes#endif 620238106Sdes } else { 621238106Sdes if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) 622238106Sdes fatal_exit("could not parse IP: %s", svr); 623238106Sdes } 624276699Sdes 625276699Sdes if(addrfamily == 0) 626356345Scy addrfamily = addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET; 627356345Scy fd = socket(addrfamily, SOCK_STREAM, proto); 628238106Sdes if(fd == -1) { 629368129Scy fatal_exit("socket: %s", sock_strerror(errno)); 630238106Sdes } 631369939Sgit2svn fd_set_nonblock(fd); 632238106Sdes if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { 633238106Sdes#ifndef USE_WINSOCK 634369939Sgit2svn#ifdef EINPROGRESS 635369939Sgit2svn if(errno != EINPROGRESS) { 636369939Sgit2svn checkconnecterr(errno, svr, &addr, 637369939Sgit2svn addrlen, statuscmd, useport); 638238106Sdes } 639369939Sgit2svn#endif 640238106Sdes#else 641369939Sgit2svn if(WSAGetLastError() != WSAEINPROGRESS && 642369939Sgit2svn WSAGetLastError() != WSAEWOULDBLOCK) { 643369939Sgit2svn checkconnecterr(WSAGetLastError(), svr, &addr, 644369939Sgit2svn addrlen, statuscmd, useport); 645238106Sdes } 646238106Sdes#endif 647238106Sdes } 648369939Sgit2svn while(1) { 649369939Sgit2svn fd_set rset, wset, eset; 650369939Sgit2svn struct timeval tv; 651369939Sgit2svn FD_ZERO(&rset); 652369939Sgit2svn FD_SET(FD_SET_T fd, &rset); 653369939Sgit2svn FD_ZERO(&wset); 654369939Sgit2svn FD_SET(FD_SET_T fd, &wset); 655369939Sgit2svn FD_ZERO(&eset); 656369939Sgit2svn FD_SET(FD_SET_T fd, &eset); 657369939Sgit2svn tv.tv_sec = UNBOUND_CONTROL_CONNECT_TIMEOUT/1000; 658369939Sgit2svn tv.tv_usec= (UNBOUND_CONTROL_CONNECT_TIMEOUT%1000)*1000; 659369939Sgit2svn if(select(fd+1, &rset, &wset, &eset, &tv) == -1) { 660369939Sgit2svn fatal_exit("select: %s", sock_strerror(errno)); 661369939Sgit2svn } 662369939Sgit2svn if(!FD_ISSET(fd, &rset) && !FD_ISSET(fd, &wset) && 663369939Sgit2svn !FD_ISSET(fd, &eset)) { 664369939Sgit2svn fatal_exit("timeout: could not connect to server"); 665369939Sgit2svn } else { 666369939Sgit2svn /* check nonblocking connect error */ 667369939Sgit2svn int error = 0; 668369939Sgit2svn socklen_t len = (socklen_t)sizeof(error); 669369939Sgit2svn if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error, 670369939Sgit2svn &len) < 0) { 671369939Sgit2svn#ifndef USE_WINSOCK 672369939Sgit2svn error = errno; /* on solaris errno is error */ 673369939Sgit2svn#else 674369939Sgit2svn error = WSAGetLastError(); 675369939Sgit2svn#endif 676369939Sgit2svn } 677369939Sgit2svn if(error != 0) { 678369939Sgit2svn#ifndef USE_WINSOCK 679369939Sgit2svn#ifdef EINPROGRESS 680369939Sgit2svn if(error == EINPROGRESS) 681369939Sgit2svn continue; /* try again later */ 682369939Sgit2svn#endif 683369939Sgit2svn#ifdef EWOULDBLOCK 684369939Sgit2svn if(error == EWOULDBLOCK) 685369939Sgit2svn continue; /* try again later */ 686369939Sgit2svn#endif 687369939Sgit2svn#else 688369939Sgit2svn if(error == WSAEINPROGRESS) 689369939Sgit2svn continue; /* try again later */ 690369939Sgit2svn if(error == WSAEWOULDBLOCK) 691369939Sgit2svn continue; /* try again later */ 692369939Sgit2svn#endif 693369939Sgit2svn checkconnecterr(error, svr, &addr, addrlen, 694369939Sgit2svn statuscmd, useport); 695369939Sgit2svn } 696369939Sgit2svn } 697369939Sgit2svn break; 698369939Sgit2svn } 699369939Sgit2svn fd_set_block(fd); 700238106Sdes return fd; 701238106Sdes} 702238106Sdes 703238106Sdes/** setup SSL on the connection */ 704238106Sdesstatic SSL* 705356345Scysetup_ssl(SSL_CTX* ctx, int fd) 706238106Sdes{ 707238106Sdes SSL* ssl; 708238106Sdes X509* x; 709238106Sdes int r; 710238106Sdes 711356345Scy if(!ctx) return NULL; 712238106Sdes ssl = SSL_new(ctx); 713238106Sdes if(!ssl) 714238106Sdes ssl_err("could not SSL_new"); 715238106Sdes SSL_set_connect_state(ssl); 716356345Scy (void)SSL_set_mode(ssl, (long)SSL_MODE_AUTO_RETRY); 717238106Sdes if(!SSL_set_fd(ssl, fd)) 718238106Sdes ssl_err("could not SSL_set_fd"); 719238106Sdes while(1) { 720238106Sdes ERR_clear_error(); 721238106Sdes if( (r=SSL_do_handshake(ssl)) == 1) 722238106Sdes break; 723238106Sdes r = SSL_get_error(ssl, r); 724238106Sdes if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) 725238106Sdes ssl_err("SSL handshake failed"); 726238106Sdes /* wants to be called again */ 727238106Sdes } 728238106Sdes 729238106Sdes /* check authenticity of server */ 730238106Sdes if(SSL_get_verify_result(ssl) != X509_V_OK) 731238106Sdes ssl_err("SSL verification failed"); 732356345Scy x = SSL_get_peer_certificate(ssl); 733356345Scy if(!x) 734356345Scy ssl_err("Server presented no peer certificate"); 735356345Scy X509_free(x); 736276699Sdes 737238106Sdes return ssl; 738238106Sdes} 739238106Sdes 740356345Scy/** read from ssl or fd, fatalexit on error, 0 EOF, 1 success */ 741356345Scystatic int 742356345Scyremote_read(SSL* ssl, int fd, char* buf, size_t len) 743356345Scy{ 744356345Scy if(ssl) { 745356345Scy int r; 746356345Scy ERR_clear_error(); 747356345Scy if((r = SSL_read(ssl, buf, (int)len-1)) <= 0) { 748356345Scy if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 749356345Scy /* EOF */ 750356345Scy return 0; 751356345Scy } 752356345Scy ssl_err("could not SSL_read"); 753356345Scy } 754356345Scy buf[r] = 0; 755356345Scy } else { 756356345Scy ssize_t rr = recv(fd, buf, len-1, 0); 757356345Scy if(rr <= 0) { 758356345Scy if(rr == 0) { 759356345Scy /* EOF */ 760356345Scy return 0; 761356345Scy } 762368129Scy fatal_exit("could not recv: %s", sock_strerror(errno)); 763356345Scy } 764356345Scy buf[rr] = 0; 765356345Scy } 766356345Scy return 1; 767356345Scy} 768356345Scy 769356345Scy/** write to ssl or fd, fatalexit on error */ 770356345Scystatic void 771356345Scyremote_write(SSL* ssl, int fd, const char* buf, size_t len) 772356345Scy{ 773356345Scy if(ssl) { 774356345Scy if(SSL_write(ssl, buf, (int)len) <= 0) 775356345Scy ssl_err("could not SSL_write"); 776356345Scy } else { 777356345Scy if(send(fd, buf, len, 0) < (ssize_t)len) { 778368129Scy fatal_exit("could not send: %s", sock_strerror(errno)); 779356345Scy } 780356345Scy } 781356345Scy} 782356345Scy 783356345Scy/** check args, to see if too many args. Because when a file is sent it 784356345Scy * would wait for the terminal, and we can check for too many arguments, 785356345Scy * eg. user put arguments on the commandline. */ 786356345Scystatic void 787356345Scycheck_args_for_listcmd(int argc, char* argv[]) 788356345Scy{ 789356345Scy if(argc >= 1 && (strcmp(argv[0], "local_zones") == 0 || 790356345Scy strcmp(argv[0], "local_zones_remove") == 0 || 791356345Scy strcmp(argv[0], "local_datas") == 0 || 792356345Scy strcmp(argv[0], "local_datas_remove") == 0) && 793356345Scy argc >= 2) { 794356345Scy fatal_exit("too many arguments for command '%s', " 795356345Scy "content is piped in from stdin", argv[0]); 796356345Scy } 797361435Scy if(argc >= 1 && (strcmp(argv[0], "view_local_datas") == 0 || 798361435Scy strcmp(argv[0], "view_local_datas_remove") == 0) && 799356345Scy argc >= 3) { 800356345Scy fatal_exit("too many arguments for command '%s', " 801356345Scy "content is piped in from stdin", argv[0]); 802356345Scy } 803356345Scy} 804356345Scy 805238106Sdes/** send stdin to server */ 806238106Sdesstatic void 807356345Scysend_file(SSL* ssl, int fd, FILE* in, char* buf, size_t sz) 808238106Sdes{ 809238106Sdes while(fgets(buf, (int)sz, in)) { 810356345Scy remote_write(ssl, fd, buf, strlen(buf)); 811238106Sdes } 812238106Sdes} 813238106Sdes 814356345Scy/** send end-of-file marker to server */ 815356345Scystatic void 816356345Scysend_eof(SSL* ssl, int fd) 817356345Scy{ 818356345Scy char e[] = {0x04, 0x0a}; 819356345Scy remote_write(ssl, fd, e, sizeof(e)); 820356345Scy} 821356345Scy 822238106Sdes/** send command and display result */ 823238106Sdesstatic int 824356345Scygo_cmd(SSL* ssl, int fd, int quiet, int argc, char* argv[]) 825238106Sdes{ 826238106Sdes char pre[10]; 827238106Sdes const char* space=" "; 828238106Sdes const char* newline="\n"; 829238106Sdes int was_error = 0, first_line = 1; 830356345Scy int i; 831238106Sdes char buf[1024]; 832238106Sdes snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); 833356345Scy remote_write(ssl, fd, pre, strlen(pre)); 834238106Sdes for(i=0; i<argc; i++) { 835356345Scy remote_write(ssl, fd, space, strlen(space)); 836356345Scy remote_write(ssl, fd, argv[i], strlen(argv[i])); 837238106Sdes } 838356345Scy remote_write(ssl, fd, newline, strlen(newline)); 839238106Sdes 840238106Sdes if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { 841356345Scy send_file(ssl, fd, stdin, buf, sizeof(buf)); 842238106Sdes } 843356345Scy else if(argc >= 1 && (strcmp(argv[0], "local_zones") == 0 || 844356345Scy strcmp(argv[0], "local_zones_remove") == 0 || 845356345Scy strcmp(argv[0], "local_datas") == 0 || 846356345Scy strcmp(argv[0], "view_local_datas") == 0 || 847361435Scy strcmp(argv[0], "local_datas_remove") == 0 || 848361435Scy strcmp(argv[0], "view_local_datas_remove") == 0)) { 849356345Scy send_file(ssl, fd, stdin, buf, sizeof(buf)); 850356345Scy send_eof(ssl, fd); 851356345Scy } 852238106Sdes 853238106Sdes while(1) { 854356345Scy if(remote_read(ssl, fd, buf, sizeof(buf)) == 0) { 855356345Scy break; /* EOF */ 856238106Sdes } 857249141Sdes if(first_line && strncmp(buf, "error", 5) == 0) { 858249141Sdes printf("%s", buf); 859238106Sdes was_error = 1; 860249141Sdes } else if (!quiet) 861249141Sdes printf("%s", buf); 862249141Sdes 863238106Sdes first_line = 0; 864238106Sdes } 865238106Sdes return was_error; 866238106Sdes} 867238106Sdes 868238106Sdes/** go ahead and read config, contact server and perform command and display */ 869238106Sdesstatic int 870249141Sdesgo(const char* cfgfile, char* svr, int quiet, int argc, char* argv[]) 871238106Sdes{ 872238106Sdes struct config_file* cfg; 873238106Sdes int fd, ret; 874238106Sdes SSL_CTX* ctx; 875238106Sdes SSL* ssl; 876238106Sdes 877238106Sdes /* read config */ 878238106Sdes if(!(cfg = config_create())) 879238106Sdes fatal_exit("out of memory"); 880238106Sdes if(!config_read(cfg, cfgfile, NULL)) 881238106Sdes fatal_exit("could not read config file"); 882238106Sdes if(!cfg->remote_control_enable) 883238106Sdes log_warn("control-enable is 'no' in the config file."); 884292206Sdes#ifdef UB_ON_WINDOWS 885292206Sdes w_config_adjust_directory(cfg); 886292206Sdes#endif 887238106Sdes ctx = setup_ctx(cfg); 888276699Sdes 889238106Sdes /* contact server */ 890238106Sdes fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0); 891356345Scy ssl = setup_ssl(ctx, fd); 892276699Sdes 893238106Sdes /* send command */ 894356345Scy ret = go_cmd(ssl, fd, quiet, argc, argv); 895238106Sdes 896356345Scy if(ssl) SSL_free(ssl); 897368129Scy sock_close(fd); 898356345Scy if(ctx) SSL_CTX_free(ctx); 899238106Sdes config_delete(cfg); 900238106Sdes return ret; 901238106Sdes} 902238106Sdes 903238106Sdes/** getopt global, in case header files fail to declare it. */ 904238106Sdesextern int optind; 905238106Sdes/** getopt global, in case header files fail to declare it. */ 906238106Sdesextern char* optarg; 907238106Sdes 908238106Sdes/** Main routine for unbound-control */ 909238106Sdesint main(int argc, char* argv[]) 910238106Sdes{ 911238106Sdes int c, ret; 912249141Sdes int quiet = 0; 913238106Sdes const char* cfgfile = CONFIGFILE; 914238106Sdes char* svr = NULL; 915238106Sdes#ifdef USE_WINSOCK 916238106Sdes int r; 917238106Sdes WSADATA wsa_data; 918238106Sdes#endif 919238106Sdes#ifdef USE_THREAD_DEBUG 920356345Scy /* stop the file output from unbound-control, overwrites the servers */ 921238106Sdes extern int check_locking_order; 922238106Sdes check_locking_order = 0; 923238106Sdes#endif /* USE_THREAD_DEBUG */ 924238106Sdes log_ident_set("unbound-control"); 925238106Sdes log_init(NULL, 0, NULL); 926238106Sdes checklock_start(); 927238106Sdes#ifdef USE_WINSOCK 928238106Sdes /* use registry config file in preference to compiletime location */ 929238106Sdes if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) 930238106Sdes cfgfile = CONFIGFILE; 931238106Sdes#endif 932238106Sdes /* parse the options */ 933249141Sdes while( (c=getopt(argc, argv, "c:s:qh")) != -1) { 934238106Sdes switch(c) { 935238106Sdes case 'c': 936238106Sdes cfgfile = optarg; 937238106Sdes break; 938238106Sdes case 's': 939238106Sdes svr = optarg; 940238106Sdes break; 941249141Sdes case 'q': 942249141Sdes quiet = 1; 943249141Sdes break; 944238106Sdes case '?': 945238106Sdes case 'h': 946238106Sdes default: 947238106Sdes usage(); 948238106Sdes } 949238106Sdes } 950238106Sdes argc -= optind; 951238106Sdes argv += optind; 952238106Sdes if(argc == 0) 953238106Sdes usage(); 954238106Sdes if(argc >= 1 && strcmp(argv[0], "start")==0) { 955368129Scy#if (defined(TARGET_OS_TV) && TARGET_OS_TV) || (defined(TARGET_OS_WATCH) && TARGET_OS_WATCH) 956366095Scy fatal_exit("could not exec unbound: %s", 957366095Scy strerror(ENOSYS)); 958366095Scy#else 959238106Sdes if(execlp("unbound", "unbound", "-c", cfgfile, 960238106Sdes (char*)NULL) < 0) { 961238106Sdes fatal_exit("could not exec unbound: %s", 962238106Sdes strerror(errno)); 963238106Sdes } 964366095Scy#endif 965238106Sdes } 966356345Scy if(argc >= 1 && strcmp(argv[0], "stats_shm")==0) { 967356345Scy print_stats_shm(cfgfile); 968356345Scy return 0; 969356345Scy } 970356345Scy check_args_for_listcmd(argc, argv); 971238106Sdes 972356345Scy#ifdef USE_WINSOCK 973356345Scy if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) 974356345Scy fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); 975356345Scy#endif 976356345Scy 977356345Scy#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS 978356345Scy ERR_load_crypto_strings(); 979356345Scy#endif 980356345Scy#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 981356345Scy ERR_load_SSL_strings(); 982356345Scy#endif 983356345Scy#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) 984356345Scy# ifndef S_SPLINT_S 985356345Scy OpenSSL_add_all_algorithms(); 986356345Scy# endif 987356345Scy#else 988356345Scy OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS 989356345Scy | OPENSSL_INIT_ADD_ALL_DIGESTS 990356345Scy | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); 991356345Scy#endif 992356345Scy#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 993356345Scy (void)SSL_library_init(); 994356345Scy#else 995356345Scy (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); 996356345Scy#endif 997356345Scy 998356345Scy if(!RAND_status()) { 999356345Scy /* try to seed it */ 1000356345Scy unsigned char buf[256]; 1001356345Scy unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid(); 1002356345Scy unsigned int v = seed; 1003356345Scy size_t i; 1004356345Scy for(i=0; i<256/sizeof(v); i++) { 1005356345Scy memmove(buf+i*sizeof(v), &v, sizeof(v)); 1006356345Scy v = v*seed + (unsigned int)i; 1007356345Scy } 1008356345Scy RAND_seed(buf, 256); 1009356345Scy log_warn("no entropy, seeding openssl PRNG with time\n"); 1010356345Scy } 1011356345Scy 1012249141Sdes ret = go(cfgfile, svr, quiet, argc, argv); 1013238106Sdes 1014238106Sdes#ifdef USE_WINSOCK 1015356345Scy WSACleanup(); 1016238106Sdes#endif 1017238106Sdes checklock_stop(); 1018238106Sdes return ret; 1019238106Sdes} 1020