mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-01-21 14:12:55 -05:00
nsec negative DS.
git-svn-id: file:///svn/unbound/trunk@1289 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
c04451cc58
commit
45afaf3e08
8 changed files with 181 additions and 35 deletions
|
|
@ -1,3 +1,6 @@
|
|||
8 October 2008: Wouter
|
||||
- NSEC negative cache for DS.
|
||||
|
||||
6 October 2008: Wouter
|
||||
- jostle-timeout option, so you can config for slow links.
|
||||
- 0x20 fallback code. Tries 3xnumber of nameserver addresses
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
#include "iterator/iter_resptype.h"
|
||||
#include "iterator/iter_scrub.h"
|
||||
#include "iterator/iter_priv.h"
|
||||
#include "validator/val_neg.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "util/module.h"
|
||||
|
|
@ -754,6 +755,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
msg = dns_cache_lookup(qstate->env, iq->qchase.qname,
|
||||
iq->qchase.qname_len, iq->qchase.qtype,
|
||||
iq->qchase.qclass, qstate->region, qstate->env->scratch);
|
||||
if(!msg && qstate->env->neg_cache) {
|
||||
/* lookup in negative cache; may result in
|
||||
* NOERROR/NODATA or NXDOMAIN answers that need validation */
|
||||
msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase,
|
||||
qstate->region, qstate->env->rrset_cache,
|
||||
*qstate->env->now);
|
||||
}
|
||||
if(msg) {
|
||||
/* handle positive cache response */
|
||||
enum response_type type = response_type_from_cache(msg,
|
||||
|
|
|
|||
46
services/cache/dns.c
vendored
46
services/cache/dns.c
vendored
|
|
@ -244,11 +244,9 @@ find_add_ds(struct module_env* env, struct regional* region,
|
|||
}
|
||||
}
|
||||
|
||||
/** create referral message with NS and query */
|
||||
static struct dns_msg*
|
||||
create_msg(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||
struct regional* region, struct ub_packed_rrset_key* nskey,
|
||||
struct packed_rrset_data* nsdata, uint32_t now)
|
||||
struct dns_msg*
|
||||
dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
uint16_t qclass, struct regional* region, size_t capacity)
|
||||
{
|
||||
struct dns_msg* msg = (struct dns_msg*)regional_alloc(region,
|
||||
sizeof(struct dns_msg));
|
||||
|
|
@ -261,32 +259,31 @@ create_msg(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
|||
msg->qinfo.qtype = qtype;
|
||||
msg->qinfo.qclass = qclass;
|
||||
/* non-packed reply_info, because it needs to grow the array */
|
||||
msg->rep = (struct reply_info*)regional_alloc(region,
|
||||
msg->rep = (struct reply_info*)regional_alloc_zero(region,
|
||||
sizeof(struct reply_info)-sizeof(struct rrset_ref));
|
||||
if(!msg->rep)
|
||||
return NULL;
|
||||
memset(msg->rep, 0,
|
||||
sizeof(struct reply_info)-sizeof(struct rrset_ref));
|
||||
msg->rep->flags = BIT_QR; /* with QR, no AA */
|
||||
msg->rep->qdcount = 1;
|
||||
/* allocate the array to as much as we could need:
|
||||
* NS rrset + DS/NSEC rrset +
|
||||
* A rrset for every NS RR
|
||||
* AAAA rrset for every NS RR
|
||||
*/
|
||||
msg->rep->rrsets = (struct ub_packed_rrset_key**)
|
||||
regional_alloc(region,
|
||||
(2 + nsdata->count*2)*sizeof(struct ub_packed_rrset_key*));
|
||||
capacity*sizeof(struct ub_packed_rrset_key*));
|
||||
if(!msg->rep->rrsets)
|
||||
return NULL;
|
||||
msg->rep->rrsets[0] = packed_rrset_copy_region(nskey, region, now);
|
||||
if(!msg->rep->rrsets[0])
|
||||
return NULL;
|
||||
msg->rep->ns_numrrsets++;
|
||||
msg->rep->rrset_count++;
|
||||
return msg;
|
||||
}
|
||||
|
||||
int
|
||||
dns_msg_authadd(struct dns_msg* msg, struct regional* region,
|
||||
struct ub_packed_rrset_key* rrset, uint32_t now)
|
||||
{
|
||||
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
|
||||
packed_rrset_copy_region(rrset, region, now)))
|
||||
return 0;
|
||||
msg->rep->ns_numrrsets++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
|
||||
size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||
|
|
@ -311,9 +308,14 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
|
|||
}
|
||||
/* create referral message */
|
||||
if(msg) {
|
||||
*msg = create_msg(qname, qnamelen, qtype, qclass, region,
|
||||
nskey, nsdata, now);
|
||||
if(!*msg) {
|
||||
/* allocate the array to as much as we could need:
|
||||
* NS rrset + DS/NSEC rrset +
|
||||
* A rrset for every NS RR
|
||||
* AAAA rrset for every NS RR
|
||||
*/
|
||||
*msg = dns_msg_create(qname, qnamelen, qtype, qclass, region,
|
||||
2 + nsdata->count*2);
|
||||
if(!*msg || !dns_msg_authadd(*msg, region, nskey, now)) {
|
||||
lock_rw_unlock(&nskey->entry.lock);
|
||||
log_err("find_delegation: out of memory");
|
||||
return NULL;
|
||||
|
|
|
|||
26
services/cache/dns.h
vendored
26
services/cache/dns.h
vendored
|
|
@ -137,4 +137,30 @@ struct dns_msg* dns_cache_lookup(struct module_env* env,
|
|||
int cache_fill_missing(struct module_env* env, uint16_t qclass,
|
||||
struct regional* region, struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* Utility, create new, unpacked data structure for cache response.
|
||||
* QR bit set, no AA. Query set as indicated. Space for number of rrsets.
|
||||
* @param qname: query section name
|
||||
* @param qnamelen: len of qname
|
||||
* @param qtype: query section type
|
||||
* @param qclass: query section class
|
||||
* @param region: where to alloc.
|
||||
* @param capacity: number of rrsets space to create in the array.
|
||||
* @return new dns_msg struct or NULL on mem fail.
|
||||
*/
|
||||
struct dns_msg* dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
uint16_t qclass, struct regional* region, size_t capacity);
|
||||
|
||||
/**
|
||||
* Add rrset to authority section in unpacked dns_msg message. Must have enough
|
||||
* space left, does not grow the array.
|
||||
* @param msg: msg to put it in.
|
||||
* @param region: region to alloc in
|
||||
* @param rrset: to add in authority section
|
||||
* @param now: now.
|
||||
* @return true if worked, false on fail
|
||||
*/
|
||||
int dns_msg_authadd(struct dns_msg* msg, struct regional* region,
|
||||
struct ub_packed_rrset_key* rrset, uint32_t now);
|
||||
|
||||
#endif /* SERVICES_CACHE_DNS_H */
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
#include "util/net_help.h"
|
||||
#include "util/config_file.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/dns.h"
|
||||
|
||||
int val_neg_data_compare(const void* a, const void* b)
|
||||
{
|
||||
|
|
@ -1038,16 +1039,119 @@ void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep,
|
|||
lock_basic_unlock(&neg->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* See if rrset exists in rrset cache.
|
||||
* If it does, the bit is checked, and if not expired, it is returned
|
||||
* allocated in region.
|
||||
* @param rrset_cache: rrset cache
|
||||
* @param qname: to lookup rrset name
|
||||
* @param qname_len: length of qname.
|
||||
* @param qtype: type of rrset to lookup, host order
|
||||
* @param qclass: class of rrset to lookup, host order
|
||||
* @param flags: flags for rrset to lookup
|
||||
* @param region: where to alloc result
|
||||
* @param checkbit: if true, a bit in the nsec typemap is checked for absence.
|
||||
* @param checktype: which bit to check
|
||||
* @param now: to check ttl against
|
||||
* @return rrset or NULL
|
||||
*/
|
||||
static struct ub_packed_rrset_key*
|
||||
grab_nsec(struct rrset_cache* rrset_cache, uint8_t* qname, size_t qname_len,
|
||||
uint16_t qtype, uint16_t qclass, uint32_t flags,
|
||||
struct regional* region, int checkbit, uint16_t checktype,
|
||||
uint32_t now)
|
||||
{
|
||||
struct ub_packed_rrset_key* r, *k = rrset_cache_lookup(rrset_cache,
|
||||
qname, qname_len, qtype, qclass, flags, now, 0);
|
||||
struct packed_rrset_data* d;
|
||||
if(!k) return NULL;
|
||||
d = (struct packed_rrset_data*)k->entry.data;
|
||||
if(d->ttl < now) {
|
||||
lock_rw_unlock(&k->entry.lock);
|
||||
return NULL;
|
||||
}
|
||||
/* only secure or unchecked records that have signatures. */
|
||||
if( ! ( d->security == sec_status_secure ||
|
||||
(d->security == sec_status_unchecked &&
|
||||
d->rrsig_count > 0) ) ) {
|
||||
lock_rw_unlock(&k->entry.lock);
|
||||
return NULL;
|
||||
}
|
||||
/* check if checktype is absent */
|
||||
if(checkbit && qtype == LDNS_RR_TYPE_NSEC &&
|
||||
nsec_has_type(k, checktype)) {
|
||||
lock_rw_unlock(&k->entry.lock);
|
||||
return NULL;
|
||||
}
|
||||
/* looks OK! copy to region and return it */
|
||||
r = packed_rrset_copy_region(k, region, now);
|
||||
/* if it failed, we return the NULL */
|
||||
lock_rw_unlock(&k->entry.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
struct dns_msg*
|
||||
val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo,
|
||||
struct regional* region, struct rrset_cache* rrset_cache)
|
||||
struct regional* region, struct rrset_cache* rrset_cache, uint32_t now)
|
||||
{
|
||||
struct dns_msg* msg;
|
||||
struct ub_packed_rrset_key* rrset;
|
||||
uint8_t* zname;
|
||||
size_t zname_len;
|
||||
int zname_labs;
|
||||
struct val_neg_zone* zone;
|
||||
struct val_neg_data* data;
|
||||
/* only for DS queries */
|
||||
if(qinfo->qtype != LDNS_RR_TYPE_DS)
|
||||
return NULL;
|
||||
|
||||
/* see if info from neg cache is available */
|
||||
/* see if info from neg cache is available
|
||||
* For NSECs, because there is no optout; a DS next to a delegation
|
||||
* always has exactly an NSEC for it itself; check its DS bit.
|
||||
* flags=0 (not the zone apex).
|
||||
*/
|
||||
rrset = grab_nsec(rrset_cache, qinfo->qname, qinfo->qname_len,
|
||||
LDNS_RR_TYPE_NSEC, qinfo->qclass, 0, region, 1,
|
||||
qinfo->qtype, now);
|
||||
if(rrset) {
|
||||
/* return msg with that rrset */
|
||||
if(!(msg = dns_msg_create(qinfo->qname, qinfo->qname_len,
|
||||
qinfo->qtype, qinfo->qclass, region, 1)))
|
||||
return NULL;
|
||||
if(!dns_msg_authadd(msg, region, rrset, now))
|
||||
return NULL;
|
||||
return msg;
|
||||
}
|
||||
|
||||
return msg;
|
||||
/* check NSEC3 neg cache for type DS */
|
||||
/* need to look one zone higher for DS type */
|
||||
zname = qinfo->qname;
|
||||
zname_len = qinfo->qname_len;
|
||||
dname_remove_label(&zname, &zname_len);
|
||||
zname_labs = dname_count_labels(zname);
|
||||
|
||||
/* lookup closest zone */
|
||||
lock_basic_lock(&neg->lock);
|
||||
zone = neg_closest_zone_parent(neg, zname, zname_len, zname_labs,
|
||||
qinfo->qclass);
|
||||
while(zone && !zone->in_use)
|
||||
zone = zone->parent;
|
||||
if(!zone) {
|
||||
lock_basic_unlock(&neg->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* lookup closest data record TODO hash NSEC3 */
|
||||
(void)neg_closest_data(zone, qinfo->qname, qinfo->qname_len,
|
||||
zname_labs+1, &data);
|
||||
while(data && !data->in_use)
|
||||
data = data->parent;
|
||||
if(!data) {
|
||||
lock_basic_unlock(&neg->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get RR and check */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -227,12 +227,13 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
|
|||
* @param qinfo: query
|
||||
* @param region: where to allocate reply.
|
||||
* @param rrset_cache: rrset cache.
|
||||
* @param now: to check TTLs against.
|
||||
* @return a reply message if something was found.
|
||||
* This reply may still need validation.
|
||||
* NULL if nothing found (or out of memory).
|
||||
*/
|
||||
struct dns_msg* val_neg_getmsg(struct val_neg_cache* neg,
|
||||
struct query_info* qinfo, struct regional* region,
|
||||
struct rrset_cache* rrset_cache);
|
||||
struct rrset_cache* rrset_cache, uint32_t now);
|
||||
|
||||
#endif /* VALIDATOR_VAL_NEG_H */
|
||||
|
|
|
|||
|
|
@ -91,15 +91,7 @@ nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if type is present in the NSEC typemap
|
||||
* @param nsec: the nsec RRset.
|
||||
* If there are multiple RRs, then each must have the same typemap,
|
||||
* since the typemap represents the types at this domain node.
|
||||
* @param type: type to check for, host order.
|
||||
* @return true if present
|
||||
*/
|
||||
static int
|
||||
int
|
||||
nsec_has_type(struct ub_packed_rrset_key* nsec, uint16_t type)
|
||||
{
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)nsec->
|
||||
|
|
|
|||
|
|
@ -84,6 +84,16 @@ enum sec_status val_nsec_prove_nodata_dsreply(struct module_env* env,
|
|||
*/
|
||||
int nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type);
|
||||
|
||||
/**
|
||||
* Check if type is present in the NSEC typemap
|
||||
* @param nsec: the nsec RRset.
|
||||
* If there are multiple RRs, then each must have the same typemap,
|
||||
* since the typemap represents the types at this domain node.
|
||||
* @param type: type to check for, host order.
|
||||
* @return true if present
|
||||
*/
|
||||
int nsec_has_type(struct ub_packed_rrset_key* nsec, uint16_t type);
|
||||
|
||||
/**
|
||||
* Determine if a NSEC proves the NOERROR/NODATA conditions. This will also
|
||||
* handle the empty non-terminal (ENT) case and partially handle the
|
||||
|
|
|
|||
Loading…
Reference in a new issue