From: Wouter Wijngaards Date: Tue, 8 Dec 2009 13:37:59 +0000 (+0000) Subject: Fix lookup of domains with parent-child zonecut data differences. X-Git-Tag: release-1.4.1~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=59c529bada6b3ce80c17f566eb7253485c436097;p=thirdparty%2Funbound.git Fix lookup of domains with parent-child zonecut data differences. git-svn-id: file:///svn/unbound/trunk@1929 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/remote.c b/daemon/remote.c index 3c0cb2e67..cd0c4a429 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1280,7 +1280,7 @@ parse_delegpt(SSL* ssl, struct regional* region, char* args, uint8_t* root) return NULL; } /* add address */ - if(!delegpt_add_addr(dp, region, &addr, addrlen, 0, 1)) { + if(!delegpt_add_addr(dp, region, &addr, addrlen, 0, 0, 1)) { (void)ssl_printf(ssl, "error out of memory\n"); return NULL; } diff --git a/doc/Changelog b/doc/Changelog index b69f9f08c..14cb1c981 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,8 @@ +8 December 2009: Wouter + - Fix for lookup of parent-child disagreement domains, where the + parent-side glue works but it does not provide proper NS, A or AAAA + for itself, fixing domains such as motorcaravanners.eu. + 7 December 2009: Wouter - Bug#287: Fix segfault when unbound-control remove nonexistent local data. Added check to tests. diff --git a/iterator/iter_delegpt.c b/iterator/iter_delegpt.c index c5bc66385..d9a2fca97 100644 --- a/iterator/iter_delegpt.c +++ b/iterator/iter_delegpt.c @@ -78,7 +78,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region) } for(a = dp->target_list; a; a = a->next_target) { if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen, - a->bogus, 0)) + a->bogus, a->lame, 0)) return NULL; } return copy; @@ -147,7 +147,7 @@ delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr, int delegpt_add_target(struct delegpt* dp, struct regional* region, uint8_t* name, size_t namelen, struct sockaddr_storage* addr, - socklen_t addrlen, int bogus, int nodup) + socklen_t addrlen, int bogus, int lame, int nodup) { struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); if(!ns) { @@ -159,12 +159,13 @@ delegpt_add_target(struct delegpt* dp, struct regional* region, else ns->got4 = 1; if(ns->got4 && ns->got6) ns->resolved = 1; - return delegpt_add_addr(dp, region, addr, addrlen, bogus, nodup); + return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame, nodup); } int delegpt_add_addr(struct delegpt* dp, struct regional* region, - struct sockaddr_storage* addr, socklen_t addrlen, int bogus, int nodup) + struct sockaddr_storage* addr, socklen_t addrlen, int bogus, + int lame, int nodup) { struct delegpt_addr* a; if(nodup) { @@ -188,6 +189,7 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region, a->addrlen = addrlen; a->attempts = 0; a->bogus = bogus; + a->lame = lame; return 1; } @@ -332,10 +334,10 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region) continue; if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { - if(!delegpt_add_rrset_A(dp, region, s, 0)) + if(!delegpt_add_rrset_A(dp, region, s, 0, 0)) return NULL; } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { - if(!delegpt_add_rrset_AAAA(dp, region, s, 0)) + if(!delegpt_add_rrset_AAAA(dp, region, s, 0, 0)) return NULL; } } @@ -365,7 +367,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, int delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ak, int nodup) + struct ub_packed_rrset_key* ak, int lame, int nodup) { struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; size_t i; @@ -380,7 +382,7 @@ delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE); if(!delegpt_add_target(dp, region, ak->rk.dname, ak->rk.dname_len, (struct sockaddr_storage*)&sa, - len, (d->security==sec_status_bogus), nodup)) + len, (d->security==sec_status_bogus), lame, nodup)) return 0; } return 1; @@ -388,7 +390,7 @@ delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ak, int nodup) + struct ub_packed_rrset_key* ak, int lame, int nodup) { struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; size_t i; @@ -403,7 +405,7 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE); if(!delegpt_add_target(dp, region, ak->rk.dname, ak->rk.dname_len, (struct sockaddr_storage*)&sa, - len, (d->security==sec_status_bogus), nodup)) + len, (d->security==sec_status_bogus), lame, nodup)) return 0; } return 1; @@ -418,9 +420,9 @@ delegpt_add_rrset(struct delegpt* dp, struct regional* region, if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) return delegpt_rrset_add_ns(dp, region, rrset); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) - return delegpt_add_rrset_A(dp, region, rrset, 0); + return delegpt_add_rrset_A(dp, region, rrset, 0, 0); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) - return delegpt_add_rrset_AAAA(dp, region, rrset, 0); + return delegpt_add_rrset_AAAA(dp, region, rrset, 0, 0); log_warn("Unknown rrset type added to delegpt"); return 1; } diff --git a/iterator/iter_delegpt.h b/iterator/iter_delegpt.h index 4445c1b0a..b1d8264f4 100644 --- a/iterator/iter_delegpt.h +++ b/iterator/iter_delegpt.h @@ -121,6 +121,8 @@ struct delegpt_addr { /** if true, the A or AAAA RR was bogus, so this address is bad. * Also check the dp->bogus to see if everything is bogus. */ int bogus; + /** if true, this address is dispreferred: it is a lame IP address */ + int lame; }; /** @@ -178,35 +180,38 @@ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional, * @param addr: the address. * @param addrlen: the length of addr. * @param bogus: security status for the address, pass true if bogus. + * @param lame: address is lame. * @param nodup: if true, no address duplicates are made by this add. * name duplicates are always filtered. * @return false on error. */ int delegpt_add_target(struct delegpt* dp, struct regional* regional, uint8_t* name, size_t namelen, struct sockaddr_storage* addr, - socklen_t addrlen, int bogus, int nodup); + socklen_t addrlen, int bogus, int lame, int nodup); /** * Add A RRset to delegpt. * @param dp: delegation point. * @param regional: where to allocate the info. * @param rrset: RRset A to add. + * @param lame: rrset is lame, disprefer it. * @param nodup: if true, no duplicates are made by this add. takes time. * @return 0 on alloc error. */ int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* rrset, int nodup); + struct ub_packed_rrset_key* rrset, int lame, int nodup); /** * Add AAAA RRset to delegpt. * @param dp: delegation point. * @param regional: where to allocate the info. * @param rrset: RRset AAAA to add. + * @param lame: rrset is lame, disprefer it. * @param nodup: if true, no duplicates are made by this add. takes time. * @return 0 on alloc error. */ int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* rrset, int nodup); + struct ub_packed_rrset_key* rrset, int lame, int nodup); /** * Add any RRset to delegpt. @@ -226,11 +231,13 @@ int delegpt_add_rrset(struct delegpt* dp, struct regional* regional, * @param addr: the address. * @param addrlen: the length of addr. * @param bogus: if address is bogus. + * @param lame: if address is lame. * @param nodup: if true, no duplicates are made by this add. takes time. * @return false on error. */ int delegpt_add_addr(struct delegpt* dp, struct regional* regional, - struct sockaddr_storage* addr, socklen_t addrlen, int bogus, int nodup); + struct sockaddr_storage* addr, socklen_t addrlen, int bogus, + int lame, int nodup); /** * Find NS record in name list of delegation point. diff --git a/iterator/iter_fwd.c b/iterator/iter_fwd.c index 488a7d3a1..a22662a8e 100644 --- a/iterator/iter_fwd.c +++ b/iterator/iter_fwd.c @@ -212,7 +212,8 @@ read_fwds_addr(struct iter_forwards* fwd, struct config_stub* s, s->name, p->str); return 0; } - if(!delegpt_add_addr(dp, fwd->region, &addr, addrlen, 0, 1)) { + if(!delegpt_add_addr(dp, fwd->region, &addr, addrlen, + 0, 0, 1)) { log_err("out of memory"); return 0; } diff --git a/iterator/iter_hints.c b/iterator/iter_hints.c index b45e57f03..15d759333 100644 --- a/iterator/iter_hints.c +++ b/iterator/iter_hints.c @@ -86,7 +86,7 @@ ah(struct delegpt* dp, struct regional* r, const char* sv, const char* ip) if(!delegpt_add_ns(dp, r, ldns_rdf_data(rdf)) || !extstrtoaddr(ip, &addr, &addrlen) || !delegpt_add_target(dp, r, ldns_rdf_data(rdf), ldns_rdf_size(rdf), - &addr, addrlen, 0, 1)) { + &addr, addrlen, 0, 0, 1)) { ldns_rdf_deep_free(rdf); return 0; } @@ -225,7 +225,8 @@ read_stubs_addr(struct iter_hints* hints, struct config_stub* s, s->name, p->str); return 0; } - if(!delegpt_add_addr(dp, hints->region, &addr, addrlen, 0, 1)) { + if(!delegpt_add_addr(dp, hints->region, &addr, addrlen, + 0, 0, 1)) { log_err("out of memory"); return 0; } @@ -318,7 +319,7 @@ read_root_hints(struct iter_hints* hints, char* fname) ldns_rdf_data(ldns_rr_owner(rr)), ldns_rdf_size(ldns_rr_owner(rr)), (struct sockaddr_storage*)&sa, len, - 0, 1)) { + 0, 0, 1)) { log_err("out of memory reading root hints"); goto stop_read; } @@ -334,7 +335,7 @@ read_root_hints(struct iter_hints* hints, char* fname) ldns_rdf_data(ldns_rr_owner(rr)), ldns_rdf_size(ldns_rr_owner(rr)), (struct sockaddr_storage*)&sa, len, - 0, 1)) { + 0, 0, 1)) { log_err("out of memory reading root hints"); goto stop_read; } diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 718fbf62b..d364ae2a8 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -160,6 +160,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg) * For non-blacklisted servers: huge timeout, but has traffic. * USEFUL_SERVER_TOP_TIMEOUT .. * dnsseclame servers get penalty + * also for parent-side lame servers (lame in delegpt). * USEFUL_SERVER_TOP_TIMEOUT*2 .. * recursion lame servers get penalty * UNKNOWN_SERVER_NICENESS @@ -202,6 +203,8 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env, lost >= USEFUL_SERVER_MAX_LOST) /* server is unresponsive */ return USEFUL_SERVER_TOP_TIMEOUT; + else if(a->lame) + return rtt+USEFUL_SERVER_TOP_TIMEOUT+1; /* nonpref */ else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT) /* not blacklisted*/ return USEFUL_SERVER_TOP_TIMEOUT+1; else if(reclame) @@ -211,6 +214,8 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env, else return rtt; } /* no server information present */ + if(a->lame) + return USEFUL_SERVER_TOP_TIMEOUT+1; /* nonpref */ return UNKNOWN_SERVER_NICENESS; } @@ -678,3 +683,54 @@ reply_equal(struct reply_info* p, struct reply_info* q) } return 1; } + +void +iter_store_inzone_glue(struct module_env* env, struct query_info* qinfo, + struct reply_info* rep) +{ + struct rrset_ref ref; + struct ub_packed_rrset_key* rrset; + if(qinfo->qtype != LDNS_RR_TYPE_A && qinfo->qtype != LDNS_RR_TYPE_AAAA) + return; + rrset = reply_find_rrset(rep, qinfo->qname, qinfo->qname_len, + qinfo->qtype, qinfo->qclass); + if(!rrset) + return; + /* got A or AAAA glue rrset. store it in case its handy */ + rrset = packed_rrset_copy_alloc(rrset, env->alloc, *env->now); + if(!rrset) { + log_err("malloc failure in store_inzone_glue"); + return; + } + rrset->rk.flags |= PACKED_RRSET_PARENT_SIDE; + rrset->entry.hash = rrset_key_hash(&rrset->rk); + ref.key = rrset; + ref.id = rrset->id; + /* ignore ret: it was in the cache, ref updated */ + (void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, *env->now); +} + +int +iter_lookup_inzone_glue(struct module_env* env, struct delegpt* dp, + struct regional* region, struct query_info* qinfo) +{ + struct ub_packed_rrset_key* akey; + akey = rrset_cache_lookup(env->rrset_cache, qinfo->qname, + qinfo->qname_len, qinfo->qtype, qinfo->qclass, + PACKED_RRSET_PARENT_SIDE, *env->now, 0); + if(akey) { + if(qinfo->qtype == LDNS_RR_TYPE_A) { + if(!delegpt_add_rrset_A(dp, region, akey, 1, 1)) { + lock_rw_unlock(&akey->entry.lock); + return 0; + } + } else if(qinfo->qtype == LDNS_RR_TYPE_AAAA) { + if(!delegpt_add_rrset_AAAA(dp, region, akey, 1, 1)) { + lock_rw_unlock(&akey->entry.lock); + return 0; + } + } + lock_rw_unlock(&akey->entry.lock); + } + return 1; +} diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 0cb106fae..4cc323380 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -210,4 +210,26 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp, */ int reply_equal(struct reply_info* p, struct reply_info* q); +/** + * Store in-zone glue in seperate rrset cache entries for later last-resort + * lookups in case the child-side versions of this information fails. + * @param env: environment with cache, time, ... + * @param qinfo: query info. must match the information stored to avoid + * Kaminsky-style trouble. + * @param rep: reply with possibly A or AAAA content to store. + */ +void iter_store_inzone_glue(struct module_env* env, struct query_info* qinfo, + struct reply_info* rep); + +/** + * Find in-zone glue from rrset cache again. + * @param env: query env with rrset cache and time. + * @param dp: delegation point to store result in. + * @param region: region to alloc result in. + * @param qinfo: query into that is pertinent. + * @return false on malloc failure. + */ +int iter_lookup_inzone_glue(struct module_env* env, struct delegpt* dp, + struct regional* region, struct query_info* qinfo); + #endif /* ITERATOR_ITER_UTILS_H */ diff --git a/iterator/iterator.c b/iterator/iterator.c index 65b649335..a2491ae29 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1585,6 +1585,12 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, val_neg_addreferral(qstate->env->neg_cache, iq->response->rep, iq->dp->name); } + /* store parent-side-in-zone-glue, if directly queried for */ + if((qstate->qinfo.qtype == LDNS_RR_TYPE_A + || qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA)) { + iter_store_inzone_glue(qstate->env, + &iq->response->qinfo, iq->response->rep); + } /* Reset the event state, setting the current delegation * point to the referral. */ @@ -1866,6 +1872,11 @@ processTargetResponse(struct module_qstate* qstate, int id, * (regardless if it succeeded or not). */ foriq->num_target_queries--; + /* perhaps we picked up interested cached addressed, like lame ones */ + if(!iter_lookup_inzone_glue(forq->env, foriq->dp, forq->region, + &iq->qchase)) + log_err("out of memory adding lame glue"); + /* This response is relevant to the current query, so we * add (attempt to add, anyway) this target(s) and reactivate * the original event. diff --git a/services/cache/dns.c b/services/cache/dns.c index a152fa726..c0c83ec7f 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -180,7 +180,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); if(akey) { - if(!delegpt_add_rrset_A(dp, region, akey, 0)) { + if(!delegpt_add_rrset_A(dp, region, akey, 0, 0)) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -198,7 +198,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0); if(akey) { - if(!delegpt_add_rrset_AAAA(dp, region, akey, 0)) { + if(!delegpt_add_rrset_AAAA(dp, region, akey, 0, 0)) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -213,6 +213,27 @@ find_add_addrs(struct module_env* env, uint16_t qclass, lock_rw_unlock(&neg->entry.lock); } } + /* see if we have parent-side-glue (dispreferred) */ + akey = rrset_cache_lookup(env->rrset_cache, ns->name, + ns->namelen, LDNS_RR_TYPE_A, qclass, + PACKED_RRSET_PARENT_SIDE, now, 0); + if(akey) { + if(!delegpt_add_rrset_A(dp, region, akey, 1, 1)) { + lock_rw_unlock(&akey->entry.lock); + return 0; + } + lock_rw_unlock(&akey->entry.lock); + } + akey = rrset_cache_lookup(env->rrset_cache, ns->name, + ns->namelen, LDNS_RR_TYPE_AAAA, qclass, + PACKED_RRSET_PARENT_SIDE, now, 0); + if(akey) { + if(!delegpt_add_rrset_AAAA(dp, region, akey, 1, 1)) { + lock_rw_unlock(&akey->entry.lock); + return 0; + } + lock_rw_unlock(&akey->entry.lock); + } } return 1; } @@ -232,7 +253,7 @@ cache_fill_missing(struct module_env* env, uint16_t qclass, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); if(akey) { - if(!delegpt_add_rrset_A(dp, region, akey, 1)) { + if(!delegpt_add_rrset_A(dp, region, akey, 0, 1)) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -250,7 +271,7 @@ cache_fill_missing(struct module_env* env, uint16_t qclass, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0); if(akey) { - if(!delegpt_add_rrset_AAAA(dp, region, akey, 1)) { + if(!delegpt_add_rrset_AAAA(dp, region, akey, 0, 1)) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -265,6 +286,27 @@ cache_fill_missing(struct module_env* env, uint16_t qclass, lock_rw_unlock(&neg->entry.lock); } } + /* see if we have parent-side-glue (dispreferred) */ + akey = rrset_cache_lookup(env->rrset_cache, ns->name, + ns->namelen, LDNS_RR_TYPE_A, qclass, + PACKED_RRSET_PARENT_SIDE, now, 0); + if(akey) { + if(!delegpt_add_rrset_A(dp, region, akey, 1, 1)) { + lock_rw_unlock(&akey->entry.lock); + return 0; + } + lock_rw_unlock(&akey->entry.lock); + } + akey = rrset_cache_lookup(env->rrset_cache, ns->name, + ns->namelen, LDNS_RR_TYPE_AAAA, qclass, + PACKED_RRSET_PARENT_SIDE, now, 0); + if(akey) { + if(!delegpt_add_rrset_AAAA(dp, region, akey, 1, 1)) { + lock_rw_unlock(&akey->entry.lock); + return 0; + } + lock_rw_unlock(&akey->entry.lock); + } } return 1; } diff --git a/testdata/iter_pcdiff.rpl b/testdata/iter_pcdiff.rpl new file mode 100644 index 000000000..18b984c16 --- /dev/null +++ b/testdata/iter_pcdiff.rpl @@ -0,0 +1,213 @@ +; config options +server: + target-fetch-policy: "0 0 0 0 0" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test resolution with recursion and parent child differ. +; and the child gives bad information. + +; 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 subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION AUTHORITY +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 subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +net. IN NS +SECTION AUTHORITY +net. IN NS e.gtld-servers.net. +SECTION ADDITIONAL +e.gtld-servers.net. IN A 192.12.94.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 subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION AUTHORITY +example.com. IN NS ns.example.net. +ENTRY_END +RANGE_END + +; e.gtld-servers.net. +RANGE_BEGIN 0 100 + ADDRESS 192.12.94.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +net. IN NS +SECTION ANSWER +net. IN NS e.gtld-servers.net. +SECTION ADDITIONAL +e.gtld-servers.net. IN A 192.12.94.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.net. IN NS +SECTION AUTHORITY +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net. IN A 1.2.3.44 +ENTRY_END + +RANGE_END + +; ns.example.net. +; The parent-IP version +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.44 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +example.net. IN NS +SECTION ANSWER +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net. IN A 1.2.3.55 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +ns.example.net. IN A +SECTION ANSWER +ns.example.net. IN A 1.2.3.55 +SECTION AUTHORITY +example.net. IN NS ns.example.net. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +ns.example.net. IN AAAA +SECTION AUTHORITY +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net. IN A 1.2.3.55 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +example.com. IN NS ns.example.net. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +SECTION AUTHORITY +example.com. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net IN A 1.2.3.55 +ENTRY_END +RANGE_END + +; ns.example.net +; The child IP version. Does not respond to anything (servfail instead +; of timeouts since this is easier to encode in .rpl file format). +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.55 +ENTRY_BEGIN +MATCH opcode +ADJUST copy_id copy_query +REPLY QR SERVFAIL +SECTION QUESTION +example.net. IN NS +SECTION ANSWER +ENTRY_END + +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 20 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +SECTION AUTHORITY +example.com. IN NS ns.example.net. +; scrubbed off +;SECTION ADDITIONAL +;ns.example.net IN A 1.2.3.44 +ENTRY_END + +SCENARIO_END diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 0db11ac90..c1fc407fb 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -751,6 +751,22 @@ struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep, return NULL; } +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; irrset_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; +} + void log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) { diff --git a/util/data/msgreply.h b/util/data/msgreply.h index c14e9227c..855554be8 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -378,6 +378,18 @@ struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep, struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep, uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass); +/** + * Find rrset in reply, inside any section. Does not follow CNAMEs. + * @param rep: looks in answer,authority and additional section of this message. + * @param name: what to look for. + * @param namelen: length of name. + * @param type: looks for (host order). + * @param dclass: looks for (host order). + * @return: pointer to rrset, or NULL if not found. + */ +struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, + uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass); + /** * Debug send the query info and reply info to the log in readable form. * @param str: descriptive string printed with packet content. diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c index eedf75746..c1791eda7 100644 --- a/util/data/packed_rrset.c +++ b/util/data/packed_rrset.c @@ -304,6 +304,33 @@ packed_rrset_copy_region(struct ub_packed_rrset_key* key, return ck; } +struct ub_packed_rrset_key* +packed_rrset_copy_alloc(struct ub_packed_rrset_key* key, + struct alloc_cache* alloc, uint32_t now) +{ + struct packed_rrset_data* fd, *dd; + struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc); + if(!dk) return NULL; + fd = (struct packed_rrset_data*)key->entry.data; + dk->entry.hash = key->entry.hash; + dk->rk = key->rk; + dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len); + if(!dk->rk.dname) { + alloc_special_release(alloc, dk); + return NULL; + } + dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd)); + if(!dd) { + free(dk->rk.dname); + alloc_special_release(alloc, dk); + return NULL; + } + packed_rrset_ptr_fixup(dd); + dk->entry.data = (void*)dd; + packed_rrset_ttl_add(dd, now); + return dk; +} + struct ub_packed_rrset_key* ub_packed_rrset_heap_key(ldns_rr_list* rrset) { diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h index a80ce24cf..ad09cae63 100644 --- a/util/data/packed_rrset.h +++ b/util/data/packed_rrset.h @@ -51,6 +51,8 @@ typedef uint64_t rrset_id_t; /** this rrset is NSEC and is at zone apex (at child side of zonecut) */ #define PACKED_RRSET_NSEC_AT_APEX 0x1 +/** this rrset is A/AAAA and is in-zone-glue (from parent side of zonecut) */ +#define PACKED_RRSET_PARENT_SIDE 0x2 /** * The identifying information for an RRset. @@ -69,6 +71,7 @@ struct packed_rrset_key { /** * Flags. 32bit to be easy for hashing: * o PACKED_RRSET_NSEC_AT_APEX + * o PACKED_RRSET_PARENT_SIDE */ uint32_t flags; /** the rrset type in network format */ @@ -376,6 +379,17 @@ struct ub_packed_rrset_key* packed_rrset_copy_region( struct ub_packed_rrset_key* key, struct regional* region, uint32_t now); +/** + * Allocate rrset with malloc (from region or you are holding the lock). + * @param key: key with data entry. + * @param alloc: alloc_cache to create rrset_keys + * @param now: adjust the TTLs to be abolsute (add to all TTLs). + * @return new region-alloced rrset key or NULL on alloc failure. + */ +struct ub_packed_rrset_key* packed_rrset_copy_alloc( + struct ub_packed_rrset_key* key, struct alloc_cache* alloc, + uint32_t now); + /** * Create a ub_packed_rrset_key allocated on the heap. * It therefore does not have the correct ID value, and cannot be used