From: Wouter Wijngaards Date: Thu, 20 Sep 2007 11:37:15 +0000 (+0000) Subject: Fixup for a wildcarded NSEC with empty nonterminal query. X-Git-Tag: release-0.5~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9865f38f695ef8d4f7f5a7ab51cadb93de7ed006;p=thirdparty%2Funbound.git Fixup for a wildcarded NSEC with empty nonterminal query. git-svn-id: file:///svn/unbound/trunk@624 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 8d0425108..bcaf5cca1 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,8 @@ +20 September 2007: Wouter + - fixup and test for NSEC wildcard with empty nonterminals. + - makedist.sh fixup for svn info. + - acl features request in plan. + 19 September 2007: Wouter - comments about non-packed usage. - plan for overload support in 0.6. diff --git a/doc/plan b/doc/plan index 7048a7fe1..77458bfbf 100644 --- a/doc/plan +++ b/doc/plan @@ -179,6 +179,11 @@ Styleguide: if phase 1, start servicing, phase is 0 again. Make robust against delays. readme: max about 1 second worth of incoming queries, 10k perhaps, or 1/number of seconds it takes start up of 10k. +* features from Jakob's graph. + * acl for allowed recursion (RD=1), then drop or refused query. + * static answers for queries, option + * blacklist (return fixed nxdomain), option + * after checking acl, static, blacklist, do iter forwards, recurse. *** Local zones feature. * Build in local zone features. First the total stop for1912. diff --git a/makedist.sh b/makedist.sh index e335bac51..9449c8935 100755 --- a/makedist.sh +++ b/makedist.sh @@ -134,7 +134,7 @@ done # Check if SVNROOT is specified. if [ -z "$SVNROOT" ]; then if test -f .svn/entries; then - eval `grep 'url=' .svn/entries | head -1` + eval `svn info | grep 'URL:' | sed -e 's/URL: /url=/' | head -1` SVNROOT="$url" fi if test -z "$SVNROOT"; then diff --git a/testdata/val_mal_wc.rpl b/testdata/val_mal_wc.rpl new file mode 100644 index 000000000..5bba1bc9b --- /dev/null +++ b/testdata/val_mal_wc.rpl @@ -0,0 +1,120 @@ +; 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 nodata, wildcards and ENT + +; 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 +b.example.com. IN DS +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 +b.example.com. IN DS +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 + +; 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 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{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 to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +b.example.com. IN DS +SECTION ANSWER +SECTION AUTHORITY +example.com. 86394 IN SOA NS.IANA.ORG. NSTLD.IANA.ORG. 2007092000 1800 900 604800 86400 +example.com. 86394 IN RRSIG SOA 3 2 86394 20070926135752 20070829135752 2854 example.com. MCwCFFHjDbVjiPywHcXm669wMUJ7dlcoAhRfuauTUoExMSx96lTVYbBHOXtQEw== ;{id = 2854} + +; note that b.example.com. is an empty nonterminal +*.example.com. 3600 IN NSEC *.b.example.com. A MX RRSIG NSEC +*.example.com. 3600 IN RRSIG NSEC 3 2 3600 20070926135752 20070829135752 2854 example.com. MCwCFE9CopvxP6w/1HqnqxNluh1Qbgk0AhRgKrdjk/YoEm4tcYflNX6McDMCgQ== ;{id = 2854} + +SECTION ADDITIONAL +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +b.example.com. IN DS +ENTRY_END + +; recursion happens here. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AD NOERROR +SECTION QUESTION +b.example.com. IN DS +SECTION ANSWER +SECTION AUTHORITY +example.com. 86394 IN SOA NS.IANA.ORG. NSTLD.IANA.ORG. 2007092000 1800 900 604800 86400 +SECTION ADDITIONAL +ENTRY_END + +SCENARIO_END diff --git a/validator/val_nsec.c b/validator/val_nsec.c index 74320096a..eb76fc834 100644 --- a/validator/val_nsec.c +++ b/validator/val_nsec.c @@ -46,6 +46,14 @@ #include "util/data/msgreply.h" #include "util/data/dname.h" +/** get ttl of rrset */ +static uint32_t +rrset_get_ttl(struct ub_packed_rrset_key* k) +{ + struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; + return d->ttl; +} + int nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type) { @@ -181,6 +189,8 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, qinfo->qclass); enum sec_status sec; size_t i; + uint8_t* wc = NULL, *ce = NULL; + int valid_nsec = 0; /* If we have a NSEC at the same name, it must prove one * of two things @@ -223,23 +233,55 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, "did not verify."); return sec_status_bogus; } - if(nsec_proves_nodata(rep->rrsets[i], qinfo)) { + if(nsec_proves_nodata(rep->rrsets[i], qinfo, &wc)) { verbose(VERB_ALGO, "NSEC for empty non-terminal " "proved no DS."); - return sec_status_secure; + *proof_ttl = rrset_get_ttl(rep->rrsets[i]); + valid_nsec = 1; + } + if(val_nsec_proves_name_error(rep->rrsets[i], qinfo->qname)) { + ce = nsec_closest_encloser(qinfo->qname, + rep->rrsets[i]); } } + if(wc && !ce) + valid_nsec = 0; + else if(wc && ce) { + /* ce and wc must match */ + if(query_dname_compare(wc, ce) != 0) + valid_nsec = 0; + } + if(valid_nsec) { + return sec_status_secure; + } /* NSEC proof did not conlusively point to DS or no DS */ return sec_status_unchecked; } int nsec_proves_nodata(struct ub_packed_rrset_key* nsec, - struct query_info* qinfo) + struct query_info* qinfo, uint8_t** wc) { + log_assert(wc); if(query_dname_compare(nsec->rk.dname, qinfo->qname) != 0) { uint8_t* nm; size_t ln; + + /* empty-non-terminal checking. + * Done before wildcard, because this is an exact match, + * and would prevent a wildcard from matching. */ + + /* If the nsec is proving that qname is an ENT, the nsec owner + * will be less than qname, and the next name will be a child + * domain of the qname. */ + if(!nsec_get_next(nsec, &nm, &ln)) + return 0; /* bad nsec */ + if(dname_strict_subdomain_c(nm, qinfo->qname) && + dname_canonical_compare(nsec->rk.dname, + qinfo->qname) < 0) { + return 1; /* proves ENT */ + } + /* wildcard checking. */ /* If this is a wildcard NSEC, make sure that a) it was @@ -254,7 +296,8 @@ int nsec_proves_nodata(struct ub_packed_rrset_key* nsec, dname_remove_label(&ce, &ce_len); /* The qname must be a strict subdomain of the - * closest encloser, for the wildcard to apply */ + * closest encloser, for the wildcard to apply + */ if(dname_strict_subdomain_c(qinfo->qname, ce)) { /* here we have a matching NSEC for the qname, * perform matching NSEC checks */ @@ -270,24 +313,13 @@ int nsec_proves_nodata(struct ub_packed_rrset_key* nsec, if(nsec_has_type(nsec, qinfo->qtype)) { return 0; } + *wc = ce; return 1; } } - /* empty-non-terminal checking. */ - - /* If the nsec is proving that qname is an ENT, the nsec owner - * will be less than qname, and the next name will be a child - * domain of the qname. */ - if(!nsec_get_next(nsec, &nm, &ln)) - return 0; /* bad nsec */ - if(dname_strict_subdomain_c(nm, qinfo->qname) && - dname_canonical_compare(nsec->rk.dname, - qinfo->qname) < 0) { - return 1; /* proves ENT */ - } - /* Otherwise, this NSEC does not prove ENT, so it does not - * prove NODATA. */ + /* Otherwise, this NSEC does not prove ENT and is not a + * wildcard, so it does not prove NODATA. */ return 0; } diff --git a/validator/val_nsec.h b/validator/val_nsec.h index 43f39a0aa..cd2c3c139 100644 --- a/validator/val_nsec.h +++ b/validator/val_nsec.h @@ -93,10 +93,14 @@ int nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type); * * @param nsec: the nsec record to check against. * @param qinfo: the query info. + * @param wc: if the nodata is proven for a wildcard match, the wildcard + * closest encloser is returned, else NULL (wc is unchanged). + * This closest encloser must then match the nameerror given for the + * nextcloser of qname. * @return true if NSEC proves this. */ int nsec_proves_nodata(struct ub_packed_rrset_key* nsec, - struct query_info* qinfo); + struct query_info* qinfo, uint8_t** wc); /** * Determine if the given NSEC proves a NameError (NXDOMAIN) for a given diff --git a/validator/validator.c b/validator/validator.c index 398c82b92..14f57078b 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -571,14 +571,9 @@ validate_nodata_response(struct module_env* env, struct val_env* ve, * NODATA. * This needs to handle the ENT NODATA case. */ if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) { - if(nsec_proves_nodata(s, qchase)) { + if(nsec_proves_nodata(s, qchase, &wc)) { has_valid_nsec = 1; - /* set wc only if wildcard applicable, which - * is a *.name, and qname sub of .name */ - if(dname_is_wild(s->rk.dname) && - dname_strict_subdomain_c( - qchase->qname, s->rk.dname+2)) - wc = s->rk.dname; + /* sets wc-encloser if wildcard applicable */ } if(val_nsec_proves_name_error(s, qchase->qname)) { ce = nsec_closest_encloser(qchase->qname, s); @@ -596,9 +591,7 @@ validate_nodata_response(struct module_env* env, struct val_env* ve, if(wc && !ce) has_valid_nsec = 0; else if(wc && ce) { - log_assert(dname_is_wild(wc)); - /* first label wc is \001*, so remove and compare to ce */ - if(query_dname_compare(wc+2, ce) != 0) { + if(query_dname_compare(wc, ce) != 0) { has_valid_nsec = 0; } } @@ -912,14 +905,9 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve, * NODATA. This needs to handle the ENT NODATA case. * Also try to prove NAMEERROR, and absence of a wildcard */ if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) { - if(nsec_proves_nodata(s, qchase)) { + if(nsec_proves_nodata(s, qchase, &wc)) { nodata_valid_nsec = 1; - /* set wc only if wildcard applicable, which - * is a *.name, and qname sub of .name */ - if(dname_is_wild(s->rk.dname) && - dname_strict_subdomain_c( - qchase->qname, s->rk.dname+2)) - wc = s->rk.dname; + /* set wc encloser if wildcard applicable */ } if(val_nsec_proves_name_error(s, qchase->qname)) { ce = nsec_closest_encloser(qchase->qname, s); @@ -941,9 +929,7 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve, if(wc && !ce) nodata_valid_nsec = 0; else if(wc && ce) { - log_assert(dname_is_wild(wc)); - /* first label wc is \001*, so remove and compare to ce */ - if(query_dname_compare(wc+2, ce) != 0) { + if(query_dname_compare(wc, ce) != 0) { nodata_valid_nsec = 0; } }