diff options
Diffstat (limited to 'daemon')
-rw-r--r-- | daemon/acl_list.h | 2 | ||||
-rw-r--r-- | daemon/daemon.c | 19 | ||||
-rw-r--r-- | daemon/remote.c | 49 | ||||
-rw-r--r-- | daemon/stats.c | 7 | ||||
-rw-r--r-- | daemon/stats.h | 2 | ||||
-rw-r--r-- | daemon/unbound.c | 5 | ||||
-rw-r--r-- | daemon/worker.c | 56 | ||||
-rw-r--r-- | daemon/worker.h | 2 |
8 files changed, 131 insertions, 11 deletions
diff --git a/daemon/acl_list.h b/daemon/acl_list.h index ca9fd2d4b9d0..d0d42bfaebf6 100644 --- a/daemon/acl_list.h +++ b/daemon/acl_list.h @@ -76,7 +76,7 @@ struct acl_list { * Tree of the addresses that are allowed/blocked. * contents of type acl_addr. */ - rbtree_t tree; + rbtree_type tree; }; /** diff --git a/daemon/daemon.c b/daemon/daemon.c index 88c695be3163..4cae4380065a 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -88,6 +88,10 @@ #include "sldns/keyraw.h" #include <signal.h> +#ifdef HAVE_SYSTEMD +#include <systemd/sd-daemon.h> +#endif + /** How many quit requests happened. */ static int sig_record_quit = 0; /** How many reload requests happened. */ @@ -175,8 +179,15 @@ static void signal_handling_playback(struct worker* wrk) { #ifdef SIGHUP - if(sig_record_reload) + if(sig_record_reload) { +# ifdef HAVE_SYSTEMD + sd_notify(0, "RELOADING=1"); +# endif worker_sighandler(SIGHUP, wrk); +# ifdef HAVE_SYSTEMD + sd_notify(0, "READY=1"); +# endif + } #endif if(sig_record_quit) worker_sighandler(SIGTERM, wrk); @@ -595,8 +606,14 @@ daemon_fork(struct daemon* daemon) signal_handling_playback(daemon->workers[0]); /* Start resolver service on main thread. */ +#ifdef HAVE_SYSTEMD + sd_notify(0, "READY=1"); +#endif log_info("start of service (%s).", PACKAGE_STRING); worker_work(daemon->workers[0]); +#ifdef HAVE_SYSTEMD + sd_notify(0, "STOPPING=1"); +#endif log_info("service stopped (%s).", PACKAGE_STRING); /* we exited! a signal happened! Stop other threads */ diff --git a/daemon/remote.c b/daemon/remote.c index d4ac833e33d0..681c57906a53 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -381,7 +381,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, if(ip[0] == '/') { /* This looks like a local socket */ - fd = create_local_accept_sock(ip, &noproto); + fd = create_local_accept_sock(ip, &noproto, cfg->use_systemd); /* * Change socket ownership and permissions so users other * than root can access it provided they are in the same @@ -424,7 +424,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, /* open fd */ fd = create_tcp_accept_sock(res, 1, &noproto, 0, - cfg->ip_transparent, 0, cfg->ip_freebind); + cfg->ip_transparent, 0, cfg->ip_freebind, cfg->use_systemd); freeaddrinfo(res); } @@ -762,6 +762,8 @@ print_stats(SSL* ssl, const char* nm, struct stats_info* s) struct timeval avg; if(!ssl_printf(ssl, "%s.num.queries"SQ"%lu\n", nm, (unsigned long)s->svr.num_queries)) return 0; + if(!ssl_printf(ssl, "%s.num.queries_ip_ratelimited"SQ"%lu\n", nm, + (unsigned long)s->svr.num_queries_ip_ratelimited)) return 0; if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%lu\n", nm, (unsigned long)(s->svr.num_queries - s->svr.num_queries_missed_cache))) return 0; @@ -1416,7 +1418,7 @@ static void do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen, uint16_t t, uint16_t c) { - hashvalue_t h; + hashvalue_type h; struct query_info k; rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, t, c, 0); if(t == LDNS_RR_TYPE_SOA) @@ -2559,6 +2561,8 @@ struct ratelimit_list_arg { time_t now; }; +#define ip_ratelimit_list_arg ratelimit_list_arg + /** list items in the ratelimit table */ static void rate_list(struct lruhash_entry* e, void* arg) @@ -2577,6 +2581,24 @@ rate_list(struct lruhash_entry* e, void* arg) ssl_printf(a->ssl, "%s %d limit %d\n", buf, max, lim); } +/** list items in the ip_ratelimit table */ +static void +ip_rate_list(struct lruhash_entry* e, void* arg) +{ + char ip[128]; + struct ip_ratelimit_list_arg* a = (struct ip_ratelimit_list_arg*)arg; + struct ip_rate_key* k = (struct ip_rate_key*)e->key; + struct ip_rate_data* d = (struct ip_rate_data*)e->data; + int lim = infra_ip_ratelimit; + int max = infra_rate_max(d, a->now); + if(a->all == 0) { + if(max < lim) + return; + } + addr_to_str(&k->addr, k->addrlen, ip, sizeof(ip)); + ssl_printf(a->ssl, "%s %d limit %d\n", ip, max, lim); +} + /** do the ratelimit_list command */ static void do_ratelimit_list(SSL* ssl, struct worker* worker, char* arg) @@ -2595,6 +2617,24 @@ do_ratelimit_list(SSL* ssl, struct worker* worker, char* arg) slabhash_traverse(a.infra->domain_rates, 0, rate_list, &a); } +/** do the ip_ratelimit_list command */ +static void +do_ip_ratelimit_list(SSL* ssl, struct worker* worker, char* arg) +{ + struct ip_ratelimit_list_arg a; + a.all = 0; + a.infra = worker->env.infra_cache; + a.now = *worker->env.now; + a.ssl = ssl; + arg = skipwhite(arg); + if(strcmp(arg, "+a") == 0) + a.all = 1; + if(a.infra->client_ip_rates==NULL || + (a.all == 0 && infra_ip_ratelimit == 0)) + return; + slabhash_traverse(a.infra->client_ip_rates, 0, ip_rate_list, &a); +} + /** tell other processes to execute the command */ static void distribute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd) @@ -2673,6 +2713,9 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, } else if(cmdcmp(p, "ratelimit_list", 14)) { do_ratelimit_list(ssl, worker, p+14); return; + } else if(cmdcmp(p, "ip_ratelimit_list", 17)) { + do_ip_ratelimit_list(ssl, worker, p+17); + return; } else if(cmdcmp(p, "stub_add", 8)) { /* must always distribute this cmd */ if(rc) distribute_cmd(rc, ssl, cmd); diff --git a/daemon/stats.c b/daemon/stats.c index 0687c0d24b43..a3c3d738976e 100644 --- a/daemon/stats.c +++ b/daemon/stats.c @@ -102,12 +102,14 @@ void server_stats_log(struct server_stats* stats, struct worker* worker, int threadnum) { log_info("server stats for thread %d: %u queries, " - "%u answers from cache, %u recursions, %u prefetch", + "%u answers from cache, %u recursions, %u prefetch, %u rejected by " + "ip ratelimiting", threadnum, (unsigned)stats->num_queries, (unsigned)(stats->num_queries - stats->num_queries_missed_cache), (unsigned)stats->num_queries_missed_cache, - (unsigned)stats->num_queries_prefetch); + (unsigned)stats->num_queries_prefetch, + (unsigned)stats->num_queries_ip_ratelimited); log_info("server stats for thread %d: requestlist max %u avg %g " "exceeded %u jostled %u", threadnum, (unsigned)stats->max_query_list_size, @@ -226,6 +228,7 @@ void server_stats_reply(struct worker* worker, int reset) void server_stats_add(struct stats_info* total, struct stats_info* a) { total->svr.num_queries += a->svr.num_queries; + total->svr.num_queries_ip_ratelimited += a->svr.num_queries_ip_ratelimited; total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache; total->svr.num_queries_prefetch += a->svr.num_queries_prefetch; total->svr.sum_query_list_size += a->svr.sum_query_list_size; diff --git a/daemon/stats.h b/daemon/stats.h index 6c4178fc5317..0b9d77b427d0 100644 --- a/daemon/stats.h +++ b/daemon/stats.h @@ -63,6 +63,8 @@ struct sldns_buffer; struct server_stats { /** number of queries from clients received. */ size_t num_queries; + /** number of queries that have been dropped/ratelimited by ip. */ + size_t num_queries_ip_ratelimited; /** number of queries that had a cache-miss. */ size_t num_queries_missed_cache; /** number of prefetch queries - cachehits with prefetch */ diff --git a/daemon/unbound.c b/daemon/unbound.c index df9504254922..ba7337d8907a 100644 --- a/daemon/unbound.c +++ b/daemon/unbound.c @@ -264,6 +264,11 @@ apply_settings(struct daemon* daemon, struct config_file* cfg, } daemon_apply_cfg(daemon, cfg); checkrlimits(cfg); + + if (cfg->use_systemd && cfg->do_daemonize) { + log_warn("use-systemd and do-daemonize should not be enabled at the same time"); + } + log_ident_set_fromdefault(cfg, log_default_identity); } diff --git a/daemon/worker.c b/daemon/worker.c index 09a1465423f3..b23bbab95d92 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -566,7 +566,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, edns->bits &= EDNS_DO; if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep, LDNS_RCODE_SERVFAIL, edns, worker->scratchpad)) - return 0; + goto bail_out; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, id, flags, edns); rrset_array_unlock_touch(worker->env.rrset_cache, @@ -599,7 +599,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, edns->bits &= EDNS_DO; if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, rep, (int)(flags&LDNS_RCODE_MASK), edns, worker->scratchpad)) - return 0; + goto bail_out; if(!reply_info_answer_encode(qinfo, rep, id, flags, repinfo->c->buffer, timenow, 1, worker->scratchpad, udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { @@ -787,7 +787,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, { struct worker* worker = (struct worker*)arg; int ret; - hashvalue_t h; + hashvalue_type h; struct lruhash_entry* e; struct query_info qinfo; struct edns_data edns; @@ -825,7 +825,29 @@ worker_handle_request(struct comm_point* c, void* arg, int error, comm_point_drop_reply(repinfo); return 0; } + worker->stats.num_queries++; + + /* check if this query should be dropped based on source ip rate limiting */ + if(!infra_ip_ratelimit_inc(worker->env.infra_cache, repinfo, + *worker->env.now)) { + /* See if we are passed through with slip factor */ + if(worker->env.cfg->ip_ratelimit_factor != 0 && + ub_random_max(worker->env.rnd, + worker->env.cfg->ip_ratelimit_factor) == 1) { + + char addrbuf[128]; + addr_to_str(&repinfo->addr, repinfo->addrlen, + addrbuf, sizeof(addrbuf)); + verbose(VERB_OPS, "ip_ratelimit allowed through for ip address %s ", + addrbuf); + } else { + worker->stats.num_queries_ip_ratelimited++; + comm_point_drop_reply(repinfo); + return 0; + } + } + /* see if query is in the cache */ if(!query_info_parse(&qinfo, c->buffer)) { verbose(VERB_ALGO, "worker parse request: formerror."); @@ -860,6 +882,28 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } goto send_reply; } + if(qinfo.qtype == LDNS_RR_TYPE_OPT || + qinfo.qtype == LDNS_RR_TYPE_TSIG || + qinfo.qtype == LDNS_RR_TYPE_TKEY || + qinfo.qtype == LDNS_RR_TYPE_MAILA || + qinfo.qtype == LDNS_RR_TYPE_MAILB || + (qinfo.qtype >= 128 && qinfo.qtype <= 248)) { + verbose(VERB_ALGO, "worker request: formerror for meta-type."); + log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { + comm_point_drop_reply(repinfo); + return 0; + } + sldns_buffer_rewind(c->buffer); + LDNS_QR_SET(sldns_buffer_begin(c->buffer)); + LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), + LDNS_RCODE_FORMERR); + if(worker->stats.extended) { + worker->stats.qtype[qinfo.qtype]++; + server_stats_insrcode(&worker->stats, c->buffer); + } + goto send_reply; + } if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) { struct edns_data reply_edns; verbose(VERB_ALGO, "worker parse edns: formerror."); @@ -1064,6 +1108,12 @@ send_reply_rc: dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, c->type, c->buffer); #endif + if(worker->env.cfg->log_replies) + { + struct timeval tv = {0, 0}; + log_reply_info(0, &qinfo, &repinfo->addr, repinfo->addrlen, + tv, 1, c->buffer); + } return rc; } diff --git a/daemon/worker.h b/daemon/worker.h index d6c87c80739c..0d7ce9521610 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -85,7 +85,7 @@ struct worker { /** global shared daemon structure */ struct daemon* daemon; /** thread id */ - ub_thread_t thr_id; + ub_thread_type thr_id; /** pipe, for commands for this worker */ struct tube* cmd; /** the event base this worker works with */ |