mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-01-28 01:19:19 -05:00
working on negative DS
git-svn-id: file:///svn/unbound/trunk@1288 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
6d721dd6bd
commit
c04451cc58
5 changed files with 336 additions and 18 deletions
191
testdata/val_unsecds_negcache.rpl
vendored
Normal file
191
testdata/val_unsecds_negcache.rpl
vendored
Normal 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
|
||||
|
|
@ -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];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue