val_nsec.c revision 292206
167754Smsmith/* 267754Smsmith * validator/val_nsec.c - validator NSEC denial of existence functions. 367754Smsmith * 467754Smsmith * Copyright (c) 2007, NLnet Labs. All rights reserved. 567754Smsmith * 667754Smsmith * This software is open source. 7217365Sjkim * 8298714Sjkim * Redistribution and use in source and binary forms, with or without 970243Smsmith * modification, are permitted provided that the following conditions 1067754Smsmith * are met: 11217365Sjkim * 12217365Sjkim * Redistributions of source code must retain the above copyright notice, 13217365Sjkim * this list of conditions and the following disclaimer. 14217365Sjkim * 15217365Sjkim * Redistributions in binary form must reproduce the above copyright notice, 16217365Sjkim * this list of conditions and the following disclaimer in the documentation 17217365Sjkim * and/or other materials provided with the distribution. 18217365Sjkim * 19217365Sjkim * Neither the name of the NLNET LABS nor the names of its contributors may 20217365Sjkim * be used to endorse or promote products derived from this software without 21217365Sjkim * specific prior written permission. 22217365Sjkim * 23217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2567754Smsmith * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27217365Sjkim * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28217365Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2967754Smsmith * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30217365Sjkim * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31217365Sjkim * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32217365Sjkim * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33217365Sjkim * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34217365Sjkim */ 35217365Sjkim 36217365Sjkim/** 37217365Sjkim * \file 38217365Sjkim * 39217365Sjkim * This file contains helper functions for the validator module. 40217365Sjkim * The functions help with NSEC checking, the different NSEC proofs 41217365Sjkim * for denial of existence, and proofs for presence of types. 42217365Sjkim */ 4367754Smsmith#include "config.h" 44193341Sjkim#include "validator/val_nsec.h" 45193341Sjkim#include "validator/val_utils.h" 46193341Sjkim#include "util/data/msgreply.h" 47193341Sjkim#include "util/data/dname.h" 48193341Sjkim#include "util/net_help.h" 49193341Sjkim#include "util/module.h" 50193341Sjkim#include "services/cache/rrset.h" 5167754Smsmith 5277424Smsmith/** get ttl of rrset */ 5391116Smsmithstatic uint32_t 5467754Smsmithrrset_get_ttl(struct ub_packed_rrset_key* k) 55167802Sjkim{ 56167802Sjkim struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 57151937Sjkim return d->ttl; 58151937Sjkim} 59151937Sjkim 60151937Sjkimint 61151937Sjkimnsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type) 6267754Smsmith{ 63151937Sjkim /* Check type present in NSEC typemap with bitmap arg */ 64100966Siwasaki /* bitmasks for determining type-lowerbits presence */ 65151937Sjkim uint8_t masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; 6667754Smsmith uint8_t type_window = type>>8; 6799146Siwasaki uint8_t type_low = type&0xff; 6867754Smsmith uint8_t win, winlen; 6999146Siwasaki /* read each of the type bitmap windows and see if the searched 7099146Siwasaki * type is amongst it */ 7167754Smsmith while(len > 0) { 7267754Smsmith if(len < 3) /* bad window, at least window# winlen bitmap */ 7367754Smsmith return 0; 7467754Smsmith win = *bitmap++; 7567754Smsmith winlen = *bitmap++; 7667754Smsmith len -= 2; 7767754Smsmith if(len < winlen || winlen < 1 || winlen > 32) 78151937Sjkim return 0; /* bad window length */ 7967754Smsmith if(win == type_window) { 80151937Sjkim /* search window bitmap for the correct byte */ 8199146Siwasaki /* mybyte is 0 if we need the first byte */ 8267754Smsmith size_t mybyte = type_low>>3; 8367754Smsmith if(winlen <= mybyte) 8467754Smsmith return 0; /* window too short */ 8567754Smsmith return (int)(bitmap[mybyte] & masks[type_low&0x7]); 8667754Smsmith } else { 8767754Smsmith /* not the window we are looking for */ 88209746Sjkim bitmap += winlen; 8967754Smsmith len -= winlen; 9067754Smsmith } 91167802Sjkim } 9267754Smsmith /* end of bitmap reached, no type found */ 9367754Smsmith return 0; 94104470Siwasaki} 9599679Siwasaki 9667754Smsmithint 9767754Smsmithnsec_has_type(struct ub_packed_rrset_key* nsec, uint16_t type) 98167802Sjkim{ 9987031Smsmith struct packed_rrset_data* d = (struct packed_rrset_data*)nsec-> 10067754Smsmith entry.data; 10167754Smsmith size_t len; 10299679Siwasaki if(!d || d->count == 0 || d->rr_len[0] < 2+1) 10367754Smsmith return 0; 104151937Sjkim len = dname_valid(d->rr_data[0]+2, d->rr_len[0]-2); 105298714Sjkim if(!len) 106298714Sjkim return 0; 107298714Sjkim return nsecbitmap_has_type_rdata(d->rr_data[0]+2+len, 108298714Sjkim d->rr_len[0]-2-len, type); 10967754Smsmith} 11067754Smsmith 111167802Sjkim/** 112167802Sjkim * Get next owner name from nsec record 113167802Sjkim * @param nsec: the nsec RRset. 114167802Sjkim * If there are multiple RRs, then this will only return one of them. 115167802Sjkim * @param nm: the next name is returned. 116167802Sjkim * @param ln: length of nm is returned. 117167802Sjkim * @return false on a bad NSEC RR (too short, malformed dname). 118167802Sjkim */ 119167802Sjkimstatic int 120167802Sjkimnsec_get_next(struct ub_packed_rrset_key* nsec, uint8_t** nm, size_t* ln) 121167802Sjkim{ 122167802Sjkim struct packed_rrset_data* d = (struct packed_rrset_data*)nsec-> 123167802Sjkim entry.data; 124167802Sjkim if(!d || d->count == 0 || d->rr_len[0] < 2+1) { 125167802Sjkim *nm = 0; 126167802Sjkim *ln = 0; 127167802Sjkim return 0; 128167802Sjkim } 129167802Sjkim *nm = d->rr_data[0]+2; 130167802Sjkim *ln = dname_valid(*nm, d->rr_len[0]-2); 131167802Sjkim if(!*ln) { 132167802Sjkim *nm = 0; 133167802Sjkim *ln = 0; 134167802Sjkim return 0; 135167802Sjkim } 136167802Sjkim return 1; 137167802Sjkim} 138104470Siwasaki 13967754Smsmith/** 14067754Smsmith * For an NSEC that matches the DS queried for, check absence of DS type. 141193267Sjkim * 142193267Sjkim * @param nsec: NSEC for proof, must be trusted. 143193267Sjkim * @param qinfo: what is queried for. 144193267Sjkim * @return if secure the nsec proves that no DS is present, or 145193267Sjkim * insecure if it proves it is not a delegation point. 146193267Sjkim * or bogus if something was wrong. 147193267Sjkim */ 148193267Sjkimstatic enum sec_status 149193267Sjkimval_nsec_proves_no_ds(struct ub_packed_rrset_key* nsec, 150193267Sjkim struct query_info* qinfo) 151193267Sjkim{ 152193267Sjkim log_assert(qinfo->qtype == LDNS_RR_TYPE_DS); 153193267Sjkim log_assert(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC); 154193267Sjkim 155193267Sjkim if(nsec_has_type(nsec, LDNS_RR_TYPE_SOA) && qinfo->qname_len != 1) { 156193267Sjkim /* SOA present means that this is the NSEC from the child, 157193267Sjkim * not the parent (so it is the wrong one). */ 158193267Sjkim return sec_status_bogus; 159193267Sjkim } 160193267Sjkim if(nsec_has_type(nsec, LDNS_RR_TYPE_DS)) { 161193267Sjkim /* DS present means that there should have been a positive 162193267Sjkim * response to the DS query, so there is something wrong. */ 163193267Sjkim return sec_status_bogus; 164298714Sjkim } 165298714Sjkim 166193267Sjkim if(!nsec_has_type(nsec, LDNS_RR_TYPE_NS)) { 167193267Sjkim /* If there is no NS at this point at all, then this 168193267Sjkim * doesn't prove anything one way or the other. */ 169193267Sjkim return sec_status_insecure; 170193267Sjkim } 171209746Sjkim /* Otherwise, this proves no DS. */ 172209746Sjkim return sec_status_secure; 173209746Sjkim} 174209746Sjkim 175209746Sjkim/** check security status from cache or verify rrset, returns true if secure */ 176209746Sjkimstatic int 177209746Sjkimnsec_verify_rrset(struct module_env* env, struct val_env* ve, 178193267Sjkim struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey, 179209746Sjkim char** reason) 180209746Sjkim{ 181209746Sjkim struct packed_rrset_data* d = (struct packed_rrset_data*) 182209746Sjkim nsec->entry.data; 183209746Sjkim if(d->security == sec_status_secure) 184209746Sjkim return 1; 185209746Sjkim rrset_check_sec_status(env->rrset_cache, nsec, *env->now); 186193267Sjkim if(d->security == sec_status_secure) 187193267Sjkim return 1; 188193267Sjkim d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason); 189193267Sjkim if(d->security == sec_status_secure) { 190193267Sjkim rrset_update_sec_status(env->rrset_cache, nsec, *env->now); 191193267Sjkim return 1; 192193267Sjkim } 193193267Sjkim return 0; 194193267Sjkim} 195193267Sjkim 196193267Sjkimenum sec_status 197193267Sjkimval_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, 198193267Sjkim struct query_info* qinfo, struct reply_info* rep, 199193267Sjkim struct key_entry_key* kkey, time_t* proof_ttl, char** reason) 200193267Sjkim{ 201193267Sjkim struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns( 202193267Sjkim rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC, 203193267Sjkim qinfo->qclass); 204193267Sjkim enum sec_status sec; 205193267Sjkim size_t i; 206193267Sjkim uint8_t* wc = NULL, *ce = NULL; 207193267Sjkim int valid_nsec = 0; 208193267Sjkim struct ub_packed_rrset_key* wc_nsec = NULL; 209193267Sjkim 210193267Sjkim /* If we have a NSEC at the same name, it must prove one 211193267Sjkim * of two things 212193267Sjkim * -- 213193267Sjkim * 1) this is a delegation point and there is no DS 214193267Sjkim * 2) this is not a delegation point */ 215193267Sjkim if(nsec) { 216193267Sjkim if(!nsec_verify_rrset(env, ve, nsec, kkey, reason)) { 217193267Sjkim verbose(VERB_ALGO, "NSEC RRset for the " 218193267Sjkim "referral did not verify."); 219193267Sjkim return sec_status_bogus; 22067754Smsmith } 22167754Smsmith sec = val_nsec_proves_no_ds(nsec, qinfo); 222167802Sjkim if(sec == sec_status_bogus) { 22367754Smsmith /* something was wrong. */ 224151937Sjkim *reason = "NSEC does not prove absence of DS"; 225298714Sjkim return sec; 22667754Smsmith } else if(sec == sec_status_insecure) { 22767754Smsmith /* this wasn't a delegation point. */ 22867754Smsmith return sec; 22967754Smsmith } else if(sec == sec_status_secure) { 23067754Smsmith /* this proved no DS. */ 231298714Sjkim *proof_ttl = ub_packed_rrset_ttl(nsec); 232298714Sjkim return sec; 23367754Smsmith } 23467754Smsmith /* if unchecked, fall through to next proof */ 23577424Smsmith } 23667754Smsmith 23767754Smsmith /* Otherwise, there is no NSEC at qname. This could be an ENT. 23867754Smsmith * (ENT=empty non terminal). If not, this is broken. */ 239193267Sjkim 24067754Smsmith /* verify NSEC rrsets in auth section */ 241193267Sjkim for(i=rep->an_numrrsets; i < rep->an_numrrsets+rep->ns_numrrsets; 24267754Smsmith i++) { 24367754Smsmith if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC)) 24467754Smsmith continue; 245151937Sjkim if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason)) { 24667754Smsmith verbose(VERB_ALGO, "NSEC for empty non-terminal " 24799146Siwasaki "did not verify."); 24867754Smsmith return sec_status_bogus; 24999679Siwasaki } 25099679Siwasaki if(nsec_proves_nodata(rep->rrsets[i], qinfo, &wc)) { 25199679Siwasaki verbose(VERB_ALGO, "NSEC for empty non-terminal " 25267754Smsmith "proved no DS."); 25367754Smsmith *proof_ttl = rrset_get_ttl(rep->rrsets[i]); 25467754Smsmith if(wc && dname_is_wild(rep->rrsets[i]->rk.dname)) 25567754Smsmith wc_nsec = rep->rrsets[i]; 25667754Smsmith valid_nsec = 1; 25767754Smsmith } 25867754Smsmith if(val_nsec_proves_name_error(rep->rrsets[i], qinfo->qname)) { 259151937Sjkim ce = nsec_closest_encloser(qinfo->qname, 26067754Smsmith rep->rrsets[i]); 26167754Smsmith } 26299146Siwasaki } 26367754Smsmith if(wc && !ce) 26467754Smsmith valid_nsec = 0; 26599146Siwasaki else if(wc && ce) { 26667754Smsmith /* ce and wc must match */ 26767754Smsmith if(query_dname_compare(wc, ce) != 0) 26867754Smsmith valid_nsec = 0; 26967754Smsmith else if(!wc_nsec) 27099679Siwasaki valid_nsec = 0; 27199146Siwasaki } 27267754Smsmith if(valid_nsec) { 27367754Smsmith if(wc) { 274167802Sjkim /* check if this is a delegation */ 27567754Smsmith *reason = "NSEC for wildcard does not prove absence of DS"; 27667754Smsmith return val_nsec_proves_no_ds(wc_nsec, qinfo); 277167802Sjkim } 278167802Sjkim /* valid nsec proves empty nonterminal */ 279167802Sjkim return sec_status_insecure; 280167802Sjkim } 281167802Sjkim 28299146Siwasaki /* NSEC proof did not conclusively point to DS or no DS */ 283167802Sjkim return sec_status_unchecked; 28467754Smsmith} 28599146Siwasaki 28667754Smsmithint nsec_proves_nodata(struct ub_packed_rrset_key* nsec, 28799146Siwasaki struct query_info* qinfo, uint8_t** wc) 28899146Siwasaki{ 28999146Siwasaki log_assert(wc); 29099146Siwasaki if(query_dname_compare(nsec->rk.dname, qinfo->qname) != 0) { 29199146Siwasaki uint8_t* nm; 29299146Siwasaki size_t ln; 29399146Siwasaki 29467754Smsmith /* empty-non-terminal checking. 29567754Smsmith * Done before wildcard, because this is an exact match, 29699146Siwasaki * and would prevent a wildcard from matching. */ 297241973Sjkim 29899146Siwasaki /* If the nsec is proving that qname is an ENT, the nsec owner 29967754Smsmith * will be less than qname, and the next name will be a child 30099679Siwasaki * domain of the qname. */ 30167754Smsmith if(!nsec_get_next(nsec, &nm, &ln)) 30299679Siwasaki return 0; /* bad nsec */ 30399146Siwasaki if(dname_strict_subdomain_c(nm, qinfo->qname) && 30467754Smsmith dname_canonical_compare(nsec->rk.dname, 30599679Siwasaki qinfo->qname) < 0) { 30699146Siwasaki return 1; /* proves ENT */ 307167802Sjkim } 308204773Sjkim 30999679Siwasaki /* wildcard checking. */ 31099146Siwasaki 31199146Siwasaki /* If this is a wildcard NSEC, make sure that a) it was 31299146Siwasaki * possible to have generated qname from the wildcard and 31399146Siwasaki * b) the type map does not contain qtype. Note that this 31499146Siwasaki * does NOT prove that this wildcard was the applicable 315117521Snjl * wildcard. */ 31667754Smsmith if(dname_is_wild(nsec->rk.dname)) { 31767754Smsmith /* the purported closest encloser. */ 31867754Smsmith uint8_t* ce = nsec->rk.dname; 31999146Siwasaki size_t ce_len = nsec->rk.dname_len; 320102550Siwasaki dname_remove_label(&ce, &ce_len); 32199146Siwasaki 32267754Smsmith /* The qname must be a strict subdomain of the 32399146Siwasaki * closest encloser, for the wildcard to apply 32499146Siwasaki */ 32567754Smsmith if(dname_strict_subdomain_c(qinfo->qname, ce)) { 32699146Siwasaki /* here we have a matching NSEC for the qname, 32799146Siwasaki * perform matching NSEC checks */ 32867754Smsmith if(nsec_has_type(nsec, LDNS_RR_TYPE_CNAME)) { 32999146Siwasaki /* should have gotten the wildcard CNAME */ 33067754Smsmith return 0; 33199146Siwasaki } 33299146Siwasaki if(nsec_has_type(nsec, LDNS_RR_TYPE_NS) && 33399146Siwasaki !nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) { 334117521Snjl /* wrong parentside (wildcard) NSEC used */ 335117521Snjl return 0; 33667754Smsmith } 337114237Snjl if(nsec_has_type(nsec, qinfo->qtype)) { 33899146Siwasaki return 0; 339298714Sjkim } 340298714Sjkim *wc = ce; 341114237Snjl return 1; 342114237Snjl } 343114237Snjl } else { 344114237Snjl /* See if the next owner name covers a wildcard 345114237Snjl * empty non-terminal. */ 34699146Siwasaki while (dname_strict_subdomain_c(nm, nsec->rk.dname)) { 347114237Snjl /* wildcard does not apply if qname below 34899146Siwasaki * the name that exists under the '*' */ 349114237Snjl if (dname_subdomain_c(qinfo->qname, nm)) 350114237Snjl break; 351284583Sjkim /* but if it is a wildcard and qname is below 352298714Sjkim * it, then the wildcard applies. The wildcard 353114237Snjl * is an empty nonterminal. nodata proven. */ 35499146Siwasaki if (dname_is_wild(nm)) { 35599146Siwasaki size_t ce_len = ln; 35699146Siwasaki uint8_t* ce = nm; 357167802Sjkim dname_remove_label(&ce, &ce_len); 35899146Siwasaki if(dname_strict_subdomain_c(qinfo->qname, ce)) { 35967754Smsmith *wc = ce; 36067754Smsmith return 1; 36167754Smsmith } 362151937Sjkim } 36367754Smsmith dname_remove_label(&nm, &ln); 36499146Siwasaki } 36567754Smsmith } 36699679Siwasaki 36799679Siwasaki /* Otherwise, this NSEC does not prove ENT and is not a 368167802Sjkim * wildcard, so it does not prove NODATA. */ 369167802Sjkim return 0; 37067754Smsmith } 37167754Smsmith 37267754Smsmith /* If the qtype exists, then we should have gotten it. */ 37367754Smsmith if(nsec_has_type(nsec, qinfo->qtype)) { 37499146Siwasaki return 0; 37599146Siwasaki } 37667754Smsmith 377167802Sjkim /* if the name is a CNAME node, then we should have gotten the CNAME*/ 378167802Sjkim if(nsec_has_type(nsec, LDNS_RR_TYPE_CNAME)) { 379167802Sjkim return 0; 380167802Sjkim } 381167802Sjkim 382167802Sjkim /* If an NS set exists at this name, and NOT a SOA (so this is a 383167802Sjkim * zone cut, not a zone apex), then we should have gotten a 384167802Sjkim * referral (or we just got the wrong NSEC). 385167802Sjkim * The reverse of this check is used when qtype is DS, since that 386167802Sjkim * must use the NSEC from above the zone cut. */ 387167802Sjkim if(qinfo->qtype != LDNS_RR_TYPE_DS && 388167802Sjkim nsec_has_type(nsec, LDNS_RR_TYPE_NS) && 389151937Sjkim !nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) { 39067754Smsmith return 0; 39167754Smsmith } else if(qinfo->qtype == LDNS_RR_TYPE_DS && 39299146Siwasaki nsec_has_type(nsec, LDNS_RR_TYPE_SOA) && 39367754Smsmith !dname_is_root(qinfo->qname)) { 39467754Smsmith return 0; 395167802Sjkim } 39667754Smsmith 39767754Smsmith return 1; 39899146Siwasaki} 39999146Siwasaki 40099146Siwasakiint 40199146Siwasakival_nsec_proves_name_error(struct ub_packed_rrset_key* nsec, uint8_t* qname) 402193267Sjkim{ 403167802Sjkim uint8_t* owner = nsec->rk.dname; 404167802Sjkim uint8_t* next; 40567754Smsmith size_t nlen; 40667754Smsmith if(!nsec_get_next(nsec, &next, &nlen)) 407167802Sjkim return 0; 40899146Siwasaki 40999146Siwasaki /* If NSEC owner == qname, then this NSEC proves that qname exists. */ 41099146Siwasaki if(query_dname_compare(qname, owner) == 0) { 41199146Siwasaki return 0; 41299679Siwasaki } 413167802Sjkim 41499679Siwasaki /* If NSEC is a parent of qname, we need to check the type map 41567754Smsmith * If the parent name has a DNAME or is a delegation point, then 41699679Siwasaki * this NSEC is being misused. */ 41799146Siwasaki if(dname_subdomain_c(qname, owner) && 41882367Smsmith (nsec_has_type(nsec, LDNS_RR_TYPE_DNAME) || 419167802Sjkim (nsec_has_type(nsec, LDNS_RR_TYPE_NS) 420167802Sjkim && !nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) 421167802Sjkim )) { 422167802Sjkim return 0; 42399146Siwasaki } 424167802Sjkim 42599146Siwasaki if(query_dname_compare(owner, next) == 0) { 42699146Siwasaki /* this nsec is the only nsec */ 42799146Siwasaki /* zone.name NSEC zone.name, disproves everything else */ 42899146Siwasaki /* but only for subdomains of that zone */ 42999146Siwasaki if(dname_strict_subdomain_c(qname, next)) 43099146Siwasaki return 1; 43199146Siwasaki } 43267754Smsmith else if(dname_canonical_compare(owner, next) > 0) { 43399679Siwasaki /* this is the last nsec, ....(bigger) NSEC zonename(smaller) */ 43499146Siwasaki /* the names after the last (owner) name do not exist 43582367Smsmith * there are no names before the zone name in the zone 43699146Siwasaki * but the qname must be a subdomain of the zone name(next). */ 437167802Sjkim if(dname_canonical_compare(owner, qname) < 0 && 438167802Sjkim dname_strict_subdomain_c(qname, next)) 439167802Sjkim return 1; 44099146Siwasaki } else { 441167802Sjkim /* regular NSEC, (smaller) NSEC (larger) */ 442167802Sjkim if(dname_canonical_compare(owner, qname) < 0 && 44399146Siwasaki dname_canonical_compare(qname, next) < 0) { 44499146Siwasaki return 1; 44599146Siwasaki } 44699146Siwasaki } 44799146Siwasaki return 0; 44899146Siwasaki} 44999146Siwasaki 450167802Sjkimint val_nsec_proves_insecuredelegation(struct ub_packed_rrset_key* nsec, 451167802Sjkim struct query_info* qinfo) 45299146Siwasaki{ 453167802Sjkim if(nsec_has_type(nsec, LDNS_RR_TYPE_NS) && 454167802Sjkim !nsec_has_type(nsec, LDNS_RR_TYPE_DS) && 455167802Sjkim !nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) { 456167802Sjkim /* see if nsec signals an insecure delegation */ 45799146Siwasaki if(qinfo->qtype == LDNS_RR_TYPE_DS) { 45899679Siwasaki /* if type is DS and qname is equal to nsec, then it 45999679Siwasaki * is an exact match nsec, result not insecure */ 460167802Sjkim if(dname_strict_subdomain_c(qinfo->qname, 46199146Siwasaki nsec->rk.dname)) 46299679Siwasaki return 1; 46399146Siwasaki } else { 464193267Sjkim if(dname_subdomain_c(qinfo->qname, nsec->rk.dname)) 465193267Sjkim return 1; 466193267Sjkim } 467193267Sjkim } 468193267Sjkim return 0; 469193267Sjkim} 470193267Sjkim 471298714Sjkimuint8_t* 472298714Sjkimnsec_closest_encloser(uint8_t* qname, struct ub_packed_rrset_key* nsec) 473193267Sjkim{ 474193267Sjkim uint8_t* next; 475193267Sjkim size_t nlen; 476193267Sjkim uint8_t* common1, *common2; 47799146Siwasaki if(!nsec_get_next(nsec, &next, &nlen)) 478193267Sjkim return NULL; 479193267Sjkim /* longest common with owner or next name */ 480193267Sjkim common1 = dname_get_shared_topdomain(nsec->rk.dname, qname); 48199146Siwasaki common2 = dname_get_shared_topdomain(next, qname); 48299146Siwasaki if(dname_count_labels(common1) > dname_count_labels(common2)) 48399146Siwasaki return common1; 484298714Sjkim return common2; 485298714Sjkim} 48699146Siwasaki 48799146Siwasakiint val_nsec_proves_positive_wildcard(struct ub_packed_rrset_key* nsec, 488167802Sjkim struct query_info* qinf, uint8_t* wc) 489167802Sjkim{ 490167802Sjkim uint8_t* ce; 491167802Sjkim /* 1) prove that qname doesn't exist and 492167802Sjkim * 2) that the correct wildcard was used 493167802Sjkim * nsec has been verified already. */ 494167802Sjkim if(!val_nsec_proves_name_error(nsec, qinf->qname)) 495167802Sjkim return 0; 496167802Sjkim /* check wildcard name */ 497167802Sjkim ce = nsec_closest_encloser(qinf->qname, nsec); 498167802Sjkim if(!ce) 499167802Sjkim return 0; 500167802Sjkim if(query_dname_compare(wc, ce) != 0) { 501167802Sjkim return 0; 502167802Sjkim } 503167802Sjkim return 1; 50499679Siwasaki} 50599146Siwasaki 50699146Siwasakiint 507193267Sjkimval_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname, 508193267Sjkim size_t qnamelen) 509193267Sjkim{ 510167802Sjkim /* Determine if a NSEC record proves the non-existence of a 511193267Sjkim * wildcard that could have produced qname. */ 512193267Sjkim int labs; 513197104Sjkim int i; 514193267Sjkim uint8_t* ce = nsec_closest_encloser(qname, nsec); 515193267Sjkim uint8_t* strip; 516193267Sjkim size_t striplen; 517199337Sjkim uint8_t buf[LDNS_MAX_DOMAINLEN+3]; 518197104Sjkim if(!ce) 519197104Sjkim return 0; 520197104Sjkim /* we can subtract the closest encloser count - since that is the 521193267Sjkim * largest shared topdomain with owner and next NSEC name, 522193267Sjkim * because the NSEC is no proof for names shorter than the owner 523193267Sjkim * and next names. */ 524197104Sjkim labs = dname_count_labels(qname) - dname_count_labels(ce); 525197104Sjkim 526197104Sjkim for(i=labs; i>0; i--) { 527197104Sjkim /* i is number of labels to strip off qname, prepend * wild */ 528197104Sjkim strip = qname; 529197104Sjkim striplen = qnamelen; 530197104Sjkim dname_remove_labels(&strip, &striplen, i); 531197104Sjkim if(striplen > LDNS_MAX_DOMAINLEN-2) 532197104Sjkim continue; /* too long to prepend wildcard */ 533197104Sjkim buf[0] = 1; 534197104Sjkim buf[1] = (uint8_t)'*'; 535193267Sjkim memmove(buf+2, strip, striplen); 536193267Sjkim if(val_nsec_proves_name_error(nsec, buf)) { 537193267Sjkim return 1; 538193267Sjkim } 539193267Sjkim } 540193267Sjkim return 0; 541298714Sjkim} 542298714Sjkim 543298714Sjkim/** 544193267Sjkim * Find shared topdomain that exists 545193267Sjkim */ 546193267Sjkimstatic void 547193267Sjkimdlv_topdomain(struct ub_packed_rrset_key* nsec, uint8_t* qname, 548193267Sjkim uint8_t** nm, size_t* nm_len) 549193267Sjkim{ 550193267Sjkim /* make sure reply is part of nm */ 551193267Sjkim /* take shared topdomain with left of NSEC. */ 552167802Sjkim 553298714Sjkim /* because, if empty nonterminal, then right is subdomain of qname. 554298714Sjkim * and any shared topdomain would be empty nonterminals. 555193267Sjkim * 556167802Sjkim * If nxdomain, then the right is bigger, and could have an 557167802Sjkim * interesting shared topdomain, but if it does have one, it is 55899146Siwasaki * an empty nonterminal. An empty nonterminal shared with the left 559167802Sjkim * one. */ 56099146Siwasaki int n; 56167754Smsmith uint8_t* common = dname_get_shared_topdomain(qname, nsec->rk.dname); 56267754Smsmith n = dname_count_labels(*nm) - dname_count_labels(common); 56367754Smsmith dname_remove_labels(nm, nm_len, n); 564151937Sjkim} 56567754Smsmith 56667754Smsmithint val_nsec_check_dlv(struct query_info* qinfo, 56767754Smsmith struct reply_info* rep, uint8_t** nm, size_t* nm_len) 56899679Siwasaki{ 56999679Siwasaki uint8_t* next; 57099679Siwasaki size_t i, nlen; 57167754Smsmith int c; 57267754Smsmith /* we should now have a NOERROR/NODATA or NXDOMAIN message */ 57367754Smsmith if(rep->an_numrrsets != 0) { 57499679Siwasaki return 0; 57567754Smsmith } 576151937Sjkim /* is this NOERROR ? */ 57767754Smsmith if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR) { 57867754Smsmith /* it can be a plain NSEC match - go up one more level. */ 57967754Smsmith /* or its an empty nonterminal - go up to nonempty level */ 58067754Smsmith for(i=0; i<rep->ns_numrrsets; i++) { 58167754Smsmith if(htons(rep->rrsets[i]->rk.type)!=LDNS_RR_TYPE_NSEC || 58267754Smsmith !nsec_get_next(rep->rrsets[i], &next, &nlen)) 58367754Smsmith continue; 58467754Smsmith c = dname_canonical_compare( 58567754Smsmith rep->rrsets[i]->rk.dname, qinfo->qname); 58667754Smsmith if(c == 0) { 58767754Smsmith /* plain match */ 588167802Sjkim if(nsec_has_type(rep->rrsets[i], 58967754Smsmith LDNS_RR_TYPE_DLV)) 59067754Smsmith return 0; 59185756Smsmith dname_remove_label(nm, nm_len); 59285756Smsmith return 1; 593241973Sjkim } else if(c < 0 && 59485756Smsmith dname_strict_subdomain_c(next, qinfo->qname)) { 59585756Smsmith /* ENT */ 59687031Smsmith dlv_topdomain(rep->rrsets[i], qinfo->qname, 59785756Smsmith nm, nm_len); 59885756Smsmith return 1; 59985756Smsmith } 60085756Smsmith } 60199679Siwasaki return 0; 60267754Smsmith } 60367754Smsmith 60467754Smsmith /* is this NXDOMAIN ? */ 60567754Smsmith if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN) { 60667754Smsmith /* find the qname denial NSEC record. It can tell us 60767754Smsmith * a closest encloser name; or that we not need bother */ 60867754Smsmith for(i=0; i<rep->ns_numrrsets; i++) { 60967754Smsmith if(htons(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC) 610298714Sjkim continue; 611298714Sjkim if(val_nsec_proves_name_error(rep->rrsets[i], 61267754Smsmith qinfo->qname)) { 61367754Smsmith log_nametypeclass(VERB_ALGO, "topdomain on", 61467754Smsmith rep->rrsets[i]->rk.dname, 61567754Smsmith ntohs(rep->rrsets[i]->rk.type), 0); 61667754Smsmith dlv_topdomain(rep->rrsets[i], qinfo->qname, 617114237Snjl nm, nm_len); 61867754Smsmith return 1; 619193267Sjkim } 62067754Smsmith } 62199146Siwasaki return 0; 62267754Smsmith } 62391116Smsmith return 0; 62467754Smsmith} 62585756Smsmith