nsec negative DS.

git-svn-id: file:///svn/unbound/trunk@1289 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-10-08 10:04:27 +00:00
parent c04451cc58
commit 45afaf3e08
8 changed files with 181 additions and 35 deletions

View file

@ -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

View file

@ -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
View file

@ -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
View file

@ -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 */

View file

@ -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;
}

View file

@ -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 */

View file

@ -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->

View file

@ -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