From: Wouter Wijngaards Date: Wed, 30 May 2007 14:19:56 +0000 (+0000) Subject: state init3. X-Git-Tag: release-0.4~116 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b03a464d58876b7babb0dcb192d4e9c675f8405f;p=thirdparty%2Funbound.git state init3. git-svn-id: file:///svn/unbound/trunk@350 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index b251777cf..4e59aab70 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -7,6 +7,8 @@ - iterator prime start. - subquery work. - processInitRequest and processInitRequest2. + - cache synthesizes referral messages, with DS and NSEC. + - processInitRequest3. 29 May 2007: Wouter - routines to lock and unlock array of rrsets moved to cache/rrset. diff --git a/iterator/iterator.c b/iterator/iterator.c index 705ca0fd7..38111ab8c 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -727,7 +727,8 @@ return nextState(event, req, state, IterEventState.INIT_REQUEST_STATE); /* Lookup the delegation in the cache. If null, then the cache needs * to be primed for the qclass. */ iq->dp = dns_cache_find_delegation(qstate->env, delname, delnamelen, - qstate->qinfo.qclass, qstate->region); + qstate->qinfo.qtype, qstate->qinfo.qclass, qstate->region, + &iq->deleg_msg); /* If the cache has returned nothing, then we have a root priming * situation. */ @@ -789,15 +790,38 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq, return next_state(qstate, iq, INIT_REQUEST_3_STATE); } -#if 0 -/** TODO */ +/** + * Process the third part of the initial request handling. This state exists + * as a separate state so that queries that generate stub priming events + * will get the tail end of the init process but not repeat the stub priming + * check. + * + * @param qstate: query state. + * @param iq: iterator query state. + * @return true if the event needs more request processing immediately, + * false if not. + */ static int -processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq, - struct iter_env* ie, int id) +processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq) { - return 0; + log_nametypeclass("resolving (init part 3): ", qstate->qinfo.qname, + qstate->qinfo.qtype, qstate->qinfo.qclass); + /* If the RD flag wasn't set, then we just finish with the + * cached referral as the response. */ + if(!(qstate->query_flags & BIT_RD)) { + iq->response = iq->deleg_msg; + return final_state(qstate, iq); + } + + /* After this point, unset the RD flag -- this query is going to + * be sent to an auth. server. */ + qstate->query_flags &= ~BIT_RD; + + /* Jump to the next state. */ + return next_state(qstate, iq, QUERYTARGETS_STATE); } +#if 0 /** TODO */ static int processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, @@ -866,10 +890,10 @@ iter_handle(struct module_qstate* qstate, struct iter_qstate* iq, case INIT_REQUEST_2_STATE: cont = processInitRequest2(qstate, iq, ie, id); break; -#if 0 case INIT_REQUEST_3_STATE: - cont = processInitRequest3(qstate, iq, ie, id); + cont = processInitRequest3(qstate, iq); break; +#if 0 case QUERYTARGETS_STATE: cont = processQueryTargets(qstate, iq, ie, id); break; diff --git a/iterator/iterator.h b/iterator/iterator.h index fa2ea2f05..f71c4054e 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -191,6 +191,9 @@ struct iter_qstate { */ struct delegpt_addr* current_target; + /** Current delegation message - returned for non-RD queries */ + struct dns_msg* deleg_msg; + /** number of outstanding target sub queries */ int num_target_queries; diff --git a/services/cache/dns.c b/services/cache/dns.c index 526a28131..59c9b9143 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -96,6 +96,41 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc); } +/** allocate rrset in region - no more locks needed */ +static struct ub_packed_rrset_key* +copy_rrset(struct ub_packed_rrset_key* key, struct region* region, + uint32_t now) +{ + struct ub_packed_rrset_key* ck = region_alloc(region, + sizeof(struct ub_packed_rrset_key)); + struct packed_rrset_data* d; + struct packed_rrset_data* data = (struct packed_rrset_data*) + key->entry.data; + size_t dsize, i; + if(!ck) + return NULL; + ck->id = key->id; + memset(&ck->entry, 0, sizeof(ck->entry)); + ck->entry.hash = key->entry.hash; + ck->entry.key = ck; + ck->rk = key->rk; + ck->rk.dname = region_alloc_init(region, key->rk.dname, + key->rk.dname_len); + if(!ck->rk.dname) + return NULL; + dsize = packed_rrset_sizeof(data); + d = (struct packed_rrset_data*)region_alloc_init(region, data, dsize); + if(!d) + return NULL; + ck->entry.data = d; + packed_rrset_ptr_fixup(d); + /* make TTLs relative - once per rrset */ + for(i=0; icount + d->rrsig_count; i++) + d->rr_ttl[i] -= now; + d->ttl -= now; + return ck; +} + /** find closest NS and returns the rrset (locked) */ static struct ub_packed_rrset_key* find_deleg_ns(struct module_env* env, uint8_t* qname, size_t qnamelen, @@ -118,10 +153,22 @@ find_deleg_ns(struct module_env* env, uint8_t* qname, size_t qnamelen, return NULL; } +/** add addr to additional section */ +static void +addr_to_additional(struct ub_packed_rrset_key* rrset, struct region* region, + struct dns_msg* msg, uint32_t now) +{ + if((msg->rep->rrsets[msg->rep->rrset_count] = + copy_rrset(rrset, region, now))) { + msg->rep->ar_numrrsets++; + msg->rep->rrset_count++; + } +} + /** add A records to delegation */ static int add_a(struct ub_packed_rrset_key* ak, struct delegpt* dp, - struct region* region) + struct region* region, struct dns_msg** msg, uint32_t now) { struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; size_t i; @@ -141,13 +188,15 @@ add_a(struct ub_packed_rrset_key* ak, struct delegpt* dp, len)) return 0; } + if(msg) + addr_to_additional(ak, region, *msg, now); return 1; } /** add AAAA records to delegation */ static int add_aaaa(struct ub_packed_rrset_key* ak, struct delegpt* dp, - struct region* region) + struct region* region, struct dns_msg** msg, uint32_t now) { struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; size_t i; @@ -167,13 +216,15 @@ add_aaaa(struct ub_packed_rrset_key* ak, struct delegpt* dp, len)) return 0; } + if(msg) + addr_to_additional(ak, region, *msg, now); return 1; } /** find and add A and AAAA records for nameservers in delegpt */ static int find_add_addrs(struct module_env* env, uint16_t qclass, struct region* region, - struct delegpt* dp, uint32_t now) + struct delegpt* dp, uint32_t now, struct dns_msg** msg) { struct delegpt_ns* ns; struct ub_packed_rrset_key* akey; @@ -181,7 +232,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass, struct region* region, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); if(akey) { - if(!add_a(akey, dp, region)) { + if(!add_a(akey, dp, region, msg, now)) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -190,7 +241,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass, struct region* region, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0); if(akey) { - if(!add_aaaa(akey, dp, region)) { + if(!add_aaaa(akey, dp, region, msg, now)) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -200,15 +251,104 @@ find_add_addrs(struct module_env* env, uint16_t qclass, struct region* region, return 1; } +/** Add NS records to delegation */ +static void +add_ns(struct packed_rrset_data* nsdata, struct delegpt* dp, + struct region* region) +{ + size_t i; + for(i=0; icount; i++) { + if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ + if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) != + (size_t)ldns_read_uint16(nsdata->rr_data[i])-2) + continue; /* bad format */ + /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ + if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2)) + log_err("find_delegation: addns out of memory"); + } +} + +/** find and add DS or NSEC to delegation msg */ +static void +find_add_ds(struct module_env* env, struct region* region, + struct dns_msg* msg, struct delegpt* dp, uint32_t now) +{ + /* Lookup the DS or NSEC at the delegation point. */ + struct ub_packed_rrset_key* rrset = rrset_cache_lookup( + env->rrset_cache, dp->name, dp->namelen, LDNS_RR_TYPE_DS, + msg->qinfo.qclass, 0, now, 0); + if(!rrset) { + /* NOTE: this won't work for alternate NSEC schemes + * (opt-in, NSEC3) */ + rrset = rrset_cache_lookup(env->rrset_cache, dp->name, + dp->namelen, LDNS_RR_TYPE_NSEC, msg->qinfo.qclass, + 0, now, 0); + /* Note: the PACKED_RRSET_NSEC_AT_APEX flag is not used. + * since this is a referral, we need the NSEC at the parent + * side of the zone cut, not the NSEC at apex side. */ + } + if(rrset) { + /* add it to auth section. This is the second rrset. */ + if((msg->rep->rrsets[msg->rep->rrset_count] = + copy_rrset(rrset, region, now))) { + msg->rep->ns_numrrsets++; + msg->rep->rrset_count++; + } + lock_rw_unlock(&rrset->entry.lock); + } +} + +/** create referral message with NS and query */ +static struct dns_msg* +create_msg(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, + struct region* region, struct ub_packed_rrset_key* nskey, + struct packed_rrset_data* nsdata, uint32_t now) +{ + struct dns_msg* msg = (struct dns_msg*)region_alloc(region, + sizeof(struct dns_msg)); + if(!msg) + return NULL; + msg->qinfo.qname = region_alloc_init(region, qname, qnamelen); + if(!msg->qinfo.qname) + return NULL; + msg->qinfo.qname_len = qnamelen; + msg->qinfo.qtype = qtype; + msg->qinfo.qclass = qclass; + /* non-packed reply_info, because it needs to grow the array */ + msg->rep = (struct reply_info*)region_alloc(region, + sizeof(struct reply_info)-sizeof(struct rrset_ref)); + if(!msg->rep) + return NULL; + memset(msg->rep, 0, + sizeof(struct reply_info)-sizeof(struct rrset_ref)); + msg->rep->flags = BIT_QR; /* with QR, no AA */ + msg->rep->qdcount = 1; + /* allocate the array to as much as we could need: + * NS rrset + DS/NSEC rrset + + * A rrset for every NS RR + * AAAA rrset for every NS RR + */ + msg->rep->rrsets = (struct ub_packed_rrset_key**)region_alloc(region, + (2 + nsdata->count*2)*sizeof(struct ub_packed_rrset_key*)); + if(!msg->rep->rrsets) + return NULL; + msg->rep->rrsets[0] = copy_rrset(nskey, region, now); + if(!msg->rep->rrsets[0]) + return NULL; + msg->rep->ns_numrrsets++; + msg->rep->rrset_count++; + return msg; +} + struct delegpt* dns_cache_find_delegation(struct module_env* env, uint8_t* qname, - size_t qnamelen, uint16_t qclass, struct region* region) + size_t qnamelen, uint16_t qtype, uint16_t qclass, + struct region* region, struct dns_msg** msg) { /* try to find closest NS rrset */ struct ub_packed_rrset_key* nskey; struct packed_rrset_data* nsdata; struct delegpt* dp; - size_t i; uint32_t now = (uint32_t)time(NULL); nskey = find_deleg_ns(env, qname, qnamelen, qclass, now); @@ -222,60 +362,29 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname, log_err("find_delegation: out of memory"); return NULL; } - /* add NS entries */ - for(i=0; icount; i++) { - if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ - if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) != - (size_t)ldns_read_uint16(nsdata->rr_data[i])-2) - continue; /* bad format */ - /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ - if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2)) - log_err("find_delegation: addns out of memory"); + /* create referral message */ + if(msg) { + *msg = create_msg(qname, qnamelen, qtype, qclass, region, + nskey, nsdata, now); + if(!*msg) { + lock_rw_unlock(&nskey->entry.lock); + log_err("find_delegation: out of memory"); + return NULL; + } } - /* find and add A entries */ + add_ns(nsdata, dp, region); lock_rw_unlock(&nskey->entry.lock); /* first unlock before next lookup*/ - if(!find_add_addrs(env, qclass, region, dp, now)) + /* find and add DS/NSEC (if any) */ + if(msg) + find_add_ds(env, region, *msg, dp, now); + /* find and add A entries */ + if(!find_add_addrs(env, qclass, region, dp, now, msg)) log_err("find_delegation: addrs out of memory"); log_info("dns_cache_find_delegation returns delegpt"); delegpt_log(dp); return dp; } -/** allocate rrset in region - no more locks needed */ -static struct ub_packed_rrset_key* -copy_rrset(struct ub_packed_rrset_key* key, struct region* region, - uint32_t now) -{ - struct ub_packed_rrset_key* ck = region_alloc(region, - sizeof(struct ub_packed_rrset_key)); - struct packed_rrset_data* d; - struct packed_rrset_data* data = (struct packed_rrset_data*) - key->entry.data; - size_t dsize, i; - if(!ck) - return NULL; - ck->id = key->id; - memset(&ck->entry, 0, sizeof(ck->entry)); - ck->entry.hash = key->entry.hash; - ck->entry.key = ck; - ck->rk = key->rk; - ck->rk.dname = region_alloc_init(region, key->rk.dname, - key->rk.dname_len); - if(!ck->rk.dname) - return NULL; - dsize = packed_rrset_sizeof(data); - d = (struct packed_rrset_data*)region_alloc_init(region, data, dsize); - if(!d) - return NULL; - ck->entry.data = d; - packed_rrset_ptr_fixup(d); - /* make TTLs relative - once per rrset */ - for(i=0; icount + d->rrsig_count; i++) - d->rr_ttl[i] -= now; - d->ttl -= now; - return ck; -} - /** allocate dns_msg from query_info and reply_info */ static struct dns_msg* tomsg(struct module_env* env, struct msgreply_entry* e, struct reply_info* r, diff --git a/services/cache/dns.h b/services/cache/dns.h index 584173d7c..396b70f48 100644 --- a/services/cache/dns.h +++ b/services/cache/dns.h @@ -79,13 +79,16 @@ void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, * @param env: module environment with the DNS cache. * @param qname: query name. * @param qnamelen: length of qname. + * @param qtype: query type. * @param qclass: query class. * @param region: where to allocate result delegation. + * @param msg: if not NULL, delegation message is returned here, synthesized + * from the cache. * @return new delegation or NULL on error or if not found in cache. */ struct delegpt* dns_cache_find_delegation(struct module_env* env, - uint8_t* qname, size_t qnamelen, uint16_t qclass, - struct region* region); + uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, + struct region* region, struct dns_msg** msg); /** * Find cached message