aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/smallapp/unbound-control.c
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/smallapp/unbound-control.c')
-rw-r--r--external/unbound/smallapp/unbound-control.c378
1 files changed, 346 insertions, 32 deletions
diff --git a/external/unbound/smallapp/unbound-control.c b/external/unbound/smallapp/unbound-control.c
index fac73b099..6cd4e7086 100644
--- a/external/unbound/smallapp/unbound-control.c
+++ b/external/unbound/smallapp/unbound-control.c
@@ -58,14 +58,24 @@
#include "util/config_file.h"
#include "util/locks.h"
#include "util/net_help.h"
+#include "util/shm_side/shm_main.h"
+#include "daemon/stats.h"
+#include "sldns/wire2str.h"
+#include "sldns/pkthdr.h"
+#ifdef HAVE_SYS_IPC_H
+#include "sys/ipc.h"
+#endif
+#ifdef HAVE_SYS_SHM_H
+#include "sys/shm.h"
+#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
/** Give unbound-control usage, and exit (1). */
static void
-usage()
+usage(void)
{
printf("Usage: unbound-control [options] command\n");
printf(" Remote control utility for unbound server.\n");
@@ -81,6 +91,9 @@ usage()
printf(" (this flushes data, stats, requestlist)\n");
printf(" stats print statistics\n");
printf(" stats_noreset peek at statistics\n");
+#ifdef HAVE_SHMGET
+ printf(" stats_shm print statistics using shm\n");
+#endif
printf(" status display status of server\n");
printf(" verbosity <number> change logging detail\n");
printf(" log_reopen close and open the logfile\n");
@@ -89,6 +102,9 @@ usage()
printf(" local_data <RR data...> add local data, for example\n");
printf(" local_data www.example.com A 192.0.2.1\n");
printf(" local_data_remove <name> remove local RR data from name\n");
+ printf(" local_zones, local_zones_remove, local_datas, local_datas_remove\n");
+ printf(" same, but read list from stdin\n");
+ printf(" (one entry per line).\n");
printf(" dump_cache print cache to stdout\n");
printf(" load_cache load cache from stdin\n");
printf(" lookup <name> print nameservers for name\n");
@@ -102,7 +118,7 @@ usage()
printf(" flush_negative flush all negative data\n");
printf(" flush_stats flush statistics, make zero\n");
printf(" flush_requestlist drop queries that are worked on\n");
- printf(" dump_requestlist show what is worked on\n");
+ printf(" dump_requestlist show what is worked on by first thread\n");
printf(" flush_infra [all | ip] remove ping, edns for one IP or all\n");
printf(" dump_infra show ping and edns entries\n");
printf(" set_option opt: val set option to value, no reload\n");
@@ -124,13 +140,270 @@ usage()
printf(" or off to turn off root forwarding\n");
printf(" or give list of ip addresses\n");
printf(" ratelimit_list [+a] list ratelimited domains\n");
+ printf(" ip_ratelimit_list [+a] list ratelimited ip addresses\n");
printf(" +a list all, also not ratelimited\n");
+ printf(" view_list_local_zones view list local-zones in view\n");
+ printf(" view_list_local_data view list local-data RRs in view\n");
+ printf(" view_local_zone view name type add local-zone in view\n");
+ printf(" view_local_zone_remove view name remove local-zone in view\n");
+ printf(" view_local_data view RR... add local-data in view\n");
+ printf(" view_local_data_remove view name remove local-data in view\n");
printf("Version %s\n", PACKAGE_VERSION);
printf("BSD licensed, see LICENSE in source package for details.\n");
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
exit(1);
}
+#ifdef HAVE_SHMGET
+/** what to put on statistics lines between var and value, ": " or "=" */
+#define SQ "="
+/** if true, inhibits a lot of =0 lines from the stats output */
+static const int inhibit_zero = 1;
+/** divide sum of timers to get average */
+static void
+timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d)
+{
+#ifndef S_SPLINT_S
+ size_t leftover;
+ if(d == 0) {
+ avg->tv_sec = 0;
+ avg->tv_usec = 0;
+ return;
+ }
+ avg->tv_sec = sum->tv_sec / d;
+ avg->tv_usec = sum->tv_usec / d;
+ /* handle fraction from seconds divide */
+ leftover = sum->tv_sec - avg->tv_sec*d;
+ avg->tv_usec += (leftover*1000000)/d;
+#endif
+}
+
+/** print unsigned long stats value */
+#define PR_UL_NM(str, var) printf("%s."str SQ"%lu\n", nm, (unsigned long)(var));
+#define PR_UL(str, var) printf(str SQ"%lu\n", (unsigned long)(var));
+#define PR_UL_SUB(str, nm, var) printf(str".%s"SQ"%lu\n", nm, (unsigned long)(var));
+#define PR_TIMEVAL(str, var) printf(str SQ ARG_LL "d.%6.6d\n", \
+ (long long)var.tv_sec, (int)var.tv_usec);
+#define PR_LL(str, var) printf(str SQ ARG_LL"d\n", (long long)(var));
+
+/** print stat block */
+static void pr_stats(const char* nm, struct stats_info* s)
+{
+ struct timeval avg;
+ PR_UL_NM("num.queries", s->svr.num_queries);
+ PR_UL_NM("num.queries_ip_ratelimited",
+ s->svr.num_queries_ip_ratelimited);
+ PR_UL_NM("num.cachehits",
+ s->svr.num_queries - s->svr.num_queries_missed_cache);
+ PR_UL_NM("num.cachemiss", s->svr.num_queries_missed_cache);
+ PR_UL_NM("num.prefetch", s->svr.num_queries_prefetch);
+ PR_UL_NM("num.zero_ttl", s->svr.zero_ttl_responses);
+ PR_UL_NM("num.recursivereplies", s->mesh_replies_sent);
+#ifdef USE_DNSCRYPT
+ PR_UL_NM("num.dnscrypt.crypted", s->svr.num_query_dnscrypt_crypted);
+ PR_UL_NM("num.dnscrypt.cert", s->svr.num_query_dnscrypt_cert);
+ PR_UL_NM("num.dnscrypt.cleartext", s->svr.num_query_dnscrypt_cleartext);
+ PR_UL_NM("num.dnscrypt.malformed",
+ s->svr.num_query_dnscrypt_crypted_malformed);
+#endif
+ printf("%s.requestlist.avg"SQ"%g\n", nm,
+ (s->svr.num_queries_missed_cache+s->svr.num_queries_prefetch)?
+ (double)s->svr.sum_query_list_size/
+ (s->svr.num_queries_missed_cache+
+ s->svr.num_queries_prefetch) : 0.0);
+ PR_UL_NM("requestlist.max", s->svr.max_query_list_size);
+ PR_UL_NM("requestlist.overwritten", s->mesh_jostled);
+ PR_UL_NM("requestlist.exceeded", s->mesh_dropped);
+ PR_UL_NM("requestlist.current.all", s->mesh_num_states);
+ PR_UL_NM("requestlist.current.user", s->mesh_num_reply_states);
+ timeval_divide(&avg, &s->mesh_replies_sum_wait, s->mesh_replies_sent);
+ printf("%s.", nm);
+ PR_TIMEVAL("recursion.time.avg", avg);
+ printf("%s.recursion.time.median"SQ"%g\n", nm, s->mesh_time_median);
+ PR_UL_NM("tcpusage", s->svr.tcp_accept_usage);
+}
+
+/** print uptime */
+static void print_uptime(struct shm_stat_info* shm_stat)
+{
+ PR_TIMEVAL("time.now", shm_stat->time.now);
+ PR_TIMEVAL("time.up", shm_stat->time.up);
+ PR_TIMEVAL("time.elapsed", shm_stat->time.elapsed);
+}
+
+/** print memory usage */
+static void print_mem(struct shm_stat_info* shm_stat)
+{
+ PR_LL("mem.cache.rrset", shm_stat->mem.rrset);
+ PR_LL("mem.cache.message", shm_stat->mem.msg);
+ PR_LL("mem.cache.iterator", shm_stat->mem.iter);
+ PR_LL("mem.cache.validator", shm_stat->mem.val);
+#ifdef CLIENT_SUBNET
+ PR_LL("mem.cache.subnet", shm_stat->mem.subnet);
+#endif
+}
+
+/** print histogram */
+static void print_hist(struct stats_info* s)
+{
+ struct timehist* hist;
+ size_t i;
+ hist = timehist_setup();
+ if(!hist)
+ fatal_exit("out of memory");
+ timehist_import(hist, s->svr.hist, NUM_BUCKETS_HIST);
+ for(i=0; i<hist->num; i++) {
+ printf("histogram.%6.6d.%6.6d.to.%6.6d.%6.6d=%lu\n",
+ (int)hist->buckets[i].lower.tv_sec,
+ (int)hist->buckets[i].lower.tv_usec,
+ (int)hist->buckets[i].upper.tv_sec,
+ (int)hist->buckets[i].upper.tv_usec,
+ (unsigned long)hist->buckets[i].count);
+ }
+ timehist_delete(hist);
+}
+
+/** print extended */
+static void print_extended(struct stats_info* s)
+{
+ int i;
+ char nm[16];
+
+ /* TYPE */
+ for(i=0; i<STATS_QTYPE_NUM; i++) {
+ if(inhibit_zero && s->svr.qtype[i] == 0)
+ continue;
+ sldns_wire2str_type_buf((uint16_t)i, nm, sizeof(nm));
+ PR_UL_SUB("num.query.type", nm, s->svr.qtype[i]);
+ }
+ if(!inhibit_zero || s->svr.qtype_big) {
+ PR_UL("num.query.type.other", s->svr.qtype_big);
+ }
+
+ /* CLASS */
+ for(i=0; i<STATS_QCLASS_NUM; i++) {
+ if(inhibit_zero && s->svr.qclass[i] == 0)
+ continue;
+ sldns_wire2str_class_buf((uint16_t)i, nm, sizeof(nm));
+ PR_UL_SUB("num.query.class", nm, s->svr.qclass[i]);
+ }
+ if(!inhibit_zero || s->svr.qclass_big) {
+ PR_UL("num.query.class.other", s->svr.qclass_big);
+ }
+
+ /* OPCODE */
+ for(i=0; i<STATS_OPCODE_NUM; i++) {
+ if(inhibit_zero && s->svr.qopcode[i] == 0)
+ continue;
+ sldns_wire2str_opcode_buf(i, nm, sizeof(nm));
+ PR_UL_SUB("num.query.opcode", nm, s->svr.qopcode[i]);
+ }
+
+ /* transport */
+ PR_UL("num.query.tcp", s->svr.qtcp);
+ PR_UL("num.query.tcpout", s->svr.qtcp_outgoing);
+ PR_UL("num.query.ipv6", s->svr.qipv6);
+
+ /* flags */
+ PR_UL("num.query.flags.QR", s->svr.qbit_QR);
+ PR_UL("num.query.flags.AA", s->svr.qbit_AA);
+ PR_UL("num.query.flags.TC", s->svr.qbit_TC);
+ PR_UL("num.query.flags.RD", s->svr.qbit_RD);
+ PR_UL("num.query.flags.RA", s->svr.qbit_RA);
+ PR_UL("num.query.flags.Z", s->svr.qbit_Z);
+ PR_UL("num.query.flags.AD", s->svr.qbit_AD);
+ PR_UL("num.query.flags.CD", s->svr.qbit_CD);
+ PR_UL("num.query.edns.present", s->svr.qEDNS);
+ PR_UL("num.query.edns.DO", s->svr.qEDNS_DO);
+
+ /* RCODE */
+ for(i=0; i<STATS_RCODE_NUM; i++) {
+ /* Always include RCODEs 0-5 */
+ if(inhibit_zero && i > LDNS_RCODE_REFUSED && s->svr.ans_rcode[i] == 0)
+ continue;
+ sldns_wire2str_rcode_buf(i, nm, sizeof(nm));
+ PR_UL_SUB("num.answer.rcode", nm, s->svr.ans_rcode[i]);
+ }
+ if(!inhibit_zero || s->svr.ans_rcode_nodata) {
+ PR_UL("num.answer.rcode.nodata", s->svr.ans_rcode_nodata);
+ }
+ /* validation */
+ PR_UL("num.answer.secure", s->svr.ans_secure);
+ PR_UL("num.answer.bogus", s->svr.ans_bogus);
+ PR_UL("num.rrset.bogus", s->svr.rrset_bogus);
+ /* threat detection */
+ PR_UL("unwanted.queries", s->svr.unwanted_queries);
+ PR_UL("unwanted.replies", s->svr.unwanted_replies);
+ /* cache counts */
+ PR_UL("msg.cache.count", s->svr.msg_cache_count);
+ PR_UL("rrset.cache.count", s->svr.rrset_cache_count);
+ PR_UL("infra.cache.count", s->svr.infra_cache_count);
+ PR_UL("key.cache.count", s->svr.key_cache_count);
+}
+
+/** print statistics out of memory structures */
+static void do_stats_shm(struct config_file* cfg, struct stats_info* stats,
+ struct shm_stat_info* shm_stat)
+{
+ int i;
+ char nm[16];
+ for(i=0; i<cfg->num_threads; i++) {
+ snprintf(nm, sizeof(nm), "thread%d", i);
+ pr_stats(nm, &stats[i+1]);
+ }
+ pr_stats("total", &stats[0]);
+ print_uptime(shm_stat);
+ if(cfg->stat_extended) {
+ print_mem(shm_stat);
+ print_hist(stats);
+ print_extended(stats);
+ }
+}
+#endif /* HAVE_SHMGET */
+
+/** print statistics from shm memory segment */
+static void print_stats_shm(const char* cfgfile)
+{
+#ifdef HAVE_SHMGET
+ struct config_file* cfg;
+ struct stats_info* stats;
+ struct shm_stat_info* shm_stat;
+ int id_ctl, id_arr;
+ /* read config */
+ if(!(cfg = config_create()))
+ fatal_exit("out of memory");
+ if(!config_read(cfg, cfgfile, NULL))
+ fatal_exit("could not read config file");
+ /* get shm segments */
+ id_ctl = shmget(cfg->shm_key, sizeof(int), SHM_R|SHM_W);
+ if(id_ctl == -1) {
+ fatal_exit("shmget(%d): %s", cfg->shm_key, strerror(errno));
+ }
+ id_arr = shmget(cfg->shm_key+1, sizeof(int), SHM_R|SHM_W);
+ if(id_arr == -1) {
+ fatal_exit("shmget(%d): %s", cfg->shm_key+1, strerror(errno));
+ }
+ shm_stat = (struct shm_stat_info*)shmat(id_ctl, NULL, 0);
+ if(shm_stat == (void*)-1) {
+ fatal_exit("shmat(%d): %s", id_ctl, strerror(errno));
+ }
+ stats = (struct stats_info*)shmat(id_arr, NULL, 0);
+ if(stats == (void*)-1) {
+ fatal_exit("shmat(%d): %s", id_arr, strerror(errno));
+ }
+
+ /* print the stats */
+ do_stats_shm(cfg, stats, shm_stat);
+
+ /* shutdown */
+ shmdt(shm_stat);
+ shmdt(stats);
+ config_delete(cfg);
+#else
+ (void)cfgfile;
+#endif /* HAVE_SHMGET */
+}
+
/** exit with ssl error */
static void ssl_err(const char* s)
{
@@ -153,13 +426,13 @@ setup_ctx(struct config_file* cfg)
if(!s_cert || !c_key || !c_cert)
fatal_exit("out of memory");
}
- ctx = SSL_CTX_new(SSLv23_client_method());
+ ctx = SSL_CTX_new(SSLv23_client_method());
if(!ctx)
ssl_err("could not allocate SSL_CTX pointer");
- if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
+ if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
!= SSL_OP_NO_SSLv2)
ssl_err("could not set SSL_OP_NO_SSLv2");
- if(cfg->remote_control_use_cert) {
+ if(cfg->remote_control_use_cert) {
if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
!= SSL_OP_NO_SSLv3)
ssl_err("could not set SSL_OP_NO_SSLv3");
@@ -176,7 +449,10 @@ setup_ctx(struct config_file* cfg)
free(c_cert);
} else {
/* Use ciphers that don't require authentication */
- if(!SSL_CTX_set_cipher_list(ctx, "aNULL"))
+#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
+ SSL_CTX_set_security_level(ctx, 0);
+#endif
+ if(!SSL_CTX_set_cipher_list(ctx, "aNULL, eNULL"))
ssl_err("Error setting NULL cipher!");
}
return ctx;
@@ -192,9 +468,13 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
int fd;
/* use svr or the first config entry */
if(!svr) {
- if(cfg->control_ifs)
+ if(cfg->control_ifs) {
svr = cfg->control_ifs->str;
- else svr = "127.0.0.1";
+ } else if(cfg->do_ip4) {
+ svr = "127.0.0.1";
+ } else {
+ svr = "::1";
+ }
/* config 0 addr (everything), means ask localhost */
if(strcmp(svr, "0.0.0.0") == 0)
svr = "127.0.0.1";
@@ -212,7 +492,7 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
struct sockaddr_un* usock = (struct sockaddr_un *) &addr;
usock->sun_family = AF_LOCAL;
#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
- usock->sun_len = (socklen_t)sizeof(usock);
+ usock->sun_len = (unsigned)sizeof(usock);
#endif
(void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path));
addrlen = (socklen_t)sizeof(struct sockaddr_un);
@@ -300,6 +580,15 @@ send_file(SSL* ssl, FILE* in, char* buf, size_t sz)
}
}
+/** send end-of-file marker to server */
+static void
+send_eof(SSL* ssl)
+{
+ char e[] = {0x04, 0x0a};
+ if(SSL_write(ssl, e, (int)sizeof(e)) <= 0)
+ ssl_err("could not SSL_write end-of-file marker");
+}
+
/** send command and display result */
static int
go_cmd(SSL* ssl, int quiet, int argc, char* argv[])
@@ -325,6 +614,13 @@ go_cmd(SSL* ssl, int quiet, int argc, char* argv[])
if(argc == 1 && strcmp(argv[0], "load_cache") == 0) {
send_file(ssl, stdin, buf, sizeof(buf));
}
+ else if(argc == 1 && (strcmp(argv[0], "local_zones") == 0 ||
+ strcmp(argv[0], "local_zones_remove") == 0 ||
+ strcmp(argv[0], "local_datas") == 0 ||
+ strcmp(argv[0], "local_datas_remove") == 0)) {
+ send_file(ssl, stdin, buf, sizeof(buf));
+ send_eof(ssl);
+ }
while(1) {
ERR_clear_error();
@@ -411,32 +707,10 @@ int main(int argc, char* argv[])
log_init(NULL, 0, NULL);
checklock_start();
#ifdef USE_WINSOCK
- if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0)
- fatal_exit("WSAStartup failed: %s", wsa_strerror(r));
/* use registry config file in preference to compiletime location */
if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile")))
cfgfile = CONFIGFILE;
#endif
-
- ERR_load_crypto_strings();
- ERR_load_SSL_strings();
- OpenSSL_add_all_algorithms();
- (void)SSL_library_init();
-
- if(!RAND_status()) {
- /* try to seed it */
- unsigned char buf[256];
- unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid();
- unsigned int v = seed;
- size_t i;
- for(i=0; i<256/sizeof(v); i++) {
- memmove(buf+i*sizeof(v), &v, sizeof(v));
- v = v*seed + (unsigned int)i;
- }
- RAND_seed(buf, 256);
- log_warn("no entropy, seeding openssl PRNG with time\n");
- }
-
/* parse the options */
while( (c=getopt(argc, argv, "c:s:qh")) != -1) {
switch(c) {
@@ -466,11 +740,51 @@ int main(int argc, char* argv[])
strerror(errno));
}
}
+ if(argc >= 1 && strcmp(argv[0], "stats_shm")==0) {
+ print_stats_shm(cfgfile);
+ return 0;
+ }
+
+#ifdef USE_WINSOCK
+ if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0)
+ fatal_exit("WSAStartup failed: %s", wsa_strerror(r));
+#endif
+
+#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
+ ERR_load_crypto_strings();
+#endif
+ ERR_load_SSL_strings();
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
+ OpenSSL_add_all_algorithms();
+#else
+ OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
+ | OPENSSL_INIT_ADD_ALL_DIGESTS
+ | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
+#endif
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
+ (void)SSL_library_init();
+#else
+ (void)OPENSSL_init_ssl(0, NULL);
+#endif
+
+ if(!RAND_status()) {
+ /* try to seed it */
+ unsigned char buf[256];
+ unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid();
+ unsigned int v = seed;
+ size_t i;
+ for(i=0; i<256/sizeof(v); i++) {
+ memmove(buf+i*sizeof(v), &v, sizeof(v));
+ v = v*seed + (unsigned int)i;
+ }
+ RAND_seed(buf, 256);
+ log_warn("no entropy, seeding openssl PRNG with time\n");
+ }
ret = go(cfgfile, svr, quiet, argc, argv);
#ifdef USE_WINSOCK
- WSACleanup();
+ WSACleanup();
#endif
checklock_stop();
return ret;