diff options
author | Cy Schubert <cy@FreeBSD.org> | 2022-02-18 00:05:15 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2022-02-18 00:05:15 +0000 |
commit | 9cf5bc93f6ba1711ae7bf96a982a2b3c8b073a18 (patch) | |
tree | ac738d3541e70099db4c216689c30f0758de951d /contrib/unbound/services | |
parent | 11c4d4b9668c3092838beb168e0bbb3187433748 (diff) | |
parent | 3574dc0bd83e731bba79edc130c0569bf05f7af5 (diff) | |
download | src-9cf5bc93f6ba1711ae7bf96a982a2b3c8b073a18.tar.gz src-9cf5bc93f6ba1711ae7bf96a982a2b3c8b073a18.zip |
unbound: Vendor import 1.15.0
Vendor import GA release of unbound 1.15.0.
MFC after: 2 weeks
Diffstat (limited to 'contrib/unbound/services')
-rw-r--r-- | contrib/unbound/services/cache/infra.c | 66 | ||||
-rw-r--r-- | contrib/unbound/services/cache/infra.h | 14 | ||||
-rw-r--r-- | contrib/unbound/services/listen_dnsport.c | 37 | ||||
-rw-r--r-- | contrib/unbound/services/localzone.c | 102 | ||||
-rw-r--r-- | contrib/unbound/services/outside_network.c | 307 | ||||
-rw-r--r-- | contrib/unbound/services/outside_network.h | 27 | ||||
-rw-r--r-- | contrib/unbound/services/rpz.c | 34 | ||||
-rw-r--r-- | contrib/unbound/services/rpz.h | 2 |
8 files changed, 415 insertions, 174 deletions
diff --git a/contrib/unbound/services/cache/infra.c b/contrib/unbound/services/cache/infra.c index 518e69622f83..252e1e288b35 100644 --- a/contrib/unbound/services/cache/infra.c +++ b/contrib/unbound/services/cache/infra.c @@ -898,8 +898,9 @@ static void infra_ip_create_ratedata(struct infra_cache* infra, slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL); } -/** find the second and return its rate counter, if none, remove oldest */ -static int* infra_rate_find_second(void* data, time_t t) +/** Find the second and return its rate counter. If none and should_add, remove + * oldest to accommodate. Else return none. */ +static int* infra_rate_find_second_or_none(void* data, time_t t, int should_add) { struct rate_data* d = (struct rate_data*)data; int i, oldest; @@ -907,6 +908,7 @@ static int* infra_rate_find_second(void* data, time_t t) if(d->timestamp[i] == t) return &(d->qps[i]); } + if(!should_add) return NULL; /* remove oldest timestamp, and insert it at t with 0 qps */ oldest = 0; for(i=0; i<RATE_WINDOW; i++) { @@ -918,21 +920,41 @@ static int* infra_rate_find_second(void* data, time_t t) return &(d->qps[oldest]); } -int infra_rate_max(void* data, time_t now) +/** find the second and return its rate counter, if none, remove oldest to + * accommodate */ +static int* infra_rate_give_second(void* data, time_t t) +{ + return infra_rate_find_second_or_none(data, t, 1); +} + +/** find the second and return its rate counter only if it exists. Caller + * should check for NULL return value */ +static int* infra_rate_get_second(void* data, time_t t) +{ + return infra_rate_find_second_or_none(data, t, 0); +} + +int infra_rate_max(void* data, time_t now, int backoff) { struct rate_data* d = (struct rate_data*)data; int i, max = 0; for(i=0; i<RATE_WINDOW; i++) { - if(now-d->timestamp[i] <= RATE_WINDOW) { - if(d->qps[i] > max) + if(backoff) { + if(now-d->timestamp[i] <= RATE_WINDOW && + d->qps[i] > max) { max = d->qps[i]; + } + } else { + if(now == d->timestamp[i]) { + return d->qps[i]; + } } } return max; } int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name, - size_t namelen, time_t timenow, struct query_info* qinfo, + size_t namelen, time_t timenow, int backoff, struct query_info* qinfo, struct comm_reply* replylist) { int lim, max; @@ -949,13 +971,13 @@ int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name, /* find or insert ratedata */ entry = infra_find_ratedata(infra, name, namelen, 1); if(entry) { - int premax = infra_rate_max(entry->data, timenow); - int* cur = infra_rate_find_second(entry->data, timenow); + int premax = infra_rate_max(entry->data, timenow, backoff); + int* cur = infra_rate_give_second(entry->data, timenow); (*cur)++; - max = infra_rate_max(entry->data, timenow); + max = infra_rate_max(entry->data, timenow, backoff); lock_rw_unlock(&entry->lock); - if(premax < lim && max >= lim) { + if(premax <= lim && max > lim) { char buf[257], qnm[257], ts[12], cs[12], ip[128]; dname_str(name, buf); dname_str(qinfo->qname, qnm); @@ -970,12 +992,12 @@ int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name, verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s", buf, lim, qnm, cs, ts); } } - return (max < lim); + return (max <= lim); } /* create */ infra_create_ratedata(infra, name, namelen, timenow); - return (1 < lim); + return (1 <= lim); } void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name, @@ -987,14 +1009,19 @@ void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name, return; /* not enabled */ entry = infra_find_ratedata(infra, name, namelen, 1); if(!entry) return; /* not cached */ - cur = infra_rate_find_second(entry->data, timenow); + cur = infra_rate_get_second(entry->data, timenow); + if(cur == NULL) { + /* our timenow is not available anymore; nothing to decrease */ + lock_rw_unlock(&entry->lock); + return; + } if((*cur) > 0) (*cur)--; lock_rw_unlock(&entry->lock); } int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name, - size_t namelen, time_t timenow) + size_t namelen, time_t timenow, int backoff) { struct lruhash_entry* entry; int lim, max; @@ -1010,7 +1037,7 @@ int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name, entry = infra_find_ratedata(infra, name, namelen, 0); if(!entry) return 0; /* not cached */ - max = infra_rate_max(entry->data, timenow); + max = infra_rate_max(entry->data, timenow, backoff); lock_rw_unlock(&entry->lock); return (max >= lim); @@ -1027,7 +1054,8 @@ infra_get_mem(struct infra_cache* infra) } int infra_ip_ratelimit_inc(struct infra_cache* infra, - struct comm_reply* repinfo, time_t timenow, struct sldns_buffer* buffer) + struct comm_reply* repinfo, time_t timenow, int backoff, + struct sldns_buffer* buffer) { int max; struct lruhash_entry* entry; @@ -1039,10 +1067,10 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra, /* find or insert ratedata */ entry = infra_find_ip_ratedata(infra, repinfo, 1); if(entry) { - int premax = infra_rate_max(entry->data, timenow); - int* cur = infra_rate_find_second(entry->data, timenow); + int premax = infra_rate_max(entry->data, timenow, backoff); + int* cur = infra_rate_give_second(entry->data, timenow); (*cur)++; - max = infra_rate_max(entry->data, timenow); + max = infra_rate_max(entry->data, timenow, backoff); lock_rw_unlock(&entry->lock); if(premax < infra_ip_ratelimit && max >= infra_ip_ratelimit) { diff --git a/contrib/unbound/services/cache/infra.h b/contrib/unbound/services/cache/infra.h index 14f97c4c64d3..6a2371aca477 100644 --- a/contrib/unbound/services/cache/infra.h +++ b/contrib/unbound/services/cache/infra.h @@ -368,6 +368,7 @@ long long infra_get_host_rto(struct infra_cache* infra, * @param name: zone name * @param namelen: zone name length * @param timenow: what time it is now. + * @param backoff: if backoff is enabled. * @param qinfo: for logging, query name. * @param replylist: for logging, querier's address (if any). * @return 1 if it could be incremented. 0 if the increment overshot the @@ -375,7 +376,7 @@ long long infra_get_host_rto(struct infra_cache* infra, * Failures like alloc failures are not returned (probably as 1). */ int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name, - size_t namelen, time_t timenow, struct query_info* qinfo, + size_t namelen, time_t timenow, int backoff, struct query_info* qinfo, struct comm_reply* replylist); /** @@ -398,13 +399,15 @@ void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name, * @param name: zone name * @param namelen: zone name length * @param timenow: what time it is now. + * @param backoff: if backoff is enabled. * @return true if exceeded. */ int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name, - size_t namelen, time_t timenow); + size_t namelen, time_t timenow, int backoff); -/** find the maximum rate stored, not too old. 0 if no information. */ -int infra_rate_max(void* data, time_t now); +/** find the maximum rate stored. 0 if no information. + * When backoff is enabled look for the maximum in the whole RATE_WINDOW. */ +int infra_rate_max(void* data, time_t now, int backoff); /** find the ratelimit in qps for a domain. 0 if no limit for domain. */ int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name, @@ -415,11 +418,12 @@ int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name, * @param infra: infra cache * @param repinfo: information about client * @param timenow: what time it is now. + * @param backoff: if backoff is enabled. * @param buffer: with query for logging. * @return 1 if it could be incremented. 0 if the increment overshot the * ratelimit and the query should be dropped. */ int infra_ip_ratelimit_inc(struct infra_cache* infra, - struct comm_reply* repinfo, time_t timenow, + struct comm_reply* repinfo, time_t timenow, int backoff, struct sldns_buffer* buffer); /** diff --git a/contrib/unbound/services/listen_dnsport.c b/contrib/unbound/services/listen_dnsport.c index 6a33fbcdaf7e..983b96f09eec 100644 --- a/contrib/unbound/services/listen_dnsport.c +++ b/contrib/unbound/services/listen_dnsport.c @@ -1370,39 +1370,38 @@ listen_create(struct comm_base* base, struct listen_port* ports, struct comm_point* cp = NULL; if(ports->ftype == listen_type_udp || ports->ftype == listen_type_udp_dnscrypt) - cp = comm_point_create_udp(base, ports->fd, + cp = comm_point_create_udp(base, ports->fd, front->udp_buff, cb, cb_arg, ports->socket); else if(ports->ftype == listen_type_tcp || ports->ftype == listen_type_tcp_dnscrypt) - cp = comm_point_create_tcp(base, ports->fd, + cp = comm_point_create_tcp(base, ports->fd, tcp_accept_count, tcp_idle_timeout, harden_large_queries, 0, NULL, tcp_conn_limit, bufsize, front->udp_buff, ports->ftype, cb, cb_arg, ports->socket); else if(ports->ftype == listen_type_ssl || ports->ftype == listen_type_http) { - cp = comm_point_create_tcp(base, ports->fd, + cp = comm_point_create_tcp(base, ports->fd, tcp_accept_count, tcp_idle_timeout, harden_large_queries, http_max_streams, http_endpoint, tcp_conn_limit, bufsize, front->udp_buff, ports->ftype, cb, cb_arg, ports->socket); - if(http_notls && ports->ftype == listen_type_http) - cp->ssl = NULL; - else - cp->ssl = sslctx; if(ports->ftype == listen_type_http) { if(!sslctx && !http_notls) { - log_warn("HTTPS port configured, but no TLS " - "tls-service-key or tls-service-pem " - "set"); + log_warn("HTTPS port configured, but " + "no TLS tls-service-key or " + "tls-service-pem set"); } #ifndef HAVE_SSL_CTX_SET_ALPN_SELECT_CB - if(!http_notls) - log_warn("Unbound is not compiled with an " - "OpenSSL version supporting ALPN " - " (OpenSSL >= 1.0.2). This is required " - "to use DNS-over-HTTPS"); + if(!http_notls) { + log_warn("Unbound is not compiled " + "with an OpenSSL version " + "supporting ALPN " + "(OpenSSL >= 1.0.2). This " + "is required to use " + "DNS-over-HTTPS"); + } #endif #ifndef HAVE_NGHTTP2_NGHTTP2_H log_warn("Unbound is not compiled with " @@ -1412,13 +1411,17 @@ listen_create(struct comm_base* base, struct listen_port* ports, } } else if(ports->ftype == listen_type_udpancil || ports->ftype == listen_type_udpancil_dnscrypt) - cp = comm_point_create_udp_ancil(base, ports->fd, + cp = comm_point_create_udp_ancil(base, ports->fd, front->udp_buff, cb, cb_arg, ports->socket); if(!cp) { - log_err("can't create commpoint"); + log_err("can't create commpoint"); listen_delete(front); return NULL; } + if(http_notls && ports->ftype == listen_type_http) + cp->ssl = NULL; + else + cp->ssl = sslctx; cp->dtenv = dtenv; cp->do_not_close = 1; #ifdef USE_DNSCRYPT diff --git a/contrib/unbound/services/localzone.c b/contrib/unbound/services/localzone.c index 77d0107f9f6f..3e3a71aea3c5 100644 --- a/contrib/unbound/services/localzone.c +++ b/contrib/unbound/services/localzone.c @@ -56,6 +56,44 @@ * with 16 bytes for an A record, a 64K packet has about 4000 max */ #define LOCALZONE_RRSET_COUNT_MAX 4096 +/** print all RRsets in local zone */ +static void +local_zone_out(struct local_zone* z) +{ + struct local_data* d; + struct local_rrset* p; + RBTREE_FOR(d, struct local_data*, &z->data) { + for(p = d->rrsets; p; p = p->next) { + log_nametypeclass(NO_VERBOSE, "rrset", d->name, + ntohs(p->rrset->rk.type), + ntohs(p->rrset->rk.rrset_class)); + } + } +} + +static void +local_zone_print(struct local_zone* z) +{ + char buf[64]; + lock_rw_rdlock(&z->lock); + snprintf(buf, sizeof(buf), "%s zone", + local_zone_type2str(z->type)); + log_nametypeclass(NO_VERBOSE, buf, z->name, 0, z->dclass); + local_zone_out(z); + lock_rw_unlock(&z->lock); +} + +void local_zones_print(struct local_zones* zones) +{ + struct local_zone* z; + lock_rw_rdlock(&zones->lock); + log_info("number of auth zones %u", (unsigned)zones->ztree.count); + RBTREE_FOR(z, struct local_zone*, &zones->ztree) { + local_zone_print(z); + } + lock_rw_unlock(&zones->lock); +} + struct local_zones* local_zones_create(void) { @@ -1010,6 +1048,38 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg) lock_rw_rdlock(&zones->lock); if(!local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type)) { + /* Check if there is a zone that this could go + * under but for different class; created zones are + * always for LDNS_RR_CLASS_IN. Create the zone with + * a different class but the same configured + * local_zone_type. */ + struct local_zone* z = local_zones_lookup(zones, + rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type); + if(z) { + uint8_t* name = memdup(z->name, z->namelen); + size_t znamelen = z->namelen; + int znamelabs = z->namelabs; + enum localzone_type ztype = z->type; + lock_rw_unlock(&zones->lock); + if(!name) { + log_err("out of memory"); + free(rr_name); + return 0; + } + if(!( +#ifndef THREADS_DISABLED + z = +#endif + lz_enter_zone_dname(zones, name, + znamelen, znamelabs, + ztype, rr_class))) { + free(rr_name); + return 0; + } + lock_rw_unlock(&z->lock); + free(rr_name); + continue; + } if(!have_name) { dclass = rr_class; nm = rr_name; @@ -1220,38 +1290,6 @@ local_zones_find_le(struct local_zones* zones, return (struct local_zone*)node; } -/** print all RRsets in local zone */ -static void -local_zone_out(struct local_zone* z) -{ - struct local_data* d; - struct local_rrset* p; - RBTREE_FOR(d, struct local_data*, &z->data) { - for(p = d->rrsets; p; p = p->next) { - log_nametypeclass(NO_VERBOSE, "rrset", d->name, - ntohs(p->rrset->rk.type), - ntohs(p->rrset->rk.rrset_class)); - } - } -} - -void local_zones_print(struct local_zones* zones) -{ - struct local_zone* z; - lock_rw_rdlock(&zones->lock); - log_info("number of auth zones %u", (unsigned)zones->ztree.count); - RBTREE_FOR(z, struct local_zone*, &zones->ztree) { - char buf[64]; - lock_rw_rdlock(&z->lock); - snprintf(buf, sizeof(buf), "%s zone", - local_zone_type2str(z->type)); - log_nametypeclass(NO_VERBOSE, buf, z->name, 0, z->dclass); - local_zone_out(z); - lock_rw_unlock(&z->lock); - } - lock_rw_unlock(&zones->lock); -} - /** encode answer consisting of 1 rrset */ static int local_encode(struct query_info* qinfo, struct module_env* env, diff --git a/contrib/unbound/services/outside_network.c b/contrib/unbound/services/outside_network.c index f4a5d0707845..a7e5fa3ad583 100644 --- a/contrib/unbound/services/outside_network.c +++ b/contrib/unbound/services/outside_network.c @@ -94,6 +94,16 @@ static void waiting_list_remove(struct outside_network* outnet, static uint16_t tcp_select_id(struct outside_network* outnet, struct reuse_tcp* reuse); +/** Perform serviced query UDP sending operation */ +static int serviced_udp_send(struct serviced_query* sq, sldns_buffer* buff); + +/** Send serviced query over TCP return false on initial failure */ +static int serviced_tcp_send(struct serviced_query* sq, sldns_buffer* buff); + +/** call the callbacks for a serviced query */ +static void serviced_callbacks(struct serviced_query* sq, int error, + struct comm_point* c, struct comm_reply* rep); + int pending_cmp(const void* key1, const void* key2) { @@ -836,6 +846,7 @@ outnet_add_tcp_waiting_first(struct outside_network* outnet, if(w->on_tcp_waiting_list) return; w->next_waiting = outnet->tcp_wait_first; + log_assert(w->next_waiting != w); if(!outnet->tcp_wait_last) outnet->tcp_wait_last = w; outnet->tcp_wait_first = w; @@ -1136,6 +1147,22 @@ static void reuse_cb_readwait_for_failure(rbtree_type* tree_by_id, int err) } } +/** mark the entry for being in the cb_and_decommission stage */ +static void mark_for_cb_and_decommission(rbnode_type* node, + void* ATTR_UNUSED(arg)) +{ + struct waiting_tcp* w = (struct waiting_tcp*)node->key; + /* Mark the waiting_tcp to signal later code (serviced_delete) that + * this item is part of the backed up tree_by_id and will be deleted + * later. */ + w->in_cb_and_decommission = 1; + /* Mark the serviced_query for deletion so that later code through + * callbacks (iter_clear .. outnet_serviced_query_stop) won't + * prematurely delete it. */ + if(w->cb) + ((struct serviced_query*)w->cb_arg)->to_be_deleted = 1; +} + /** perform callbacks for failure and also decommission pending tcp. * the callbacks remove references in sq->pending to the waiting_tcp * members of the tree_by_id in the pending tcp. The pending_tcp is @@ -1151,6 +1178,9 @@ static void reuse_cb_and_decommission(struct outside_network* outnet, pend->reuse.write_wait_first = NULL; pend->reuse.write_wait_last = NULL; decommission_pending_tcp(outnet, pend); + if(store.root != NULL && store.root != RBTREE_NULL) { + traverse_postorder(&store, &mark_for_cb_and_decommission, NULL); + } reuse_cb_readwait_for_failure(&store, error); reuse_del_readwait(&store); } @@ -1248,6 +1278,12 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error, c->buffer)); /* find the query the reply is for */ w = reuse_tcp_by_id_find(&pend->reuse, id); + /* Make sure that the reply we got is at least for a + * sent query with the same ID; the waiting_tcp that + * gets a reply is assumed to not be waiting to be + * sent. */ + if(w && (w->on_tcp_waiting_list || w->write_wait_queued)) + w = NULL; } } if(error == NETEVENT_NOERROR && !w) { @@ -1265,6 +1301,8 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error, } } if(w) { + log_assert(!w->on_tcp_waiting_list); + log_assert(!w->write_wait_queued); reuse_tree_by_id_delete(&pend->reuse, w); verbose(VERB_CLIENT, "outnet tcp callback query err %d buflen %d", error, (int)sldns_buffer_limit(c->buffer)); @@ -1324,7 +1362,7 @@ outnet_send_wait_udp(struct outside_network* outnet) { struct pending* pend; /* process waiting queries */ - while(outnet->udp_wait_first && outnet->unused_fds + while(outnet->udp_wait_first && outnet->unused_fds && !outnet->want_to_quit) { pend = outnet->udp_wait_first; outnet->udp_wait_first = pend->next_waiting; @@ -1333,8 +1371,10 @@ outnet_send_wait_udp(struct outside_network* outnet) sldns_buffer_write(outnet->udp_buff, pend->pkt, pend->pkt_len); sldns_buffer_flip(outnet->udp_buff); free(pend->pkt); /* freeing now makes get_mem correct */ - pend->pkt = NULL; + pend->pkt = NULL; pend->pkt_len = 0; + log_assert(!pend->sq->busy); + pend->sq->busy = 1; if(!randomize_and_send_udp(pend, outnet->udp_buff, pend->timeout)) { /* callback error on pending */ @@ -1344,6 +1384,8 @@ outnet_send_wait_udp(struct outside_network* outnet) NETEVENT_CLOSED, NULL); } pending_delete(outnet, pend); + } else { + pend->sq->busy = 0; } } } @@ -1454,7 +1496,6 @@ calc_num46(char** ifs, int num_ifs, int do_ip4, int do_ip6, (*num_ip4)++; } } - } void @@ -1708,16 +1749,9 @@ static void serviced_node_del(rbnode_type* node, void* ATTR_UNUSED(arg)) { struct serviced_query* sq = (struct serviced_query*)node; - struct service_callback* p = sq->cblist, *np; - free(sq->qbuf); - free(sq->zone); - free(sq->tls_auth_name); - edns_opt_list_free(sq->opt_list); - while(p) { - np = p->next; - free(p); - p = np; - } + alloc_reg_release(sq->alloc, sq->region); + if(sq->timer) + comm_timer_delete(sq->timer); free(sq); } @@ -2174,10 +2208,13 @@ pending_udp_query(struct serviced_query* sq, struct sldns_buffer* packet, sq->outnet->udp_wait_last = pend; return pend; } + log_assert(!sq->busy); + sq->busy = 1; if(!randomize_and_send_udp(pend, packet, timeout)) { pending_delete(sq->outnet, pend); return NULL; } + sq->busy = 0; return pend; } @@ -2247,7 +2284,7 @@ reuse_tcp_select_id(struct reuse_tcp* reuse, struct outside_network* outnet) } /* equally pick a random unused element from the tree that is - * not in use. Pick a the n-th index of an ununused number, + * not in use. Pick a the n-th index of an unused number, * then loop over the empty spaces in the tree and find it */ log_assert(reuse->tree_by_id.count < 0xffff); select = ub_random_max(outnet->rnd, 0xffff - reuse->tree_by_id.count); @@ -2360,6 +2397,7 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet, #ifdef USE_DNSTAP w->sq = NULL; #endif + w->in_cb_and_decommission = 0; if(pend) { /* we have a buffer available right now */ if(reuse) { @@ -2456,30 +2494,62 @@ lookup_serviced(struct outside_network* outnet, sldns_buffer* buff, int dnssec, return (struct serviced_query*)rbtree_search(outnet->serviced, &key); } +void +serviced_timer_cb(void* arg) +{ + struct serviced_query* sq = (struct serviced_query*)arg; + struct outside_network* outnet = sq->outnet; + verbose(VERB_ALGO, "serviced send timer"); + /* By the time this cb is called, if we don't have any registered + * callbacks for this serviced_query anymore; do not send. */ + if(!sq->cblist) + goto delete; + /* perform first network action */ + if(outnet->do_udp && !(sq->tcp_upstream || sq->ssl_upstream)) { + if(!serviced_udp_send(sq, outnet->udp_buff)) + goto delete; + } else { + if(!serviced_tcp_send(sq, outnet->udp_buff)) + goto delete; + } + /* Maybe by this time we don't have callbacks attached anymore. Don't + * proactively try to delete; let it run and maybe another callback + * will get attached by the time we get an answer. */ + return; +delete: + serviced_callbacks(sq, NETEVENT_CLOSED, NULL, NULL); +} + /** Create new serviced entry */ static struct serviced_query* serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec, int want_dnssec, int nocaps, int tcp_upstream, int ssl_upstream, char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int qtype, struct edns_option* opt_list, - size_t pad_queries_block_size) + size_t pad_queries_block_size, struct alloc_cache* alloc, + struct regional* region) { struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq)); + struct timeval t; #ifdef UNBOUND_DEBUG rbnode_type* ins; #endif if(!sq) return NULL; sq->node.key = sq; - sq->qbuf = memdup(sldns_buffer_begin(buff), sldns_buffer_limit(buff)); + sq->alloc = alloc; + sq->region = region; + sq->qbuf = regional_alloc_init(region, sldns_buffer_begin(buff), + sldns_buffer_limit(buff)); if(!sq->qbuf) { + alloc_reg_release(alloc, region); free(sq); return NULL; } sq->qbuflen = sldns_buffer_limit(buff); - sq->zone = memdup(zone, zonelen); + sq->zone = regional_alloc_init(region, zone, zonelen); if(!sq->zone) { - free(sq->qbuf); + alloc_reg_release(alloc, region); free(sq); return NULL; } @@ -2491,10 +2561,9 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec, sq->tcp_upstream = tcp_upstream; sq->ssl_upstream = ssl_upstream; if(tls_auth_name) { - sq->tls_auth_name = strdup(tls_auth_name); + sq->tls_auth_name = regional_strdup(region, tls_auth_name); if(!sq->tls_auth_name) { - free(sq->zone); - free(sq->qbuf); + alloc_reg_release(alloc, region); free(sq); return NULL; } @@ -2503,17 +2572,16 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec, } memcpy(&sq->addr, addr, addrlen); sq->addrlen = addrlen; - sq->opt_list = NULL; - if(opt_list) { - sq->opt_list = edns_opt_copy_alloc(opt_list); - if(!sq->opt_list) { - free(sq->tls_auth_name); - free(sq->zone); - free(sq->qbuf); - free(sq); - return NULL; - } + sq->opt_list = opt_list; + sq->busy = 0; + sq->timer = comm_timer_create(outnet->base, serviced_timer_cb, sq); + if(!sq->timer) { + alloc_reg_release(alloc, region); + free(sq); + return NULL; } + memset(&t, 0, sizeof(t)); + comm_timer_set(sq->timer, &t); sq->outnet = outnet; sq->cblist = NULL; sq->pending = NULL; @@ -2522,7 +2590,7 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec, sq->to_be_deleted = 0; sq->padding_block_size = pad_queries_block_size; #ifdef UNBOUND_DEBUG - ins = + ins = #else (void) #endif @@ -2620,29 +2688,38 @@ serviced_delete(struct serviced_query* sq) struct waiting_tcp* w = (struct waiting_tcp*) sq->pending; verbose(VERB_CLIENT, "serviced_delete: TCP"); + log_assert(!(w->write_wait_queued && w->on_tcp_waiting_list)); /* if on stream-write-waiting list then * remove from waiting list and waiting_tcp_delete */ if(w->write_wait_queued) { struct pending_tcp* pend = (struct pending_tcp*)w->next_waiting; verbose(VERB_CLIENT, "serviced_delete: writewait"); - reuse_tree_by_id_delete(&pend->reuse, w); + if(!w->in_cb_and_decommission) + reuse_tree_by_id_delete(&pend->reuse, w); reuse_write_wait_remove(&pend->reuse, w); - waiting_tcp_delete(w); + if(!w->in_cb_and_decommission) + waiting_tcp_delete(w); } else if(!w->on_tcp_waiting_list) { struct pending_tcp* pend = (struct pending_tcp*)w->next_waiting; verbose(VERB_CLIENT, "serviced_delete: tcpreusekeep"); + /* w needs to stay on tree_by_id to not assign + * the same ID; remove the callback since its + * serviced_query will be gone. */ + w->cb = NULL; if(!reuse_tcp_remove_serviced_keep(w, sq)) { - reuse_cb_and_decommission(sq->outnet, - pend, NETEVENT_CLOSED); + if(!w->in_cb_and_decommission) + reuse_cb_and_decommission(sq->outnet, + pend, NETEVENT_CLOSED); use_free_buffer(sq->outnet); } sq->pending = NULL; } else { verbose(VERB_CLIENT, "serviced_delete: tcpwait"); waiting_list_remove(sq->outnet, w); - waiting_tcp_delete(w); + if(!w->in_cb_and_decommission) + waiting_tcp_delete(w); } } } @@ -2892,7 +2969,8 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c, * use secondary buffer to store the query. * This is a data copy, but faster than packet to server */ backlen = sldns_buffer_limit(c->buffer); - backup_p = memdup(sldns_buffer_begin(c->buffer), backlen); + backup_p = regional_alloc_init(sq->region, + sldns_buffer_begin(c->buffer), backlen); if(!backup_p) { log_err("malloc failure in serviced query callbacks"); error = NETEVENT_CLOSED; @@ -2910,10 +2988,8 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c, } fptr_ok(fptr_whitelist_serviced_query(p->cb)); (void)(*p->cb)(c, p->cb_arg, error, rep); - free(p); } if(backup_p) { - free(backup_p); sq->outnet->svcd_overhead = 0; } verbose(VERB_ALGO, "svcd callbacks end"); @@ -2931,7 +3007,7 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error, struct waiting_tcp* w = (struct waiting_tcp*)sq->pending; struct pending_tcp* pend_tcp = NULL; struct port_if* pi = NULL; - if(!w->on_tcp_waiting_list && w->next_waiting) { + if(w && !w->on_tcp_waiting_list && w->next_waiting) { pend_tcp = (struct pending_tcp*)w->next_waiting; pi = pend_tcp->pi; } @@ -3027,8 +3103,11 @@ serviced_tcp_initiate(struct serviced_query* sq, sldns_buffer* buff) sq->status==serviced_query_TCP_EDNS?"EDNS":""); serviced_encode(sq, buff, sq->status == serviced_query_TCP_EDNS); sq->last_sent_time = *sq->outnet->now_tv; + log_assert(!sq->busy); + sq->busy = 1; sq->pending = pending_tcp_query(sq, buff, sq->outnet->tcp_auth_query_timeout, serviced_tcp_callback, sq); + sq->busy = 0; if(!sq->pending) { /* delete from tree so that a retry by above layer does not * clash with this entry */ @@ -3060,8 +3139,11 @@ serviced_tcp_send(struct serviced_query* sq, sldns_buffer* buff) } else { timeout = sq->outnet->tcp_auth_query_timeout; } + log_assert(!sq->busy); + sq->busy = 1; sq->pending = pending_tcp_query(sq, buff, timeout, serviced_tcp_callback, sq); + sq->busy = 0; return sq->pending != NULL; } @@ -3112,7 +3194,6 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, struct timeval now = *sq->outnet->now_tv; #ifdef USE_DNSTAP struct pending* p = (struct pending*)sq->pending; - struct port_if* pi = p->pc->pif; #endif sq->pending = NULL; /* removed after callback */ @@ -3154,14 +3235,16 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, /* * sending src (local service)/dst (upstream) addresses over DNSTAP */ - if(error == NETEVENT_NOERROR && outnet->dtenv && - (outnet->dtenv->log_resolver_response_messages || - outnet->dtenv->log_forwarder_response_messages)) { + if(error == NETEVENT_NOERROR && outnet->dtenv && p->pc && + (outnet->dtenv->log_resolver_response_messages || + outnet->dtenv->log_forwarder_response_messages)) { log_addr(VERB_ALGO, "response from upstream", &sq->addr, sq->addrlen); - log_addr(VERB_ALGO, "to local addr", &pi->addr, pi->addrlen); - dt_msg_send_outside_response(outnet->dtenv, &sq->addr, &pi->addr, c->type, - sq->zone, sq->zonelen, sq->qbuf, sq->qbuflen, - &sq->last_sent_time, sq->outnet->now_tv, c->buffer); + log_addr(VERB_ALGO, "to local addr", &p->pc->pif->addr, + p->pc->pif->addrlen); + dt_msg_send_outside_response(outnet->dtenv, &sq->addr, + &p->pc->pif->addr, c->type, sq->zone, sq->zonelen, + sq->qbuf, sq->qbuflen, &sq->last_sent_time, + sq->outnet->now_tv, c->buffer); } #endif if( (sq->status == serviced_query_UDP_EDNS @@ -3251,64 +3334,117 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, struct serviced_query* outnet_serviced_query(struct outside_network* outnet, struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec, - int nocaps, int tcp_upstream, int ssl_upstream, char* tls_auth_name, - struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, struct module_qstate* qstate, - comm_point_callback_type* callback, void* callback_arg, sldns_buffer* buff, - struct module_env* env) + int nocaps, int check_ratelimit, int tcp_upstream, int ssl_upstream, + char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, struct module_qstate* qstate, + comm_point_callback_type* callback, void* callback_arg, + sldns_buffer* buff, struct module_env* env, int* was_ratelimited) { struct serviced_query* sq; struct service_callback* cb; struct edns_string_addr* client_string_addr; - - if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen, zone, zonelen, - qstate, qstate->region)) + struct regional* region; + struct edns_option* backed_up_opt_list = qstate->edns_opts_back_out; + struct edns_option* per_upstream_opt_list = NULL; + time_t timenow = 0; + + /* If we have an already populated EDNS option list make a copy since + * we may now add upstream specific EDNS options. */ + /* Use a region that could be attached to a serviced_query, if it needs + * to be created. If an existing one is found then this region will be + * destroyed here. */ + region = alloc_reg_obtain(env->alloc); + if(!region) return NULL; + if(qstate->edns_opts_back_out) { + per_upstream_opt_list = edns_opt_copy_region( + qstate->edns_opts_back_out, region); + if(!per_upstream_opt_list) { + alloc_reg_release(env->alloc, region); return NULL; + } + qstate->edns_opts_back_out = per_upstream_opt_list; + } + + if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen, zone, + zonelen, qstate, region)) { + alloc_reg_release(env->alloc, region); + return NULL; + } + /* Restore the option list; we can explicitly use the copied one from + * now on. */ + per_upstream_opt_list = qstate->edns_opts_back_out; + qstate->edns_opts_back_out = backed_up_opt_list; if((client_string_addr = edns_string_addr_lookup( &env->edns_strings->client_strings, addr, addrlen))) { - edns_opt_list_append(&qstate->edns_opts_back_out, + edns_opt_list_append(&per_upstream_opt_list, env->edns_strings->client_string_opcode, client_string_addr->string_len, - client_string_addr->string, qstate->region); + client_string_addr->string, region); } serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype, qinfo->qclass, flags); sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen, - qstate->edns_opts_back_out); - /* duplicate entries are included in the callback list, because - * there is a counterpart registration by our caller that needs to - * be doubly-removed (with callbacks perhaps). */ - if(!(cb = (struct service_callback*)malloc(sizeof(*cb)))) - return NULL; + per_upstream_opt_list); if(!sq) { + /* Check ratelimit only for new serviced_query */ + if(check_ratelimit) { + timenow = *env->now; + if(!infra_ratelimit_inc(env->infra_cache, zone, + zonelen, timenow, env->cfg->ratelimit_backoff, + &qstate->qinfo, qstate->reply)) { + /* Can we pass through with slip factor? */ + if(env->cfg->ratelimit_factor == 0 || + ub_random_max(env->rnd, + env->cfg->ratelimit_factor) != 1) { + *was_ratelimited = 1; + alloc_reg_release(env->alloc, region); + return NULL; + } + log_nametypeclass(VERB_ALGO, + "ratelimit allowed through for " + "delegation point", zone, + LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN); + } + } /* make new serviced query entry */ sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps, tcp_upstream, ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, (int)qinfo->qtype, - qstate->edns_opts_back_out, + per_upstream_opt_list, ( ssl_upstream && env->cfg->pad_queries - ? env->cfg->pad_queries_block_size : 0 )); + ? env->cfg->pad_queries_block_size : 0 ), + env->alloc, region); if(!sq) { - free(cb); + if(check_ratelimit) { + infra_ratelimit_dec(env->infra_cache, + zone, zonelen, timenow); + } + alloc_reg_release(env->alloc, region); return NULL; } - /* perform first network action */ - if(outnet->do_udp && !(tcp_upstream || ssl_upstream)) { - if(!serviced_udp_send(sq, buff)) { - (void)rbtree_delete(outnet->serviced, sq); - serviced_node_del(&sq->node, NULL); - free(cb); - return NULL; - } - } else { - if(!serviced_tcp_send(sq, buff)) { - (void)rbtree_delete(outnet->serviced, sq); - serviced_node_del(&sq->node, NULL); - free(cb); - return NULL; + if(!(cb = (struct service_callback*)regional_alloc( + sq->region, sizeof(*cb)))) { + if(check_ratelimit) { + infra_ratelimit_dec(env->infra_cache, + zone, zonelen, timenow); } + (void)rbtree_delete(outnet->serviced, sq); + serviced_node_del(&sq->node, NULL); + return NULL; + } + /* No network action at this point; it will be invoked with the + * serviced_query timer instead to run outside of the mesh. */ + } else { + /* We don't need this region anymore. */ + alloc_reg_release(env->alloc, region); + /* duplicate entries are included in the callback list, because + * there is a counterpart registration by our caller that needs + * to be doubly-removed (with callbacks perhaps). */ + if(!(cb = (struct service_callback*)regional_alloc( + sq->region, sizeof(*cb)))) { + return NULL; } } /* add callback to list of callbacks */ @@ -3328,7 +3464,6 @@ callback_list_remove(struct serviced_query* sq, void* cb_arg) if((*pp)->cb_arg == cb_arg) { struct service_callback* del = *pp; *pp = del->next; - free(del); return; } pp = &(*pp)->next; @@ -3337,13 +3472,13 @@ callback_list_remove(struct serviced_query* sq, void* cb_arg) void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg) { - if(!sq) + if(!sq) return; callback_list_remove(sq, cb_arg); /* if callbacks() routine scheduled deletion, let it do that */ - if(!sq->cblist && !sq->to_be_deleted) { + if(!sq->cblist && !sq->busy && !sq->to_be_deleted) { (void)rbtree_delete(sq->outnet->serviced, sq); - serviced_delete(sq); + serviced_delete(sq); } } diff --git a/contrib/unbound/services/outside_network.h b/contrib/unbound/services/outside_network.h index d0d532e6425f..4c5b96f83424 100644 --- a/contrib/unbound/services/outside_network.h +++ b/contrib/unbound/services/outside_network.h @@ -43,7 +43,9 @@ #ifndef OUTSIDE_NETWORK_H #define OUTSIDE_NETWORK_H +#include "util/alloc.h" #include "util/rbtree.h" +#include "util/regional.h" #include "util/netevent.h" #include "dnstap/dnstap_config.h" struct pending; @@ -412,6 +414,8 @@ struct waiting_tcp { char* tls_auth_name; /** the packet was involved in an error, to stop looping errors */ int error_count; + /** if true, the item is at the cb_and_decommission stage */ + int in_cb_and_decommission; #ifdef USE_DNSTAP /** serviced query pointer for dnstap to get logging info, if nonNULL*/ struct serviced_query* sq; @@ -512,6 +516,15 @@ struct serviced_query { void* pending; /** block size with which to pad encrypted queries (default: 128) */ size_t padding_block_size; + /** region for this serviced query. Will be cleared when this + * serviced_query will be deleted */ + struct regional* region; + /** allocation service for the region */ + struct alloc_cache* alloc; + /** flash timer to start the net I/O as a separate event */ + struct comm_timer* timer; + /** true if serviced_query is currently doing net I/O and may block */ + int busy; }; /** @@ -619,6 +632,7 @@ void pending_delete(struct outside_network* outnet, struct pending* p); * @param want_dnssec: signatures are needed, without EDNS the answer is * likely to be useless. * @param nocaps: ignore use_caps_for_id and use unperturbed qname. + * @param check_ratelimit: if set, will check ratelimit before sending out. * @param tcp_upstream: use TCP for upstream queries. * @param ssl_upstream: use SSL for upstream queries. * @param tls_auth_name: when ssl_upstream is true, use this name to check @@ -635,16 +649,18 @@ void pending_delete(struct outside_network* outnet, struct pending* p); * @param callback_arg: user argument to callback function. * @param buff: scratch buffer to create query contents in. Empty on exit. * @param env: the module environment. + * @param was_ratelimited: it will signal back if the query failed to pass the + * ratelimit check. * @return 0 on error, or pointer to serviced query that is used to answer * this serviced query may be shared with other callbacks as well. */ struct serviced_query* outnet_serviced_query(struct outside_network* outnet, struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec, - int nocaps, int tcp_upstream, int ssl_upstream, char* tls_auth_name, - struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, struct module_qstate* qstate, + int nocaps, int check_ratelimit, int tcp_upstream, int ssl_upstream, + char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, struct module_qstate* qstate, comm_point_callback_type* callback, void* callback_arg, - struct sldns_buffer* buff, struct module_env* env); + struct sldns_buffer* buff, struct module_env* env, int* was_ratelimited); /** * Remove service query callback. @@ -785,6 +801,9 @@ void pending_udp_timer_delay_cb(void *arg); /** callback for outgoing TCP timer event */ void outnet_tcptimer(void* arg); +/** callback to send serviced queries */ +void serviced_timer_cb(void *arg); + /** callback for serviced query UDP answers */ int serviced_udp_callback(struct comm_point* c, void* arg, int error, struct comm_reply* rep); diff --git a/contrib/unbound/services/rpz.c b/contrib/unbound/services/rpz.c index d408f9383d24..322e9d1393c4 100644 --- a/contrib/unbound/services/rpz.c +++ b/contrib/unbound/services/rpz.c @@ -542,6 +542,7 @@ rpz_create(struct config_auth* p) } } r->log = p->rpz_log; + r->signal_nxdomain_ra = p->rpz_signal_nxdomain_ra; if(p->rpz_log_name) { if(!(r->log_name = strdup(p->rpz_log_name))) { log_err("malloc failure on RPZ log_name strdup"); @@ -836,7 +837,7 @@ rpz_report_rrset_error(const char* msg, uint8_t* rr, size_t rr_len) { } /* from localzone.c; difference is we don't have a dname */ -struct local_rrset* +static struct local_rrset* rpz_clientip_new_rrset(struct regional* region, struct clientip_synthesized_rr* raddr, uint16_t rrtype, uint16_t rrclass) { @@ -1384,9 +1385,9 @@ log_rpz_apply(char* trigger, uint8_t* dname, struct addr_tree_node* addrnode, if(dname) { dname_str(dname, dnamestr); } else if(addrnode) { - char a[128]; - addr_to_str(&addrnode->addr, addrnode->addrlen, a, sizeof(a)); - snprintf(dnamestr, sizeof(dnamestr), "%s/%d", a, addrnode->net); + char addrbuf[128]; + addr_to_str(&addrnode->addr, addrnode->addrlen, addrbuf, sizeof(addrbuf)); + snprintf(dnamestr, sizeof(dnamestr), "%s/%d", addrbuf, addrnode->net); } else { dnamestr[0]=0; } @@ -1697,7 +1698,7 @@ rpz_synthesize_nodata(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms, if(msg == NULL) { return msg; } msg->qinfo = *qinfo; msg->rep = construct_reply_info_base(ms->region, - LDNS_RCODE_NOERROR | BIT_RD | BIT_QR | BIT_AA | BIT_RA, + LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA, 1, /* qd */ 0, /* ttl */ 0, /* prettl */ @@ -1715,14 +1716,18 @@ rpz_synthesize_nodata(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms, } static inline struct dns_msg* -rpz_synthesize_nxdomain(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms, +rpz_synthesize_nxdomain(struct rpz* r, struct module_qstate* ms, struct query_info* qinfo, struct auth_zone* az) { struct dns_msg* msg = rpz_dns_msg_new(ms->region); + uint16_t flags; if(msg == NULL) { return msg; } msg->qinfo = *qinfo; + flags = LDNS_RCODE_NXDOMAIN | BIT_QR | BIT_AA | BIT_RA; + if(r->signal_nxdomain_ra) + flags &= ~BIT_RA; msg->rep = construct_reply_info_base(ms->region, - LDNS_RCODE_NXDOMAIN | BIT_RD | BIT_QR | BIT_AA | BIT_RA, + flags, 1, /* qd */ 0, /* ttl */ 0, /* prettl */ @@ -1752,7 +1757,7 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs if(msg == NULL) { return NULL; } new_reply_info = construct_reply_info_base(ms->region, - LDNS_RCODE_NOERROR | BIT_RD | BIT_QR | BIT_AA | BIT_RA, + LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA, 1, /* qd */ 0, /* ttl */ 0, /* prettl */ @@ -1922,6 +1927,9 @@ rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r, ret = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, 0 /* no local data used */, lzt); + if(r->signal_nxdomain_ra && LDNS_RCODE_WIRE(sldns_buffer_begin(buf)) + == LDNS_RCODE_NXDOMAIN) + LDNS_RA_CLR(sldns_buffer_begin(buf)); if(r->log) { log_rpz_apply("qname", z->name, NULL, localzone_type_to_rpz_action(lzt), qinfo, repinfo, NULL, r->log_name); @@ -1930,7 +1938,7 @@ rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r, return ret; } -struct clientip_synthesized_rr* +static struct clientip_synthesized_rr* rpz_delegation_point_ipbased_trigger_lookup(struct rpz* rpz, struct iter_qstate* is) { struct delegpt_addr* cursor; @@ -1947,7 +1955,7 @@ rpz_delegation_point_ipbased_trigger_lookup(struct rpz* rpz, struct iter_qstate* return NULL; } -struct dns_msg* +static struct dns_msg* rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r, struct clientip_synthesized_rr* raddr, struct auth_zone* az) { @@ -2006,7 +2014,7 @@ done: return ret; } -struct dns_msg* +static struct dns_msg* rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r, struct local_zone* z, struct matched_delegation_point const* match, struct auth_zone* az) @@ -2295,6 +2303,10 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env, local_zones_zone_answer(*z_out /*likely NULL, no zone*/, env, qinfo, edns, repinfo, buf, temp, 0 /* no local data used */, rpz_action_to_localzone_type(client_action)); + if(*r_out && (*r_out)->signal_nxdomain_ra && + LDNS_RCODE_WIRE(sldns_buffer_begin(buf)) + == LDNS_RCODE_NXDOMAIN) + LDNS_RA_CLR(sldns_buffer_begin(buf)); } ret = 1; goto done; diff --git a/contrib/unbound/services/rpz.h b/contrib/unbound/services/rpz.h index 691475743606..c29d30dff506 100644 --- a/contrib/unbound/services/rpz.h +++ b/contrib/unbound/services/rpz.h @@ -123,6 +123,8 @@ struct rpz { struct ub_packed_rrset_key* cname_override; int log; char* log_name; + /** signal NXDOMAIN blocked with unset RA flag */ + int signal_nxdomain_ra; struct regional* region; int disabled; }; |