summaryrefslogtreecommitdiff
path: root/daemon/worker.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/worker.c')
-rw-r--r--daemon/worker.c84
1 files changed, 78 insertions, 6 deletions
diff --git a/daemon/worker.c b/daemon/worker.c
index 389a1de530ec..6121c7dbe363 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -342,7 +342,8 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker)
verbose(VERB_QUERY, "request bad, has TC bit on");
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
}
- if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
+ if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY &&
+ LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY) {
verbose(VERB_QUERY, "request unknown opcode %d",
LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
return worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL);
@@ -352,7 +353,9 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker)
LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
}
- if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) {
+ if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0 &&
+ (LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 1 ||
+ LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY)) {
verbose(VERB_QUERY, "request wrong nr an=%d",
LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
@@ -499,6 +502,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
* let validator do that */
return 0;
case sec_status_bogus:
+ case sec_status_secure_sentinel_fail:
/* some rrsets are bogus, reply servfail */
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
@@ -655,7 +659,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
}
}
/* check security status of the cached answer */
- if( rep->security == sec_status_bogus && must_validate) {
+ if(must_validate && (rep->security == sec_status_bogus ||
+ rep->security == sec_status_secure_sentinel_fail)) {
/* BAD cached */
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
@@ -940,6 +945,66 @@ answer_chaos(struct worker* w, struct query_info* qinfo,
return 0;
}
+/**
+ * Answer notify queries. These are notifies for authoritative zones,
+ * the reply is an ack that the notify has been received. We need to check
+ * access permission here.
+ * @param w: worker
+ * @param qinfo: query info. Pointer into packet buffer.
+ * @param edns: edns info from query.
+ * @param repinfo: reply info with source address.
+ * @param pkt: packet buffer.
+ */
+static void
+answer_notify(struct worker* w, struct query_info* qinfo,
+ struct edns_data* edns, sldns_buffer* pkt, struct comm_reply* repinfo)
+{
+ int refused = 0;
+ int rcode = LDNS_RCODE_NOERROR;
+ uint32_t serial = 0;
+ int has_serial;
+ if(!w->env.auth_zones) return;
+ has_serial = auth_zone_parse_notify_serial(pkt, &serial);
+ if(auth_zones_notify(w->env.auth_zones, &w->env, qinfo->qname,
+ qinfo->qname_len, qinfo->qclass, &repinfo->addr,
+ repinfo->addrlen, has_serial, serial, &refused)) {
+ rcode = LDNS_RCODE_NOERROR;
+ } else {
+ if(refused)
+ rcode = LDNS_RCODE_REFUSED;
+ else rcode = LDNS_RCODE_SERVFAIL;
+ }
+
+ if(verbosity >= VERB_DETAIL) {
+ char buf[380];
+ char zname[255+1];
+ char sr[25];
+ dname_str(qinfo->qname, zname);
+ sr[0]=0;
+ if(has_serial)
+ snprintf(sr, sizeof(sr), "serial %u ",
+ (unsigned)serial);
+ if(rcode == LDNS_RCODE_REFUSED)
+ snprintf(buf, sizeof(buf),
+ "refused NOTIFY %sfor %s from", sr, zname);
+ else if(rcode == LDNS_RCODE_SERVFAIL)
+ snprintf(buf, sizeof(buf),
+ "servfail for NOTIFY %sfor %s from", sr, zname);
+ else snprintf(buf, sizeof(buf),
+ "received NOTIFY %sfor %s from", sr, zname);
+ log_addr(VERB_DETAIL, buf, &repinfo->addr, repinfo->addrlen);
+ }
+ edns->edns_version = EDNS_ADVERTISED_VERSION;
+ edns->udp_size = EDNS_ADVERTISED_SIZE;
+ edns->ext_rcode = 0;
+ edns->bits &= EDNS_DO;
+ edns->opt_list = NULL;
+ error_encode(pkt, rcode, qinfo,
+ *(uint16_t*)(void *)sldns_buffer_begin(pkt),
+ sldns_buffer_read_u16_at(pkt, 2), edns);
+ LDNS_OPCODE_SET(sldns_buffer_begin(pkt), LDNS_PACKET_NOTIFY);
+}
+
static int
deny_refuse(struct comm_point* c, enum acl_access acl,
enum acl_access deny, enum acl_access refuse,
@@ -1238,6 +1303,12 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
regional_free_all(worker->scratchpad);
goto send_reply;
}
+ if(LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ==
+ LDNS_PACKET_NOTIFY) {
+ answer_notify(worker, &qinfo, &edns, c->buffer, repinfo);
+ regional_free_all(worker->scratchpad);
+ goto send_reply;
+ }
if(local_zones_answer(worker->daemon->local_zones, &worker->env, &qinfo,
&edns, c->buffer, worker->scratchpad, repinfo, acladdr->taglist,
acladdr->taglen, acladdr->tag_actions,
@@ -1806,7 +1877,7 @@ struct outbound_entry*
worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
int want_dnssec, int nocaps, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* zone, size_t zonelen, int ssl_upstream,
- struct module_qstate* q)
+ char* tls_auth_name, struct module_qstate* q)
{
struct worker* worker = q->env->worker;
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -1816,7 +1887,7 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
e->qstate = q;
e->qsent = outnet_serviced_query(worker->back, qinfo, flags, dnssec,
want_dnssec, nocaps, q->env->cfg->tcp_upstream,
- ssl_upstream, addr, addrlen, zone, zonelen, q,
+ ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
worker_handle_service_reply, e, worker->back->udp_buff, q->env);
if(!e->qsent) {
return NULL;
@@ -1863,7 +1934,8 @@ struct outbound_entry* libworker_send_query(
int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
- int ATTR_UNUSED(ssl_upstream), struct module_qstate* ATTR_UNUSED(q))
+ int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
+ struct module_qstate* ATTR_UNUSED(q))
{
log_assert(0);
return 0;