summaryrefslogtreecommitdiff
path: root/daemon/worker.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/worker.c')
-rw-r--r--daemon/worker.c146
1 files changed, 93 insertions, 53 deletions
diff --git a/daemon/worker.c b/daemon/worker.c
index e2ce0e87009be..eb7fdf2f576df 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -61,6 +61,7 @@
#include "services/authzone.h"
#include "services/mesh.h"
#include "services/localzone.h"
+#include "services/rpz.h"
#include "util/data/msgparse.h"
#include "util/data/msgencode.h"
#include "util/data/dname.h"
@@ -572,9 +573,10 @@ static int
apply_respip_action(struct worker* worker, const struct query_info* qinfo,
struct respip_client_info* cinfo, struct reply_info* rep,
struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset,
- struct reply_info** encode_repp)
+ struct reply_info** encode_repp, struct auth_zones* az)
{
- struct respip_action_info actinfo = {respip_none, NULL};
+ struct respip_action_info actinfo = {0};
+ actinfo.action = respip_none;
if(qinfo->qtype != LDNS_RR_TYPE_A &&
qinfo->qtype != LDNS_RR_TYPE_AAAA &&
@@ -582,7 +584,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
return 1;
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
- alias_rrset, 0, worker->scratchpad))
+ alias_rrset, 0, worker->scratchpad, az))
return 0;
/* xxx_deny actions mean dropping the reply, unless the original reply
@@ -595,9 +597,19 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
/* If address info is returned, it means the action should be an
* 'inform' variant and the information should be logged. */
if(actinfo.addrinfo) {
- respip_inform_print(actinfo.addrinfo, qinfo->qname,
+ respip_inform_print(&actinfo, qinfo->qname,
qinfo->qtype, qinfo->qclass, qinfo->local_alias,
repinfo);
+
+ if(worker->stats.extended && actinfo.rpz_used) {
+ if(actinfo.rpz_disabled)
+ worker->stats.rpz_action[RPZ_DISABLED_ACTION]++;
+ if(actinfo.rpz_cname_override)
+ worker->stats.rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
+ else
+ worker->stats.rpz_action[
+ respip_action_to_rpz_action(actinfo.action)]++;
+ }
}
return 1;
@@ -613,10 +625,10 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
* be completely dropped, '*need_drop' will be set to 1. */
static int
answer_from_cache(struct worker* worker, struct query_info* qinfo,
- struct respip_client_info* cinfo, int* need_drop,
- struct ub_packed_rrset_key** alias_rrset,
+ struct respip_client_info* cinfo, int* need_drop, int* is_expired_answer,
+ int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset,
struct reply_info** partial_repp,
- struct reply_info* rep, uint16_t id, uint16_t flags,
+ struct reply_info* rep, uint16_t id, uint16_t flags,
struct comm_reply* repinfo, struct edns_data* edns)
{
struct edns_data edns_bak;
@@ -624,38 +636,37 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
uint16_t udpsize = edns->udp_size;
struct reply_info* encode_rep = rep;
struct reply_info* partial_rep = *partial_repp;
- int secure;
int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd)
&& worker->env.need_to_validate;
- *partial_repp = NULL; /* avoid accidental further pass */
- if(worker->env.cfg->serve_expired) {
- if(worker->env.cfg->serve_expired_ttl &&
- rep->serve_expired_ttl < timenow)
- return 0;
- if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
- return 0;
- /* below, rrsets with ttl before timenow become TTL 0 in
- * the response */
- /* This response was served with zero TTL */
- if (timenow >= rep->ttl) {
- worker->stats.zero_ttl_responses++;
- }
- } else {
- /* see if it is possible */
- if(rep->ttl < timenow) {
+ *partial_repp = NULL; /* avoid accidental further pass */
+
+ /* Check TTL */
+ if(rep->ttl < timenow) {
+ /* Check if we need to serve expired now */
+ if(worker->env.cfg->serve_expired &&
+ !worker->env.cfg->serve_expired_client_timeout) {
+ if(worker->env.cfg->serve_expired_ttl &&
+ rep->serve_expired_ttl < timenow)
+ return 0;
+ if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
+ return 0;
+ *is_expired_answer = 1;
+ } else {
/* the rrsets may have been updated in the meantime.
* we will refetch the message format from the
- * authoritative server
+ * authoritative server
*/
return 0;
}
+ } else {
if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow))
return 0;
- /* locked and ids and ttls are OK. */
}
+ /* locked and ids and ttls are OK. */
+
/* check CNAME chain (if any) */
- if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type ==
- htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type ==
+ if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type ==
+ htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type ==
htons(LDNS_RR_TYPE_DNAME))) {
if(!reply_check_cname_chain(qinfo, rep)) {
/* cname chain invalid, redo iterator steps */
@@ -674,31 +685,31 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
goto bail_out;
- error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
+ error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns);
- rrset_array_unlock_touch(worker->env.rrset_cache,
+ rrset_array_unlock_touch(worker->env.rrset_cache,
worker->scratchpad, rep->ref, rep->rrset_count);
if(worker->stats.extended) {
worker->stats.ans_bogus ++;
worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++;
}
return 1;
- } else if( rep->security == sec_status_unchecked && must_validate) {
+ } else if(rep->security == sec_status_unchecked && must_validate) {
verbose(VERB_ALGO, "Cache reply: unchecked entry needs "
"validation");
goto bail_out; /* need to validate cache entry first */
} else if(rep->security == sec_status_secure) {
- if(reply_all_rrsets_secure(rep))
- secure = 1;
- else {
+ if(reply_all_rrsets_secure(rep)) {
+ *is_secure_answer = 1;
+ } else {
if(must_validate) {
verbose(VERB_ALGO, "Cache reply: secure entry"
" changed status");
goto bail_out; /* rrset changed, re-verify */
}
- secure = 0;
+ *is_secure_answer = 0;
}
- } else secure = 0;
+ } else *is_secure_answer = 0;
edns_bak = *edns;
edns->edns_version = EDNS_ADVERTISED_VERSION;
@@ -709,17 +720,21 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
(int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
goto bail_out;
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
- if(worker->daemon->use_response_ip && !partial_rep &&
- !apply_respip_action(worker, qinfo, cinfo, rep, repinfo, alias_rrset,
- &encode_rep)) {
+ if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
+ !partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
+ repinfo, alias_rrset,
+ &encode_rep, worker->env.auth_zones)) {
goto bail_out;
} else if(partial_rep &&
!respip_merge_cname(partial_rep, qinfo, rep, cinfo,
- must_validate, &encode_rep, worker->scratchpad)) {
+ must_validate, &encode_rep, worker->scratchpad,
+ worker->env.auth_zones)) {
goto bail_out;
}
- if(encode_rep != rep)
- secure = 0; /* if rewritten, it can't be considered "secure" */
+ if(encode_rep != rep) {
+ /* if rewritten, it can't be considered "secure" */
+ *is_secure_answer = 0;
+ }
if(!encode_rep || *alias_rrset) {
if(!encode_rep)
*need_drop = 1;
@@ -736,7 +751,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
repinfo->c, worker->scratchpad) ||
!reply_info_answer_encode(qinfo, encode_rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad,
- udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
+ udpsize, edns, (int)(edns->bits & EDNS_DO), *is_secure_answer)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
edns->opt_list = NULL;
@@ -747,10 +762,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
* is bad while holding locks. */
rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
rep->ref, rep->rrset_count);
- if(worker->stats.extended) {
- if(secure) worker->stats.ans_secure++;
- server_stats_insrcode(&worker->stats, repinfo->c->buffer);
- }
/* go and return this buffer to the client */
return 1;
@@ -1085,6 +1096,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
struct acl_addr* acladdr;
int rc = 0;
int need_drop = 0;
+ int is_expired_answer = 0;
+ int is_secure_answer = 0;
/* We might have to chase a CNAME chain internally, in which case
* we'll have up to two replies and combine them to build a complete
* answer. These variables control this case. */
@@ -1365,6 +1378,18 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
goto send_reply;
}
if(worker->env.auth_zones &&
+ rpz_apply_qname_trigger(worker->env.auth_zones,
+ &worker->env, &qinfo, &edns, c->buffer, worker->scratchpad,
+ repinfo, acladdr->taglist, acladdr->taglen, &worker->stats)) {
+ regional_free_all(worker->scratchpad);
+ if(sldns_buffer_limit(c->buffer) == 0) {
+ comm_point_drop_reply(repinfo);
+ return 0;
+ }
+ server_stats_insrcode(&worker->stats, c->buffer);
+ goto send_reply;
+ }
+ if(worker->env.auth_zones &&
auth_zones_answer(worker->env.auth_zones, &worker->env,
&qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) {
regional_free_all(worker->scratchpad);
@@ -1434,7 +1459,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
/* If we may apply IP-based actions to the answer, build the client
* information. As this can be expensive, skip it if there is
* absolutely no possibility of it. */
- if(worker->daemon->use_response_ip &&
+ if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
(qinfo.qtype == LDNS_RR_TYPE_A ||
qinfo.qtype == LDNS_RR_TYPE_AAAA ||
qinfo.qtype == LDNS_RR_TYPE_ANY)) {
@@ -1455,12 +1480,14 @@ lookup_cache:
* each pass. We should still pass the original qinfo to
* answer_from_cache(), however, since it's used to build the reply. */
if(!edns_bypass_cache_stage(edns.opt_list, &worker->env)) {
+ is_expired_answer = 0;
+ is_secure_answer = 0;
h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) {
/* answer from cache - we have acquired a readlock on it */
if(answer_from_cache(worker, &qinfo,
- cinfo, &need_drop, &alias_rrset, &partial_rep,
- (struct reply_info*)e->data,
+ cinfo, &need_drop, &is_expired_answer, &is_secure_answer,
+ &alias_rrset, &partial_rep, (struct reply_info*)e->data,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
&edns)) {
@@ -1468,9 +1495,11 @@ lookup_cache:
* Note that if there is more than one pass
* its qname must be that used for cache
* lookup. */
- if((worker->env.cfg->prefetch || worker->env.cfg->serve_expired)
- && *worker->env.now >=
- ((struct reply_info*)e->data)->prefetch_ttl) {
+ if((worker->env.cfg->prefetch && *worker->env.now >=
+ ((struct reply_info*)e->data)->prefetch_ttl) ||
+ (worker->env.cfg->serve_expired &&
+ *worker->env.now >= ((struct reply_info*)e->data)->ttl)) {
+
time_t leeway = ((struct reply_info*)e->
data)->ttl - *worker->env.now;
if(((struct reply_info*)e->data)->ttl
@@ -1555,6 +1584,13 @@ send_reply_rc:
comm_point_drop_reply(repinfo);
return 0;
}
+ if(is_expired_answer) {
+ worker->stats.ans_expired++;
+ }
+ if(worker->stats.extended) {
+ if(is_secure_answer) worker->stats.ans_secure++;
+ server_stats_insrcode(&worker->stats, repinfo->c->buffer);
+ }
#ifdef USE_DNSTAP
if(worker->dtenv.log_client_response_messages)
dt_msg_send_client_response(&worker->dtenv, &repinfo->addr,
@@ -1830,6 +1866,10 @@ worker_init(struct worker* worker, struct config_file *cfg,
return 0;
}
worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env);
+ /* Pass on daemon variables that we would need in the mesh area */
+ worker->env.mesh->use_response_ip = worker->daemon->use_response_ip;
+ worker->env.mesh->use_rpz = worker->daemon->use_rpz;
+
worker->env.detach_subs = &mesh_detach_subs;
worker->env.attach_sub = &mesh_attach_sub;
worker->env.add_sub = &mesh_add_sub;