mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-01-03 13:29:36 -05:00
- auth zone notify work.
git-svn-id: file:///svn/unbound/trunk@4619 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
c239c3f395
commit
ad9784c5e8
6 changed files with 216 additions and 6 deletions
|
|
@ -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);
|
||||
|
|
@ -940,6 +943,64 @@ 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 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, 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);
|
||||
}
|
||||
|
||||
static int
|
||||
deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
enum acl_access deny, enum acl_access refuse,
|
||||
|
|
@ -1238,6 +1299,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,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
10 April 2018: Wouter
|
||||
- documentation for low-rtt and low-rtt-pct.
|
||||
- auth zone notify work.
|
||||
|
||||
9 April 2018: Wouter
|
||||
- Fix that flush_zone sets prefetch ttl expired, so that with
|
||||
|
|
|
|||
|
|
@ -3189,6 +3189,94 @@ int auth_zones_can_fallback(struct auth_zones* az, uint8_t* nm, size_t nmlen,
|
|||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
auth_zone_parse_notify_serial(sldns_buffer* pkt, uint32_t *serial)
|
||||
{
|
||||
struct query_info q;
|
||||
uint16_t rdlen;
|
||||
memset(&q, 0, sizeof(q));
|
||||
sldns_buffer_set_position(pkt, 0);
|
||||
if(!query_info_parse(&q, pkt)) return 0;
|
||||
if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0) return 0;
|
||||
/* skip name of RR in answer section */
|
||||
if(sldns_buffer_remaining(pkt) < 1) return 0;
|
||||
if(pkt_dname_len(pkt) == 0) return 0;
|
||||
/* check type */
|
||||
if(sldns_buffer_remaining(pkt) < 10 /* type,class,ttl,rdatalen*/)
|
||||
return 0;
|
||||
if(sldns_buffer_read_u16(pkt) != LDNS_RR_TYPE_SOA) return 0;
|
||||
sldns_buffer_skip(pkt, 2); /* class */
|
||||
sldns_buffer_skip(pkt, 4); /* ttl */
|
||||
rdlen = sldns_buffer_read_u16(pkt); /* rdatalen */
|
||||
if(sldns_buffer_remaining(pkt) < rdlen) return 0;
|
||||
if(rdlen < 22) return 0; /* bad soa length */
|
||||
sldns_buffer_skip(pkt, rdlen-20);
|
||||
*serial = sldns_buffer_read_u32(pkt);
|
||||
/* return true when has serial in answer section */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** check access list for notifies */
|
||||
static int
|
||||
az_xfr_allowed_notify(struct auth_xfer* xfr, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
/* TODO */
|
||||
(void)xfr;
|
||||
(void)addr;
|
||||
(void)addrlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** process a notify serial, start new probe or note serial. xfr is locked */
|
||||
static int
|
||||
xfr_process_notify(struct auth_xfer* xfr, int has_serial, uint32_t serial)
|
||||
{
|
||||
/* start new probe with this addr src, or note serial */
|
||||
/* TODO */
|
||||
(void)xfr;
|
||||
(void)has_serial;
|
||||
(void)serial;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int auth_zones_notify(struct auth_zones* az, uint8_t* nm, size_t nmlen,
|
||||
uint16_t dclass, struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
int has_serial, uint32_t serial, int* refused)
|
||||
{
|
||||
struct auth_xfer* xfr;
|
||||
/* see which zone this is */
|
||||
lock_rw_rdlock(&az->lock);
|
||||
xfr = auth_xfer_find(az, nm, nmlen, dclass);
|
||||
if(!xfr) {
|
||||
lock_rw_unlock(&az->lock);
|
||||
/* no such zone, refuse the notify */
|
||||
*refused = 1;
|
||||
return 0;
|
||||
}
|
||||
lock_basic_lock(&xfr->lock);
|
||||
lock_rw_unlock(&az->lock);
|
||||
|
||||
/* check access list for notifies */
|
||||
if(!az_xfr_allowed_notify(xfr, addr, addrlen)) {
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
/* notify not allowed, refuse the notify */
|
||||
*refused = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* process the notify */
|
||||
if(!xfr_process_notify(xfr, has_serial, serial)) {
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
/* servfail */
|
||||
*refused = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** set a zone expired */
|
||||
static void
|
||||
auth_xfer_set_expired(struct auth_xfer* xfr, struct module_env* env,
|
||||
|
|
|
|||
|
|
@ -545,6 +545,29 @@ int auth_zone_set_fallback(struct auth_zone* z, char* fallbackstr);
|
|||
int auth_zones_can_fallback(struct auth_zones* az, uint8_t* nm, size_t nmlen,
|
||||
uint16_t dclass);
|
||||
|
||||
/** process notify for auth zones.
|
||||
* first checks the access list. Then processes the notify. This starts
|
||||
* the probe sequence or it notes the serial number (if any)
|
||||
* @param az: auth zones structure.
|
||||
* @param nm: name of the zone. Uncompressed. from query.
|
||||
* @param nmlen: length of name.
|
||||
* @param dclass: class of zone.
|
||||
* @param addr: source address of notify
|
||||
* @param addrlen: length of addr.
|
||||
* @param has_serial: if true, the notify has a serial attached.
|
||||
* @param serial: the serial number, if has_serial is true.
|
||||
* @param refused: is set to true on failure to note refused access.
|
||||
* @return fail on failures (refused is false) and when access is
|
||||
* denied (refused is true). True when processed.
|
||||
*/
|
||||
int auth_zones_notify(struct auth_zones* az, uint8_t* nm, size_t nmlen,
|
||||
uint16_t dclass, struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
int has_serial, uint32_t serial, int* refused);
|
||||
|
||||
/** process notify packet and read serial number from SOA.
|
||||
* returns 0 if no soa record in the notify */
|
||||
int auth_zone_parse_notify_serial(struct sldns_buffer* pkt, uint32_t *serial);
|
||||
|
||||
/** read auth zone from zonefile. caller must lock zone. false on failure */
|
||||
int auth_zone_read_zonefile(struct auth_zone* z);
|
||||
|
||||
|
|
|
|||
|
|
@ -1028,6 +1028,32 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** skip RR in packet */
|
||||
static int
|
||||
skip_pkt_rr(sldns_buffer* pkt)
|
||||
{
|
||||
if(sldns_buffer_remaining(pkt) < 1) return 0;
|
||||
if(!pkt_dname_len(pkt))
|
||||
return 0;
|
||||
if(sldns_buffer_remaining(pkt) < 4) return 0;
|
||||
sldns_buffer_skip(pkt, 4); /* type and class */
|
||||
if(!skip_ttl_rdata(pkt))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** skip RRs from packet */
|
||||
static int
|
||||
skip_pkt_rrs(sldns_buffer* pkt, int num)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<num; i++) {
|
||||
if(!skip_pkt_rr(pkt))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
|
||||
struct regional* region)
|
||||
|
|
@ -1035,8 +1061,12 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
|
|||
size_t rdata_len;
|
||||
uint8_t* rdata_ptr;
|
||||
log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1);
|
||||
log_assert(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0);
|
||||
log_assert(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) == 0);
|
||||
if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0 ||
|
||||
LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) {
|
||||
if(!skip_pkt_rrs(pkt, ((int)LDNS_ANCOUNT(sldns_buffer_begin(pkt)))+
|
||||
((int)LDNS_NSCOUNT(sldns_buffer_begin(pkt)))))
|
||||
return 0;
|
||||
}
|
||||
/* check edns section is present */
|
||||
if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
|
||||
return LDNS_RCODE_FORMERR;
|
||||
|
|
|
|||
|
|
@ -534,8 +534,9 @@ query_info_parse(struct query_info* m, sldns_buffer* query)
|
|||
/* minimum size: header + \0 + qtype + qclass */
|
||||
if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5)
|
||||
return 0;
|
||||
if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY ||
|
||||
LDNS_QDCOUNT(q) != 1 || sldns_buffer_position(query) != 0)
|
||||
if((LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY && LDNS_OPCODE_WIRE(q) !=
|
||||
LDNS_PACKET_NOTIFY) || LDNS_QDCOUNT(q) != 1 ||
|
||||
sldns_buffer_position(query) != 0)
|
||||
return 0;
|
||||
sldns_buffer_skip(query, LDNS_HEADER_SIZE);
|
||||
m->qname = sldns_buffer_current(query);
|
||||
|
|
|
|||
Loading…
Reference in a new issue