aboutsummaryrefslogtreecommitdiff
path: root/contrib/unbound/services/mesh.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/unbound/services/mesh.c')
-rw-r--r--contrib/unbound/services/mesh.c416
1 files changed, 210 insertions, 206 deletions
diff --git a/contrib/unbound/services/mesh.c b/contrib/unbound/services/mesh.c
index 30bcf7cda155..47cfb04249b5 100644
--- a/contrib/unbound/services/mesh.c
+++ b/contrib/unbound/services/mesh.c
@@ -4,22 +4,22 @@
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
+ *
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
- *
+ *
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -63,81 +63,18 @@
#include "util/data/dname.h"
#include "respip/respip.h"
#include "services/listen_dnsport.h"
+#include "util/timeval_func.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)
-{
-#ifndef S_SPLINT_S
- time_t end_usec = end->tv_usec;
- d->tv_sec = end->tv_sec - start->tv_sec;
- if(end_usec < start->tv_usec) {
- end_usec += 1000000;
- d->tv_sec--;
- }
- d->tv_usec = end_usec - start->tv_usec;
-#endif
-}
-
-/** add timers and the values do not overflow or become negative */
-static void
-timeval_add(struct timeval* d, const struct timeval* add)
-{
-#ifndef S_SPLINT_S
- d->tv_sec += add->tv_sec;
- d->tv_usec += add->tv_usec;
- if(d->tv_usec >= 1000000 ) {
- d->tv_usec -= 1000000;
- d->tv_sec++;
- }
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
#endif
-}
-
-/** divide sum of timers to get average */
-static void
-timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d)
-{
-#ifndef S_SPLINT_S
- size_t leftover;
- if(d <= 0) {
- avg->tv_sec = 0;
- avg->tv_usec = 0;
- return;
- }
- avg->tv_sec = sum->tv_sec / d;
- avg->tv_usec = sum->tv_usec / d;
- /* handle fraction from seconds divide */
- leftover = sum->tv_sec - avg->tv_sec*d;
- if(leftover <= 0)
- leftover = 0;
- avg->tv_usec += (((long long)leftover)*((long long)1000000))/d;
- if(avg->tv_sec < 0)
- avg->tv_sec = 0;
- if(avg->tv_usec < 0)
- avg->tv_usec = 0;
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
#endif
-}
-
-/** histogram compare of time values */
-static int
-timeval_smaller(const struct timeval* x, const struct timeval* y)
-{
-#ifndef S_SPLINT_S
- if(x->tv_sec < y->tv_sec)
- return 1;
- else if(x->tv_sec == y->tv_sec) {
- if(x->tv_usec <= y->tv_usec)
- return 1;
- else return 0;
- }
- else return 0;
-#endif
-}
/**
* Compare two response-ip client info entries for the purpose of mesh state
@@ -249,7 +186,7 @@ mesh_state_ref_compare(const void* ap, const void* bp)
return mesh_state_compare(a->s, b->s);
}
-struct mesh_area*
+struct mesh_area*
mesh_create(struct module_stack* stack, struct module_env* env)
{
struct mesh_area* mesh = calloc(1, sizeof(struct mesh_area));
@@ -275,6 +212,7 @@ mesh_create(struct module_stack* stack, struct module_env* env)
mesh->stats_jostled = 0;
mesh->stats_dropped = 0;
mesh->ans_expired = 0;
+ mesh->ans_cachedb = 0;
mesh->max_reply_states = env->cfg->num_queries_per_thread;
mesh->max_forever_states = (mesh->max_reply_states+1)/2;
#ifndef S_SPLINT_S
@@ -298,7 +236,7 @@ mesh_delete_helper(rbnode_type* n)
* traversal and rbtree rebalancing do not work together */
}
-void
+void
mesh_delete(struct mesh_area* mesh)
{
if(!mesh)
@@ -341,7 +279,7 @@ int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf)
if(m && m->reply_list && m->list_select == mesh_jostle_list) {
/* how old is it? */
struct timeval age;
- timeval_subtract(&age, mesh->env->now_tv,
+ timeval_subtract(&age, mesh->env->now_tv,
&m->reply_list->start_time);
if(timeval_smaller(&mesh->jostle_max, &age)) {
/* its a goner */
@@ -517,6 +455,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
comm_point_send_reply(rep);
return;
}
+ /* set detached (it is now) */
+ mesh->num_detached_states++;
if(unique)
mesh_state_make_unique(s);
s->s.rpz_passthru = rpz_passthru;
@@ -525,13 +465,14 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
s->s.region);
if(!s->s.edns_opts_front_in) {
- log_err("mesh_state_create: out of memory; SERVFAIL");
+ log_err("edns_opt_copy_region: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL,
NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
edns->opt_list_inplace_cb_out = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
comm_point_send_reply(rep);
+ mesh_state_delete(&s->s);
return;
}
}
@@ -543,8 +484,6 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
#endif
rbtree_insert(&mesh->all, &s->node);
log_assert(n != NULL);
- /* set detached (it is now) */
- mesh->num_detached_states++;
added = 1;
}
if(!s->reply_list && !s->cb_list) {
@@ -585,11 +524,11 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
/* 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;
}
@@ -610,9 +549,9 @@ servfail_mem:
return;
}
-int
+int
mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
- uint16_t qflags, struct edns_data* edns, sldns_buffer* buf,
+ uint16_t qflags, struct edns_data* edns, sldns_buffer* buf,
uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru)
{
struct mesh_state* s = NULL;
@@ -637,6 +576,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
if(!s) {
return 0;
}
+ /* set detached (it is now) */
+ mesh->num_detached_states++;
if(unique)
mesh_state_make_unique(s);
s->s.rpz_passthru = rpz_passthru;
@@ -644,6 +585,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
s->s.region);
if(!s->s.edns_opts_front_in) {
+ mesh_state_delete(&s->s);
return 0;
}
}
@@ -654,8 +596,6 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
#endif
rbtree_insert(&mesh->all, &s->node);
log_assert(n != NULL);
- /* set detached (it is now) */
- mesh->num_detached_states++;
added = 1;
}
if(!s->reply_list && !s->cb_list) {
@@ -672,6 +612,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
}
/* add serve expired timer if not already there */
if(timeout && !mesh_serve_expired_init(s, timeout)) {
+ if(added)
+ mesh_state_delete(&s->s);
return 0;
}
/* update statistics */
@@ -773,7 +715,7 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
* 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)
+ int rpz_passthru, struct sockaddr_storage* addr, struct edns_option* edns_list)
{
struct mesh_state* s = NULL;
struct edns_option* opt = NULL;
@@ -803,20 +745,10 @@ static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh,
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, s->s.region);
- if(!s->s.edns_opts_front_in) {
- log_err("prefetch_subnet subnet_ecs_opt_list_append: out of memory");
- return;
- }
+ /* Store the client's address. Later in the subnet module,
+ * it is decided whether to include an ECS option or not.
+ */
+ s->s.client_addr = *addr;
}
#ifdef UNBOUND_DEBUG
n =
@@ -863,14 +795,14 @@ static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh,
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, time_t leeway, int rpz_passthru,
- struct comm_reply* rep, struct edns_option* opt_list)
+ struct sockaddr_storage* addr, struct edns_option* opt_list)
{
+ (void)addr;
(void)opt_list;
- (void)rep;
#ifdef CLIENT_SUBNET
- if(rep)
+ if(addr)
mesh_schedule_prefetch_subnet(mesh, qinfo, qflags, leeway, 1,
- rpz_passthru, rep, opt_list);
+ rpz_passthru, addr, opt_list);
else
#endif
mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1,
@@ -900,7 +832,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
int i;
if(!region)
return NULL;
- mstate = (struct mesh_state*)regional_alloc(region,
+ mstate = (struct mesh_state*)regional_alloc(region,
sizeof(struct mesh_state));
if(!mstate) {
alloc_reg_release(env->alloc, region);
@@ -970,19 +902,13 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
return mstate;
}
-int
-mesh_state_is_unique(struct mesh_state* mstate)
-{
- return mstate->unique != NULL;
-}
-
void
mesh_state_make_unique(struct mesh_state* mstate)
{
mstate->unique = mstate;
}
-void
+void
mesh_state_cleanup(struct mesh_state* mstate)
{
struct mesh_area* mesh;
@@ -1028,7 +954,7 @@ mesh_state_cleanup(struct mesh_state* mstate)
alloc_reg_release(mstate->s.env->alloc, mstate->s.region);
}
-void
+void
mesh_state_delete(struct module_qstate* qstate)
{
struct mesh_area* mesh;
@@ -1041,10 +967,10 @@ mesh_state_delete(struct module_qstate* qstate)
mesh_detach_subs(&mstate->s);
if(mstate->list_select == mesh_forever_list) {
mesh->num_forever_states --;
- mesh_list_remove(mstate, &mesh->forever_first,
+ mesh_list_remove(mstate, &mesh->forever_first,
&mesh->forever_last);
} else if(mstate->list_select == mesh_jostle_list) {
- mesh_list_remove(mstate, &mesh->jostle_first,
+ mesh_list_remove(mstate, &mesh->jostle_first,
&mesh->jostle_last);
}
if(!mstate->reply_list && !mstate->cb_list
@@ -1116,7 +1042,7 @@ void mesh_detach_subs(struct module_qstate* qstate)
if(!ref->s->reply_list && !ref->s->cb_list
&& ref->s->super_set.count == 0) {
mesh->num_detached_states++;
- log_assert(mesh->num_detached_states +
+ log_assert(mesh->num_detached_states +
mesh->num_reply_states <= mesh->all.count);
}
}
@@ -1181,7 +1107,7 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
if(!mesh_state_attachment(qstate->mesh_info, sub))
return 0;
/* if it was a duplicate attachment, the count was not zero before */
- if(!sub->reply_list && !sub->cb_list && was_detached &&
+ if(!sub->reply_list && !sub->cb_list && was_detached &&
sub->super_set.count == 1) {
/* it used to be detached, before this one got added */
log_assert(mesh->num_detached_states > 0);
@@ -1251,7 +1177,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
else secure = 0;
if(!rep && rcode == LDNS_RCODE_NOERROR)
rcode = LDNS_RCODE_SERVFAIL;
- if(!rcode && (rep->security == sec_status_bogus ||
+ if(!rcode && rep && (rep->security == sec_status_bogus ||
rep->security == sec_status_secure_sentinel_fail)) {
if(!(reason = errinf_to_str_bogus(&m->s)))
rcode = LDNS_RCODE_SERVFAIL;
@@ -1277,13 +1203,15 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
r->edns.udp_size = EDNS_ADVERTISED_SIZE;
r->edns.ext_rcode = 0;
r->edns.bits &= EDNS_DO;
+ if(m->s.env->cfg->disable_edns_do && (r->edns.bits&EDNS_DO))
+ r->edns.edns_present = 0;
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
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,
- (int)(r->edns.bits & EDNS_DO), secure))
+ !reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
+ r->qflags, r->buf, 0, 1,
+ m->s.env->scratch, udp_size, &r->edns,
+ (int)(r->edns.bits & EDNS_DO), secure))
{
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
(*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf,
@@ -1291,7 +1219,8 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
} else {
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
(*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf,
- rep->security, reason, was_ratelimited);
+ (rep?rep->security:sec_status_unchecked),
+ reason, was_ratelimited);
}
}
free(reason);
@@ -1303,18 +1232,45 @@ static inline int
mesh_is_rpz_respip_tcponly_action(struct mesh_state const* m)
{
struct respip_action_info const* respip_info = m->s.respip_action_info;
- return respip_info == NULL
+ return (respip_info == NULL
? 0
: (respip_info->rpz_used
&& !respip_info->rpz_disabled
- && respip_info->action == respip_truncate);
+ && respip_info->action == respip_truncate))
+ || m->s.tcp_required;
}
static inline int
-mesh_is_udp(struct mesh_reply const* r) {
+mesh_is_udp(struct mesh_reply const* r)
+{
return r->query_reply.c->type == comm_udp;
}
+static inline void
+mesh_find_and_attach_ede_and_reason(struct mesh_state* m,
+ struct reply_info* rep, struct mesh_reply* r)
+{
+ /* OLD note:
+ * 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
+ * NEW note:
+ * The compelling reason is that with caching support, the value
+ * in the reply_info is cached.
+ * The reason members of the reply_info struct should be
+ * updated as they are already cached. No reason to
+ * try and find the EDE information in errinf anymore.
+ */
+ if(rep->reason_bogus != LDNS_EDE_NONE) {
+ edns_opt_list_append_ede(&r->edns.opt_list_out,
+ m->s.region, rep->reason_bogus, rep->reason_bogus_str);
+ }
+}
+
/**
* Send reply to mesh reply entry
* @param m: mesh state to send it for.
@@ -1346,7 +1302,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
/* examine security status */
if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
- m->s.env->cfg->ignore_cd) && rep &&
+ m->s.env->cfg->ignore_cd) && rep &&
(rep->security <= sec_status_bogus ||
rep->security == sec_status_secure_sentinel_fail)) {
rcode = LDNS_RCODE_SERVFAIL;
@@ -1401,40 +1357,17 @@ 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, rcode, &r->edns, &r->query_reply, m->s.region, &r->start_time))
r->edns.opt_list_inplace_cb_out = NULL;
- } else {
+ } 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->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);
+ /* Send along EDE EDNS0 option when SERVFAILing; usually
+ * DNSSEC validation failures */
+ /* Since we are SERVFAILing here, CD bit and rep->security
+ * is already handled. */
+ if(m->s.env->cfg->ede && rep) {
+ mesh_find_and_attach_ede_and_reason(m, rep, r);
}
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
r->qflags, &r->edns);
@@ -1447,14 +1380,26 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
r->edns.udp_size = EDNS_ADVERTISED_SIZE;
r->edns.ext_rcode = 0;
r->edns.bits &= EDNS_DO;
+ if(m->s.env->cfg->disable_edns_do && (r->edns.bits&EDNS_DO))
+ r->edns.edns_present = 0;
m->s.qinfo.qname = r->qname;
m->s.qinfo.local_alias = r->local_alias;
+
+ /* Attach EDE without SERVFAIL if the validation failed.
+ * Need to explicitly check for rep->security otherwise failed
+ * validation paths may attach to a secure answer. */
+ if(m->s.env->cfg->ede && rep &&
+ (rep->security <= sec_status_bogus ||
+ rep->security == sec_status_secure_sentinel_fail)) {
+ mesh_find_and_attach_ede_and_reason(m, rep, r);
+ }
+
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, &r->start_time) ||
- !reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
+ !reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r_buffer, 0, 1, m->s.env->scratch,
udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO),
- secure))
+ 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, &r->start_time))
@@ -1488,8 +1433,11 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
}
/* Log reply sent */
if(m->s.env->cfg->log_replies) {
- log_reply_info(NO_VERBOSE, &m->s.qinfo, &r->query_reply.addr,
- r->query_reply.addrlen, duration, 0, r_buffer);
+ log_reply_info(NO_VERBOSE, &m->s.qinfo,
+ &r->query_reply.client_addr,
+ r->query_reply.client_addrlen, duration, 0, r_buffer,
+ (m->s.env->cfg->log_destaddr?(void*)r->query_reply.c->socket->addr->ai_addr:NULL),
+ r->query_reply.c->type);
}
}
@@ -1502,6 +1450,7 @@ void mesh_query_done(struct mesh_state* mstate)
struct reply_info* rep = (mstate->s.return_msg?
mstate->s.return_msg->rep:NULL);
struct timeval tv = {0, 0};
+ int i = 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);
@@ -1521,6 +1470,7 @@ void mesh_query_done(struct mesh_state* mstate)
}
}
for(r = mstate->reply_list; r; r = r->next) {
+ i++;
tv = r->start_time;
/* if a response-ip address block has been stored the
@@ -1530,17 +1480,8 @@ void mesh_query_done(struct mesh_state* mstate)
respip_inform_print(mstate->s.respip_action_info,
r->qname, mstate->s.qinfo.qtype,
mstate->s.qinfo.qclass, r->local_alias,
- &r->query_reply);
- if(mstate->s.env->cfg->stat_extended &&
- mstate->s.respip_action_info->rpz_used) {
- if(mstate->s.respip_action_info->rpz_disabled)
- mstate->s.env->mesh->rpz_action[RPZ_DISABLED_ACTION]++;
- if(mstate->s.respip_action_info->rpz_cname_override)
- mstate->s.env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
- else
- mstate->s.env->mesh->rpz_action[respip_action_to_rpz_action(
- mstate->s.respip_action_info->action)]++;
- }
+ &r->query_reply.client_addr,
+ r->query_reply.client_addrlen);
}
/* if this query is determined to be dropped during the
@@ -1571,6 +1512,27 @@ void mesh_query_done(struct mesh_state* mstate)
prev_buffer = r_buffer;
}
}
+ /* Account for each reply sent. */
+ if(i > 0 && mstate->s.respip_action_info &&
+ mstate->s.respip_action_info->addrinfo &&
+ mstate->s.env->cfg->stat_extended &&
+ mstate->s.respip_action_info->rpz_used) {
+ if(mstate->s.respip_action_info->rpz_disabled)
+ mstate->s.env->mesh->rpz_action[RPZ_DISABLED_ACTION] += i;
+ if(mstate->s.respip_action_info->rpz_cname_override)
+ mstate->s.env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION] += i;
+ else
+ mstate->s.env->mesh->rpz_action[respip_action_to_rpz_action(
+ mstate->s.respip_action_info->action)] += i;
+ }
+ if(!mstate->s.is_drop && i > 0) {
+ if(mstate->s.env->cfg->stat_extended
+ && mstate->s.is_cachedb_answer) {
+ mstate->s.env->mesh->ans_cachedb += i;
+ }
+ }
+
+ /* Mesh area accounting */
if(mstate->reply_list) {
mstate->reply_list = NULL;
if(!mstate->reply_list && !mstate->cb_list) {
@@ -1583,6 +1545,7 @@ void mesh_query_done(struct mesh_state* mstate)
mstate->s.env->mesh->num_detached_states++;
}
mstate->replies_sent = 1;
+
while((c = mstate->cb_list) != NULL) {
/* take this cb off the list; so that the list can be
* changed, eg. by adds from the callback routine */
@@ -1609,7 +1572,7 @@ void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate)
/* callback the function to inform super of result */
fptr_ok(fptr_whitelist_mod_inform_super(
mesh->mods.mod[ref->s->s.curmod]->inform_super));
- (*mesh->mods.mod[ref->s->s.curmod]->inform_super)(&mstate->s,
+ (*mesh->mods.mod[ref->s->s.curmod]->inform_super)(&mstate->s,
ref->s->s.curmod, &ref->s->s);
/* copy state that is always relevant to super */
copy_state_to_super(&mstate->s, ref->s->s.curmod, &ref->s->s);
@@ -1633,7 +1596,7 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
* desire aggregation).*/
key.unique = NULL;
key.s.client_info = cinfo;
-
+
result = (struct mesh_state*)rbtree_search(&mesh->all, &key);
return result;
}
@@ -1642,7 +1605,7 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg,
uint16_t qid, uint16_t qflags)
{
- struct mesh_cb* r = regional_alloc(s->s.region,
+ struct mesh_cb* r = regional_alloc(s->s.region,
sizeof(struct mesh_cb));
if(!r)
return 0;
@@ -1774,7 +1737,7 @@ mesh_copy_qinfo(struct mesh_state* mstate, struct query_info** qinfop,
* Handles module finished.
* @param mesh: the mesh area.
* @param mstate: currently active mesh state.
- * Deleted if finished, calls _done and _supers to
+ * Deleted if finished, calls _done and _supers to
* send replies to clients and inform other mesh states.
* This in turn may create additional runnable mesh states.
* @param s: state at which the current module exited.
@@ -1808,7 +1771,7 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
}
if(s == module_restart_next) {
int curmod = mstate->s.curmod;
- for(; mstate->s.curmod < mesh->mods.num;
+ for(; mstate->s.curmod < mesh->mods.num;
mstate->s.curmod++) {
fptr_ok(fptr_whitelist_mod_clear(
mesh->mods.mod[mstate->s.curmod]->clear));
@@ -1840,9 +1803,21 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
if(s == module_finished) {
if(mstate->s.curmod == 0) {
struct query_info* qinfo = NULL;
+ struct edns_option* opt_list = NULL;
+ struct sockaddr_storage addr;
uint16_t qflags;
int rpz_p = 0;
+#ifdef CLIENT_SUBNET
+ struct edns_option* ecs;
+ if(mstate->s.need_refetch && mstate->reply_list &&
+ modstack_find(&mesh->mods, "subnetcache") != -1 &&
+ mstate->s.env->unique_mesh) {
+ addr = mstate->reply_list->query_reply.client_addr;
+ } else
+#endif
+ memset(&addr, 0, sizeof(addr));
+
mesh_query_done(mstate);
mesh_walk_supers(mesh, mstate);
@@ -1852,13 +1827,28 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
* we need to make a copy of the query info here. */
if(mstate->s.need_refetch) {
mesh_copy_qinfo(mstate, &qinfo, &qflags);
+#ifdef CLIENT_SUBNET
+ /* Make also a copy of the ecs option if any */
+ if((ecs = edns_opt_list_find(
+ mstate->s.edns_opts_front_in,
+ mstate->s.env->cfg->client_subnet_opcode)) != NULL) {
+ (void)edns_opt_list_append(&opt_list,
+ ecs->opt_code, ecs->opt_len,
+ ecs->opt_data,
+ mstate->s.env->scratch);
+ }
+#endif
rpz_p = mstate->s.rpz_passthru;
}
- mesh_state_delete(&mstate->s);
if(qinfo) {
- mesh_schedule_prefetch(mesh, qinfo, qflags,
- 0, 1, rpz_p);
+ mesh_state_delete(&mstate->s);
+ mesh_new_prefetch(mesh, qinfo, qflags, 0,
+ rpz_p,
+ addr.ss_family!=AF_UNSPEC?&addr:NULL,
+ opt_list);
+ } else {
+ mesh_state_delete(&mstate->s);
}
return 0;
}
@@ -1886,7 +1876,7 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate,
mstate->s.reply = NULL;
regional_free_all(mstate->s.env->scratch);
s = mstate->s.ext_state[mstate->s.curmod];
- verbose(VERB_ALGO, "mesh_run: %s module exit state is %s",
+ verbose(VERB_ALGO, "mesh_run: %s module exit state is %s",
mesh->mods.mod[mstate->s.curmod]->name, strextstate(s));
e = NULL;
if(mesh_continue(mesh, mstate, s, &ev))
@@ -1906,14 +1896,14 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate,
}
}
-void
+void
mesh_log_list(struct mesh_area* mesh)
{
char buf[30];
struct mesh_state* m;
int num = 0;
RBTREE_FOR(m, struct mesh_state*, &mesh->all) {
- snprintf(buf, sizeof(buf), "%d%s%s%s%s%s%s mod%d %s%s",
+ snprintf(buf, sizeof(buf), "%d%s%s%s%s%s%s mod%d %s%s",
num++, (m->s.is_priming)?"p":"", /* prime */
(m->s.is_valrec)?"v":"", /* prime */
(m->s.query_flags&BIT_RD)?"RD":"",
@@ -1922,18 +1912,18 @@ mesh_log_list(struct mesh_area* mesh)
(m->sub_set.count!=0)?"c":"", /* children */
m->s.curmod, (m->reply_list)?"rep":"", /*hasreply*/
(m->cb_list)?"cb":"" /* callbacks */
- );
+ );
log_query_info(VERB_ALGO, buf, &m->s.qinfo);
}
}
-void
+void
mesh_stats(struct mesh_area* mesh, const char* str)
{
verbose(VERB_DETAIL, "%s %u recursion states (%u with reply, "
"%u detached), %u waiting replies, %u recursion replies "
- "sent, %d replies dropped, %d states jostled out",
- str, (unsigned)mesh->all.count,
+ "sent, %d replies dropped, %d states jostled out",
+ str, (unsigned)mesh->all.count,
(unsigned)mesh->num_reply_states,
(unsigned)mesh->num_detached_states,
(unsigned)mesh->num_reply_addrs,
@@ -1942,7 +1932,7 @@ mesh_stats(struct mesh_area* mesh, const char* str)
(unsigned)mesh->stats_jostled);
if(mesh->replies_sent > 0) {
struct timeval avg;
- timeval_divide(&avg, &mesh->replies_sum_wait,
+ timeval_divide(&avg, &mesh->replies_sum_wait,
mesh->replies_sent);
log_info("average recursion processing time "
ARG_LL "d.%6.6d sec",
@@ -1952,7 +1942,7 @@ mesh_stats(struct mesh_area* mesh, const char* str)
}
}
-void
+void
mesh_stats_clear(struct mesh_area* mesh)
{
if(!mesh)
@@ -1966,12 +1956,13 @@ mesh_stats_clear(struct mesh_area* mesh)
mesh->ans_secure = 0;
mesh->ans_bogus = 0;
mesh->ans_expired = 0;
+ mesh->ans_cachedb = 0;
memset(&mesh->ans_rcode[0], 0, sizeof(size_t)*UB_STATS_RCODE_NUM);
memset(&mesh->rpz_action[0], 0, sizeof(size_t)*UB_STATS_RPZ_ACTION_NUM);
mesh->ans_nodata = 0;
}
-size_t
+size_t
mesh_get_mem(struct mesh_area* mesh)
{
struct mesh_state* m;
@@ -1985,7 +1976,7 @@ mesh_get_mem(struct mesh_area* mesh)
return s;
}
-int
+int
mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo,
uint16_t flags, int prime, int valrec)
{
@@ -2102,6 +2093,7 @@ mesh_serve_expired_callback(void* arg)
struct timeval tv = {0, 0};
int must_validate = (!(qstate->query_flags&BIT_CD)
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
+ int i = 0;
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);
@@ -2173,6 +2165,7 @@ 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) {
+ i++;
tv = r->start_time;
/* If address info is returned, it means the action should be an
@@ -2180,17 +2173,8 @@ mesh_serve_expired_callback(void* arg)
if(actinfo.addrinfo) {
respip_inform_print(&actinfo, r->qname,
qstate->qinfo.qtype, qstate->qinfo.qclass,
- r->local_alias, &r->query_reply);
-
- if(qstate->env->cfg->stat_extended && actinfo.rpz_used) {
- if(actinfo.rpz_disabled)
- qstate->env->mesh->rpz_action[RPZ_DISABLED_ACTION]++;
- if(actinfo.rpz_cname_override)
- qstate->env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
- else
- qstate->env->mesh->rpz_action[
- respip_action_to_rpz_action(actinfo.action)]++;
- }
+ r->local_alias, &r->query_reply.client_addr,
+ r->query_reply.client_addrlen);
}
/* Add EDE Stale Answer (RCF8914). Ignore global ede as this is
@@ -2210,11 +2194,23 @@ mesh_serve_expired_callback(void* arg)
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
prev = r;
prev_buffer = r_buffer;
-
- /* Account for each reply sent. */
- mesh->ans_expired++;
-
}
+ /* Account for each reply sent. */
+ if(i > 0) {
+ mesh->ans_expired += i;
+ if(actinfo.addrinfo && qstate->env->cfg->stat_extended &&
+ actinfo.rpz_used) {
+ if(actinfo.rpz_disabled)
+ qstate->env->mesh->rpz_action[RPZ_DISABLED_ACTION] += i;
+ if(actinfo.rpz_cname_override)
+ qstate->env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION] += i;
+ else
+ qstate->env->mesh->rpz_action[
+ respip_action_to_rpz_action(actinfo.action)] += i;
+ }
+ }
+
+ /* Mesh area accounting */
if(mstate->reply_list) {
mstate->reply_list = NULL;
if(!mstate->reply_list && !mstate->cb_list) {
@@ -2225,6 +2221,7 @@ mesh_serve_expired_callback(void* arg)
}
}
}
+
while((c = mstate->cb_list) != NULL) {
/* take this cb off the list; so that the list can be
* changed, eg. by adds from the callback routine */
@@ -2240,3 +2237,10 @@ mesh_serve_expired_callback(void* arg)
mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c, &tv);
}
}
+
+int mesh_jostle_exceeded(struct mesh_area* mesh)
+{
+ if(mesh->all.count < mesh->max_reply_states)
+ return 0;
+ return 1;
+}