diff options
Diffstat (limited to 'usr.sbin/unbound/daemon/worker.c')
-rw-r--r-- | usr.sbin/unbound/daemon/worker.c | 152 |
1 files changed, 95 insertions, 57 deletions
diff --git a/usr.sbin/unbound/daemon/worker.c b/usr.sbin/unbound/daemon/worker.c index 010c4dc0a28..caefad62140 100644 --- a/usr.sbin/unbound/daemon/worker.c +++ b/usr.sbin/unbound/daemon/worker.c @@ -547,7 +547,8 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, static int apply_respip_action(struct worker* worker, const struct query_info* qinfo, struct respip_client_info* cinfo, struct reply_info* rep, - struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset, + struct sockaddr_storage* addr, socklen_t addrlen, + struct ub_packed_rrset_key** alias_rrset, struct reply_info** encode_repp, struct auth_zones* az) { struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; @@ -574,7 +575,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo, if(actinfo.addrinfo) { respip_inform_print(&actinfo, qinfo->qname, qinfo->qtype, qinfo->qclass, qinfo->local_alias, - repinfo); + addr, addrlen); if(worker->stats.extended && actinfo.rpz_used) { if(actinfo.rpz_disabled) @@ -703,7 +704,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, *alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */ if((worker->daemon->use_response_ip || worker->daemon->use_rpz) && !partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep, - repinfo, alias_rrset, + &repinfo->client_addr, repinfo->client_addrlen, alias_rrset, &encode_rep, worker->env.auth_zones)) { goto bail_out; } else if(partial_rep && @@ -991,12 +992,14 @@ answer_chaos(struct worker* w, struct query_info* qinfo, * @param w: worker * @param qinfo: query info. Pointer into packet buffer. * @param edns: edns info from query. - * @param repinfo: reply info with source address. + * @param addr: client address. + * @param addrlen: client address length. * @param pkt: packet buffer. */ static void -answer_notify(struct worker* w, struct query_info* qinfo, - struct edns_data* edns, sldns_buffer* pkt, struct comm_reply* repinfo) +answer_notify(struct worker* w, struct query_info* qinfo, + struct edns_data* edns, sldns_buffer* pkt, + struct sockaddr_storage* addr, socklen_t addrlen) { int refused = 0; int rcode = LDNS_RCODE_NOERROR; @@ -1005,8 +1008,8 @@ answer_notify(struct worker* w, struct query_info* qinfo, if(!w->env.auth_zones) return; has_serial = auth_zone_parse_notify_serial(pkt, &serial); if(auth_zones_notify(w->env.auth_zones, &w->env, qinfo->qname, - qinfo->qname_len, qinfo->qclass, &repinfo->addr, - repinfo->addrlen, has_serial, serial, &refused)) { + qinfo->qname_len, qinfo->qclass, addr, + addrlen, has_serial, serial, &refused)) { rcode = LDNS_RCODE_NOERROR; } else { if(refused) @@ -1031,7 +1034,7 @@ answer_notify(struct worker* w, struct query_info* qinfo, "servfail for NOTIFY %sfor %s from", sr, zname); else snprintf(buf, sizeof(buf), "received NOTIFY %sfor %s from", sr, zname); - log_addr(VERB_DETAIL, buf, &repinfo->addr, repinfo->addrlen); + log_addr(VERB_DETAIL, buf, addr, addrlen); } edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; @@ -1051,8 +1054,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl, { if(acl == deny) { if(verbosity >= VERB_ALGO) { - log_acl_action("dropped", &repinfo->addr, - repinfo->addrlen, acl, acladdr); + log_acl_action("dropped", &repinfo->client_addr, + repinfo->client_addrlen, acl, acladdr); log_buf(VERB_ALGO, "dropped", c->buffer); } comm_point_drop_reply(repinfo); @@ -1063,8 +1066,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl, size_t opt_rr_mark; if(verbosity >= VERB_ALGO) { - log_acl_action("refused", &repinfo->addr, - repinfo->addrlen, acl, acladdr); + log_acl_action("refused", &repinfo->client_addr, + repinfo->client_addrlen, acl, acladdr); log_buf(VERB_ALGO, "refuse", c->buffer); } @@ -1224,12 +1227,24 @@ deny_refuse(struct comm_point* c, enum acl_access acl, } static int -deny_refuse_all(struct comm_point* c, enum acl_access acl, +deny_refuse_all(struct comm_point* c, enum acl_access* acl, struct worker* worker, struct comm_reply* repinfo, - struct acl_addr* acladdr, int ede) + struct acl_addr** acladdr, int ede, int check_proxy) { - return deny_refuse(c, acl, acl_deny, acl_refuse, worker, repinfo, - acladdr, ede); + if(check_proxy) { + *acladdr = acl_addr_lookup(worker->daemon->acl, + &repinfo->remote_addr, repinfo->remote_addrlen); + } else { + *acladdr = acl_addr_lookup(worker->daemon->acl, + &repinfo->client_addr, repinfo->client_addrlen); + } + /* If there is no ACL based on client IP use the interface ACL. */ + if(!(*acladdr) && c->socket) { + *acladdr = c->socket->acl; + } + *acl = acl_get_control(*acladdr); + return deny_refuse(c, *acl, acl_deny, acl_refuse, worker, repinfo, + *acladdr, ede); } static int @@ -1241,7 +1256,7 @@ deny_refuse_non_local(struct comm_point* c, enum acl_access acl, worker, repinfo, acladdr, ede); } -int +int worker_handle_request(struct comm_point* c, void* arg, int error, struct comm_reply* repinfo) { @@ -1286,16 +1301,16 @@ worker_handle_request(struct comm_point* c, void* arg, int error, if(worker_check_request(c->buffer, worker) != 0) { verbose(VERB_ALGO, "dnscrypt: worker check request: bad query."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, - repinfo->addrlen); + log_addr(VERB_CLIENT,"from",&repinfo->client_addr, + repinfo->client_addrlen); comm_point_drop_reply(repinfo); return 0; } if(!query_info_parse(&qinfo, c->buffer)) { verbose(VERB_ALGO, "dnscrypt: worker parse request: formerror."); - log_addr(VERB_CLIENT, "from", &repinfo->addr, - repinfo->addrlen); + log_addr(VERB_CLIENT, "from", &repinfo->client_addr, + repinfo->client_addrlen); comm_point_drop_reply(repinfo); return 0; } @@ -1323,25 +1338,30 @@ worker_handle_request(struct comm_point* c, void* arg, int error, * sending src (client)/dst (local service) addresses over DNSTAP from incoming request handler */ if(worker->dtenv.log_client_query_messages) { - log_addr(VERB_ALGO, "request from client", &repinfo->addr, repinfo->addrlen); + log_addr(VERB_ALGO, "request from client", &repinfo->client_addr, repinfo->client_addrlen); log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen); - dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer); + dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer); } #endif - acladdr = acl_addr_lookup(worker->daemon->acl, &repinfo->addr, - repinfo->addrlen); - acl = acl_get_control(acladdr); - - if((ret=deny_refuse_all(c, acl, worker, repinfo, acladdr, - worker->env.cfg->ede)) != -1) - { + /* Check deny/refuse ACLs */ + if(repinfo->is_proxied) { + if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr, + worker->env.cfg->ede, 1)) != -1) { + if(ret == 1) + goto send_reply; + return ret; + } + } + if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr, + worker->env.cfg->ede, 0)) != -1) { if(ret == 1) goto send_reply; return ret; } + if((ret=worker_check_request(c->buffer, worker)) != 0) { verbose(VERB_ALGO, "worker check request: bad query."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen); if(ret != -1) { LDNS_QR_SET(sldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); @@ -1353,20 +1373,24 @@ worker_handle_request(struct comm_point* c, void* arg, int error, 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, + /* check if this query should be dropped based on source ip rate limiting + * NOTE: we always check the repinfo->client_address. IP ratelimiting is + * implicitly disabled for proxies. */ + if(!infra_ip_ratelimit_inc(worker->env.infra_cache, + &repinfo->client_addr, repinfo->client_addrlen, *worker->env.now, worker->env.cfg->ip_ratelimit_backoff, c->buffer)) { /* 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) == 0) { - + worker->env.cfg->ip_ratelimit_factor) == 0) { char addrbuf[128]; - addr_to_str(&repinfo->addr, repinfo->addrlen, - addrbuf, sizeof(addrbuf)); - verbose(VERB_QUERY, "ip_ratelimit allowed through for ip address %s because of slip in ip_ratelimit_factor", - addrbuf); + addr_to_str(&repinfo->client_addr, + repinfo->client_addrlen, addrbuf, + sizeof(addrbuf)); + verbose(VERB_QUERY, "ip_ratelimit allowed through for " + "ip address %s because of slip in " + "ip_ratelimit_factor", addrbuf); } else { worker->stats.num_queries_ip_ratelimited++; comm_point_drop_reply(repinfo); @@ -1377,7 +1401,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, /* see if query is in the cache */ if(!query_info_parse(&qinfo, c->buffer)) { verbose(VERB_ALGO, "worker parse request: formerror."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + log_addr(VERB_CLIENT, "from", &repinfo->client_addr, + repinfo->client_addrlen); memset(&qinfo, 0, sizeof(qinfo)); /* zero qinfo.qname */ if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { comm_point_drop_reply(repinfo); @@ -1391,13 +1416,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } if(worker->env.cfg->log_queries) { char ip[128]; - addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); + addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip)); log_query_in(ip, qinfo.qname, qinfo.qtype, qinfo.qclass); } if(qinfo.qtype == LDNS_RR_TYPE_AXFR || qinfo.qtype == LDNS_RR_TYPE_IXFR) { verbose(VERB_ALGO, "worker request: refused zone transfer."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + log_addr(VERB_CLIENT, "from", &repinfo->client_addr, + repinfo->client_addrlen); sldns_buffer_rewind(c->buffer); LDNS_QR_SET(sldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), @@ -1414,7 +1440,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, 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); + log_addr(VERB_CLIENT, "from", &repinfo->client_addr, + repinfo->client_addrlen); if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { comm_point_drop_reply(repinfo); return 0; @@ -1432,7 +1459,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, worker->scratchpad)) != 0) { struct edns_data reply_edns; verbose(VERB_ALGO, "worker parse edns: formerror."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + log_addr(VERB_CLIENT, "from", &repinfo->client_addr, + repinfo->client_addrlen); memset(&reply_edns, 0, sizeof(reply_edns)); reply_edns.edns_present = 1; reply_edns.udp_size = EDNS_ADVERTISED_SIZE; @@ -1454,7 +1482,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, edns.opt_list_inplace_cb_out = NULL; edns.padding_block_size = 0; verbose(VERB_ALGO, "query with bad edns version."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + log_addr(VERB_CLIENT, "from", &repinfo->client_addr, + repinfo->client_addrlen); error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), NULL); @@ -1468,7 +1497,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, worker->daemon->cfg->harden_short_bufsize) { verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored", (int)edns.udp_size); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + log_addr(VERB_CLIENT, "from", &repinfo->client_addr, + repinfo->client_addrlen); edns.udp_size = NORMAL_UDP_SIZE; } } @@ -1477,12 +1507,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error, verbose(VERB_QUERY, "worker request: max UDP reply size modified" " (%d to max-udp-size)", (int)edns.udp_size); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + log_addr(VERB_CLIENT, "from", &repinfo->client_addr, + repinfo->client_addrlen); edns.udp_size = worker->daemon->cfg->max_udp_size; } if(edns.udp_size < LDNS_HEADER_SIZE) { verbose(VERB_ALGO, "worker request: edns is too small."); - log_addr(VERB_CLIENT, "from", &repinfo->addr, repinfo->addrlen); + log_addr(VERB_CLIENT, "from", &repinfo->client_addr, + repinfo->client_addrlen); LDNS_QR_SET(sldns_buffer_begin(c->buffer)); LDNS_TC_SET(sldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), @@ -1506,7 +1538,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } if(LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) == LDNS_PACKET_NOTIFY) { - answer_notify(worker, &qinfo, &edns, c->buffer, repinfo); + answer_notify(worker, &qinfo, &edns, c->buffer, + &repinfo->client_addr, repinfo->client_addrlen); regional_free_all(worker->scratchpad); goto send_reply; } @@ -1582,7 +1615,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, sldns_buffer_read_u16_at(c->buffer, 2), &edns); regional_free_all(worker->scratchpad); log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from", - &repinfo->addr, repinfo->addrlen); + &repinfo->client_addr, repinfo->client_addrlen); goto send_reply; } @@ -1722,9 +1755,9 @@ lookup_cache: if(verbosity >= VERB_CLIENT) { if(c->type == comm_udp) log_addr(VERB_CLIENT, "udp request from", - &repinfo->addr, repinfo->addrlen); + &repinfo->client_addr, repinfo->client_addrlen); else log_addr(VERB_CLIENT, "tcp request from", - &repinfo->addr, repinfo->addrlen); + &repinfo->client_addr, repinfo->client_addrlen); } /* grab a work request structure for this new request */ @@ -1756,8 +1789,8 @@ send_reply_rc: */ if(worker->dtenv.log_client_response_messages) { log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen); - log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen); - dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer); + log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen); + dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer); } #endif if(worker->env.cfg->log_replies) @@ -1769,10 +1802,12 @@ send_reply_rc: /* log original qname, before the local alias was * used to resolve that CNAME to something else */ qinfo.qname = qinfo.local_alias->rrset->rk.dname; - log_reply_info(NO_VERBOSE, &qinfo, &repinfo->addr, repinfo->addrlen, + log_reply_info(NO_VERBOSE, &qinfo, + &repinfo->client_addr, repinfo->client_addrlen, tv, 1, c->buffer); } else { - log_reply_info(NO_VERBOSE, &qinfo, &repinfo->addr, repinfo->addrlen, + log_reply_info(NO_VERBOSE, &qinfo, + &repinfo->client_addr, repinfo->client_addrlen, tv, 1, c->buffer); } } @@ -1904,6 +1939,9 @@ worker_init(struct worker* worker, struct config_file *cfg, #else void* dtenv = NULL; #endif +#ifdef HAVE_GETTID + worker->thread_tid = gettid(); +#endif worker->need_to_exit = 0; worker->base = comm_base_create(do_sigs); if(!worker->base) { |