aboutsummaryrefslogtreecommitdiff
path: root/contrib/unbound/services
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/unbound/services')
-rw-r--r--contrib/unbound/services/authzone.c17
-rw-r--r--contrib/unbound/services/cache/rrset.c2
-rw-r--r--contrib/unbound/services/listen_dnsport.c14
-rw-r--r--contrib/unbound/services/listen_dnsport.h2
-rw-r--r--contrib/unbound/services/localzone.c107
-rw-r--r--contrib/unbound/services/localzone.h7
-rw-r--r--contrib/unbound/services/mesh.c38
-rw-r--r--contrib/unbound/services/outside_network.c77
-rw-r--r--contrib/unbound/services/outside_network.h2
-rw-r--r--contrib/unbound/services/rpz.c21
-rw-r--r--contrib/unbound/services/rpz.h13
11 files changed, 251 insertions, 49 deletions
diff --git a/contrib/unbound/services/authzone.c b/contrib/unbound/services/authzone.c
index a43a25def993..ecd63ec144f5 100644
--- a/contrib/unbound/services/authzone.c
+++ b/contrib/unbound/services/authzone.c
@@ -2331,7 +2331,8 @@ static int
az_add_negative_soa(struct auth_zone* z, struct regional* region,
struct dns_msg* msg)
{
- uint32_t minimum;
+ time_t minimum;
+ size_t i;
struct packed_rrset_data* d;
struct auth_rrset* soa;
struct auth_data* apex = az_find_name(z, z->name, z->namelen);
@@ -2348,9 +2349,11 @@ az_add_negative_soa(struct auth_zone* z, struct regional* region,
/* last 4 bytes are minimum ttl in network format */
if(d->count == 0) return 0;
if(d->rr_len[0] < 2+4) return 0;
- minimum = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-4));
- d->ttl = (time_t)minimum;
- d->rr_ttl[0] = (time_t)minimum;
+ minimum = (time_t)sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-4));
+ minimum = d->ttl<minimum?d->ttl:minimum;
+ d->ttl = minimum;
+ for(i=0; i < d->count + d->rrsig_count; i++)
+ d->rr_ttl[i] = minimum;
msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[0]);
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
@@ -3286,7 +3289,7 @@ auth_answer_encode(struct query_info* qinfo, struct module_env* env,
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, msg->rep,
- (int)FLAGS_GET_RCODE(msg->rep->flags), edns, repinfo, temp)
+ (int)FLAGS_GET_RCODE(msg->rep->flags), edns, repinfo, temp, env->now_tv)
|| !reply_info_answer_encode(qinfo, msg->rep,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2),
@@ -3310,7 +3313,7 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env,
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
- rcode, edns, repinfo, temp))
+ rcode, edns, repinfo, temp, env->now_tv))
edns->opt_list = NULL;
error_encode(buf, rcode|BIT_AA, qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
@@ -5107,6 +5110,7 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
edns.edns_version = 0;
edns.bits = EDNS_DO;
edns.opt_list = NULL;
+ edns.padding_block_size = 0;
if(sldns_buffer_capacity(buf) < 65535)
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
else edns.udp_size = 65535;
@@ -6295,6 +6299,7 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
edns.edns_version = 0;
edns.bits = EDNS_DO;
edns.opt_list = NULL;
+ edns.padding_block_size = 0;
if(sldns_buffer_capacity(buf) < 65535)
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
else edns.udp_size = 65535;
diff --git a/contrib/unbound/services/cache/rrset.c b/contrib/unbound/services/cache/rrset.c
index 8c0251bcb939..4e3d08bdaaf5 100644
--- a/contrib/unbound/services/cache/rrset.c
+++ b/contrib/unbound/services/cache/rrset.c
@@ -45,6 +45,7 @@
#include "util/config_file.h"
#include "util/data/packed_rrset.h"
#include "util/data/msgreply.h"
+#include "util/data/msgparse.h"
#include "util/regional.h"
#include "util/alloc.h"
#include "util/net_help.h"
@@ -396,6 +397,7 @@ rrset_update_sec_status(struct rrset_cache* r,
cachedata->ttl = updata->ttl + now;
for(i=0; i<cachedata->count+cachedata->rrsig_count; i++)
cachedata->rr_ttl[i] = updata->rr_ttl[i]+now;
+ cachedata->ttl_add = now;
}
}
lock_rw_unlock(&e->lock);
diff --git a/contrib/unbound/services/listen_dnsport.c b/contrib/unbound/services/listen_dnsport.c
index d63c0e0aab00..b790660f2396 100644
--- a/contrib/unbound/services/listen_dnsport.c
+++ b/contrib/unbound/services/listen_dnsport.c
@@ -1456,7 +1456,7 @@ resolve_ifa_name(struct ifaddrs *ifas, const char *search_ifa, char ***ip_addres
log_err("inet_ntop failed");
return 0;
}
- if_indextoname(in6->sin6_scope_id,
+ (void)if_indextoname(in6->sin6_scope_id,
(char *)if_index_name);
if (strlen(if_index_name) != 0) {
snprintf(addr_buf, sizeof(addr_buf),
@@ -1821,12 +1821,12 @@ tcp_req_info_setup_listen(struct tcp_req_info* req)
req->cp->tcp_is_reading = 0;
comm_point_stop_listening(req->cp);
comm_point_start_listening(req->cp, -1,
- req->cp->tcp_timeout_msec);
+ adjusted_tcp_timeout(req->cp));
} else if(rd) {
req->cp->tcp_is_reading = 1;
comm_point_stop_listening(req->cp);
comm_point_start_listening(req->cp, -1,
- req->cp->tcp_timeout_msec);
+ adjusted_tcp_timeout(req->cp));
/* and also read it (from SSL stack buffers), so
* no event read event is expected since the remainder of
* the TLS frame is sitting in the buffers. */
@@ -1834,7 +1834,7 @@ tcp_req_info_setup_listen(struct tcp_req_info* req)
} else {
comm_point_stop_listening(req->cp);
comm_point_start_listening(req->cp, -1,
- req->cp->tcp_timeout_msec);
+ adjusted_tcp_timeout(req->cp));
comm_point_listen_for_rw(req->cp, 0, 0);
}
}
@@ -1947,7 +1947,7 @@ tcp_req_info_handle_readdone(struct tcp_req_info* req)
send_it:
c->tcp_is_reading = 0;
comm_point_stop_listening(c);
- comm_point_start_listening(c, -1, c->tcp_timeout_msec);
+ comm_point_start_listening(c, -1, adjusted_tcp_timeout(c));
return;
}
req->in_worker_handle = 0;
@@ -2065,7 +2065,7 @@ tcp_req_info_send_reply(struct tcp_req_info* req)
/* switch to listen to write events */
comm_point_stop_listening(req->cp);
comm_point_start_listening(req->cp, -1,
- req->cp->tcp_timeout_msec);
+ adjusted_tcp_timeout(req->cp));
return;
}
/* queue up the answer behind the others already pending */
@@ -2793,7 +2793,7 @@ void http2_req_stream_clear(struct http2_stream* h2_stream)
}
}
-nghttp2_session_callbacks* http2_req_callbacks_create()
+nghttp2_session_callbacks* http2_req_callbacks_create(void)
{
nghttp2_session_callbacks *callbacks;
if(nghttp2_session_callbacks_new(&callbacks) == NGHTTP2_ERR_NOMEM) {
diff --git a/contrib/unbound/services/listen_dnsport.h b/contrib/unbound/services/listen_dnsport.h
index 9d6ea2c33adf..f438ff4580f7 100644
--- a/contrib/unbound/services/listen_dnsport.h
+++ b/contrib/unbound/services/listen_dnsport.h
@@ -404,7 +404,7 @@ size_t http2_get_response_buffer_size(void);
* Create nghttp2 callbacks to handle HTTP2 requests.
* @return malloc'ed struct, NULL on failure
*/
-nghttp2_session_callbacks* http2_req_callbacks_create();
+nghttp2_session_callbacks* http2_req_callbacks_create(void);
/** Free http2 stream buffers and decrease buffer counters */
void http2_req_stream_clear(struct http2_stream* h2_stream);
diff --git a/contrib/unbound/services/localzone.c b/contrib/unbound/services/localzone.c
index cad46066334c..fd2ff2bb67f7 100644
--- a/contrib/unbound/services/localzone.c
+++ b/contrib/unbound/services/localzone.c
@@ -463,6 +463,48 @@ lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
return 1;
}
+/* Mark the SOA record for the zone. This only marks the SOA rrset; the data
+ * for the RR is entered later on local_zone_enter_rr() as with the other
+ * records. An artifical soa_negative record with a modified TTL (minimum of
+ * the TTL and the SOA.MINIMUM) is also created and marked for usage with
+ * negative answers and to avoid allocations during those answers. */
+static int
+lz_mark_soa_for_zone(struct local_zone* z, struct ub_packed_rrset_key* soa_rrset,
+ uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr)
+{
+ struct packed_rrset_data* pd = (struct packed_rrset_data*)
+ regional_alloc_zero(z->region, sizeof(*pd));
+ struct ub_packed_rrset_key* rrset_negative = (struct ub_packed_rrset_key*)
+ regional_alloc_zero(z->region, sizeof(*rrset_negative));
+ time_t minimum;
+ if(!rrset_negative||!pd) {
+ log_err("out of memory");
+ return 0;
+ }
+ /* Mark the original SOA record and then continue with the negative one. */
+ z->soa = soa_rrset;
+ rrset_negative->entry.key = rrset_negative;
+ pd->trust = rrset_trust_prim_noglue;
+ pd->security = sec_status_insecure;
+ rrset_negative->entry.data = pd;
+ rrset_negative->rk.dname = soa_rrset->rk.dname;
+ rrset_negative->rk.dname_len = soa_rrset->rk.dname_len;
+ rrset_negative->rk.type = soa_rrset->rk.type;
+ rrset_negative->rk.rrset_class = soa_rrset->rk.rrset_class;
+ if(!rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr))
+ return 0;
+ /* last 4 bytes are minimum ttl in network format */
+ if(pd->count == 0 || pd->rr_len[0] < 2+4)
+ return 0;
+ minimum = (time_t)sldns_read_uint32(pd->rr_data[0]+(pd->rr_len[0]-4));
+ minimum = ttl<minimum?ttl:minimum;
+ pd->ttl = minimum;
+ pd->rr_ttl[0] = minimum;
+
+ z->soa_negative = rrset_negative;
+ return 1;
+}
+
int
local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl,
@@ -502,8 +544,10 @@ local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
if(query_dname_compare(node->name, z->name) == 0) {
if(rrtype == LDNS_RR_TYPE_NSEC)
rrset->rrset->rk.flags = PACKED_RRSET_NSEC_AT_APEX;
- if(rrtype == LDNS_RR_TYPE_SOA)
- z->soa = rrset->rrset;
+ if(rrtype == LDNS_RR_TYPE_SOA &&
+ !lz_mark_soa_for_zone(z, rrset->rrset, rdata, rdata_len, ttl,
+ rrstr))
+ return 0;
}
}
pd = (struct packed_rrset_data*)rrset->rrset->entry.data;
@@ -1215,7 +1259,7 @@ local_encode(struct query_info* qinfo, struct module_env* env,
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
- repinfo, temp) || !reply_info_answer_encode(qinfo, &rep,
+ repinfo, temp, env->now_tv) || !reply_info_answer_encode(qinfo, &rep,
*(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
@@ -1237,7 +1281,7 @@ local_error_encode(struct query_info* qinfo, struct module_env* env,
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
- rcode, edns, repinfo, temp))
+ rcode, edns, repinfo, temp, env->now_tv))
edns->opt_list = NULL;
error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
@@ -1548,9 +1592,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
lz_type == local_zone_inform_redirect ||
lz_type == local_zone_always_nodata)?
LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
- if(z->soa)
+ if(z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
- z->soa, 0, rcode);
+ z->soa_negative, 0, rcode);
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
(rcode|BIT_AA));
return 1;
@@ -1558,6 +1602,46 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
|| lz_type == local_zone_always_transparent) {
/* no NODATA or NXDOMAINS for this zone type */
return 0;
+ } else if(lz_type == local_zone_always_null) {
+ /* 0.0.0.0 or ::0 or noerror/nodata for this zone type,
+ * used for blocklists. */
+ if(qinfo->qtype == LDNS_RR_TYPE_A ||
+ qinfo->qtype == LDNS_RR_TYPE_AAAA) {
+ struct ub_packed_rrset_key lrr;
+ struct packed_rrset_data d;
+ time_t rr_ttl = 3600;
+ size_t rr_len = 0;
+ uint8_t rr_data[2+16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ uint8_t* rr_datas = rr_data;
+ memset(&lrr, 0, sizeof(lrr));
+ memset(&d, 0, sizeof(d));
+ lrr.entry.data = &d;
+ lrr.rk.dname = qinfo->qname;
+ lrr.rk.dname_len = qinfo->qname_len;
+ lrr.rk.type = htons(qinfo->qtype);
+ lrr.rk.rrset_class = htons(qinfo->qclass);
+ if(qinfo->qtype == LDNS_RR_TYPE_A) {
+ rr_len = 4;
+ sldns_write_uint16(rr_data, rr_len);
+ rr_len += 2;
+ } else {
+ rr_len = 16;
+ sldns_write_uint16(rr_data, rr_len);
+ rr_len += 2;
+ }
+ d.ttl = rr_ttl;
+ d.count = 1;
+ d.rr_len = &rr_len;
+ d.rr_data = &rr_datas;
+ d.rr_ttl = &rr_ttl;
+ return local_encode(qinfo, env, edns, repinfo, buf, temp,
+ &lrr, 1, LDNS_RCODE_NOERROR);
+ } else {
+ local_error_encode(qinfo, env, edns, repinfo, buf,
+ temp, LDNS_RCODE_NOERROR,
+ (LDNS_RCODE_NOERROR|BIT_AA));
+ }
+ return 1;
}
/* else lz_type == local_zone_transparent */
@@ -1565,9 +1649,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
* does not, then we should make this noerror/nodata */
if(ld && ld->rrsets) {
int rcode = LDNS_RCODE_NOERROR;
- if(z->soa)
+ if(z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
- z->soa, 0, rcode);
+ z->soa_negative, 0, rcode);
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
(rcode|BIT_AA));
return 1;
@@ -1762,6 +1846,7 @@ const char* local_zone_type2str(enum localzone_type t)
case local_zone_always_nxdomain: return "always_nxdomain";
case local_zone_always_nodata: return "always_nodata";
case local_zone_always_deny: return "always_deny";
+ case local_zone_always_null: return "always_null";
case local_zone_noview: return "noview";
case local_zone_invalid: return "invalid";
}
@@ -1798,6 +1883,8 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
*t = local_zone_always_nodata;
else if(strcmp(type, "always_deny") == 0)
*t = local_zone_always_deny;
+ else if(strcmp(type, "always_null") == 0)
+ *t = local_zone_always_null;
else if(strcmp(type, "noview") == 0)
*t = local_zone_noview;
else if(strcmp(type, "nodefault") == 0)
@@ -2000,8 +2087,10 @@ void local_zones_del_data(struct local_zones* zones,
/* no memory recycling for zone deletions ... */
d->rrsets = NULL;
/* did we delete the soa record ? */
- if(query_dname_compare(d->name, z->name) == 0)
+ if(query_dname_compare(d->name, z->name) == 0) {
z->soa = NULL;
+ z->soa_negative = NULL;
+ }
/* cleanup the empty nonterminals for this name */
del_empty_term(z, d, name, len, labs);
diff --git a/contrib/unbound/services/localzone.h b/contrib/unbound/services/localzone.h
index bb35939366a7..3da5c8754bf3 100644
--- a/contrib/unbound/services/localzone.h
+++ b/contrib/unbound/services/localzone.h
@@ -96,6 +96,9 @@ enum localzone_type {
local_zone_always_nodata,
/** drop query, even when there is local data */
local_zone_always_deny,
+ /** answer with 0.0.0.0 or ::0 or noerror/nodata, even when there is
+ * local data */
+ local_zone_always_null,
/** answer not from the view, but global or no-answer */
local_zone_noview,
/** Invalid type, cannot be used to generate answer */
@@ -155,6 +158,10 @@ struct local_zone {
rbtree_type data;
/** if data contains zone apex SOA data, this is a ptr to it. */
struct ub_packed_rrset_key* soa;
+ /** if data contains zone apex SOA data, this is a prt to an
+ * artificial negative SOA rrset (TTL is the minimum of the TTL and the
+ * SOA.MINIMUM). */
+ struct ub_packed_rrset_key* soa_negative;
};
/**
diff --git a/contrib/unbound/services/mesh.c b/contrib/unbound/services/mesh.c
index cd90509366f2..91d23debf351 100644
--- a/contrib/unbound/services/mesh.c
+++ b/contrib/unbound/services/mesh.c
@@ -498,7 +498,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
if(!s) {
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
- LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
+ LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
edns->opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
@@ -514,7 +514,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
if(!s->s.edns_opts_front_in) {
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL,
- NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
+ NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
edns->opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
@@ -587,7 +587,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
servfail_mem:
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
- NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
+ NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
edns->opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
@@ -1112,10 +1112,12 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub)
* @param rcode: if not 0, error code.
* @param rep: reply to send (or NULL if rcode is set).
* @param r: callback entry
+ * @param start_time: the time to pass to callback functions, it is 0 or
+ * a value from one of the packets if the mesh state had packets.
*/
static void
mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
- struct mesh_cb* r)
+ struct mesh_cb* r, struct timeval* start_time)
{
int secure;
char* reason = NULL;
@@ -1136,11 +1138,11 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
if(rcode) {
if(rcode == LDNS_RCODE_SERVFAIL) {
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, rcode, &r->edns, NULL, m->s.region))
+ rep, rcode, &r->edns, NULL, m->s.region, start_time))
r->edns.opt_list = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
- &r->edns, NULL, m->s.region))
+ &r->edns, NULL, m->s.region, start_time))
r->edns.opt_list = NULL;
}
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
@@ -1155,7 +1157,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
r->edns.bits &= EDNS_DO;
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
- LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region) ||
+ LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region, start_time) ||
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r->buf, 0, 1,
m->s.env->scratch, udp_size, &r->edns,
@@ -1256,11 +1258,11 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
m->s.qinfo.local_alias = r->local_alias;
if(rcode == LDNS_RCODE_SERVFAIL) {
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, rcode, &r->edns, &r->query_reply, m->s.region))
+ rep, rcode, &r->edns, &r->query_reply, m->s.region, &r->start_time))
r->edns.opt_list = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
- &r->edns, &r->query_reply, m->s.region))
+ &r->edns, &r->query_reply, m->s.region, &r->start_time))
r->edns.opt_list = NULL;
}
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
@@ -1277,7 +1279,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
m->s.qinfo.qname = r->qname;
m->s.qinfo.local_alias = r->local_alias;
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
- LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region) ||
+ LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region, &r->start_time) ||
!apply_edns_options(&r->edns, &edns_bak,
m->s.env->cfg, r->query_reply.c,
m->s.region) ||
@@ -1287,7 +1289,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
secure))
{
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))
+ rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time))
r->edns.opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
&m->s.qinfo, r->qid, r->qflags, &r->edns);
@@ -1330,6 +1332,7 @@ void mesh_query_done(struct mesh_state* mstate)
struct mesh_cb* c;
struct reply_info* rep = (mstate->s.return_msg?
mstate->s.return_msg->rep:NULL);
+ struct timeval tv = {0, 0};
/* No need for the serve expired timer anymore; we are going to reply. */
if(mstate->s.serve_expired_data) {
comm_timer_delete(mstate->s.serve_expired_data->timer);
@@ -1349,6 +1352,8 @@ void mesh_query_done(struct mesh_state* mstate)
}
}
for(r = mstate->reply_list; r; r = r->next) {
+ tv = r->start_time;
+
/* if a response-ip address block has been stored the
* information should be logged for each client. */
if(mstate->s.respip_action_info &&
@@ -1421,7 +1426,7 @@ void mesh_query_done(struct mesh_state* mstate)
if(!mstate->reply_list && !mstate->cb_list &&
mstate->super_set.count == 0)
mstate->s.env->mesh->num_detached_states++;
- mesh_do_callback(mstate, mstate->s.return_rcode, rep, c);
+ mesh_do_callback(mstate, mstate->s.return_rcode, rep, c, &tv);
}
}
@@ -1917,13 +1922,16 @@ mesh_serve_expired_callback(void* arg)
struct respip_action_info actinfo;
struct query_info* lookup_qinfo = &qstate->qinfo;
struct query_info qinfo_tmp;
+ struct timeval tv = {0, 0};
int must_validate = (!(qstate->query_flags&BIT_CD)
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
if(!qstate->serve_expired_data) return;
verbose(VERB_ALGO, "Serve expired: Trying to reply with expired data");
comm_timer_delete(qstate->serve_expired_data->timer);
qstate->serve_expired_data->timer = NULL;
- if(qstate->blacklist || qstate->no_cache_lookup || qstate->is_drop) {
+ /* If is_drop or no_cache_lookup (modules that handle their own cache e.g.,
+ * subnetmod) ignore stale data from the main cache. */
+ if(qstate->no_cache_lookup || qstate->is_drop) {
verbose(VERB_ALGO,
"Serve expired: Not allowed to look into cache for stale");
return;
@@ -1988,6 +1996,8 @@ mesh_serve_expired_callback(void* arg)
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
for(r = mstate->reply_list; r; r = r->next) {
+ tv = r->start_time;
+
/* If address info is returned, it means the action should be an
* 'inform' variant and the information should be logged. */
if(actinfo.addrinfo) {
@@ -2042,6 +2052,6 @@ mesh_serve_expired_callback(void* arg)
if(!mstate->reply_list && !mstate->cb_list &&
mstate->super_set.count == 0)
qstate->env->mesh->num_detached_states++;
- mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c);
+ mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c, &tv);
}
}
diff --git a/contrib/unbound/services/outside_network.c b/contrib/unbound/services/outside_network.c
index e87aba893d98..6c6b42ccbdb8 100644
--- a/contrib/unbound/services/outside_network.c
+++ b/contrib/unbound/services/outside_network.c
@@ -90,6 +90,10 @@ static int randomize_and_send_udp(struct pending* pend, sldns_buffer* packet,
static void waiting_list_remove(struct outside_network* outnet,
struct waiting_tcp* w);
+/** remove reused element from tree and lru list */
+static void reuse_tcp_remove_tree_list(struct outside_network* outnet,
+ struct reuse_tcp* reuse);
+
int
pending_cmp(const void* key1, const void* key2)
{
@@ -424,8 +428,11 @@ static int
reuse_tcp_insert(struct outside_network* outnet, struct pending_tcp* pend_tcp)
{
log_reuse_tcp(VERB_CLIENT, "reuse_tcp_insert", &pend_tcp->reuse);
- if(pend_tcp->reuse.item_on_lru_list)
+ if(pend_tcp->reuse.item_on_lru_list) {
+ if(!pend_tcp->reuse.node.key)
+ log_err("internal error: reuse_tcp_insert: on lru list without key");
return 1;
+ }
pend_tcp->reuse.node.key = &pend_tcp->reuse;
pend_tcp->reuse.pending = pend_tcp;
if(!rbtree_insert(&outnet->tcp_reuse, &pend_tcp->reuse.node)) {
@@ -477,7 +484,7 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
if(outnet->tcp_reuse.root == NULL ||
outnet->tcp_reuse.root == RBTREE_NULL)
return NULL;
- if(rbtree_find_less_equal(&outnet->tcp_reuse, &key_p.reuse.node,
+ if(rbtree_find_less_equal(&outnet->tcp_reuse, &key_p.reuse,
&result)) {
/* exact match */
/* but the key is on stack, and ptr is compared, impossible */
@@ -661,6 +668,14 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
pend->reuse.cp_more_write_again = 0;
memcpy(&pend->c->repinfo.addr, &w->addr, w->addrlen);
pend->reuse.pending = pend;
+
+ /* Remove from tree in case the is_ssl will be different and causes the
+ * identity of the reuse_tcp to change; could result in nodes not being
+ * deleted from the tree (because the new identity does not match the
+ * previous node) but their ->key would be changed to NULL. */
+ if(pend->reuse.node.key)
+ reuse_tcp_remove_tree_list(w->outnet, &pend->reuse);
+
if(pend->c->ssl)
pend->reuse.is_ssl = 1;
else pend->reuse.is_ssl = 0;
@@ -677,8 +692,10 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
static void
reuse_tcp_lru_touch(struct outside_network* outnet, struct reuse_tcp* reuse)
{
- if(!reuse->item_on_lru_list)
+ if(!reuse->item_on_lru_list) {
+ log_err("internal error: we need to touch the lru_list but item not in list");
return; /* not on the list, no lru to modify */
+ }
if(!reuse->lru_prev)
return; /* already first in the list */
/* remove at current position */
@@ -847,7 +864,7 @@ reuse_tcp_remove_tree_list(struct outside_network* outnet,
verbose(VERB_CLIENT, "reuse_tcp_remove_tree_list");
if(reuse->node.key) {
/* delete it from reuse tree */
- (void)rbtree_delete(&outnet->tcp_reuse, &reuse->node);
+ (void)rbtree_delete(&outnet->tcp_reuse, reuse);
reuse->node.key = NULL;
}
/* delete from reuse list */
@@ -1745,6 +1762,33 @@ select_id(struct outside_network* outnet, struct pending* pend,
return 1;
}
+/** return true is UDP connect error needs to be logged */
+static int udp_connect_needs_log(int err)
+{
+ switch(err) {
+ case ECONNREFUSED:
+# ifdef ENETUNREACH
+ case ENETUNREACH:
+# endif
+# ifdef EHOSTDOWN
+ case EHOSTDOWN:
+# endif
+# ifdef EHOSTUNREACH
+ case EHOSTUNREACH:
+# endif
+# ifdef ENETDOWN
+ case ENETDOWN:
+# endif
+ if(verbosity >= VERB_ALGO)
+ return 1;
+ return 0;
+ default:
+ break;
+ }
+ return 1;
+}
+
+
/** Select random interface and port */
static int
select_ifport(struct outside_network* outnet, struct pending* pend,
@@ -1804,9 +1848,11 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
/* connect() to the destination */
if(connect(fd, (struct sockaddr*)&pend->addr,
pend->addrlen) < 0) {
- log_err_addr("udp connect failed",
- strerror(errno), &pend->addr,
- pend->addrlen);
+ if(udp_connect_needs_log(errno)) {
+ log_err_addr("udp connect failed",
+ strerror(errno), &pend->addr,
+ pend->addrlen);
+ }
sock_close(fd);
return 0;
}
@@ -2213,7 +2259,8 @@ 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)
+ uint8_t* zone, size_t zonelen, int qtype, struct edns_option* opt_list,
+ size_t pad_queries_block_size)
{
struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq));
#ifdef UNBOUND_DEBUG
@@ -2271,6 +2318,7 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
sq->status = serviced_initial;
sq->retry = 0;
sq->to_be_deleted = 0;
+ sq->padding_block_size = pad_queries_block_size;
#ifdef UNBOUND_DEBUG
ins =
#else
@@ -2452,6 +2500,7 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
if(with_edns) {
/* add edns section */
struct edns_data edns;
+ struct edns_option padding_option;
edns.edns_present = 1;
edns.ext_rcode = 0;
edns.edns_version = EDNS_ADVERTISED_VERSION;
@@ -2474,6 +2523,14 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
edns.bits = EDNS_DO;
if(sq->dnssec & BIT_CD)
LDNS_CD_SET(sldns_buffer_begin(buff));
+ if (sq->ssl_upstream && sq->padding_block_size) {
+ padding_option.opt_code = LDNS_EDNS_PADDING;
+ padding_option.opt_len = 0;
+ padding_option.opt_data = NULL;
+ padding_option.next = edns.opt_list;
+ edns.opt_list = &padding_option;
+ edns.padding_block_size = sq->padding_block_size;
+ }
attach_edns_record(buff, &edns);
}
}
@@ -2997,7 +3054,9 @@ outnet_serviced_query(struct outside_network* outnet,
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);
+ qstate->edns_opts_back_out,
+ ( ssl_upstream && env->cfg->pad_queries
+ ? env->cfg->pad_queries_block_size : 0 ));
if(!sq) {
free(cb);
return NULL;
diff --git a/contrib/unbound/services/outside_network.h b/contrib/unbound/services/outside_network.h
index 2fe97fa6c5c9..fe287af4fcce 100644
--- a/contrib/unbound/services/outside_network.h
+++ b/contrib/unbound/services/outside_network.h
@@ -502,6 +502,8 @@ struct serviced_query {
struct service_callback* cblist;
/** the UDP or TCP query that is pending, see status which */
void* pending;
+ /** block size with which to pad encrypted queries (default: 128) */
+ size_t padding_block_size;
};
/**
diff --git a/contrib/unbound/services/rpz.c b/contrib/unbound/services/rpz.c
index 13304652cc02..2b6b0ac3fccf 100644
--- a/contrib/unbound/services/rpz.c
+++ b/contrib/unbound/services/rpz.c
@@ -668,7 +668,8 @@ rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
int only_exact, int wr, int zones_keep_lock)
{
uint8_t* ce;
- size_t ce_len, ce_labs;
+ size_t ce_len;
+ int ce_labs;
uint8_t wc[LDNS_MAX_DOMAINLEN+1];
int exact;
struct local_zone* z = NULL;
@@ -963,8 +964,8 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
for(a = az->rpz_first; a; a = a->rpz_az_next) {
lock_rw_rdlock(&a->lock);
r = a->rpz;
- if(!r->taglist || taglist_intersect(r->taglist,
- r->taglistlen, taglist, taglen)) {
+ if(!r->disabled && (!r->taglist || taglist_intersect(r->taglist,
+ r->taglistlen, taglist, taglen))) {
z = rpz_find_zone(r, qinfo->qname, qinfo->qname_len,
qinfo->qclass, 0, 0, 0);
if(z && r->action_override == RPZ_DISABLED_ACTION) {
@@ -1044,3 +1045,17 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
return ret;
}
+
+void rpz_enable(struct rpz* r)
+{
+ if(!r)
+ return;
+ r->disabled = 0;
+}
+
+void rpz_disable(struct rpz* r)
+{
+ if(!r)
+ return;
+ r->disabled = 1;
+}
diff --git a/contrib/unbound/services/rpz.h b/contrib/unbound/services/rpz.h
index 77a2db55ced4..d5996a6cfa26 100644
--- a/contrib/unbound/services/rpz.h
+++ b/contrib/unbound/services/rpz.h
@@ -99,6 +99,7 @@ struct rpz {
int log;
char* log_name;
struct regional* region;
+ int disabled;
};
/**
@@ -198,4 +199,16 @@ void rpz_finish_config(struct rpz* r);
enum respip_action
rpz_action_to_respip_action(enum rpz_action a);
+/**
+ * Enable RPZ
+ * @param r: RPZ struct to enable
+ */
+void rpz_enable(struct rpz* r);
+
+/**
+ * Disable RPZ
+ * @param r: RPZ struct to disable
+ */
+void rpz_disable(struct rpz* r);
+
#endif /* SERVICES_RPZ_H */