1933707f3Ssthen /* 2191f22c6Ssthen * smallapp/unbound-control.c - remote control utility for unbound. 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2008, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen 36933707f3Ssthen /** 37933707f3Ssthen * \file 38933707f3Ssthen * 39933707f3Ssthen * The remote control utility contacts the unbound server over ssl and 40933707f3Ssthen * sends the command, receives the answer, and displays the result 41933707f3Ssthen * from the commandline. 42933707f3Ssthen */ 43933707f3Ssthen 44933707f3Ssthen #include "config.h" 45933707f3Ssthen #ifdef HAVE_GETOPT_H 46933707f3Ssthen #include <getopt.h> 47933707f3Ssthen #endif 48933707f3Ssthen #ifdef HAVE_OPENSSL_SSL_H 49933707f3Ssthen #include <openssl/ssl.h> 50933707f3Ssthen #endif 51933707f3Ssthen #ifdef HAVE_OPENSSL_ERR_H 52933707f3Ssthen #include <openssl/err.h> 53933707f3Ssthen #endif 54933707f3Ssthen #ifdef HAVE_OPENSSL_RAND_H 55933707f3Ssthen #include <openssl/rand.h> 56933707f3Ssthen #endif 57933707f3Ssthen #include "util/log.h" 58933707f3Ssthen #include "util/config_file.h" 59933707f3Ssthen #include "util/locks.h" 60933707f3Ssthen #include "util/net_help.h" 612be9e038Ssthen #include "util/shm_side/shm_main.h" 628b7325afSsthen #include "util/timeval_func.h" 632be9e038Ssthen #include "daemon/stats.h" 642be9e038Ssthen #include "sldns/wire2str.h" 652be9e038Ssthen #include "sldns/pkthdr.h" 66eaf2578eSsthen #include "services/rpz.h" 67191f22c6Ssthen #include "services/listen_dnsport.h" 68933707f3Ssthen 692be9e038Ssthen #ifdef HAVE_SYS_IPC_H 702be9e038Ssthen #include "sys/ipc.h" 712be9e038Ssthen #endif 722be9e038Ssthen #ifdef HAVE_SYS_SHM_H 732be9e038Ssthen #include "sys/shm.h" 742be9e038Ssthen #endif 75b2cdf21fSsthen #ifdef HAVE_SYS_UN_H 76b2cdf21fSsthen #include <sys/un.h> 77b2cdf21fSsthen #endif 78b2cdf21fSsthen 79a3167c07Ssthen #ifdef HAVE_TARGETCONDITIONALS_H 80a3167c07Ssthen #include <TargetConditionals.h> 81a3167c07Ssthen #endif 82a3167c07Ssthen 83452a1548Ssthen static void usage(void) ATTR_NORETURN; 84452a1548Ssthen static void ssl_err(const char* s) ATTR_NORETURN; 85452a1548Ssthen static void ssl_path_err(const char* s, const char *path) ATTR_NORETURN; 86452a1548Ssthen 879982a05dSsthen /** timeout to wait for connection over stream, in msec */ 889982a05dSsthen #define UNBOUND_CONTROL_CONNECT_TIMEOUT 5000 899982a05dSsthen 90933707f3Ssthen /** Give unbound-control usage, and exit (1). */ 91933707f3Ssthen static void 9277079be7Ssthen usage(void) 93933707f3Ssthen { 94933707f3Ssthen printf("Usage: unbound-control [options] command\n"); 95933707f3Ssthen printf(" Remote control utility for unbound server.\n"); 96933707f3Ssthen printf("Options:\n"); 97933707f3Ssthen printf(" -c file config file, default is %s\n", CONFIGFILE); 98933707f3Ssthen printf(" -s ip[@port] server address, if omitted config is used.\n"); 99229e174cSsthen printf(" -q quiet (don't print anything if it works ok).\n"); 100933707f3Ssthen printf(" -h show this usage help.\n"); 101933707f3Ssthen printf("Commands:\n"); 102933707f3Ssthen printf(" start start server; runs unbound(8)\n"); 103933707f3Ssthen printf(" stop stops the server\n"); 104933707f3Ssthen printf(" reload reloads the server\n"); 105933707f3Ssthen printf(" (this flushes data, stats, requestlist)\n"); 1068b7325afSsthen printf(" reload_keep_cache reloads the server but tries to\n"); 1078b7325afSsthen printf(" keep the RRset and message cache\n"); 1088b7325afSsthen printf(" if (re)configuration allows for it.\n"); 1098b7325afSsthen printf(" That means the caches sizes and\n"); 1108b7325afSsthen printf(" the number of threads must not\n"); 1118b7325afSsthen printf(" change between reloads.\n"); 112933707f3Ssthen printf(" stats print statistics\n"); 113933707f3Ssthen printf(" stats_noreset peek at statistics\n"); 1142be9e038Ssthen #ifdef HAVE_SHMGET 1152be9e038Ssthen printf(" stats_shm print statistics using shm\n"); 1162be9e038Ssthen #endif 117933707f3Ssthen printf(" status display status of server\n"); 118933707f3Ssthen printf(" verbosity <number> change logging detail\n"); 119933707f3Ssthen printf(" log_reopen close and open the logfile\n"); 120933707f3Ssthen printf(" local_zone <name> <type> add new local zone\n"); 121933707f3Ssthen printf(" local_zone_remove <name> remove local zone and its contents\n"); 122933707f3Ssthen printf(" local_data <RR data...> add local data, for example\n"); 123933707f3Ssthen printf(" local_data www.example.com A 192.0.2.1\n"); 124933707f3Ssthen printf(" local_data_remove <name> remove local RR data from name\n"); 125*98bc733bSsthen printf(" local_zones,\n"); 126*98bc733bSsthen printf(" local_zones_remove,\n"); 127*98bc733bSsthen printf(" local_datas,\n"); 128*98bc733bSsthen printf(" local_datas_remove same, but read list from stdin\n"); 1292be9e038Ssthen printf(" (one entry per line).\n"); 130933707f3Ssthen printf(" dump_cache print cache to stdout\n"); 131*98bc733bSsthen printf(" (not supported in remote unbounds in\n"); 132*98bc733bSsthen printf(" multi-process operation)\n"); 133933707f3Ssthen printf(" load_cache load cache from stdin\n"); 134*98bc733bSsthen printf(" (not supported in remote unbounds in\n"); 135*98bc733bSsthen printf(" multi-process operation)\n"); 136933707f3Ssthen printf(" lookup <name> print nameservers for name\n"); 137*98bc733bSsthen printf(" flush [+c] <name> flushes common types for name from cache\n"); 138933707f3Ssthen printf(" types: A, AAAA, MX, PTR, NS,\n"); 139933707f3Ssthen printf(" SOA, CNAME, DNAME, SRV, NAPTR\n"); 140*98bc733bSsthen printf(" flush_type [+c] <name> <type> flush name, type from cache\n"); 141*98bc733bSsthen printf(" +c remove from cachedb too\n"); 142*98bc733bSsthen printf(" flush_zone [+c] <name> flush everything at or under name\n"); 143933707f3Ssthen printf(" from rr and dnssec caches\n"); 144*98bc733bSsthen printf(" flush_bogus [+c] flush all bogus data\n"); 145*98bc733bSsthen printf(" flush_negative [+c] flush all negative data\n"); 146933707f3Ssthen printf(" flush_stats flush statistics, make zero\n"); 147933707f3Ssthen printf(" flush_requestlist drop queries that are worked on\n"); 1482ee382b6Ssthen printf(" dump_requestlist show what is worked on by first thread\n"); 149933707f3Ssthen printf(" flush_infra [all | ip] remove ping, edns for one IP or all\n"); 150933707f3Ssthen printf(" dump_infra show ping and edns entries\n"); 151933707f3Ssthen printf(" set_option opt: val set option to value, no reload\n"); 152933707f3Ssthen printf(" get_option opt get option value\n"); 153933707f3Ssthen printf(" list_stubs list stub-zones and root hints in use\n"); 154933707f3Ssthen printf(" list_forwards list forward-zones in use\n"); 155fdfb4ba6Ssthen printf(" list_insecure list domain-insecure zones\n"); 156933707f3Ssthen printf(" list_local_zones list local-zones in use\n"); 157933707f3Ssthen printf(" list_local_data list local-data RRs in use\n"); 158229e174cSsthen printf(" insecure_add zone add domain-insecure zone\n"); 159229e174cSsthen printf(" insecure_remove zone remove domain-insecure zone\n"); 1602bdc0ed1Ssthen printf(" forward_add [+it] zone addr.. add forward-zone with servers\n"); 161d8d14d0cSsthen printf(" forward_remove [+i] zone remove forward zone\n"); 1622bdc0ed1Ssthen printf(" stub_add [+ipt] zone addr.. add stub-zone with servers\n"); 163d8d14d0cSsthen printf(" stub_remove [+i] zone remove stub zone\n"); 164d8d14d0cSsthen printf(" +i also do dnssec insecure point\n"); 165d8d14d0cSsthen printf(" +p set stub to use priming\n"); 1662bdc0ed1Ssthen printf(" +t set to use tls upstream\n"); 167933707f3Ssthen printf(" forward [off | addr ...] without arg show forward setup\n"); 168933707f3Ssthen printf(" or off to turn off root forwarding\n"); 169933707f3Ssthen printf(" or give list of ip addresses\n"); 170fdfb4ba6Ssthen printf(" ratelimit_list [+a] list ratelimited domains\n"); 17177079be7Ssthen printf(" ip_ratelimit_list [+a] list ratelimited ip addresses\n"); 172fdfb4ba6Ssthen printf(" +a list all, also not ratelimited\n"); 1730bdb4f62Ssthen printf(" list_auth_zones list auth zones (includes RPZ zones)\n"); 1740bdb4f62Ssthen printf(" auth_zone_reload zone reload auth zone (or RPZ zone) from zonefile\n"); 1750bdb4f62Ssthen printf(" auth_zone_transfer zone transfer auth zone (or RPZ zone) from master\n"); 17677079be7Ssthen printf(" view_list_local_zones view list local-zones in view\n"); 17777079be7Ssthen printf(" view_list_local_data view list local-data RRs in view\n"); 17877079be7Ssthen printf(" view_local_zone view name type add local-zone in view\n"); 17977079be7Ssthen printf(" view_local_zone_remove view name remove local-zone in view\n"); 18077079be7Ssthen printf(" view_local_data view RR... add local-data in view\n"); 1813150e5f6Ssthen printf(" view_local_datas view add list of local-data to view\n"); 1823150e5f6Ssthen printf(" one entry per line read from stdin\n"); 18377079be7Ssthen printf(" view_local_data_remove view name remove local-data in view\n"); 184eaf2578eSsthen printf(" view_local_datas_remove view remove list of local-data from view\n"); 185eaf2578eSsthen printf(" one entry per line read from stdin\n"); 1869982a05dSsthen printf(" rpz_enable zone Enable the RPZ zone if it had previously\n"); 1879982a05dSsthen printf(" been disabled\n"); 1889982a05dSsthen printf(" rpz_disable zone Disable the RPZ zone\n"); 189*98bc733bSsthen printf(" add_cookie_secret <secret> add (or replace) a new cookie secret <secret>\n"); 190*98bc733bSsthen printf(" drop_cookie_secret drop a staging cookie secret\n"); 191*98bc733bSsthen printf(" activate_cookie_secret make a staging cookie secret active\n"); 192*98bc733bSsthen printf(" print_cookie_secrets show all cookie secrets with their status\n"); 193933707f3Ssthen printf("Version %s\n", PACKAGE_VERSION); 194933707f3Ssthen printf("BSD licensed, see LICENSE in source package for details.\n"); 195933707f3Ssthen printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 196933707f3Ssthen exit(1); 197933707f3Ssthen } 198933707f3Ssthen 1992be9e038Ssthen #ifdef HAVE_SHMGET 2002be9e038Ssthen /** what to put on statistics lines between var and value, ": " or "=" */ 2012be9e038Ssthen #define SQ "=" 2022be9e038Ssthen /** print unsigned long stats value */ 2032be9e038Ssthen #define PR_UL_NM(str, var) printf("%s."str SQ"%lu\n", nm, (unsigned long)(var)); 2042be9e038Ssthen #define PR_UL(str, var) printf(str SQ"%lu\n", (unsigned long)(var)); 2052be9e038Ssthen #define PR_UL_SUB(str, nm, var) printf(str".%s"SQ"%lu\n", nm, (unsigned long)(var)); 2062be9e038Ssthen #define PR_TIMEVAL(str, var) printf(str SQ ARG_LL "d.%6.6d\n", \ 2072be9e038Ssthen (long long)var.tv_sec, (int)var.tv_usec); 2082be9e038Ssthen #define PR_STATSTIME(str, var) printf(str SQ ARG_LL "d.%6.6d\n", \ 2092be9e038Ssthen (long long)var ## _sec, (int)var ## _usec); 2102be9e038Ssthen #define PR_LL(str, var) printf(str SQ ARG_LL"d\n", (long long)(var)); 2112be9e038Ssthen 2122be9e038Ssthen /** print stat block */ 2132be9e038Ssthen static void pr_stats(const char* nm, struct ub_stats_info* s) 2142be9e038Ssthen { 2152be9e038Ssthen struct timeval sumwait, avg; 2162be9e038Ssthen PR_UL_NM("num.queries", s->svr.num_queries); 2172be9e038Ssthen PR_UL_NM("num.queries_ip_ratelimited", 2182be9e038Ssthen s->svr.num_queries_ip_ratelimited); 2198b7325afSsthen PR_UL_NM("num.queries_cookie_valid", 2208b7325afSsthen s->svr.num_queries_cookie_valid); 2218b7325afSsthen PR_UL_NM("num.queries_cookie_client", 2228b7325afSsthen s->svr.num_queries_cookie_client); 2238b7325afSsthen PR_UL_NM("num.queries_cookie_invalid", 2248b7325afSsthen s->svr.num_queries_cookie_invalid); 2252be9e038Ssthen PR_UL_NM("num.cachehits", 2262be9e038Ssthen s->svr.num_queries - s->svr.num_queries_missed_cache); 2272be9e038Ssthen PR_UL_NM("num.cachemiss", s->svr.num_queries_missed_cache); 2282be9e038Ssthen PR_UL_NM("num.prefetch", s->svr.num_queries_prefetch); 2298b7325afSsthen PR_UL_NM("num.queries_timed_out", s->svr.num_queries_timed_out); 2308b7325afSsthen PR_UL_NM("query.queue_time_us.max", s->svr.max_query_time_us); 231eaf2578eSsthen PR_UL_NM("num.expired", s->svr.ans_expired); 2322be9e038Ssthen PR_UL_NM("num.recursivereplies", s->mesh_replies_sent); 2332be9e038Ssthen #ifdef USE_DNSCRYPT 2342be9e038Ssthen PR_UL_NM("num.dnscrypt.crypted", s->svr.num_query_dnscrypt_crypted); 2352be9e038Ssthen PR_UL_NM("num.dnscrypt.cert", s->svr.num_query_dnscrypt_cert); 2362be9e038Ssthen PR_UL_NM("num.dnscrypt.cleartext", s->svr.num_query_dnscrypt_cleartext); 2372be9e038Ssthen PR_UL_NM("num.dnscrypt.malformed", 2382be9e038Ssthen s->svr.num_query_dnscrypt_crypted_malformed); 2397191de28Ssthen #endif /* USE_DNSCRYPT */ 2402be9e038Ssthen printf("%s.requestlist.avg"SQ"%g\n", nm, 2412be9e038Ssthen (s->svr.num_queries_missed_cache+s->svr.num_queries_prefetch)? 2422be9e038Ssthen (double)s->svr.sum_query_list_size/ 2432be9e038Ssthen (double)(s->svr.num_queries_missed_cache+ 2442be9e038Ssthen s->svr.num_queries_prefetch) : 0.0); 2452be9e038Ssthen PR_UL_NM("requestlist.max", s->svr.max_query_list_size); 2462be9e038Ssthen PR_UL_NM("requestlist.overwritten", s->mesh_jostled); 2472be9e038Ssthen PR_UL_NM("requestlist.exceeded", s->mesh_dropped); 2482be9e038Ssthen PR_UL_NM("requestlist.current.all", s->mesh_num_states); 2492be9e038Ssthen PR_UL_NM("requestlist.current.user", s->mesh_num_reply_states); 2502be9e038Ssthen #ifndef S_SPLINT_S 2512be9e038Ssthen sumwait.tv_sec = s->mesh_replies_sum_wait_sec; 2522be9e038Ssthen sumwait.tv_usec = s->mesh_replies_sum_wait_usec; 2532be9e038Ssthen #endif 2542be9e038Ssthen timeval_divide(&avg, &sumwait, s->mesh_replies_sent); 2552be9e038Ssthen printf("%s.", nm); 2562be9e038Ssthen PR_TIMEVAL("recursion.time.avg", avg); 2572be9e038Ssthen printf("%s.recursion.time.median"SQ"%g\n", nm, s->mesh_time_median); 2582be9e038Ssthen PR_UL_NM("tcpusage", s->svr.tcp_accept_usage); 2592be9e038Ssthen } 2602be9e038Ssthen 2612be9e038Ssthen /** print uptime */ 2622be9e038Ssthen static void print_uptime(struct ub_shm_stat_info* shm_stat) 2632be9e038Ssthen { 2642be9e038Ssthen PR_STATSTIME("time.now", shm_stat->time.now); 2652be9e038Ssthen PR_STATSTIME("time.up", shm_stat->time.up); 2662be9e038Ssthen PR_STATSTIME("time.elapsed", shm_stat->time.elapsed); 2672be9e038Ssthen } 2682be9e038Ssthen 2692be9e038Ssthen /** print memory usage */ 270f6b99bafSsthen static void print_mem(struct ub_shm_stat_info* shm_stat, 271f6b99bafSsthen struct ub_stats_info* s) 2722be9e038Ssthen { 2732be9e038Ssthen PR_LL("mem.cache.rrset", shm_stat->mem.rrset); 2742be9e038Ssthen PR_LL("mem.cache.message", shm_stat->mem.msg); 2752be9e038Ssthen PR_LL("mem.mod.iterator", shm_stat->mem.iter); 2762be9e038Ssthen PR_LL("mem.mod.validator", shm_stat->mem.val); 2772be9e038Ssthen PR_LL("mem.mod.respip", shm_stat->mem.respip); 2782be9e038Ssthen #ifdef CLIENT_SUBNET 2792be9e038Ssthen PR_LL("mem.mod.subnet", shm_stat->mem.subnet); 2802be9e038Ssthen #endif 2812be9e038Ssthen #ifdef USE_IPSECMOD 2822be9e038Ssthen PR_LL("mem.mod.ipsecmod", shm_stat->mem.ipsecmod); 2832be9e038Ssthen #endif 284a3167c07Ssthen #ifdef WITH_DYNLIBMODULE 285a3167c07Ssthen PR_LL("mem.mod.dynlib", shm_stat->mem.dynlib); 286a3167c07Ssthen #endif 2877191de28Ssthen #ifdef USE_DNSCRYPT 2887191de28Ssthen PR_LL("mem.cache.dnscrypt_shared_secret", 2897191de28Ssthen shm_stat->mem.dnscrypt_shared_secret); 290bdfc4d55Sflorian PR_LL("mem.cache.dnscrypt_nonce", 291bdfc4d55Sflorian shm_stat->mem.dnscrypt_nonce); 2927191de28Ssthen #endif 293f6b99bafSsthen PR_LL("mem.streamwait", s->svr.mem_stream_wait); 2942c144df0Ssthen PR_LL("mem.http.query_buffer", s->svr.mem_http2_query_buffer); 2952c144df0Ssthen PR_LL("mem.http.response_buffer", s->svr.mem_http2_response_buffer); 2962be9e038Ssthen } 2972be9e038Ssthen 2982be9e038Ssthen /** print histogram */ 2992be9e038Ssthen static void print_hist(struct ub_stats_info* s) 3002be9e038Ssthen { 3012be9e038Ssthen struct timehist* hist; 3022be9e038Ssthen size_t i; 3032be9e038Ssthen hist = timehist_setup(); 3042be9e038Ssthen if(!hist) 3052be9e038Ssthen fatal_exit("out of memory"); 3062be9e038Ssthen timehist_import(hist, s->svr.hist, NUM_BUCKETS_HIST); 3072be9e038Ssthen for(i=0; i<hist->num; i++) { 3082be9e038Ssthen printf("histogram.%6.6d.%6.6d.to.%6.6d.%6.6d=%lu\n", 3092be9e038Ssthen (int)hist->buckets[i].lower.tv_sec, 3102be9e038Ssthen (int)hist->buckets[i].lower.tv_usec, 3112be9e038Ssthen (int)hist->buckets[i].upper.tv_sec, 3122be9e038Ssthen (int)hist->buckets[i].upper.tv_usec, 3132be9e038Ssthen (unsigned long)hist->buckets[i].count); 3142be9e038Ssthen } 3152be9e038Ssthen timehist_delete(hist); 3162be9e038Ssthen } 3172be9e038Ssthen 3182be9e038Ssthen /** print extended */ 3198b7325afSsthen static void print_extended(struct ub_stats_info* s, int inhibit_zero) 3202be9e038Ssthen { 3212be9e038Ssthen int i; 3222be9e038Ssthen char nm[16]; 3232be9e038Ssthen 3242be9e038Ssthen /* TYPE */ 3252be9e038Ssthen for(i=0; i<UB_STATS_QTYPE_NUM; i++) { 3262be9e038Ssthen if(inhibit_zero && s->svr.qtype[i] == 0) 3272be9e038Ssthen continue; 3282be9e038Ssthen sldns_wire2str_type_buf((uint16_t)i, nm, sizeof(nm)); 3292be9e038Ssthen PR_UL_SUB("num.query.type", nm, s->svr.qtype[i]); 3302be9e038Ssthen } 3312be9e038Ssthen if(!inhibit_zero || s->svr.qtype_big) { 3322be9e038Ssthen PR_UL("num.query.type.other", s->svr.qtype_big); 3332be9e038Ssthen } 3342be9e038Ssthen 3352be9e038Ssthen /* CLASS */ 3362be9e038Ssthen for(i=0; i<UB_STATS_QCLASS_NUM; i++) { 3372be9e038Ssthen if(inhibit_zero && s->svr.qclass[i] == 0) 3382be9e038Ssthen continue; 3392be9e038Ssthen sldns_wire2str_class_buf((uint16_t)i, nm, sizeof(nm)); 3402be9e038Ssthen PR_UL_SUB("num.query.class", nm, s->svr.qclass[i]); 3412be9e038Ssthen } 3422be9e038Ssthen if(!inhibit_zero || s->svr.qclass_big) { 3432be9e038Ssthen PR_UL("num.query.class.other", s->svr.qclass_big); 3442be9e038Ssthen } 3452be9e038Ssthen 3462be9e038Ssthen /* OPCODE */ 3472be9e038Ssthen for(i=0; i<UB_STATS_OPCODE_NUM; i++) { 3482be9e038Ssthen if(inhibit_zero && s->svr.qopcode[i] == 0) 3492be9e038Ssthen continue; 3502be9e038Ssthen sldns_wire2str_opcode_buf(i, nm, sizeof(nm)); 3512be9e038Ssthen PR_UL_SUB("num.query.opcode", nm, s->svr.qopcode[i]); 3522be9e038Ssthen } 3532be9e038Ssthen 3542be9e038Ssthen /* transport */ 3552be9e038Ssthen PR_UL("num.query.tcp", s->svr.qtcp); 3562be9e038Ssthen PR_UL("num.query.tcpout", s->svr.qtcp_outgoing); 357d1e2768aSsthen PR_UL("num.query.udpout", s->svr.qudp_outgoing); 3582308e98cSsthen PR_UL("num.query.tls", s->svr.qtls); 359f6b99bafSsthen PR_UL("num.query.tls_resume", s->svr.qtls_resume); 3602be9e038Ssthen PR_UL("num.query.ipv6", s->svr.qipv6); 3612c144df0Ssthen PR_UL("num.query.https", s->svr.qhttps); 3622be9e038Ssthen 3632be9e038Ssthen /* flags */ 3642be9e038Ssthen PR_UL("num.query.flags.QR", s->svr.qbit_QR); 3652be9e038Ssthen PR_UL("num.query.flags.AA", s->svr.qbit_AA); 3662be9e038Ssthen PR_UL("num.query.flags.TC", s->svr.qbit_TC); 3672be9e038Ssthen PR_UL("num.query.flags.RD", s->svr.qbit_RD); 3682be9e038Ssthen PR_UL("num.query.flags.RA", s->svr.qbit_RA); 3692be9e038Ssthen PR_UL("num.query.flags.Z", s->svr.qbit_Z); 3702be9e038Ssthen PR_UL("num.query.flags.AD", s->svr.qbit_AD); 3712be9e038Ssthen PR_UL("num.query.flags.CD", s->svr.qbit_CD); 3722be9e038Ssthen PR_UL("num.query.edns.present", s->svr.qEDNS); 3732be9e038Ssthen PR_UL("num.query.edns.DO", s->svr.qEDNS_DO); 3742be9e038Ssthen 3752be9e038Ssthen /* RCODE */ 3762be9e038Ssthen for(i=0; i<UB_STATS_RCODE_NUM; i++) { 3772be9e038Ssthen /* Always include RCODEs 0-5 */ 3782be9e038Ssthen if(inhibit_zero && i > LDNS_RCODE_REFUSED && s->svr.ans_rcode[i] == 0) 3792be9e038Ssthen continue; 3802be9e038Ssthen sldns_wire2str_rcode_buf(i, nm, sizeof(nm)); 3812be9e038Ssthen PR_UL_SUB("num.answer.rcode", nm, s->svr.ans_rcode[i]); 3822be9e038Ssthen } 3832be9e038Ssthen if(!inhibit_zero || s->svr.ans_rcode_nodata) { 3842be9e038Ssthen PR_UL("num.answer.rcode.nodata", s->svr.ans_rcode_nodata); 3852be9e038Ssthen } 3867191de28Ssthen /* iteration */ 3877191de28Ssthen PR_UL("num.query.ratelimited", s->svr.queries_ratelimited); 3882be9e038Ssthen /* validation */ 3892be9e038Ssthen PR_UL("num.answer.secure", s->svr.ans_secure); 3902be9e038Ssthen PR_UL("num.answer.bogus", s->svr.ans_bogus); 3912be9e038Ssthen PR_UL("num.rrset.bogus", s->svr.rrset_bogus); 39220237c55Ssthen PR_UL("num.query.aggressive.NOERROR", s->svr.num_neg_cache_noerror); 39320237c55Ssthen PR_UL("num.query.aggressive.NXDOMAIN", s->svr.num_neg_cache_nxdomain); 3942be9e038Ssthen /* threat detection */ 3952be9e038Ssthen PR_UL("unwanted.queries", s->svr.unwanted_queries); 3962be9e038Ssthen PR_UL("unwanted.replies", s->svr.unwanted_replies); 3972be9e038Ssthen /* cache counts */ 3982be9e038Ssthen PR_UL("msg.cache.count", s->svr.msg_cache_count); 3992be9e038Ssthen PR_UL("rrset.cache.count", s->svr.rrset_cache_count); 4002be9e038Ssthen PR_UL("infra.cache.count", s->svr.infra_cache_count); 4012be9e038Ssthen PR_UL("key.cache.count", s->svr.key_cache_count); 4028b7325afSsthen /* max collisions */ 4038b7325afSsthen PR_UL("msg.cache.max_collisions", s->svr.msg_cache_max_collisions); 4048b7325afSsthen PR_UL("rrset.cache.max_collisions", s->svr.rrset_cache_max_collisions); 405eaf2578eSsthen /* applied RPZ actions */ 406eaf2578eSsthen for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++) { 407eaf2578eSsthen if(i == RPZ_NO_OVERRIDE_ACTION) 408eaf2578eSsthen continue; 409eaf2578eSsthen if(inhibit_zero && s->svr.rpz_action[i] == 0) 410eaf2578eSsthen continue; 411eaf2578eSsthen PR_UL_SUB("num.rpz.action", rpz_action_to_string(i), s->svr.rpz_action[i]); 412eaf2578eSsthen } 4137191de28Ssthen #ifdef USE_DNSCRYPT 4147191de28Ssthen PR_UL("dnscrypt_shared_secret.cache.count", 4157191de28Ssthen s->svr.shared_secret_cache_count); 4167191de28Ssthen PR_UL("num.query.dnscrypt.shared_secret.cachemiss", 4177191de28Ssthen s->svr.num_query_dnscrypt_secret_missed_cache); 418bdfc4d55Sflorian PR_UL("dnscrypt_nonce.cache.count", s->svr.nonce_cache_count); 419bdfc4d55Sflorian PR_UL("num.query.dnscrypt.replay", 420bdfc4d55Sflorian s->svr.num_query_dnscrypt_replay); 4217191de28Ssthen #endif /* USE_DNSCRYPT */ 42220237c55Ssthen PR_UL("num.query.authzone.up", s->svr.num_query_authzone_up); 42320237c55Ssthen PR_UL("num.query.authzone.down", s->svr.num_query_authzone_down); 4242308e98cSsthen #ifdef CLIENT_SUBNET 4252308e98cSsthen PR_UL("num.query.subnet", s->svr.num_query_subnet); 4262308e98cSsthen PR_UL("num.query.subnet_cache", s->svr.num_query_subnet_cache); 4272308e98cSsthen #endif 4288b7325afSsthen #ifdef USE_CACHEDB 4298b7325afSsthen PR_UL("num.query.cachedb", s->svr.num_query_cachedb); 4308b7325afSsthen #endif 4312be9e038Ssthen } 4322be9e038Ssthen 4332be9e038Ssthen /** print statistics out of memory structures */ 4342be9e038Ssthen static void do_stats_shm(struct config_file* cfg, struct ub_stats_info* stats, 4352be9e038Ssthen struct ub_shm_stat_info* shm_stat) 4362be9e038Ssthen { 4372be9e038Ssthen int i; 4387191de28Ssthen char nm[32]; 4392be9e038Ssthen for(i=0; i<cfg->num_threads; i++) { 4402be9e038Ssthen snprintf(nm, sizeof(nm), "thread%d", i); 4412be9e038Ssthen pr_stats(nm, &stats[i+1]); 4422be9e038Ssthen } 4432be9e038Ssthen pr_stats("total", &stats[0]); 4442be9e038Ssthen print_uptime(shm_stat); 4452be9e038Ssthen if(cfg->stat_extended) { 446f6b99bafSsthen print_mem(shm_stat, &stats[0]); 4472be9e038Ssthen print_hist(stats); 4488b7325afSsthen print_extended(stats, cfg->stat_inhibit_zero); 4492be9e038Ssthen } 4502be9e038Ssthen } 4512be9e038Ssthen #endif /* HAVE_SHMGET */ 4522be9e038Ssthen 4532be9e038Ssthen /** print statistics from shm memory segment */ 4540bdb4f62Ssthen static void print_stats_shm(const char* cfgfile, int quiet) 4552be9e038Ssthen { 4562be9e038Ssthen #ifdef HAVE_SHMGET 4572be9e038Ssthen struct config_file* cfg; 4582be9e038Ssthen struct ub_stats_info* stats; 4592be9e038Ssthen struct ub_shm_stat_info* shm_stat; 4602be9e038Ssthen int id_ctl, id_arr; 4612be9e038Ssthen /* read config */ 4622be9e038Ssthen if(!(cfg = config_create())) 4632be9e038Ssthen fatal_exit("out of memory"); 4642be9e038Ssthen if(!config_read(cfg, cfgfile, NULL)) 4652be9e038Ssthen fatal_exit("could not read config file"); 4662be9e038Ssthen /* get shm segments */ 467ebf5bb73Ssthen id_ctl = shmget(cfg->shm_key, sizeof(int), SHM_R); 4682be9e038Ssthen if(id_ctl == -1) { 4692be9e038Ssthen fatal_exit("shmget(%d): %s", cfg->shm_key, strerror(errno)); 4702be9e038Ssthen } 471ebf5bb73Ssthen id_arr = shmget(cfg->shm_key+1, sizeof(int), SHM_R); 4722be9e038Ssthen if(id_arr == -1) { 4732be9e038Ssthen fatal_exit("shmget(%d): %s", cfg->shm_key+1, strerror(errno)); 4742be9e038Ssthen } 475ebf5bb73Ssthen shm_stat = (struct ub_shm_stat_info*)shmat(id_ctl, NULL, SHM_RDONLY); 4762be9e038Ssthen if(shm_stat == (void*)-1) { 4772be9e038Ssthen fatal_exit("shmat(%d): %s", id_ctl, strerror(errno)); 4782be9e038Ssthen } 479ebf5bb73Ssthen stats = (struct ub_stats_info*)shmat(id_arr, NULL, SHM_RDONLY); 4802be9e038Ssthen if(stats == (void*)-1) { 4812be9e038Ssthen fatal_exit("shmat(%d): %s", id_arr, strerror(errno)); 4822be9e038Ssthen } 4832be9e038Ssthen 4840bdb4f62Ssthen 4850bdb4f62Ssthen if(!quiet) { 4862be9e038Ssthen /* print the stats */ 4872be9e038Ssthen do_stats_shm(cfg, stats, shm_stat); 4880bdb4f62Ssthen } 4892be9e038Ssthen 4902be9e038Ssthen /* shutdown */ 4912be9e038Ssthen shmdt(shm_stat); 4922be9e038Ssthen shmdt(stats); 4932be9e038Ssthen config_delete(cfg); 4942be9e038Ssthen #else 4952be9e038Ssthen (void)cfgfile; 496d1e2768aSsthen (void)quiet; 4972be9e038Ssthen #endif /* HAVE_SHMGET */ 4982be9e038Ssthen } 4992be9e038Ssthen 500933707f3Ssthen /** exit with ssl error */ 501933707f3Ssthen static void ssl_err(const char* s) 502933707f3Ssthen { 503933707f3Ssthen fprintf(stderr, "error: %s\n", s); 504933707f3Ssthen ERR_print_errors_fp(stderr); 505933707f3Ssthen exit(1); 506933707f3Ssthen } 507933707f3Ssthen 5082308e98cSsthen /** exit with ssl error related to a file path */ 5092308e98cSsthen static void ssl_path_err(const char* s, const char *path) 5102308e98cSsthen { 5112308e98cSsthen unsigned long err; 5122308e98cSsthen err = ERR_peek_error(); 513191f22c6Ssthen if(ERR_GET_LIB(err) == ERR_LIB_SYS) { 5142308e98cSsthen fprintf(stderr, "error: %s\n%s: %s\n", 5152308e98cSsthen s, path, ERR_reason_error_string(err)); 5162308e98cSsthen exit(1); 5172308e98cSsthen } else { 5182308e98cSsthen ssl_err(s); 5192308e98cSsthen } 5202308e98cSsthen } 5212308e98cSsthen 522933707f3Ssthen /** setup SSL context */ 523933707f3Ssthen static SSL_CTX* 524933707f3Ssthen setup_ctx(struct config_file* cfg) 525933707f3Ssthen { 526b2cdf21fSsthen char* s_cert=NULL, *c_key=NULL, *c_cert=NULL; 527933707f3Ssthen SSL_CTX* ctx; 528933707f3Ssthen 52920237c55Ssthen if(!(options_remote_is_address(cfg) && cfg->control_use_cert)) 53020237c55Ssthen return NULL; 531933707f3Ssthen s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); 532933707f3Ssthen c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); 533933707f3Ssthen c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); 534933707f3Ssthen if(!s_cert || !c_key || !c_cert) 535933707f3Ssthen fatal_exit("out of memory"); 536933707f3Ssthen ctx = SSL_CTX_new(SSLv23_client_method()); 537933707f3Ssthen if(!ctx) 538933707f3Ssthen ssl_err("could not allocate SSL_CTX pointer"); 539eaf2578eSsthen #if SSL_OP_NO_SSLv2 != 0 5403c667526Sdoug if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) 5413c667526Sdoug != SSL_OP_NO_SSLv2) 542933707f3Ssthen ssl_err("could not set SSL_OP_NO_SSLv2"); 543eaf2578eSsthen #endif 5443c667526Sdoug if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) 5453c667526Sdoug != SSL_OP_NO_SSLv3) 54698f3ca02Sbrad ssl_err("could not set SSL_OP_NO_SSLv3"); 5478240c1b9Ssthen #if defined(SSL_OP_NO_RENEGOTIATION) 5488240c1b9Ssthen /* disable client renegotiation */ 5498240c1b9Ssthen if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) & 5508240c1b9Ssthen SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) 5518240c1b9Ssthen ssl_err("could not set SSL_OP_NO_RENEGOTIATION"); 5528240c1b9Ssthen #endif 5532308e98cSsthen if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert)) 5542308e98cSsthen ssl_path_err("Error setting up SSL_CTX client cert", c_cert); 5552308e98cSsthen if(!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)) 5562308e98cSsthen ssl_path_err("Error setting up SSL_CTX client key", c_key); 5572308e98cSsthen if(!SSL_CTX_check_private_key(ctx)) 5582308e98cSsthen ssl_err("Error setting up SSL_CTX client key"); 559933707f3Ssthen if(SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) 5602308e98cSsthen ssl_path_err("Error setting up SSL_CTX verify, server cert", 5612308e98cSsthen s_cert); 562933707f3Ssthen SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 563933707f3Ssthen 564933707f3Ssthen free(s_cert); 565933707f3Ssthen free(c_key); 566933707f3Ssthen free(c_cert); 567933707f3Ssthen return ctx; 568933707f3Ssthen } 569933707f3Ssthen 5709982a05dSsthen /** check connect error */ 5719982a05dSsthen static void 5729982a05dSsthen checkconnecterr(int err, const char* svr, struct sockaddr_storage* addr, 5739982a05dSsthen socklen_t addrlen, int statuscmd, int useport) 5749982a05dSsthen { 5759982a05dSsthen #ifndef USE_WINSOCK 5769982a05dSsthen if(!useport) log_err("connect: %s for %s", strerror(err), svr); 5779982a05dSsthen else log_err_addr("connect", strerror(err), addr, addrlen); 5789982a05dSsthen if(err == ECONNREFUSED && statuscmd) { 5799982a05dSsthen printf("unbound is stopped\n"); 5809982a05dSsthen exit(3); 5819982a05dSsthen } 5829982a05dSsthen #else 5839982a05dSsthen int wsaerr = err; 5849982a05dSsthen if(!useport) log_err("connect: %s for %s", wsa_strerror(wsaerr), svr); 5859982a05dSsthen else log_err_addr("connect", wsa_strerror(wsaerr), addr, addrlen); 5869982a05dSsthen if(wsaerr == WSAECONNREFUSED && statuscmd) { 5879982a05dSsthen printf("unbound is stopped\n"); 5889982a05dSsthen exit(3); 5899982a05dSsthen } 5909982a05dSsthen #endif 5919982a05dSsthen exit(1); 5929982a05dSsthen } 5939982a05dSsthen 594933707f3Ssthen /** contact the server with TCP connect */ 595933707f3Ssthen static int 596933707f3Ssthen contact_server(const char* svr, struct config_file* cfg, int statuscmd) 597933707f3Ssthen { 598933707f3Ssthen struct sockaddr_storage addr; 599933707f3Ssthen socklen_t addrlen; 60020237c55Ssthen int addrfamily = 0, proto = IPPROTO_TCP; 60120237c55Ssthen int fd, useport = 1; 602191f22c6Ssthen char** rcif = NULL; 603191f22c6Ssthen int num_rcif = 0; 604933707f3Ssthen /* use svr or the first config entry */ 605933707f3Ssthen if(!svr) { 60620237c55Ssthen if(cfg->control_ifs.first) { 607191f22c6Ssthen struct sockaddr_storage addr2; 608191f22c6Ssthen socklen_t addrlen2; 609191f22c6Ssthen if(extstrtoaddr(cfg->control_ifs.first->str, &addr2, 61045872187Ssthen &addrlen2, UNBOUND_DNS_PORT)) { 61120237c55Ssthen svr = cfg->control_ifs.first->str; 612191f22c6Ssthen } else { 613191f22c6Ssthen if(!resolve_interface_names(NULL, 0, 614191f22c6Ssthen cfg->control_ifs.first, &rcif, 615191f22c6Ssthen &num_rcif)) { 616191f22c6Ssthen fatal_exit("could not resolve interface names"); 617191f22c6Ssthen } 618191f22c6Ssthen if(rcif == NULL || num_rcif == 0) { 619191f22c6Ssthen fatal_exit("no control interfaces"); 620191f22c6Ssthen } 621191f22c6Ssthen svr = rcif[0]; 622191f22c6Ssthen } 62377079be7Ssthen } else if(cfg->do_ip4) { 62477079be7Ssthen svr = "127.0.0.1"; 62577079be7Ssthen } else { 62677079be7Ssthen svr = "::1"; 62777079be7Ssthen } 628933707f3Ssthen /* config 0 addr (everything), means ask localhost */ 629933707f3Ssthen if(strcmp(svr, "0.0.0.0") == 0) 630933707f3Ssthen svr = "127.0.0.1"; 631933707f3Ssthen else if(strcmp(svr, "::0") == 0 || 632933707f3Ssthen strcmp(svr, "0::0") == 0 || 633933707f3Ssthen strcmp(svr, "0::") == 0 || 634933707f3Ssthen strcmp(svr, "::") == 0) 635933707f3Ssthen svr = "::1"; 636933707f3Ssthen } 637933707f3Ssthen if(strchr(svr, '@')) { 63845872187Ssthen if(!extstrtoaddr(svr, &addr, &addrlen, UNBOUND_DNS_PORT)) 639933707f3Ssthen fatal_exit("could not parse IP@port: %s", svr); 640b2cdf21fSsthen #ifdef HAVE_SYS_UN_H 641b2cdf21fSsthen } else if(svr[0] == '/') { 642b2cdf21fSsthen struct sockaddr_un* usock = (struct sockaddr_un *) &addr; 643b2cdf21fSsthen usock->sun_family = AF_LOCAL; 644b2cdf21fSsthen #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 64577079be7Ssthen usock->sun_len = (unsigned)sizeof(usock); 646b2cdf21fSsthen #endif 647b2cdf21fSsthen (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path)); 648b2cdf21fSsthen addrlen = (socklen_t)sizeof(struct sockaddr_un); 649b2cdf21fSsthen addrfamily = AF_LOCAL; 65020237c55Ssthen useport = 0; 65120237c55Ssthen proto = 0; 652b2cdf21fSsthen #endif 653933707f3Ssthen } else { 654933707f3Ssthen if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) 655933707f3Ssthen fatal_exit("could not parse IP: %s", svr); 656933707f3Ssthen } 657b2cdf21fSsthen 658b2cdf21fSsthen if(addrfamily == 0) 65920237c55Ssthen addrfamily = addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET; 66020237c55Ssthen fd = socket(addrfamily, SOCK_STREAM, proto); 661933707f3Ssthen if(fd == -1) { 6622c144df0Ssthen fatal_exit("socket: %s", sock_strerror(errno)); 663933707f3Ssthen } 6649982a05dSsthen fd_set_nonblock(fd); 665933707f3Ssthen if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { 666933707f3Ssthen #ifndef USE_WINSOCK 6679982a05dSsthen #ifdef EINPROGRESS 6689982a05dSsthen if(errno != EINPROGRESS) { 6699982a05dSsthen checkconnecterr(errno, svr, &addr, 6709982a05dSsthen addrlen, statuscmd, useport); 671933707f3Ssthen } 672933707f3Ssthen #endif 6739982a05dSsthen #else 6749982a05dSsthen if(WSAGetLastError() != WSAEINPROGRESS && 6759982a05dSsthen WSAGetLastError() != WSAEWOULDBLOCK) { 6769982a05dSsthen checkconnecterr(WSAGetLastError(), svr, &addr, 6779982a05dSsthen addrlen, statuscmd, useport); 678933707f3Ssthen } 6799982a05dSsthen #endif 6809982a05dSsthen } 6819982a05dSsthen while(1) { 6829982a05dSsthen fd_set rset, wset, eset; 6839982a05dSsthen struct timeval tv; 6849982a05dSsthen FD_ZERO(&rset); 6859982a05dSsthen FD_SET(FD_SET_T fd, &rset); 6869982a05dSsthen FD_ZERO(&wset); 6879982a05dSsthen FD_SET(FD_SET_T fd, &wset); 6889982a05dSsthen FD_ZERO(&eset); 6899982a05dSsthen FD_SET(FD_SET_T fd, &eset); 6909982a05dSsthen tv.tv_sec = UNBOUND_CONTROL_CONNECT_TIMEOUT/1000; 6919982a05dSsthen tv.tv_usec= (UNBOUND_CONTROL_CONNECT_TIMEOUT%1000)*1000; 6929982a05dSsthen if(select(fd+1, &rset, &wset, &eset, &tv) == -1) { 6939982a05dSsthen fatal_exit("select: %s", sock_strerror(errno)); 6949982a05dSsthen } 6959982a05dSsthen if(!FD_ISSET(fd, &rset) && !FD_ISSET(fd, &wset) && 6969982a05dSsthen !FD_ISSET(fd, &eset)) { 6979982a05dSsthen fatal_exit("timeout: could not connect to server"); 6989982a05dSsthen } else { 6999982a05dSsthen /* check nonblocking connect error */ 7009982a05dSsthen int error = 0; 7019982a05dSsthen socklen_t len = (socklen_t)sizeof(error); 7029982a05dSsthen if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error, 7039982a05dSsthen &len) < 0) { 7049982a05dSsthen #ifndef USE_WINSOCK 7059982a05dSsthen error = errno; /* on solaris errno is error */ 7069982a05dSsthen #else 7079982a05dSsthen error = WSAGetLastError(); 7089982a05dSsthen #endif 7099982a05dSsthen } 7109982a05dSsthen if(error != 0) { 7119982a05dSsthen #ifndef USE_WINSOCK 7129982a05dSsthen #ifdef EINPROGRESS 7139982a05dSsthen if(error == EINPROGRESS) 7149982a05dSsthen continue; /* try again later */ 7159982a05dSsthen #endif 7169982a05dSsthen #ifdef EWOULDBLOCK 7179982a05dSsthen if(error == EWOULDBLOCK) 7189982a05dSsthen continue; /* try again later */ 7199982a05dSsthen #endif 7209982a05dSsthen #else 7219982a05dSsthen if(error == WSAEINPROGRESS) 7229982a05dSsthen continue; /* try again later */ 7239982a05dSsthen if(error == WSAEWOULDBLOCK) 7249982a05dSsthen continue; /* try again later */ 7259982a05dSsthen #endif 7269982a05dSsthen checkconnecterr(error, svr, &addr, addrlen, 7279982a05dSsthen statuscmd, useport); 7289982a05dSsthen } 7299982a05dSsthen } 7309982a05dSsthen break; 7319982a05dSsthen } 7329982a05dSsthen fd_set_block(fd); 733191f22c6Ssthen config_del_strarray(rcif, num_rcif); 734933707f3Ssthen return fd; 735933707f3Ssthen } 736933707f3Ssthen 737933707f3Ssthen /** setup SSL on the connection */ 738933707f3Ssthen static SSL* 73920237c55Ssthen setup_ssl(SSL_CTX* ctx, int fd) 740933707f3Ssthen { 741933707f3Ssthen SSL* ssl; 742933707f3Ssthen X509* x; 743933707f3Ssthen int r; 744933707f3Ssthen 74520237c55Ssthen if(!ctx) return NULL; 746933707f3Ssthen ssl = SSL_new(ctx); 747933707f3Ssthen if(!ssl) 748933707f3Ssthen ssl_err("could not SSL_new"); 749933707f3Ssthen SSL_set_connect_state(ssl); 750ebf5bb73Ssthen (void)SSL_set_mode(ssl, (long)SSL_MODE_AUTO_RETRY); 751933707f3Ssthen if(!SSL_set_fd(ssl, fd)) 752933707f3Ssthen ssl_err("could not SSL_set_fd"); 753933707f3Ssthen while(1) { 754933707f3Ssthen ERR_clear_error(); 755933707f3Ssthen if( (r=SSL_do_handshake(ssl)) == 1) 756933707f3Ssthen break; 757933707f3Ssthen r = SSL_get_error(ssl, r); 758933707f3Ssthen if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) 759933707f3Ssthen ssl_err("SSL handshake failed"); 760933707f3Ssthen /* wants to be called again */ 761933707f3Ssthen } 762933707f3Ssthen 763933707f3Ssthen /* check authenticity of server */ 764933707f3Ssthen if(SSL_get_verify_result(ssl) != X509_V_OK) 765933707f3Ssthen ssl_err("SSL verification failed"); 766*98bc733bSsthen #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE 767*98bc733bSsthen x = SSL_get1_peer_certificate(ssl); 768*98bc733bSsthen #else 769933707f3Ssthen x = SSL_get_peer_certificate(ssl); 770*98bc733bSsthen #endif 771933707f3Ssthen if(!x) 772933707f3Ssthen ssl_err("Server presented no peer certificate"); 773933707f3Ssthen X509_free(x); 774b2cdf21fSsthen 775933707f3Ssthen return ssl; 776933707f3Ssthen } 777933707f3Ssthen 77820237c55Ssthen /** read from ssl or fd, fatalexit on error, 0 EOF, 1 success */ 77920237c55Ssthen static int 78020237c55Ssthen remote_read(SSL* ssl, int fd, char* buf, size_t len) 78120237c55Ssthen { 78220237c55Ssthen if(ssl) { 78320237c55Ssthen int r; 78420237c55Ssthen ERR_clear_error(); 78520237c55Ssthen if((r = SSL_read(ssl, buf, (int)len-1)) <= 0) { 78620237c55Ssthen if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 78720237c55Ssthen /* EOF */ 78820237c55Ssthen return 0; 78920237c55Ssthen } 79020237c55Ssthen ssl_err("could not SSL_read"); 79120237c55Ssthen } 79220237c55Ssthen buf[r] = 0; 79320237c55Ssthen } else { 79420237c55Ssthen ssize_t rr = recv(fd, buf, len-1, 0); 79520237c55Ssthen if(rr <= 0) { 79620237c55Ssthen if(rr == 0) { 79720237c55Ssthen /* EOF */ 79820237c55Ssthen return 0; 79920237c55Ssthen } 8002c144df0Ssthen fatal_exit("could not recv: %s", sock_strerror(errno)); 80120237c55Ssthen } 80220237c55Ssthen buf[rr] = 0; 80320237c55Ssthen } 80420237c55Ssthen return 1; 80520237c55Ssthen } 80620237c55Ssthen 80720237c55Ssthen /** write to ssl or fd, fatalexit on error */ 80820237c55Ssthen static void 80920237c55Ssthen remote_write(SSL* ssl, int fd, const char* buf, size_t len) 81020237c55Ssthen { 81120237c55Ssthen if(ssl) { 81220237c55Ssthen if(SSL_write(ssl, buf, (int)len) <= 0) 81320237c55Ssthen ssl_err("could not SSL_write"); 81420237c55Ssthen } else { 81520237c55Ssthen if(send(fd, buf, len, 0) < (ssize_t)len) { 8162c144df0Ssthen fatal_exit("could not send: %s", sock_strerror(errno)); 81720237c55Ssthen } 81820237c55Ssthen } 81920237c55Ssthen } 82020237c55Ssthen 821ebf5bb73Ssthen /** check args, to see if too many args. Because when a file is sent it 822ebf5bb73Ssthen * would wait for the terminal, and we can check for too many arguments, 823ebf5bb73Ssthen * eg. user put arguments on the commandline. */ 824ebf5bb73Ssthen static void 825ebf5bb73Ssthen check_args_for_listcmd(int argc, char* argv[]) 826ebf5bb73Ssthen { 827ebf5bb73Ssthen if(argc >= 1 && (strcmp(argv[0], "local_zones") == 0 || 828ebf5bb73Ssthen strcmp(argv[0], "local_zones_remove") == 0 || 829ebf5bb73Ssthen strcmp(argv[0], "local_datas") == 0 || 830ebf5bb73Ssthen strcmp(argv[0], "local_datas_remove") == 0) && 831ebf5bb73Ssthen argc >= 2) { 832ebf5bb73Ssthen fatal_exit("too many arguments for command '%s', " 833ebf5bb73Ssthen "content is piped in from stdin", argv[0]); 834ebf5bb73Ssthen } 835eaf2578eSsthen if(argc >= 1 && (strcmp(argv[0], "view_local_datas") == 0 || 836eaf2578eSsthen strcmp(argv[0], "view_local_datas_remove") == 0) && 837ebf5bb73Ssthen argc >= 3) { 838ebf5bb73Ssthen fatal_exit("too many arguments for command '%s', " 839ebf5bb73Ssthen "content is piped in from stdin", argv[0]); 840ebf5bb73Ssthen } 841ebf5bb73Ssthen } 842ebf5bb73Ssthen 843933707f3Ssthen /** send stdin to server */ 844933707f3Ssthen static void 84520237c55Ssthen send_file(SSL* ssl, int fd, FILE* in, char* buf, size_t sz) 846933707f3Ssthen { 847933707f3Ssthen while(fgets(buf, (int)sz, in)) { 84820237c55Ssthen remote_write(ssl, fd, buf, strlen(buf)); 849933707f3Ssthen } 850933707f3Ssthen } 851933707f3Ssthen 85277079be7Ssthen /** send end-of-file marker to server */ 85377079be7Ssthen static void 85420237c55Ssthen send_eof(SSL* ssl, int fd) 85577079be7Ssthen { 85677079be7Ssthen char e[] = {0x04, 0x0a}; 85720237c55Ssthen remote_write(ssl, fd, e, sizeof(e)); 85877079be7Ssthen } 85977079be7Ssthen 860933707f3Ssthen /** send command and display result */ 861933707f3Ssthen static int 86220237c55Ssthen go_cmd(SSL* ssl, int fd, int quiet, int argc, char* argv[]) 863933707f3Ssthen { 864933707f3Ssthen char pre[10]; 865933707f3Ssthen const char* space=" "; 866933707f3Ssthen const char* newline="\n"; 867933707f3Ssthen int was_error = 0, first_line = 1; 86820237c55Ssthen int i; 869933707f3Ssthen char buf[1024]; 870933707f3Ssthen snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); 87120237c55Ssthen remote_write(ssl, fd, pre, strlen(pre)); 872933707f3Ssthen for(i=0; i<argc; i++) { 87320237c55Ssthen remote_write(ssl, fd, space, strlen(space)); 87420237c55Ssthen remote_write(ssl, fd, argv[i], strlen(argv[i])); 875933707f3Ssthen } 87620237c55Ssthen remote_write(ssl, fd, newline, strlen(newline)); 877933707f3Ssthen 878933707f3Ssthen if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { 87920237c55Ssthen send_file(ssl, fd, stdin, buf, sizeof(buf)); 880933707f3Ssthen } 8813150e5f6Ssthen else if(argc >= 1 && (strcmp(argv[0], "local_zones") == 0 || 88277079be7Ssthen strcmp(argv[0], "local_zones_remove") == 0 || 88377079be7Ssthen strcmp(argv[0], "local_datas") == 0 || 8843150e5f6Ssthen strcmp(argv[0], "view_local_datas") == 0 || 885eaf2578eSsthen strcmp(argv[0], "local_datas_remove") == 0 || 886eaf2578eSsthen strcmp(argv[0], "view_local_datas_remove") == 0)) { 88720237c55Ssthen send_file(ssl, fd, stdin, buf, sizeof(buf)); 88820237c55Ssthen send_eof(ssl, fd); 88977079be7Ssthen } 890933707f3Ssthen 891933707f3Ssthen while(1) { 89220237c55Ssthen if(remote_read(ssl, fd, buf, sizeof(buf)) == 0) { 89320237c55Ssthen break; /* EOF */ 894933707f3Ssthen } 895229e174cSsthen if(first_line && strncmp(buf, "error", 5) == 0) { 896933707f3Ssthen printf("%s", buf); 897933707f3Ssthen was_error = 1; 8980bdb4f62Ssthen } else if(!quiet) { 899229e174cSsthen printf("%s", buf); 9000bdb4f62Ssthen } 901229e174cSsthen 902933707f3Ssthen first_line = 0; 903933707f3Ssthen } 904933707f3Ssthen return was_error; 905933707f3Ssthen } 906933707f3Ssthen 907933707f3Ssthen /** go ahead and read config, contact server and perform command and display */ 908933707f3Ssthen static int 909229e174cSsthen go(const char* cfgfile, char* svr, int quiet, int argc, char* argv[]) 910933707f3Ssthen { 911933707f3Ssthen struct config_file* cfg; 912933707f3Ssthen int fd, ret; 913933707f3Ssthen SSL_CTX* ctx; 914933707f3Ssthen SSL* ssl; 915933707f3Ssthen 916933707f3Ssthen /* read config */ 917933707f3Ssthen if(!(cfg = config_create())) 918933707f3Ssthen fatal_exit("out of memory"); 919933707f3Ssthen if(!config_read(cfg, cfgfile, NULL)) 920933707f3Ssthen fatal_exit("could not read config file"); 921933707f3Ssthen if(!cfg->remote_control_enable) 922933707f3Ssthen log_warn("control-enable is 'no' in the config file."); 92324893edcSsthen #ifdef UB_ON_WINDOWS 92424893edcSsthen w_config_adjust_directory(cfg); 92524893edcSsthen #endif 926933707f3Ssthen ctx = setup_ctx(cfg); 927933707f3Ssthen 928933707f3Ssthen /* contact server */ 929933707f3Ssthen fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0); 93020237c55Ssthen ssl = setup_ssl(ctx, fd); 931933707f3Ssthen 932933707f3Ssthen /* send command */ 93320237c55Ssthen ret = go_cmd(ssl, fd, quiet, argc, argv); 934933707f3Ssthen 93520237c55Ssthen if(ssl) SSL_free(ssl); 9362c144df0Ssthen sock_close(fd); 93720237c55Ssthen if(ctx) SSL_CTX_free(ctx); 938933707f3Ssthen config_delete(cfg); 939933707f3Ssthen return ret; 940933707f3Ssthen } 941933707f3Ssthen 942933707f3Ssthen /** getopt global, in case header files fail to declare it. */ 943933707f3Ssthen extern int optind; 944933707f3Ssthen /** getopt global, in case header files fail to declare it. */ 945933707f3Ssthen extern char* optarg; 946933707f3Ssthen 947933707f3Ssthen /** Main routine for unbound-control */ 948933707f3Ssthen int main(int argc, char* argv[]) 949933707f3Ssthen { 950933707f3Ssthen int c, ret; 951229e174cSsthen int quiet = 0; 952933707f3Ssthen const char* cfgfile = CONFIGFILE; 953933707f3Ssthen char* svr = NULL; 954933707f3Ssthen #ifdef USE_WINSOCK 955933707f3Ssthen int r; 956933707f3Ssthen WSADATA wsa_data; 957933707f3Ssthen #endif 958933707f3Ssthen #ifdef USE_THREAD_DEBUG 959bdfc4d55Sflorian /* stop the file output from unbound-control, overwrites the servers */ 960933707f3Ssthen extern int check_locking_order; 961933707f3Ssthen check_locking_order = 0; 962933707f3Ssthen #endif /* USE_THREAD_DEBUG */ 963e21c60efSsthen checklock_start(); 964933707f3Ssthen log_ident_set("unbound-control"); 965933707f3Ssthen log_init(NULL, 0, NULL); 966933707f3Ssthen #ifdef USE_WINSOCK 967d8d14d0cSsthen /* use registry config file in preference to compiletime location */ 968d8d14d0cSsthen if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) 969d8d14d0cSsthen cfgfile = CONFIGFILE; 970933707f3Ssthen #endif 9712be9e038Ssthen /* parse the options */ 9722be9e038Ssthen while( (c=getopt(argc, argv, "c:s:qh")) != -1) { 9732be9e038Ssthen switch(c) { 9742be9e038Ssthen case 'c': 9752be9e038Ssthen cfgfile = optarg; 9762be9e038Ssthen break; 9772be9e038Ssthen case 's': 9782be9e038Ssthen svr = optarg; 9792be9e038Ssthen break; 9802be9e038Ssthen case 'q': 9812be9e038Ssthen quiet = 1; 9822be9e038Ssthen break; 9832be9e038Ssthen case '?': 9842be9e038Ssthen case 'h': 9852be9e038Ssthen default: 9862be9e038Ssthen usage(); 9872be9e038Ssthen } 9882be9e038Ssthen } 9892be9e038Ssthen argc -= optind; 9902be9e038Ssthen argv += optind; 9912be9e038Ssthen if(argc == 0) 9922be9e038Ssthen usage(); 9932be9e038Ssthen if(argc >= 1 && strcmp(argv[0], "start")==0) { 9942c144df0Ssthen #if (defined(TARGET_OS_TV) && TARGET_OS_TV) || (defined(TARGET_OS_WATCH) && TARGET_OS_WATCH) 995a3167c07Ssthen fatal_exit("could not exec unbound: %s", 996a3167c07Ssthen strerror(ENOSYS)); 997a3167c07Ssthen #else 9982be9e038Ssthen if(execlp("unbound", "unbound", "-c", cfgfile, 9992be9e038Ssthen (char*)NULL) < 0) { 10002be9e038Ssthen fatal_exit("could not exec unbound: %s", 10012be9e038Ssthen strerror(errno)); 10022be9e038Ssthen } 1003a3167c07Ssthen #endif 10042be9e038Ssthen } 10052be9e038Ssthen if(argc >= 1 && strcmp(argv[0], "stats_shm")==0) { 10060bdb4f62Ssthen print_stats_shm(cfgfile, quiet); 10072be9e038Ssthen return 0; 10082be9e038Ssthen } 1009ebf5bb73Ssthen check_args_for_listcmd(argc, argv); 10102be9e038Ssthen 10112be9e038Ssthen #ifdef USE_WINSOCK 10122be9e038Ssthen if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) 10132be9e038Ssthen fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); 10142be9e038Ssthen #endif 1015933707f3Ssthen 101677079be7Ssthen #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS 1017933707f3Ssthen ERR_load_crypto_strings(); 101877079be7Ssthen #endif 10197191de28Ssthen #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 1020933707f3Ssthen ERR_load_SSL_strings(); 10217191de28Ssthen #endif 102277079be7Ssthen #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) 1023ebf5bb73Ssthen # ifndef S_SPLINT_S 1024933707f3Ssthen OpenSSL_add_all_algorithms(); 1025ebf5bb73Ssthen # endif 102677079be7Ssthen #else 102777079be7Ssthen OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS 102877079be7Ssthen | OPENSSL_INIT_ADD_ALL_DIGESTS 102977079be7Ssthen | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); 103077079be7Ssthen #endif 103177079be7Ssthen #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 1032933707f3Ssthen (void)SSL_library_init(); 103377079be7Ssthen #else 10347191de28Ssthen (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); 103577079be7Ssthen #endif 1036933707f3Ssthen 1037933707f3Ssthen if(!RAND_status()) { 1038933707f3Ssthen /* try to seed it */ 1039933707f3Ssthen unsigned char buf[256]; 10403dcb24b8Ssthen unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid(); 10413dcb24b8Ssthen unsigned int v = seed; 1042933707f3Ssthen size_t i; 1043933707f3Ssthen for(i=0; i<256/sizeof(v); i++) { 1044933707f3Ssthen memmove(buf+i*sizeof(v), &v, sizeof(v)); 1045933707f3Ssthen v = v*seed + (unsigned int)i; 1046933707f3Ssthen } 1047933707f3Ssthen RAND_seed(buf, 256); 1048933707f3Ssthen log_warn("no entropy, seeding openssl PRNG with time\n"); 1049933707f3Ssthen } 1050933707f3Ssthen 1051229e174cSsthen ret = go(cfgfile, svr, quiet, argc, argv); 1052933707f3Ssthen 1053933707f3Ssthen #ifdef USE_WINSOCK 1054933707f3Ssthen WSACleanup(); 1055933707f3Ssthen #endif 1056933707f3Ssthen checklock_stop(); 1057933707f3Ssthen return ret; 1058933707f3Ssthen } 1059