aboutsummaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2022-06-08 14:43:13 +0000
committerCy Schubert <cy@FreeBSD.org>2022-06-08 14:43:13 +0000
commit5f9f82264b91e041df7cba2406625146e7268ce4 (patch)
treeba7309ee547bf22115420277f45a3478aafb6397 /services
parent3574dc0bd83e731bba79edc130c0569bf05f7af5 (diff)
downloadsrc-5f9f82264b91e041df7cba2406625146e7268ce4.tar.gz
src-5f9f82264b91e041df7cba2406625146e7268ce4.zip
unbound: Vendor import 1.16.0vendor/unbound/1.16.0
Diffstat (limited to 'services')
-rw-r--r--services/authzone.c103
-rw-r--r--services/authzone.h3
-rw-r--r--services/cache/dns.c5
-rw-r--r--services/listen_dnsport.c79
-rw-r--r--services/localzone.c26
-rw-r--r--services/mesh.c181
-rw-r--r--services/mesh.h17
-rw-r--r--services/outside_network.c5
-rw-r--r--services/rpz.c41
-rw-r--r--services/rpz.h4
10 files changed, 405 insertions, 59 deletions
diff --git a/services/authzone.c b/services/authzone.c
index e83af533dbc0..02fb621a22ff 100644
--- a/services/authzone.c
+++ b/services/authzone.c
@@ -132,6 +132,7 @@ msg_create(struct regional* region, struct query_info* qinfo)
return NULL;
msg->rep->flags = (uint16_t)(BIT_QR | BIT_AA);
msg->rep->authoritative = 1;
+ msg->rep->reason_bogus = LDNS_EDE_NONE;
msg->rep->qdcount = 1;
/* rrsets is NULL, no rrsets yet */
return msg;
@@ -1882,6 +1883,8 @@ static int auth_zone_zonemd_check_hash(struct auth_zone* z,
struct regional* region = NULL;
struct sldns_buffer* buf = NULL;
uint32_t soa_serial = 0;
+ char* unsupported_reason = NULL;
+ int only_unsupported = 1;
region = env->scratch;
regional_free_all(region);
buf = env->scratch_buffer;
@@ -1911,6 +1914,7 @@ static int auth_zone_zonemd_check_hash(struct auth_zone* z,
&hashalgo, &hash, &hashlen)) {
/* malformed RR */
*reason = "ZONEMD rdata malformed";
+ only_unsupported = 0;
continue;
}
/* check for duplicates */
@@ -1920,25 +1924,51 @@ static int auth_zone_zonemd_check_hash(struct auth_zone* z,
* is not allowed. */
*reason = "ZONEMD RRSet contains more than one RR "
"with the same scheme and hash algorithm";
+ only_unsupported = 0;
continue;
}
regional_free_all(region);
if(serial != soa_serial) {
*reason = "ZONEMD serial is wrong";
+ only_unsupported = 0;
continue;
}
+ *reason = NULL;
if(auth_zone_generate_zonemd_check(z, scheme, hashalgo,
hash, hashlen, region, buf, reason)) {
/* success */
+ if(*reason) {
+ if(!unsupported_reason)
+ unsupported_reason = *reason;
+ /* continue to check for valid ZONEMD */
+ if(verbosity >= VERB_ALGO) {
+ char zstr[255+1];
+ dname_str(z->name, zstr);
+ verbose(VERB_ALGO, "auth-zone %s ZONEMD %d %d is unsupported: %s", zstr, (int)scheme, (int)hashalgo, *reason);
+ }
+ *reason = NULL;
+ continue;
+ }
if(verbosity >= VERB_ALGO) {
char zstr[255+1];
dname_str(z->name, zstr);
- verbose(VERB_ALGO, "auth-zone %s ZONEMD hash is correct", zstr);
+ if(!*reason)
+ verbose(VERB_ALGO, "auth-zone %s ZONEMD hash is correct", zstr);
}
return 1;
}
+ only_unsupported = 0;
/* try next one */
}
+ /* have we seen no failures but only unsupported algo,
+ * and one unsupported algorithm, or more. */
+ if(only_unsupported && unsupported_reason) {
+ /* only unsupported algorithms, with valid serial, not
+ * malformed. Did not see supported algorithms, failed or
+ * successful ones. */
+ *reason = unsupported_reason;
+ return 1;
+ }
/* fail, we may have reason */
if(!*reason)
*reason = "no ZONEMD records found";
@@ -4456,7 +4486,7 @@ chunkline_get_line_collated(struct auth_chunk** chunk, size_t* chunk_pos,
return 1;
}
-/** process $ORIGIN for http */
+/** process $ORIGIN for http, 0 nothing, 1 done, 2 error */
static int
http_parse_origin(sldns_buffer* buf, struct sldns_file_parse_state* pstate)
{
@@ -4467,13 +4497,16 @@ http_parse_origin(sldns_buffer* buf, struct sldns_file_parse_state* pstate)
pstate->origin_len = sizeof(pstate->origin);
s = sldns_str2wire_dname_buf(sldns_strip_ws(line+8),
pstate->origin, &pstate->origin_len);
- if(s) pstate->origin_len = 0;
+ if(s) {
+ pstate->origin_len = 0;
+ return 2;
+ }
return 1;
}
return 0;
}
-/** process $TTL for http */
+/** process $TTL for http, 0 nothing, 1 done, 2 error */
static int
http_parse_ttl(sldns_buffer* buf, struct sldns_file_parse_state* pstate)
{
@@ -4481,8 +4514,12 @@ http_parse_ttl(sldns_buffer* buf, struct sldns_file_parse_state* pstate)
if(strncmp(line, "$TTL", 4) == 0 &&
isspace((unsigned char)line[4])) {
const char* end = NULL;
+ int overflow = 0;
pstate->default_ttl = sldns_str2period(
- sldns_strip_ws(line+5), &end);
+ sldns_strip_ws(line+5), &end, &overflow);
+ if(overflow) {
+ return 2;
+ }
return 1;
}
return 0;
@@ -4493,15 +4530,20 @@ static int
chunkline_non_comment_RR(struct auth_chunk** chunk, size_t* chunk_pos,
sldns_buffer* buf, struct sldns_file_parse_state* pstate)
{
+ int ret;
while(chunkline_get_line_collated(chunk, chunk_pos, buf)) {
if(chunkline_is_comment_line_or_empty(buf)) {
/* a comment, go to next line */
continue;
}
- if(http_parse_origin(buf, pstate)) {
+ if((ret=http_parse_origin(buf, pstate))!=0) {
+ if(ret == 2)
+ return 0;
continue; /* $ORIGIN has been handled */
}
- if(http_parse_ttl(buf, pstate)) {
+ if((ret=http_parse_ttl(buf, pstate))!=0) {
+ if(ret == 2)
+ return 0;
continue; /* $TTL has been handled */
}
return 1;
@@ -5007,6 +5049,7 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
struct sldns_file_parse_state pstate;
struct auth_chunk* chunk;
size_t chunk_pos;
+ int ret;
memset(&pstate, 0, sizeof(pstate));
pstate.default_ttl = 3600;
if(xfr->namelen < sizeof(pstate.origin)) {
@@ -5063,10 +5106,24 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
continue;
}
/* parse line and add RR */
- if(http_parse_origin(scratch_buffer, &pstate)) {
+ if((ret=http_parse_origin(scratch_buffer, &pstate))!=0) {
+ if(ret == 2) {
+ verbose(VERB_ALGO, "error parsing ORIGIN on line [%s:%d] %s",
+ xfr->task_transfer->master->file,
+ pstate.lineno,
+ sldns_buffer_begin(scratch_buffer));
+ return 0;
+ }
continue; /* $ORIGIN has been handled */
}
- if(http_parse_ttl(scratch_buffer, &pstate)) {
+ if((ret=http_parse_ttl(scratch_buffer, &pstate))!=0) {
+ if(ret == 2) {
+ verbose(VERB_ALGO, "error parsing TTL on line [%s:%d] %s",
+ xfr->task_transfer->master->file,
+ pstate.lineno,
+ sldns_buffer_begin(scratch_buffer));
+ return 0;
+ }
continue; /* $TTL has been handled */
}
if(!http_parse_add_rr(xfr, z, scratch_buffer, &pstate)) {
@@ -5370,7 +5427,7 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
* called straight away */
lock_basic_unlock(&xfr->lock);
if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
- &auth_xfer_transfer_lookup_callback, xfr)) {
+ &auth_xfer_transfer_lookup_callback, xfr, 0)) {
lock_basic_lock(&xfr->lock);
log_err("out of memory lookup up master %s", master->host);
return 0;
@@ -6561,7 +6618,7 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
* called straight away */
lock_basic_unlock(&xfr->lock);
if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
- &auth_xfer_probe_lookup_callback, xfr)) {
+ &auth_xfer_probe_lookup_callback, xfr, 0)) {
lock_basic_lock(&xfr->lock);
log_err("out of memory lookup up master %s", master->host);
return 0;
@@ -7632,13 +7689,16 @@ int auth_zone_generate_zonemd_check(struct auth_zone* z, int scheme,
{
uint8_t gen[512];
size_t genlen = 0;
+ *reason = NULL;
if(!zonemd_hashalgo_supported(hashalgo)) {
+ /* allow it */
*reason = "unsupported algorithm";
- return 0;
+ return 1;
}
if(!zonemd_scheme_supported(scheme)) {
+ /* allow it */
*reason = "unsupported scheme";
- return 0;
+ return 1;
}
if(hashlen < 12) {
/* the ZONEMD draft requires digests to fail if too small */
@@ -7726,7 +7786,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
auth_zone_log(z->name, VERB_ALGO,
"zonemd: verify %s RRset with DNSKEY", typestr);
}
- sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus,
+ sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL,
LDNS_SECTION_ANSWER, NULL);
if(sec == sec_status_secure) {
return 1;
@@ -8003,9 +8063,13 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
}
/* success! log the success */
- auth_zone_log(z->name, VERB_ALGO, "ZONEMD verification successful");
+ if(reason)
+ auth_zone_log(z->name, VERB_ALGO, "ZONEMD %s", reason);
+ else auth_zone_log(z->name, VERB_ALGO, "ZONEMD verification successful");
if(result) {
- *result = strdup("ZONEMD verification successful");
+ if(reason)
+ *result = strdup(reason);
+ else *result = strdup("ZONEMD verification successful");
if(!*result) log_err("out of memory");
}
}
@@ -8065,7 +8129,7 @@ zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env,
auth_zone_log(z->name, VERB_QUERY,
"zonemd: verify DNSKEY RRset with trust anchor");
sec = val_verify_DNSKEY_with_TA(env, ve, keystorage, anchor->ds_rrset,
- anchor->dnskey_rrset, NULL, why_bogus, NULL);
+ anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL);
regional_free_all(env->scratch);
if(sec == sec_status_secure) {
/* success */
@@ -8123,8 +8187,9 @@ auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z,
keystorage->rk.type = htons(LDNS_RR_TYPE_DNSKEY);
keystorage->rk.rrset_class = htons(z->dclass);
auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS");
+ // @TODO add EDE here? we currently just pass NULL
sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg,
- why_bogus, NULL);
+ why_bogus, NULL, NULL);
regional_free_all(env->scratch);
if(sec == sec_status_secure) {
/* success */
@@ -8340,7 +8405,7 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
/* the callback can be called straight away */
lock_rw_unlock(&z->lock);
if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
- &auth_zonemd_dnskey_lookup_callback, z)) {
+ &auth_zonemd_dnskey_lookup_callback, z, 0)) {
lock_rw_wrlock(&z->lock);
log_err("out of memory lookup of %s for zonemd",
(fetch_ds?"DS":"DNSKEY"));
diff --git a/services/authzone.h b/services/authzone.h
index d24e569d3b85..07614ed82963 100644
--- a/services/authzone.h
+++ b/services/authzone.h
@@ -747,6 +747,9 @@ int zonemd_scheme_supported(int scheme);
* @param region: temp region for allocs during canonicalisation.
* @param buf: temp buffer during canonicalisation.
* @param reason: string returned with failure reason.
+ * If the hash cannot be checked, but it is allowed, for unknown
+ * algorithms, the routine returns success, and the reason is nonNULL,
+ * with the allowance reason.
* @return false on failure.
*/
int auth_zone_generate_zonemd_check(struct auth_zone* z, int scheme,
diff --git a/services/cache/dns.c b/services/cache/dns.c
index 5b64fe47520c..f6c11451c93a 100644
--- a/services/cache/dns.c
+++ b/services/cache/dns.c
@@ -428,6 +428,7 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype,
return NULL; /* integer overflow protection */
msg->rep->flags = BIT_QR; /* with QR, no AA */
msg->rep->qdcount = 1;
+ msg->rep->reason_bogus = LDNS_EDE_NONE;
msg->rep->rrsets = (struct ub_packed_rrset_key**)
regional_alloc(region,
capacity*sizeof(struct ub_packed_rrset_key*));
@@ -524,6 +525,7 @@ gen_dns_msg(struct regional* region, struct query_info* q, size_t num)
sizeof(struct reply_info) - sizeof(struct rrset_ref));
if(!msg->rep)
return NULL;
+ msg->rep->reason_bogus = LDNS_EDE_NONE;
if(num > RR_COUNT_MAX)
return NULL; /* integer overflow protection */
msg->rep->rrsets = (struct ub_packed_rrset_key**)
@@ -577,6 +579,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
msg->rep->ar_numrrsets = r->ar_numrrsets;
msg->rep->rrset_count = r->rrset_count;
msg->rep->authoritative = r->authoritative;
+ msg->rep->reason_bogus = r->reason_bogus;
if(!rrset_array_lock(r->ref, r->rrset_count, now_control)) {
return NULL;
}
@@ -632,6 +635,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
msg->rep->ns_numrrsets = 0;
msg->rep->ar_numrrsets = 0;
msg->rep->rrset_count = 1;
+ msg->rep->reason_bogus = LDNS_EDE_NONE;
msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now);
if(!msg->rep->rrsets[0]) /* copy CNAME */
return NULL;
@@ -670,6 +674,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
msg->rep->ns_numrrsets = 0;
msg->rep->ar_numrrsets = 0;
msg->rep->rrset_count = 1;
+ msg->rep->reason_bogus = LDNS_EDE_NONE;
msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now);
if(!msg->rep->rrsets[0]) /* copy DNAME */
return NULL;
diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c
index 983b96f09eec..03153bd64778 100644
--- a/services/listen_dnsport.c
+++ b/services/listen_dnsport.c
@@ -47,6 +47,7 @@
#ifdef USE_TCP_FASTOPEN
#include <netinet/tcp.h>
#endif
+#include <ctype.h>
#include "services/listen_dnsport.h"
#include "services/outside_network.h"
#include "util/netevent.h"
@@ -1157,7 +1158,7 @@ if_is_ssl(const char* ifname, const char* port, int ssl_port,
* @param do_auto: use automatic interface detection.
* If enabled, then ifname must be the wildcard name.
* @param do_udp: if udp should be used.
- * @param do_tcp: if udp should be used.
+ * @param do_tcp: if tcp should be used.
* @param hints: for getaddrinfo. family and flags have to be set by caller.
* @param port: Port number to use (as string).
* @param list: list of open ports, appended to, changed to point to list head.
@@ -1369,17 +1370,17 @@ listen_create(struct comm_base* base, struct listen_port* ports,
while(ports) {
struct comm_point* cp = NULL;
if(ports->ftype == listen_type_udp ||
- ports->ftype == listen_type_udp_dnscrypt)
+ ports->ftype == listen_type_udp_dnscrypt) {
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)
+ } else if(ports->ftype == listen_type_tcp ||
+ ports->ftype == listen_type_tcp_dnscrypt) {
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 ||
+ } else if(ports->ftype == listen_type_ssl ||
ports->ftype == listen_type_http) {
cp = comm_point_create_tcp(base, ports->fd,
tcp_accept_count, tcp_idle_timeout,
@@ -1410,15 +1411,22 @@ listen_create(struct comm_base* base, struct listen_port* ports,
#endif
}
} else if(ports->ftype == listen_type_udpancil ||
- ports->ftype == listen_type_udpancil_dnscrypt)
+ ports->ftype == listen_type_udpancil_dnscrypt) {
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");
listen_delete(front);
return NULL;
}
- if(http_notls && ports->ftype == listen_type_http)
+ if((http_notls && ports->ftype == listen_type_http) ||
+ (ports->ftype == listen_type_tcp) ||
+ (ports->ftype == listen_type_udp) ||
+ (ports->ftype == listen_type_udpancil) ||
+ (ports->ftype == listen_type_tcp_dnscrypt) ||
+ (ports->ftype == listen_type_udp_dnscrypt) ||
+ (ports->ftype == listen_type_udpancil_dnscrypt))
cp->ssl = NULL;
else
cp->ssl = sslctx;
@@ -1709,6 +1717,63 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
}
/* create ip4 and ip6 ports so that return addresses are nice. */
if(do_auto || num_ifs == 0) {
+ if(do_auto && cfg->if_automatic_ports &&
+ cfg->if_automatic_ports[0]!=0) {
+ char* now = cfg->if_automatic_ports;
+ while(now && *now) {
+ char* after;
+ int extraport;
+ while(isspace((unsigned char)*now))
+ now++;
+ if(!*now)
+ break;
+ after = now;
+ extraport = (int)strtol(now, &after, 10);
+ if(extraport < 0 || extraport > 65535) {
+ log_err("interface-automatic-ports port number out of range, at position %d of '%s'", (int)(now-cfg->if_automatic_ports)+1, cfg->if_automatic_ports);
+ listening_ports_free(list);
+ return NULL;
+ }
+ if(extraport == 0 && now == after) {
+ log_err("interface-automatic-ports could not be parsed, at position %d of '%s'", (int)(now-cfg->if_automatic_ports)+1, cfg->if_automatic_ports);
+ listening_ports_free(list);
+ return NULL;
+ }
+ now = after;
+ snprintf(portbuf, sizeof(portbuf), "%d", extraport);
+ if(do_ip6) {
+ hints.ai_family = AF_INET6;
+ if(!ports_create_if("::0",
+ do_auto, cfg->do_udp, do_tcp,
+ &hints, portbuf, &list,
+ cfg->so_rcvbuf, cfg->so_sndbuf,
+ cfg->ssl_port, cfg->tls_additional_port,
+ cfg->https_port, reuseport, cfg->ip_transparent,
+ cfg->tcp_mss, cfg->ip_freebind,
+ cfg->http_nodelay, cfg->use_systemd,
+ cfg->dnscrypt_port, cfg->ip_dscp)) {
+ listening_ports_free(list);
+ return NULL;
+ }
+ }
+ if(do_ip4) {
+ hints.ai_family = AF_INET;
+ if(!ports_create_if("0.0.0.0",
+ do_auto, cfg->do_udp, do_tcp,
+ &hints, portbuf, &list,
+ cfg->so_rcvbuf, cfg->so_sndbuf,
+ cfg->ssl_port, cfg->tls_additional_port,
+ cfg->https_port, reuseport, cfg->ip_transparent,
+ cfg->tcp_mss, cfg->ip_freebind,
+ cfg->http_nodelay, cfg->use_systemd,
+ cfg->dnscrypt_port, cfg->ip_dscp)) {
+ listening_ports_free(list);
+ return NULL;
+ }
+ }
+ }
+ return list;
+ }
if(do_ip6) {
hints.ai_family = AF_INET6;
if(!ports_create_if(do_auto?"::0":"::1",
diff --git a/services/localzone.c b/services/localzone.c
index 3e3a71aea3c5..3ed7d835d33e 100644
--- a/services/localzone.c
+++ b/services/localzone.c
@@ -1328,7 +1328,8 @@ local_encode(struct query_info* qinfo, struct module_env* env,
static void
local_error_encode(struct query_info* qinfo, struct module_env* env,
struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
- struct regional* temp, int rcode, int r)
+ struct regional* temp, int rcode, int r, int ede_code,
+ const char* ede_txt)
{
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
@@ -1338,6 +1339,12 @@ local_error_encode(struct query_info* qinfo, struct module_env* env,
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
rcode, edns, repinfo, temp, env->now_tv))
edns->opt_list_inplace_cb_out = NULL;
+
+ if(ede_code != LDNS_EDE_NONE && env->cfg->ede) {
+ edns_opt_list_append_ede(&edns->opt_list_out, temp,
+ ede_code, ede_txt);
+ }
+
error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
}
@@ -1535,7 +1542,9 @@ local_data_answer(struct local_zone* z, struct module_env* env,
qinfo->local_alias = NULL;
local_error_encode(qinfo, env, edns, repinfo,
buf, temp, LDNS_RCODE_YXDOMAIN,
- (LDNS_RCODE_YXDOMAIN|BIT_AA));
+ (LDNS_RCODE_YXDOMAIN|BIT_AA),
+ LDNS_EDE_OTHER,
+ "DNAME expansion became too large");
return 1;
}
memset(&qinfo->local_alias->rrset->entry, 0,
@@ -1638,7 +1647,8 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
} else if(lz_type == local_zone_refuse
|| lz_type == local_zone_always_refuse) {
local_error_encode(qinfo, env, edns, repinfo, buf, temp,
- LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA));
+ LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA),
+ LDNS_EDE_NONE, NULL);
return 1;
} else if(lz_type == local_zone_static ||
lz_type == local_zone_redirect ||
@@ -1663,8 +1673,8 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
- local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
- (rcode|BIT_AA));
+ local_error_encode(qinfo, env, edns, repinfo, buf, temp,
+ rcode, (rcode|BIT_AA), LDNS_EDE_NONE, NULL);
return 1;
} else if(lz_type == local_zone_typetransparent
|| lz_type == local_zone_always_transparent) {
@@ -1705,9 +1715,10 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
return local_encode(qinfo, env, edns, repinfo, buf, temp,
&lrr, 1, LDNS_RCODE_NOERROR);
} else {
+ /* NODATA: No EDE needed */
local_error_encode(qinfo, env, edns, repinfo, buf,
temp, LDNS_RCODE_NOERROR,
- (LDNS_RCODE_NOERROR|BIT_AA));
+ (LDNS_RCODE_NOERROR|BIT_AA), -1, NULL);
}
return 1;
}
@@ -1720,8 +1731,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
+ /* NODATA: No EDE needed */
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
- (rcode|BIT_AA));
+ (rcode|BIT_AA), LDNS_EDE_NONE, NULL);
return 1;
}
diff --git a/services/mesh.c b/services/mesh.c
index cdcfedda270c..fbaa966bdd05 100644
--- a/services/mesh.c
+++ b/services/mesh.c
@@ -64,6 +64,11 @@
#include "respip/respip.h"
#include "services/listen_dnsport.h"
+#ifdef CLIENT_SUBNET
+#include "edns-subnet/subnetmod.h"
+#include "edns-subnet/edns-subnet.h"
+#endif
+
/** subtract timers and the values do not overflow or become negative */
static void
timeval_subtract(struct timeval* d, const struct timeval* end, const struct timeval* start)
@@ -458,7 +463,8 @@ mesh_serve_expired_init(struct mesh_state* mstate, int timeout)
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
struct respip_client_info* cinfo, uint16_t qflags,
- struct edns_data* edns, struct comm_reply* rep, uint16_t qid)
+ struct edns_data* edns, struct comm_reply* rep, uint16_t qid,
+ int rpz_passthru)
{
struct mesh_state* s = NULL;
int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
@@ -513,6 +519,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
}
if(unique)
mesh_state_make_unique(s);
+ s->s.rpz_passthru = rpz_passthru;
/* copy the edns options we got from the front */
if(edns->opt_list_in) {
s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
@@ -606,7 +613,7 @@ servfail_mem:
int
mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, struct edns_data* edns, sldns_buffer* buf,
- uint16_t qid, mesh_cb_func_type cb, void* cb_arg)
+ uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru)
{
struct mesh_state* s = NULL;
int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
@@ -632,6 +639,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
}
if(unique)
mesh_state_make_unique(s);
+ s->s.rpz_passthru = rpz_passthru;
if(edns->opt_list_in) {
s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
s->s.region);
@@ -686,7 +694,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
* 0 (false), in which case the new state is only made runnable so it
* will not be run recursively on top of the current state. */
static void mesh_schedule_prefetch(struct mesh_area* mesh,
- struct query_info* qinfo, uint16_t qflags, time_t leeway, int run)
+ struct query_info* qinfo, uint16_t qflags, time_t leeway, int run,
+ int rpz_passthru)
{
struct mesh_state* s = mesh_area_find(mesh, NULL, qinfo,
qflags&(BIT_RD|BIT_CD), 0, 0);
@@ -732,15 +741,109 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
/* move to either the forever or the jostle_list */
if(mesh->num_forever_states < mesh->max_forever_states) {
mesh->num_forever_states ++;
- mesh_list_insert(s, &mesh->forever_first,
+ mesh_list_insert(s, &mesh->forever_first,
&mesh->forever_last);
s->list_select = mesh_forever_list;
} else {
- mesh_list_insert(s, &mesh->jostle_first,
+ mesh_list_insert(s, &mesh->jostle_first,
+ &mesh->jostle_last);
+ s->list_select = mesh_jostle_list;
+ }
+ }
+ s->s.rpz_passthru = rpz_passthru;
+
+ if(!run) {
+#ifdef UNBOUND_DEBUG
+ n =
+#else
+ (void)
+#endif
+ rbtree_insert(&mesh->run, &s->run_node);
+ log_assert(n != NULL);
+ return;
+ }
+
+ mesh_run(mesh, s, module_event_new, NULL);
+}
+
+#ifdef CLIENT_SUBNET
+/* Same logic as mesh_schedule_prefetch but tailored to the subnet module logic
+ * like passing along the comm_reply info. This will be faked into an EDNS
+ * option for processing by the subnet module if the client has not already
+ * attached its own ECS data. */
+static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh,
+ struct query_info* qinfo, uint16_t qflags, time_t leeway, int run,
+ int rpz_passthru, struct comm_reply* rep, struct edns_option* edns_list)
+{
+ struct mesh_state* s = NULL;
+ struct edns_option* opt = NULL;
+#ifdef UNBOUND_DEBUG
+ struct rbnode_type* n;
+#endif
+ if(!mesh_make_new_space(mesh, NULL)) {
+ verbose(VERB_ALGO, "Too many queries. dropped prefetch.");
+ mesh->stats_dropped ++;
+ return;
+ }
+
+ s = mesh_state_create(mesh->env, qinfo, NULL,
+ qflags&(BIT_RD|BIT_CD), 0, 0);
+ if(!s) {
+ log_err("prefetch_subnet mesh_state_create: out of memory");
+ return;
+ }
+ mesh_state_make_unique(s);
+
+ opt = edns_opt_list_find(edns_list, mesh->env->cfg->client_subnet_opcode);
+ if(opt) {
+ /* Use the client's ECS data */
+ if(!edns_opt_list_append(&s->s.edns_opts_front_in, opt->opt_code,
+ opt->opt_len, opt->opt_data, s->s.region)) {
+ log_err("prefetch_subnet edns_opt_list_append: out of memory");
+ return;
+ }
+ } else {
+ /* Fake the ECS data from the client's IP */
+ struct ecs_data ecs;
+ memset(&ecs, 0, sizeof(ecs));
+ subnet_option_from_ss(&rep->addr, &ecs, mesh->env->cfg);
+ if(ecs.subnet_validdata == 0) {
+ log_err("prefetch_subnet subnet_option_from_ss: invalid data");
+ return;
+ }
+ subnet_ecs_opt_list_append(&ecs, &s->s.edns_opts_front_in, &s->s);
+ if(!s->s.edns_opts_front_in) {
+ log_err("prefetch_subnet subnet_ecs_opt_list_append: out of memory");
+ return;
+ }
+ }
+#ifdef UNBOUND_DEBUG
+ n =
+#else
+ (void)
+#endif
+ rbtree_insert(&mesh->all, &s->node);
+ log_assert(n != NULL);
+ /* set detached (it is now) */
+ mesh->num_detached_states++;
+ /* make it ignore the cache */
+ sock_list_insert(&s->s.blacklist, NULL, 0, s->s.region);
+ s->s.prefetch_leeway = leeway;
+
+ if(s->list_select == mesh_no_list) {
+ /* move to either the forever or the jostle_list */
+ if(mesh->num_forever_states < mesh->max_forever_states) {
+ mesh->num_forever_states ++;
+ mesh_list_insert(s, &mesh->forever_first,
+ &mesh->forever_last);
+ s->list_select = mesh_forever_list;
+ } else {
+ mesh_list_insert(s, &mesh->jostle_first,
&mesh->jostle_last);
s->list_select = mesh_jostle_list;
}
}
+ s->s.rpz_passthru = rpz_passthru;
if(!run) {
#ifdef UNBOUND_DEBUG
@@ -755,11 +858,22 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
mesh_run(mesh, s, module_event_new, NULL);
}
+#endif /* CLIENT_SUBNET */
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
- uint16_t qflags, time_t leeway)
+ uint16_t qflags, time_t leeway, int rpz_passthru,
+ struct comm_reply* rep, struct edns_option* opt_list)
{
- mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1);
+ (void)opt_list;
+ (void)rep;
+#ifdef CLIENT_SUBNET
+ if(rep)
+ mesh_schedule_prefetch_subnet(mesh, qinfo, qflags, leeway, 1,
+ rpz_passthru, rep, opt_list);
+ else
+#endif
+ mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1,
+ rpz_passthru);
}
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
@@ -1234,7 +1348,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
(rep->security <= sec_status_bogus ||
rep->security == sec_status_secure_sentinel_fail)) {
rcode = LDNS_RCODE_SERVFAIL;
- if(m->s.env->cfg->stat_extended)
+ if(m->s.env->cfg->stat_extended)
m->s.env->mesh->ans_bogus++;
}
if(rep && rep->security == sec_status_secure)
@@ -1290,6 +1404,36 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
&r->edns, &r->query_reply, m->s.region, &r->start_time))
r->edns.opt_list_inplace_cb_out = NULL;
}
+ /* Send along EDE BOGUS EDNS0 option when answer is bogus */
+ if(m->s.env->cfg->ede && rcode == LDNS_RCODE_SERVFAIL &&
+ m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
+ m->s.env->cfg->ignore_cd) && rep &&
+ (rep->security <= sec_status_bogus ||
+ rep->security == sec_status_secure_sentinel_fail)) {
+ char *reason = m->s.env->cfg->val_log_level >= 2
+ ? errinf_to_str_bogus(&m->s) : NULL;
+
+ /* During validation the EDE code can be received via two
+ * code paths. One code path fills the reply_info EDE, and
+ * the other fills it in the errinf_strlist. These paths
+ * intersect at some points, but where is opaque due to
+ * the complexity of the validator. At the time of writing
+ * we make the choice to prefer the EDE from errinf_strlist
+ * but a compelling reason to do otherwise is just as valid
+ */
+ sldns_ede_code reason_bogus = errinf_to_reason_bogus(&m->s);
+ if ((reason_bogus == LDNS_EDE_DNSSEC_BOGUS &&
+ rep->reason_bogus != LDNS_EDE_NONE) ||
+ reason_bogus == LDNS_EDE_NONE) {
+ reason_bogus = rep->reason_bogus;
+ }
+
+ if(reason_bogus != LDNS_EDE_NONE) {
+ edns_opt_list_append_ede(&r->edns.opt_list_out,
+ m->s.region, reason_bogus, reason);
+ }
+ free(reason);
+ }
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
r->qflags, &r->edns);
m->reply_list = NULL;
@@ -1313,6 +1457,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time))
r->edns.opt_list_inplace_cb_out = NULL;
+ /* internal server error (probably malloc failure) so no
+ * EDE (RFC8914) needed */
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
&m->s.qinfo, r->qid, r->qflags, &r->edns);
}
@@ -1524,7 +1670,7 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
struct comm_reply* rep, uint16_t qid, uint16_t qflags,
const struct query_info* qinfo)
{
- struct mesh_reply* r = regional_alloc(s->s.region,
+ struct mesh_reply* r = regional_alloc(s->s.region,
sizeof(struct mesh_reply));
if(!r)
return 0;
@@ -1693,6 +1839,7 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
if(mstate->s.curmod == 0) {
struct query_info* qinfo = NULL;
uint16_t qflags;
+ int rpz_p = 0;
mesh_query_done(mstate);
mesh_walk_supers(mesh, mstate);
@@ -1701,13 +1848,15 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
* from an external DNS server, we'll need to schedule
* a prefetch after removing the current state, so
* we need to make a copy of the query info here. */
- if(mstate->s.need_refetch)
+ if(mstate->s.need_refetch) {
mesh_copy_qinfo(mstate, &qinfo, &qflags);
+ rpz_p = mstate->s.rpz_passthru;
+ }
mesh_state_delete(&mstate->s);
if(qinfo) {
mesh_schedule_prefetch(mesh, qinfo, qflags,
- 0, 1);
+ 0, 1, rpz_p);
}
return 0;
}
@@ -1917,7 +2066,7 @@ apply_respip_action(struct module_qstate* qstate,
return 1;
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, actinfo,
- alias_rrset, 0, qstate->region, az))
+ alias_rrset, 0, qstate->region, az, NULL))
return 0;
/* xxx_deny actions mean dropping the reply, unless the original reply
@@ -2042,6 +2191,14 @@ mesh_serve_expired_callback(void* arg)
}
}
+ /* Add EDE Stale Answer (RCF8914). Ignore global ede as this is
+ * warning instead of an error */
+ if (r->edns.edns_present && qstate->env->cfg->ede_serve_expired &&
+ qstate->env->cfg->ede) {
+ edns_opt_list_append_ede(&r->edns.opt_list_out,
+ mstate->s.region, LDNS_EDE_STALE_ANSWER, NULL);
+ }
+
r_buffer = r->query_reply.c->buffer;
if(r->query_reply.c->tcp_req_info)
r_buffer = r->query_reply.c->tcp_req_info->spool_buffer;
diff --git a/services/mesh.h b/services/mesh.h
index d0a4b5fb3d0d..3be9b63faedd 100644
--- a/services/mesh.h
+++ b/services/mesh.h
@@ -296,10 +296,13 @@ void mesh_delete(struct mesh_area* mesh);
* @param edns: edns data from client query.
* @param rep: where to reply to.
* @param qid: query id to reply with.
+ * @param rpz_passthru: if true, the rpz passthru was previously found and
+ * further rpz processing is stopped.
*/
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
struct respip_client_info* cinfo, uint16_t qflags,
- struct edns_data* edns, struct comm_reply* rep, uint16_t qid);
+ struct edns_data* edns, struct comm_reply* rep, uint16_t qid,
+ int rpz_passthru);
/**
* New query with callback. Create new query state if needed, and
@@ -314,11 +317,13 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
* @param qid: query id to reply with.
* @param cb: callback function.
* @param cb_arg: callback user arg.
+ * @param rpz_passthru: if true, the rpz passthru was previously found and
+ * further rpz processing is stopped.
* @return 0 on error.
*/
int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, struct edns_data* edns, struct sldns_buffer* buf,
- uint16_t qid, mesh_cb_func_type cb, void* cb_arg);
+ uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru);
/**
* New prefetch message. Create new query state if needed.
@@ -328,9 +333,15 @@ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
* @param qinfo: query from client.
* @param qflags: flags from client query.
* @param leeway: TTL leeway what to expire earlier for this update.
+ * @param rpz_passthru: if true, the rpz passthru was previously found and
+ * further rpz processing is stopped.
+ * @param rep: comm_reply for the client; to be used when subnet is enabled.
+ * @param opt_list: edns opt_list from the client; to be used when subnet is
+ * enabled.
*/
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
- uint16_t qflags, time_t leeway);
+ uint16_t qflags, time_t leeway, int rpz_passthru,
+ struct comm_reply* rep, struct edns_option* opt_list);
/**
* Handle new event from the wire. A serviced query has returned.
diff --git a/services/outside_network.c b/services/outside_network.c
index a7e5fa3ad583..ec37a4a80d71 100644
--- a/services/outside_network.c
+++ b/services/outside_network.c
@@ -1995,6 +1995,9 @@ static int udp_connect_needs_log(int err)
# ifdef ENETDOWN
case ENETDOWN:
# endif
+# ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL:
+# endif
case EPERM:
case EACCES:
if(verbosity >= VERB_ALGO)
@@ -2294,7 +2297,7 @@ reuse_tcp_select_id(struct reuse_tcp* reuse, struct outside_network* outnet)
node = rbtree_first(&reuse->tree_by_id);
log_assert(node && node != RBTREE_NULL); /* tree not empty */
/* see if select is before first node */
- if(select < tree_by_id_get_id(node))
+ if(select < (unsigned)tree_by_id_get_id(node))
return select;
count += tree_by_id_get_id(node);
/* perhaps select is between nodes */
diff --git a/services/rpz.c b/services/rpz.c
index 322e9d1393c4..77b6266fecb9 100644
--- a/services/rpz.c
+++ b/services/rpz.c
@@ -526,13 +526,13 @@ rpz_create(struct config_auth* p)
size_t nmlen = sizeof(nm);
if(!p->rpz_cname) {
- log_err("RPZ override with cname action found, but no "
+ log_err("rpz: override with cname action found, but no "
"rpz-cname-override configured");
goto err;
}
if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) {
- log_err("cannot parse RPZ cname override: %s",
+ log_err("rpz: cannot parse cname override: %s",
p->rpz_cname);
goto err;
}
@@ -614,7 +614,7 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname,
return; /* no need to log these types as unsupported */
}
dname_str(dname, str);
- verbose(VERB_ALGO, "RPZ: qname trigger, %s skipping unsupported action: %s",
+ verbose(VERB_ALGO, "rpz: qname trigger, %s skipping unsupported action: %s",
str, rpz_action_to_string(a));
free(dname);
return;
@@ -999,7 +999,7 @@ rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
rpz_action_to_respip_action(a) == respip_invalid) {
char str[255+1];
dname_str(dname, str);
- verbose(VERB_ALGO, "RPZ: respip trigger, %s skipping unsupported action: %s",
+ verbose(VERB_ALGO, "rpz: respip trigger, %s skipping unsupported action: %s",
str, rpz_action_to_string(a));
return 0;
}
@@ -1560,7 +1560,9 @@ rpz_local_encode(struct module_env* env, struct query_info* qinfo,
}
static struct local_rrset*
-rpz_find_synthesized_rrset(int qtype, struct clientip_synthesized_rr* data) {
+rpz_find_synthesized_rrset(uint16_t qtype,
+ struct clientip_synthesized_rr* data)
+{
struct local_rrset* cursor = data->data;
while( cursor != NULL) {
struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
@@ -1997,6 +1999,7 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
break;
case RPZ_PASSTHRU_ACTION:
ret = NULL;
+ ms->rpz_passthru = 1;
break;
default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
@@ -2051,6 +2054,7 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
break;
case RPZ_PASSTHRU_ACTION:
ret = NULL;
+ ms->rpz_passthru = 1;
break;
default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
@@ -2114,6 +2118,11 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
struct local_zone* z = NULL;
struct matched_delegation_point match = {0};
+ if(ms->rpz_passthru) {
+ verbose(VERB_ALGO, "query is rpz_passthru, no further processing");
+ return NULL;
+ }
+
if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
az = ms->env->auth_zones;
@@ -2179,6 +2188,11 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
enum localzone_type lzt;
struct dns_msg* ret = NULL;
+ if(ms->rpz_passthru) {
+ verbose(VERB_ALGO, "query is rpz_passthru, no further processing");
+ return NULL;
+ }
+
if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
az = ms->env->auth_zones;
@@ -2253,6 +2267,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
break;
case RPZ_PASSTHRU_ACTION:
ret = NULL;
+ ms->rpz_passthru = 1;
break;
default:
verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'",
@@ -2270,7 +2285,8 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
uint8_t* taglist, size_t taglen, struct ub_server_stats* stats,
sldns_buffer* buf, struct regional* temp,
/* output parameters */
- struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out)
+ struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out,
+ int* passthru)
{
int ret = 0;
enum rpz_action client_action;
@@ -2278,7 +2294,9 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out);
client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action);
-
+ if(client_action == RPZ_PASSTHRU_ACTION) {
+ *passthru = 1;
+ }
if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION &&
client_action != RPZ_PASSTHRU_ACTION)) {
if(client_action == RPZ_PASSTHRU_ACTION
@@ -2323,7 +2341,7 @@ int
rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist,
- size_t taglen, struct ub_server_stats* stats)
+ size_t taglen, struct ub_server_stats* stats, int* passthru)
{
struct rpz* r = NULL;
struct auth_zone* a = NULL;
@@ -2332,7 +2350,8 @@ rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
enum localzone_type lzt;
int clientip_trigger = rpz_apply_maybe_clientip_trigger(az, env, qinfo,
- edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r);
+ edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r,
+ passthru);
if(clientip_trigger >= 0) {
if(a) {
lock_rw_unlock(&a->lock);
@@ -2357,6 +2376,10 @@ rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
} else {
lzt = rpz_action_to_localzone_type(r->action_override);
}
+ if(r->action_override == RPZ_PASSTHRU_ACTION ||
+ lzt == local_zone_always_transparent /* RPZ_PASSTHRU_ACTION */) {
+ *passthru = 1;
+ }
if(verbosity >= VERB_ALGO) {
char nm[255+1], zn[255+1];
diff --git a/services/rpz.h b/services/rpz.h
index c29d30dff506..53781197aeec 100644
--- a/services/rpz.h
+++ b/services/rpz.h
@@ -176,12 +176,14 @@ void rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
* @param taglist: taglist to lookup.
* @param taglen: length of taglist.
* @param stats: worker stats struct
+ * @param passthru: returns if the query can passthru further rpz processing.
* @return: 1 if client answer is ready, 0 to continue resolving
*/
int rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
struct regional* temp, struct comm_reply* repinfo,
- uint8_t* taglist, size_t taglen, struct ub_server_stats* stats);
+ uint8_t* taglist, size_t taglen, struct ub_server_stats* stats,
+ int* passthru);
/**
* Callback to process when the iterator module is about to send queries.