working on negative DS

git-svn-id: file:///svn/unbound/trunk@1288 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-10-07 15:22:32 +00:00
parent 6d721dd6bd
commit c04451cc58
5 changed files with 336 additions and 18 deletions

191
testdata/val_unsecds_negcache.rpl vendored Normal file
View file

@ -0,0 +1,191 @@
; config options
; The island of trust is at example.com
server:
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
val-override-date: "20070916134226"
stub-zone:
name: "."
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
CONFIG_END
SCENARIO_BEGIN Test validator with insecure delegation and DS negative cache
; K.ROOT-SERVERS.NET.
RANGE_BEGIN 0 100
ADDRESS 193.0.14.129
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.sub.example.com. IN A
SECTION AUTHORITY
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
RANGE_END
; a.gtld-servers.net.
RANGE_BEGIN 0 100
ADDRESS 192.5.6.30
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
com. IN NS
SECTION ANSWER
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.sub.example.com. IN A
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
RANGE_END
; ns.example.com.
RANGE_BEGIN 0 100
ADDRESS 1.2.3.4
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.com. IN NS
SECTION ANSWER
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
ENTRY_END
; response to DNSKEY priming query
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.com. IN DNSKEY
SECTION ANSWER
example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
example.com. 3600 IN RRSIG DNSKEY DSA 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFBQRtlR4BEv9ohi+PGFjp+AHsJuHAhRCvz0shggvnvI88DFnBDCczHUcVA== ;{id = 2854}
SECTION AUTHORITY
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
ENTRY_END
; response for delegation to sub.example.com.
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
sub.example.com. IN NS ns.sub.example.com.
sub.example.com. IN NSEC www.example.com. NS RRSIG NSEC
sub.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926134150 20070829134150 2854 example.com. MCwCFDCaiDM6G+glwNW276HWdH+McmjgAhRSwF5OfimNQCqkWgnYotLOwUghKQ== ;{id = 2854}
SECTION ADDITIONAL
ns.sub.example.com. IN A 1.2.3.6
ENTRY_END
; query for missing DS record.
; get it from the negative cache instead!
;ENTRY_BEGIN
;MATCH opcode qtype qname
;ADJUST copy_id
;REPLY QR NOERROR
;SECTION QUESTION
;sub.example.com. IN DS
;SECTION ANSWER
;SECTION AUTHORITY
;example.com. IN SOA ns.example.com. h.example.com. 2007090504 1800 1800 2419200 7200
;example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFC5uwIHSehZtetK2CMNXttSFUB0XAhROFDAgy/FaxR8zFXJzyPdpQG93Sw== ;{id = 2854}
;sub.example.com. IN NSEC www.example.com. NS RRSIG NSEC
;sub.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926134150 20070829134150 2854 example.com. MCwCFDCaiDM6G+glwNW276HWdH+McmjgAhRSwF5OfimNQCqkWgnYotLOwUghKQ== ;{id = 2854}
;SECTION ADDITIONAL
;ns.sub.example.com. IN A 1.2.3.6
;ENTRY_END
RANGE_END
; ns.sub.example.com.
RANGE_BEGIN 0 100
ADDRESS 1.2.3.6
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
sub.example.com. IN NS
SECTION ANSWER
sub.example.com. IN NS ns.sub.example.com.
SECTION ADDITIONAL
ns.sub.example.com. IN A 1.2.3.6
ENTRY_END
; response to query of interest
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
www.sub.example.com. IN A 11.11.11.11
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
www.sub.example.com. IN A
ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
www.sub.example.com. 3600 IN A 11.11.11.11
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END

View file

@ -56,6 +56,8 @@ struct module_qstate;
struct ub_randstate;
struct mesh_area;
struct mesh_state;
struct val_anchors;
struct val_neg_cache;
/** Maximum number of modules in operation */
#define MAX_MODULE 5
@ -203,6 +205,9 @@ struct module_env {
* and are not primed and ready for validation, but on the bright
* side, they are read only memory, thus no locks and fast. */
struct val_anchors* anchors;
/** negative cache, configured by the validator. if not NULL,
* contains NSEC record lookup trees. */
struct val_neg_cache* neg_cache;
/** module specific data. indexed by module id. */
void* modinfo[MAX_MODULE];
};

View file

@ -44,6 +44,7 @@
#include "config.h"
#include "validator/val_neg.h"
#include "validator/val_nsec.h"
#include "validator/val_utils.h"
#include "util/data/dname.h"
#include "util/data/msgreply.h"
#include "util/log.h"
@ -272,19 +273,21 @@ static void neg_make_space(struct val_neg_cache* neg, size_t need)
/**
* Find the given zone, from the SOA owner name and class
* @param neg: negative cache
* @param soa: what to look for.
* @param nm: what to look for.
* @param len: length of nm
* @param dclass: class to look for.
* @return zone or NULL if not found.
*/
static struct val_neg_zone* neg_find_zone(struct val_neg_cache* neg,
struct ub_packed_rrset_key* soa)
uint8_t* nm, size_t len, uint16_t dclass)
{
struct val_neg_zone lookfor;
struct val_neg_zone* result;
lookfor.node.key = &lookfor;
lookfor.name = soa->rk.dname;
lookfor.len = soa->rk.dname_len;
lookfor.name = nm;
lookfor.len = len;
lookfor.labs = dname_count_labels(lookfor.name);
lookfor.dclass = ntohs(soa->rk.rrset_class);
lookfor.dclass = dclass;
result = (struct val_neg_zone*)
rbtree_search(&neg->tree, lookfor.node.key);
@ -318,13 +321,12 @@ static size_t calc_data_need(struct reply_info* rep)
/**
* Calculate space needed for zone and all its parents
* @param soa: with name.
* @param d: name of zone
* @param len: length of name
* @return size.
*/
static size_t calc_zone_need(struct ub_packed_rrset_key* soa)
static size_t calc_zone_need(uint8_t* d, size_t len)
{
uint8_t* d = soa->rk.dname;
size_t len = soa->rk.dname_len;
size_t res = sizeof(struct val_neg_zone) + len;
while(!dname_is_root(d)) {
log_assert(len > 1); /* not root label */
@ -419,7 +421,7 @@ static struct val_neg_data* neg_closest_data_parent(
* @param nm: name for zone (copied)
* @param nm_len: length of name
* @param labs: labels in name.
* @param dclass: class of zone.
* @param dclass: class of zone, host order.
* @return new zone or NULL on failure
*/
static struct val_neg_zone* neg_setup_zone_node(
@ -494,19 +496,18 @@ static struct val_neg_zone* neg_zone_chain(
/**
* Create a new zone.
* @param neg: negative cache
* @param soa: what to look for.
* @param nm: what to look for.
* @param nm_len: length of name.
* @param dclass: class of zone, host order.
* @return zone or NULL if out of memory.
*/
static struct val_neg_zone* neg_create_zone(struct val_neg_cache* neg,
struct ub_packed_rrset_key* soa)
uint8_t* nm, size_t nm_len, uint16_t dclass)
{
struct val_neg_zone* zone;
struct val_neg_zone* parent;
struct val_neg_zone* p, *np;
uint8_t* nm = soa->rk.dname;
size_t nm_len = soa->rk.dname_len;
int labs = dname_count_labels(nm);
uint16_t dclass = ntohs(soa->rk.rrset_class);
/* find closest enclosing parent zone that (still) exists */
parent = neg_closest_zone_parent(neg, nm, nm_len, labs, dclass);
@ -809,14 +810,17 @@ void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep)
soa->rk.dname, LDNS_RR_TYPE_SOA, ntohs(soa->rk.rrset_class));
/* ask for enough space to store all of it */
need = calc_data_need(rep) + calc_zone_need(soa);
need = calc_data_need(rep) +
calc_zone_need(soa->rk.dname, soa->rk.dname_len);
lock_basic_lock(&neg->lock);
neg_make_space(neg, need);
/* find or create the zone entry */
zone = neg_find_zone(neg, soa);
zone = neg_find_zone(neg, soa->rk.dname, soa->rk.dname_len,
ntohs(soa->rk.rrset_class));
if(!zone) {
if(!(zone = neg_create_zone(neg, soa))) {
if(!(zone = neg_create_zone(neg, soa->rk.dname,
soa->rk.dname_len, ntohs(soa->rk.rrset_class)))) {
lock_basic_unlock(&neg->lock);
log_err("out of memory adding negative zone");
return;
@ -958,3 +962,92 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
verbose(VERB_ALGO, "negcache DLV denial proven");
return 1;
}
/** see if the reply has signed NSEC records and return the signer */
static uint8_t* reply_nsec_signer(struct reply_info* rep, size_t* signer_len,
uint16_t* dclass)
{
size_t i;
struct packed_rrset_data* d;
uint8_t* s;
for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC) {
d = (struct packed_rrset_data*)rep->rrsets[i]->
entry.data;
/* return first signer name of first NSEC */
if(d->rrsig_count != 0) {
val_find_rrset_signer(rep->rrsets[i],
&s, signer_len);
if(s && *signer_len) {
*dclass = ntohs(rep->rrsets[i]->
rk.rrset_class);
return s;
}
}
}
}
return 0;
}
void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep,
uint8_t* zone_name)
{
size_t i, need;
uint8_t* signer;
size_t signer_len;
uint16_t dclass;
struct val_neg_zone* zone;
/* no SOA in this message, find RRSIG over NSEC's signer name.
* note the NSEC records are maybe not validated yet */
signer = reply_nsec_signer(rep, &signer_len, &dclass);
if(!signer)
return;
if(!dname_subdomain_c(signer, zone_name)) {
/* the signer is not in the bailiwick, throw it out */
return;
}
log_nametypeclass(VERB_ALGO, "negcache insert referral ",
signer, LDNS_RR_TYPE_NS, dclass);
/* ask for enough space to store all of it */
need = calc_data_need(rep) + calc_zone_need(signer, signer_len);
lock_basic_lock(&neg->lock);
neg_make_space(neg, need);
/* find or create the zone entry */
zone = neg_find_zone(neg, signer, signer_len, dclass);
if(!zone) {
if(!(zone = neg_create_zone(neg, signer, signer_len,
dclass))) {
lock_basic_unlock(&neg->lock);
log_err("out of memory adding negative zone");
return;
}
}
/* insert the NSECs */
for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
if(ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC)
continue;
if(!dname_subdomain_c(rep->rrsets[i]->rk.dname,
zone->name)) continue;
/* insert NSEC into this zone's tree */
neg_insert_data(neg, zone, rep->rrsets[i]);
}
lock_basic_unlock(&neg->lock);
}
struct dns_msg*
val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo,
struct regional* region, struct rrset_cache* rrset_cache)
{
struct dns_msg* msg;
/* only for DS queries */
if(qinfo->qtype != LDNS_RR_TYPE_DS)
return NULL;
/* see if info from neg cache is available */
return msg;
}

View file

@ -50,6 +50,9 @@ struct val_neg_data;
struct config_file;
struct reply_info;
struct rrset_cache;
struct regional;
struct query_info;
struct dns_msg;
/**
* The negative cache. It is shared between the threads, so locked.
@ -187,6 +190,16 @@ int val_neg_zone_compare(const void* a, const void* b);
*/
void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep);
/**
* Insert NSECs from this referral into the negative cache for reference.
* @param neg: negative cache
* @param rep: referral reply with NS, NSECs.
* @param zone: bailiwick for the referral.
* Errors are ignored, means that storage is omitted.
*/
void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep,
uint8_t* zone);
/**
* Perform a DLV style lookup
* During the lookup, we could find out that data has expired. In that
@ -207,4 +220,19 @@ void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep);
int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
uint16_t qclass, struct rrset_cache* rrset_cache, uint32_t now);
/**
* For the given query, try to get a reply out of the negative cache.
* The reply still needs to be validated.
* @param neg: negative cache.
* @param qinfo: query
* @param region: where to allocate reply.
* @param rrset_cache: rrset cache.
* @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);
#endif /* VALIDATOR_VAL_NEG_H */

View file

@ -127,6 +127,7 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
log_err("out of memory");
return 0;
}
env->neg_cache = val_env->neg_cache;
val_env->date_override = cfg->val_date_override;
c = cfg_count_numbers(cfg->val_nsec3_key_iterations);
if(c < 1 || (c&1)) {