/** fill data into result */ static int fill_res(struct ub_result* res, struct ub_packed_rrset_key* answer, uint8_t* finalcname, struct query_info* rq) { size_t i; struct packed_rrset_data* data; if(!answer) { if(finalcname) { if(!fill_canon(res, finalcname)) return 0; /* out of memory */ } res->data = (char**)calloc(1, sizeof(char*)); res->len = (int*)calloc(1, sizeof(int)); return (res->data && res->len); } data = (struct packed_rrset_data*)answer->entry.data; if(query_dname_compare(rq->qname, answer->rk.dname) != 0) { if(!fill_canon(res, answer->rk.dname)) return 0; /* out of memory */ } else res->canonname = NULL; res->data = (char**)calloc(data->count+1, sizeof(char*)); res->len = (int*)calloc(data->count+1, sizeof(int)); if(!res->data || !res->len) return 0; /* out of memory */ for(i=0; i<data->count; i++) { /* remove rdlength from rdata */ res->len[i] = (int)(data->rr_len[i] - 2); res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]); if(!res->data[i]) return 0; /* out of memory */ } res->data[data->count] = NULL; res->len[data->count] = 0; return 1; }
/* nsec3_cache_compare for rbtree */ int nsec3_hash_cmp(const void* c1, const void* c2) { struct nsec3_cached_hash* h1 = (struct nsec3_cached_hash*)c1; struct nsec3_cached_hash* h2 = (struct nsec3_cached_hash*)c2; uint8_t* s1, *s2; size_t s1len, s2len; int c = query_dname_compare(h1->dname, h2->dname); if(c != 0) return c; /* compare parameters */ /* if both malformed, its equal, robustness */ if(nsec3_get_algo(h1->nsec3, h1->rr) != nsec3_get_algo(h2->nsec3, h2->rr)) { if(nsec3_get_algo(h1->nsec3, h1->rr) < nsec3_get_algo(h2->nsec3, h2->rr)) return -1; return 1; } if(nsec3_get_iter(h1->nsec3, h1->rr) != nsec3_get_iter(h2->nsec3, h2->rr)) { if(nsec3_get_iter(h1->nsec3, h1->rr) < nsec3_get_iter(h2->nsec3, h2->rr)) return -1; return 1; } (void)nsec3_get_salt(h1->nsec3, h1->rr, &s1, &s1len); (void)nsec3_get_salt(h2->nsec3, h2->rr, &s2, &s2len); if(s1len != s2len) { if(s1len < s2len) return -1; return 1; } return memcmp(s1, s2, s1len); }
int ub_rrset_compare(void* k1, void* k2) { struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1; struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2; int c; if(key1 == key2) return 0; if(key1->rk.type != key2->rk.type) { if(key1->rk.type < key2->rk.type) return -1; return 1; } if(key1->rk.dname_len != key2->rk.dname_len) { if(key1->rk.dname_len < key2->rk.dname_len) return -1; return 1; } if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0) return c; if(key1->rk.rrset_class != key2->rk.rrset_class) { if(key1->rk.rrset_class < key2->rk.rrset_class) return -1; return 1; } if(key1->rk.flags != key2->rk.flags) { if(key1->rk.flags < key2->rk.flags) return -1; return 1; } return 0; }
void local_zones_del_data(struct local_zones* zones, uint8_t* name, size_t len, int labs, uint16_t dclass) { /* find zone */ struct local_zone* z; struct local_data* d; lock_rw_rdlock(&zones->lock); z = local_zones_lookup(zones, name, len, labs, dclass); if(!z) { /* no such zone, we're done */ lock_rw_unlock(&zones->lock); return; } lock_rw_wrlock(&z->lock); lock_rw_unlock(&zones->lock); /* find the domain */ d = lz_find_node(z, name, len, labs); if(d) { /* no memory recycling for zone deletions ... */ d->rrsets = NULL; /* did we delete the soa record ? */ if(query_dname_compare(d->name, z->name) == 0) z->soa = NULL; /* cleanup the empty nonterminals for this name */ del_empty_term(z, d, name, len, labs); } lock_rw_unlock(&z->lock); }
int iter_ds_toolow(struct dns_msg* msg, struct delegpt* dp) { /* if for query example.com, there is example.com SOA or a subdomain * of example.com, then we are too low and need to fetch NS. */ size_t i; /* if we have a DNAME or CNAME we are probably wrong */ /* if we have a qtype DS in the answer section, its fine */ for(i=0; i < msg->rep->an_numrrsets; i++) { struct ub_packed_rrset_key* s = msg->rep->rrsets[i]; if(ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME || ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) { /* not the right answer, maybe too low, check the * RRSIG signer name (if there is any) for a hint * that it is from the dp zone anyway */ uint8_t* sname; size_t slen; val_find_rrset_signer(s, &sname, &slen); if(sname && query_dname_compare(dp->name, sname)==0) return 0; /* it is fine, from the right dp */ return 1; } if(ntohs(s->rk.type) == LDNS_RR_TYPE_DS) return 0; /* fine, we have a DS record */ } for(i=msg->rep->an_numrrsets; i < msg->rep->an_numrrsets + msg->rep->ns_numrrsets; i++) { struct ub_packed_rrset_key* s = msg->rep->rrsets[i]; if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA) { if(dname_subdomain_c(s->rk.dname, msg->qinfo.qname)) return 1; /* point is too low */ if(query_dname_compare(s->rk.dname, dp->name)==0) return 0; /* right dp */ } if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC || ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) { uint8_t* sname; size_t slen; val_find_rrset_signer(s, &sname, &slen); if(sname && query_dname_compare(dp->name, sname)==0) return 0; /* it is fine, from the right dp */ return 1; } } /* we do not know */ return 1; }
/** * proveClosestEncloser * Given a List of nsec3 RRs, find and prove the closest encloser to qname. * @param env: module environment with temporary region and buffer. * @param flt: the NSEC3 RR filter, contains zone name and RRs. * @param ct: cached hashes table. * @param qinfo: query that is verified for. * @param prove_does_not_exist: If true, then if the closest encloser * turns out to be qname, then null is returned. * If set true, and the return value is true, then you can be * certain that the ce.nc_rrset and ce.nc_rr are set properly. * @param ce: closest encloser information is returned in here. * @return bogus if no closest encloser could be proven. * secure if a closest encloser could be proven, ce is set. * insecure if the closest-encloser candidate turns out to prove * that an insecure delegation exists above the qname. */ static enum sec_status nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, rbtree_t* ct, struct query_info* qinfo, int prove_does_not_exist, struct ce_response* ce) { uint8_t* nc; size_t nc_len; /* robust: clean out ce, in case it gets abused later */ memset(ce, 0, sizeof(*ce)); if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce)) { verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could " "not find a candidate for the closest encloser."); return sec_status_bogus; } log_nametypeclass(VERB_ALGO, "ce candidate", ce->ce, 0, 0); if(query_dname_compare(ce->ce, qinfo->qname) == 0) { if(prove_does_not_exist) { verbose(VERB_ALGO, "nsec3 proveClosestEncloser: " "proved that qname existed, bad"); return sec_status_bogus; } /* otherwise, we need to nothing else to prove that qname * is its own closest encloser. */ return sec_status_secure; } /* If the closest encloser is actually a delegation, then the * response should have been a referral. If it is a DNAME, then * it should have been a DNAME response. */ if(nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_NS) && !nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_SOA)) { if(!nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_DS)) { verbose(VERB_ALGO, "nsec3 proveClosestEncloser: " "closest encloser is insecure delegation"); return sec_status_insecure; } verbose(VERB_ALGO, "nsec3 proveClosestEncloser: closest " "encloser was a delegation, bad"); return sec_status_bogus; } if(nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_DNAME)) { verbose(VERB_ALGO, "nsec3 proveClosestEncloser: closest " "encloser was a DNAME, bad"); return sec_status_bogus; } /* Otherwise, we need to show that the next closer name is covered. */ next_closer(qinfo->qname, qinfo->qname_len, ce->ce, &nc, &nc_len); if(!find_covering_nsec3(env, flt, ct, nc, nc_len, &ce->nc_rrset, &ce->nc_rr)) { verbose(VERB_ALGO, "nsec3: Could not find proof that the " "candidate encloser was the closest encloser"); return sec_status_bogus; } return sec_status_secure; }
/** print root forwards */ static int print_root_fwds(SSL* ssl, struct iter_forwards* fwds, uint8_t* root) { struct delegpt* dp; dp = forwards_lookup(fwds, root, LDNS_RR_CLASS_IN); if(!dp) return ssl_printf(ssl, "off (using root hints)\n"); /* if dp is returned it must be the root */ log_assert(query_dname_compare(dp->name, root)==0); return ssl_print_name_dp(ssl, NULL, root, LDNS_RR_CLASS_IN, dp); }
/** Test dname_get_shared_topdomain */ static void dname_test_topdomain(void) { unit_show_func("util/data/dname.c", "dname_get_shared_topdomain"); unit_assert( query_dname_compare( dname_get_shared_topdomain( (uint8_t*)"", (uint8_t*)""), (uint8_t*)"") == 0); unit_assert( query_dname_compare( dname_get_shared_topdomain( (uint8_t*)"\003www\007example\003com", (uint8_t*)"\003www\007example\003com"), (uint8_t*)"\003www\007example\003com") == 0); unit_assert( query_dname_compare( dname_get_shared_topdomain( (uint8_t*)"\003www\007example\003com", (uint8_t*)"\003bla\007example\003com"), (uint8_t*)"\007example\003com") == 0); }
/** * Answer CH class queries. * @param w: worker * @param qinfo: query info. Pointer into packet buffer. * @param edns: edns info from query. * @param pkt: packet buffer. * @return: true if a reply is to be sent. */ static int answer_chaos(struct worker* w, struct query_info* qinfo, struct edns_data* edns, sldns_buffer* pkt) { struct config_file* cfg = w->env.cfg; if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT) return 0; if(query_dname_compare(qinfo->qname, (uint8_t*)"\002id\006server") == 0 || query_dname_compare(qinfo->qname, (uint8_t*)"\010hostname\004bind") == 0) { if(cfg->hide_identity) return 0; if(cfg->identity==NULL || cfg->identity[0]==0) { char buf[MAXHOSTNAMELEN+1]; if (gethostname(buf, MAXHOSTNAMELEN) == 0) { buf[MAXHOSTNAMELEN] = 0; chaos_replystr(pkt, buf, edns, w); } else { log_err("gethostname: %s", strerror(errno)); chaos_replystr(pkt, "no hostname", edns, w); } } else chaos_replystr(pkt, cfg->identity, edns, w); return 1; } if(query_dname_compare(qinfo->qname, (uint8_t*)"\007version\006server") == 0 || query_dname_compare(qinfo->qname, (uint8_t*)"\007version\004bind") == 0) { if(cfg->hide_version) return 0; if(cfg->version==NULL || cfg->version[0]==0) chaos_replystr(pkt, PACKAGE_STRING, edns, w); else chaos_replystr(pkt, cfg->version, edns, w); return 1; } return 0; }
/** fill data into result */ static int fill_res(struct ub_result* res, struct ub_packed_rrset_key* answer, uint8_t* finalcname, struct query_info* rq, struct reply_info* rep) { size_t i; struct packed_rrset_data* data; res->ttl = 0; if(!answer) { if(finalcname) { if(!fill_canon(res, finalcname)) return 0; /* out of memory */ } if(rep->rrset_count != 0) res->ttl = (int)rep->ttl; res->data = (char**)calloc(1, sizeof(char*)); res->len = (int*)calloc(1, sizeof(int)); return (res->data && res->len); } data = (struct packed_rrset_data*)answer->entry.data; if(query_dname_compare(rq->qname, answer->rk.dname) != 0) { if(!fill_canon(res, answer->rk.dname)) return 0; /* out of memory */ } else res->canonname = NULL; res->data = (char**)calloc(data->count+1, sizeof(char*)); res->len = (int*)calloc(data->count+1, sizeof(int)); if(!res->data || !res->len) return 0; /* out of memory */ for(i=0; i<data->count; i++) { /* remove rdlength from rdata */ res->len[i] = (int)(data->rr_len[i] - 2); res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]); if(!res->data[i]) return 0; /* out of memory */ } /* ttl for positive answers, from CNAME and answer RRs */ if(data->count != 0) { size_t j; res->ttl = (int)data->ttl; for(j=0; j<rep->an_numrrsets; j++) { struct packed_rrset_data* d = (struct packed_rrset_data*)rep->rrsets[j]-> entry.data; if((int)d->ttl < res->ttl) res->ttl = (int)d->ttl; } } /* ttl for negative answers */ if(data->count == 0 && rep->rrset_count != 0) res->ttl = (int)rep->ttl; res->data[data->count] = NULL; res->len[data->count] = 0; return 1; }
int rate_compfunc(void* key1, void* key2) { struct rate_key* k1 = (struct rate_key*)key1; struct rate_key* k2 = (struct rate_key*)key2; if(k1->namelen != k2->namelen) { if(k1->namelen < k2->namelen) return -1; return 1; } return query_dname_compare(k1->name, k2->name); }
struct delegpt_ns* delegpt_find_ns(struct delegpt* dp, uint8_t* name, size_t namelen) { struct delegpt_ns* p = dp->nslist; while(p) { if(namelen == p->namelen && query_dname_compare(name, p->name) == 0) { return p; } p = p->next; } return NULL; }
/** check that there is no data element that matches the RRSIG */ static int no_data_for_rrsig(struct reply_info* rep, struct ub_packed_rrset_key* rrsig) { size_t i; for(i=0; i<rep->rrset_count; i++) { if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_RRSIG) continue; if(query_dname_compare(rep->rrsets[i]->rk.dname, rrsig->rk.dname) == 0) /* only name is compared right now */ return 0; } return 1; }
int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp) { /* no delegation point, do not see how we can go down, * robust check, it should really exist */ if(!dp) return 0; /* see if dp equals the qname, then we cannot go down further */ if(query_dname_compare(qinfo->qname, dp->name) == 0) return 0; /* if dp is one label above the name we also cannot go down further */ if(dname_count_labels(qinfo->qname) == dp->namelabs+1) return 0; return 1; }
int query_info_compare(void* m1, void* m2) { struct query_info* msg1 = (struct query_info*)m1; struct query_info* msg2 = (struct query_info*)m2; int mc; /* from most different to least different for speed */ COMPARE_IT(msg1->qtype, msg2->qtype); if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0) return mc; log_assert(msg1->qname_len == msg2->qname_len); COMPARE_IT(msg1->qclass, msg2->qclass); return 0; #undef COMPARE_IT }
int infra_compfunc(void* key1, void* key2) { struct infra_key* k1 = (struct infra_key*)key1; struct infra_key* k2 = (struct infra_key*)key2; int r = sockaddr_cmp(&k1->addr, k1->addrlen, &k2->addr, k2->addrlen); if(r != 0) return r; if(k1->namelen != k2->namelen) { if(k1->namelen < k2->namelen) return -1; return 1; } return query_dname_compare(k1->zonename, k2->zonename); }
struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) { size_t i; for(i=0; i<rep->rrset_count; i++) { struct ub_packed_rrset_key* s = rep->rrsets[i]; if(ntohs(s->rk.type) == type && ntohs(s->rk.rrset_class) == dclass && namelen == s->rk.dname_len && query_dname_compare(name, s->rk.dname) == 0) { return s; } } return NULL; }
int nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash, struct ub_packed_rrset_key* rrset, int rr, ldns_buffer* buf) { uint8_t* next, *owner; size_t nextlen; int len; if(!nsec3_get_nextowner(rrset, rr, &next, &nextlen)) return 0; /* malformed RR proves nothing */ /* check the owner name is a hashed value . apex * base32 encoded values must have equal length. * hash_value and next hash value must have equal length. */ if(nextlen != hash->hash_len || hash->hash_len==0||hash->b32_len==0|| (size_t)*rrset->rk.dname != hash->b32_len || query_dname_compare(rrset->rk.dname+1+ (size_t)*rrset->rk.dname, zone) != 0) return 0; /* bad lengths or owner name */ /* This is the "normal case: owner < next and owner < hash < next */ if(label_compare_lower(rrset->rk.dname+1, hash->b32, hash->b32_len) < 0 && memcmp(hash->hash, next, nextlen) < 0) return 1; /* convert owner name from text to binary */ ldns_buffer_clear(buf); owner = ldns_buffer_begin(buf); len = ldns_b32_pton_extended_hex((char*)rrset->rk.dname+1, hash->b32_len, owner, ldns_buffer_limit(buf)); if(len<1) return 0; /* bad owner name in some way */ if((size_t)len != hash->hash_len || (size_t)len != nextlen) return 0; /* wrong length */ /* this is the end of zone case: next <= owner && * (hash > owner || hash < next) * this also covers the only-apex case of next==owner. */ if(memcmp(next, owner, nextlen) <= 0 && ( memcmp(hash->hash, owner, nextlen) > 0 || memcmp(hash->hash, next, nextlen) < 0)) { return 1; } return 0; }
/** see if rrset has signer name as one of the rrsig signers */ static int rrset_has_signer(struct ub_packed_rrset_key* rrset, uint8_t* name, size_t len) { struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> entry.data; size_t i; for(i = d->count; i< d->count+d->rrsig_count; i++) { if(d->rr_len[i] > 2+18+len) { /* at least rdatalen + signature + signame (+1 sig)*/ if(query_dname_compare(name, d->rr_data[i]+2+18) == 0) { return 1; } } } return 0; }
/** check if negative cache is still valid */ static void check_zone_invariants(struct val_neg_cache* neg, struct val_neg_zone* zone) { unit_assert(zone->nsec3_hash == 0); unit_assert(zone->tree.cmp == &val_neg_data_compare); unit_assert(zone->count != 0); if(zone->tree.count == 0) unit_assert(!zone->in_use); else { if(!zone->in_use) { /* details on error */ log_nametypeclass(0, "zone", zone->name, 0, 0); log_err("inuse %d count=%d tree.count=%d", zone->in_use, zone->count, (int)zone->tree.count); if(negverbose) print_neg_cache(neg); } unit_assert(zone->in_use); } if(zone->parent) { unit_assert(zone->parent->count >= zone->count); if(zone->parent->in_use) { unit_assert(zone->parent->count > zone->count); } unit_assert(zone->parent->labs == zone->labs-1); /* and parent must be one label shorter */ unit_assert(zone->name[0] == (zone->len-zone->parent->len-1)); unit_assert(query_dname_compare(zone->name + zone->name[0]+1, zone->parent->name) == 0); } else { /* must be apex */ unit_assert(dname_is_root(zone->name)); } /* tree property: */ unit_assert(zone->count == sum_zone_subtree_inuse(neg, zone)); /* check structure of zone data tree */ checkzonetree(zone); }
uint8_t* reply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep) { uint8_t* sname = qinfo->qname; size_t snamelen = qinfo->qname_len; size_t i; for(i=0; i<rep->an_numrrsets; i++) { struct ub_packed_rrset_key* s = rep->rrsets[i]; /* follow CNAME chain (if any) */ if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && ntohs(s->rk.rrset_class) == qinfo->qclass && snamelen == s->rk.dname_len && query_dname_compare(sname, s->rk.dname) == 0) { get_cname_target(s, &sname, &snamelen); } } if(sname != qinfo->qname) return sname; return NULL; }
int val_chase_cname(struct query_info* qchase, struct reply_info* rep, size_t* cname_skip) { size_t i; /* skip any DNAMEs, go to the CNAME for next part */ for(i = *cname_skip; i < rep->an_numrrsets; i++) { if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME && query_dname_compare(qchase->qname, rep->rrsets[i]-> rk.dname) == 0) { qchase->qname = NULL; get_cname_target(rep->rrsets[i], &qchase->qname, &qchase->qname_len); if(!qchase->qname) return 0; /* bad CNAME rdata */ (*cname_skip) = i+1; return 1; } } return 0; /* CNAME classified but no matching CNAME ?! */ }
/** * Compare a hashed name with the owner name of an NSEC3 RRset. * @param flt: filter with zone name. * @param hash: the hashed name. * @param s: rrset with owner name. * @return true if matches exactly, false if not. */ static int nsec3_hash_matches_owner(struct nsec3_filter* flt, struct nsec3_cached_hash* hash, struct ub_packed_rrset_key* s) { uint8_t* nm = s->rk.dname; /* compare, does hash of name based on params in this NSEC3 * match the owner name of this NSEC3? * name must be: <hashlength>base32 . zone name * so; first label must not be root label (not zero length), * and match the b32 encoded hash length, * and the label content match the b32 encoded hash * and the rest must be the zone name. */ if(hash->b32_len != 0 && (size_t)nm[0] == hash->b32_len && label_compare_lower(nm+1, hash->b32, hash->b32_len) == 0 && query_dname_compare(nm+(size_t)nm[0]+1, flt->zone) == 0) { return 1; } return 0; }
/** check point in data tree */ static void check_data(struct val_neg_zone* zone, struct val_neg_data* data) { unit_assert(data->count > 0); if(data->parent) { unit_assert(data->parent->count >= data->count); if(data->parent->in_use) { unit_assert(data->parent->count > data->count); } unit_assert(data->parent->labs == data->labs-1); /* and parent must be one label shorter */ unit_assert(data->name[0] == (data->len-data->parent->len-1)); unit_assert(query_dname_compare(data->name + data->name[0]+1, data->parent->name) == 0); } else { /* must be apex */ unit_assert(dname_is_root(data->name)); } /* tree property: */ unit_assert(data->count == sum_subtree_inuse(zone, data)); }
/** * Initialize the filter structure. * Finds the zone by looking at available NSEC3 records and best match. * (skips the unknown flag and unknown algo NSEC3s). * * @param filter: nsec3 filter structure. * @param list: list of rrsets, an array of them. * @param num: number of rrsets in list. * @param qinfo: * query name to match a zone for. * query type (if DS a higher zone must be chosen) * qclass, to filter NSEC3s with. */ static void filter_init(struct nsec3_filter* filter, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo) { size_t i; uint8_t* nm; size_t nmlen; filter->zone = NULL; filter->zone_len = 0; filter->list = list; filter->num = num; filter->fclass = qinfo->qclass; for(i=0; i<num; i++) { /* ignore other stuff in the list */ if(ntohs(list[i]->rk.type) != LDNS_RR_TYPE_NSEC3 || ntohs(list[i]->rk.rrset_class) != qinfo->qclass) continue; /* skip unknown flags, algo */ if(!nsec3_rrset_has_known(list[i])) continue; /* since NSEC3s are base32.zonename, we can find the zone * name by stripping off the first label of the record */ nm = list[i]->rk.dname; nmlen = list[i]->rk.dname_len; dname_remove_label(&nm, &nmlen); /* if we find a domain that can prove about the qname, * and if this domain is closer to the qname */ if(dname_subdomain_c(qinfo->qname, nm) && (!filter->zone || dname_subdomain_c(nm, filter->zone))) { /* for a type DS do not accept a zone equal to qname*/ if(qinfo->qtype == LDNS_RR_TYPE_DS && query_dname_compare(qinfo->qname, nm) == 0 && !dname_is_root(qinfo->qname)) continue; filter->zone = nm; filter->zone_len = nmlen; } } }
int iter_indicates_dnssec(struct module_env* env, struct delegpt* dp, struct dns_msg* msg, uint16_t dclass) { struct trust_anchor* a; /* information not available, !env->anchors can be common */ if(!env || !env->anchors || !dp || !dp->name) return 0; /* a trust anchor exists with this name, RRSIGs expected */ if((a=anchor_find(env->anchors, dp->name, dp->namelabs, dp->namelen, dclass))) { lock_basic_unlock(&a->lock); return 1; } /* see if DS rrset was given, in AUTH section */ if(msg && msg->rep && reply_find_rrset_section_ns(msg->rep, dp->name, dp->namelen, LDNS_RR_TYPE_DS, dclass)) return 1; /* look in key cache */ if(env->key_cache) { struct key_entry_key* kk = key_cache_obtain(env->key_cache, dp->name, dp->namelen, dclass, env->scratch, *env->now); if(kk) { if(query_dname_compare(kk->name, dp->name) == 0) { if(key_entry_isgood(kk) || key_entry_isbad(kk)) { regional_free_all(env->scratch); return 1; } else if(key_entry_isnull(kk)) { regional_free_all(env->scratch); return 0; } } regional_free_all(env->scratch); } } return 0; }
/** * Iterate through NSEC3 list, per RR * This routine gives the next RR in the list (or sets rrset null). * Usage: * * size_t rrsetnum; * int rrnum; * struct ub_packed_rrset_key* rrset; * for(rrset=filter_first(filter, &rrsetnum, &rrnum); rrset; * rrset=filter_next(filter, &rrsetnum, &rrnum)) * do_stuff; * * Also filters out * o unknown flag NSEC3s * o unknown algorithm NSEC3s. * @param filter: nsec3 filter structure. * @param rrsetnum: in/out rrset number to look at. * @param rrnum: in/out rr number in rrset to look at. * @returns ptr to the next rrset (or NULL at end). */ static struct ub_packed_rrset_key* filter_next(struct nsec3_filter* filter, size_t* rrsetnum, int* rrnum) { size_t i; int r; uint8_t* nm; size_t nmlen; if(!filter->zone) /* empty list */ return NULL; for(i=*rrsetnum; i<filter->num; i++) { /* see if RRset qualifies */ if(ntohs(filter->list[i]->rk.type) != LDNS_RR_TYPE_NSEC3 || ntohs(filter->list[i]->rk.rrset_class) != filter->fclass) continue; /* check RRset zone */ nm = filter->list[i]->rk.dname; nmlen = filter->list[i]->rk.dname_len; dname_remove_label(&nm, &nmlen); if(query_dname_compare(nm, filter->zone) != 0) continue; if(i == *rrsetnum) r = (*rrnum) + 1; /* continue at next RR */ else r = 0; /* new RRset start at first RR */ for(; r < (int)rrset_get_count(filter->list[i]); r++) { /* skip unknown flags, algo */ if(nsec3_unknown_flags(filter->list[i], r) || !nsec3_known_algo(filter->list[i], r)) continue; /* this one is a good target */ *rrsetnum = i; *rrnum = r; return filter->list[i]; } } return NULL; }
struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints, uint8_t* qname, uint16_t qclass, struct delegpt* cache_dp) { size_t len; int labs; struct iter_hints_stub *r; /* first lookup the stub */ labs = dname_count_size_labels(qname, &len); r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname, len, labs, qclass); if(!r) return NULL; /* If there is no cache (root prime situation) */ if(cache_dp == NULL) { if(r->dp->namelabs != 1) return r; /* no cache dp, use any non-root stub */ return NULL; } /* * If the stub is same as the delegation we got * And has noprime set, we need to 'prime' to use this stub instead. */ if(r->noprime && query_dname_compare(cache_dp->name, r->dp->name)==0) return r; /* use this stub instead of cached dp */ /* * If our cached delegation point is above the hint, we need to prime. */ if(dname_strict_subdomain(r->dp->name, r->dp->namelabs, cache_dp->name, cache_dp->namelabs)) return r; /* need to prime this stub */ return NULL; }
int reply_check_cname_chain(struct reply_info* rep) { /* check only answer section rrs for matching cname chain. * the cache may return changed rdata, but owner names are untouched.*/ size_t i; uint8_t* sname = rep->rrsets[0]->rk.dname; size_t snamelen = rep->rrsets[0]->rk.dname_len; for(i=0; i<rep->an_numrrsets; i++) { uint16_t t = ntohs(rep->rrsets[i]->rk.type); if(t == LDNS_RR_TYPE_DNAME) continue; /* skip dnames; note TTL 0 not cached */ /* verify that owner matches current sname */ if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){ /* cname chain broken */ return 0; } /* if this is a cname; move on */ if(t == LDNS_RR_TYPE_CNAME) { get_cname_target(rep->rrsets[i], &sname, &snamelen); } } return 1; }
void val_fill_reply(struct reply_info* chase, struct reply_info* orig, size_t skip, uint8_t* name, size_t len, uint8_t* signer) { size_t i; int seen_dname = 0; chase->rrset_count = 0; chase->an_numrrsets = 0; chase->ns_numrrsets = 0; chase->ar_numrrsets = 0; /* ANSWER section */ for(i=skip; i<orig->an_numrrsets; i++) { if(!signer) { if(query_dname_compare(name, orig->rrsets[i]->rk.dname) == 0) chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i]; } else if(seen_dname && ntohs(orig->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME) { chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i]; seen_dname = 0; } else if(rrset_has_signer(orig->rrsets[i], name, len)) { chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i]; if(ntohs(orig->rrsets[i]->rk.type) == LDNS_RR_TYPE_DNAME) { seen_dname = 1; } } } /* AUTHORITY section */ for(i = (skip > orig->an_numrrsets)?skip:orig->an_numrrsets; i<orig->an_numrrsets+orig->ns_numrrsets; i++) { if(!signer) { if(query_dname_compare(name, orig->rrsets[i]->rk.dname) == 0) chase->rrsets[chase->an_numrrsets+ chase->ns_numrrsets++] = orig->rrsets[i]; } else if(rrset_has_signer(orig->rrsets[i], name, len)) { chase->rrsets[chase->an_numrrsets+ chase->ns_numrrsets++] = orig->rrsets[i]; } } /* ADDITIONAL section */ for(i= (skip>orig->an_numrrsets+orig->ns_numrrsets)? skip:orig->an_numrrsets+orig->ns_numrrsets; i<orig->rrset_count; i++) { if(!signer) { if(query_dname_compare(name, orig->rrsets[i]->rk.dname) == 0) chase->rrsets[chase->an_numrrsets +orig->ns_numrrsets+chase->ar_numrrsets++] = orig->rrsets[i]; } else if(rrset_has_signer(orig->rrsets[i], name, len)) { chase->rrsets[chase->an_numrrsets+orig->ns_numrrsets+ chase->ar_numrrsets++] = orig->rrsets[i]; } } chase->rrset_count = chase->an_numrrsets + chase->ns_numrrsets + chase->ar_numrrsets; }