diff --git a/services/authzone.c b/services/authzone.c index 853de5f34..f2baafb31 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -462,13 +462,17 @@ auth_zones_find_zone(struct auth_zones* az, uint8_t* name, size_t name_len, * but not below it. */ nm = dname_get_shared_topdomain(z->name, name); dname_count_size_labels(nm, &nmlen); + z = NULL; } + /* search up */ - while(!z && !dname_is_root(nm)) { - dname_remove_label(&nm, &nmlen); + while(!z) { z = auth_zone_find(az, nm, nmlen, dclass); + if(z) return z; + if(dname_is_root(nm)) break; + dname_remove_label(&nm, &nmlen); } - return z; + return NULL; } /** find or create zone with name str. caller must have lock on az. @@ -4043,13 +4047,16 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); else edns.udp_size = 65535; + /* unlock xfr during mesh_new_callback() because the callback can be + * called straight away */ + lock_basic_unlock(&xfr->lock); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, &auth_xfer_transfer_lookup_callback, xfr)) { + lock_basic_lock(&xfr->lock); log_err("out of memory lookup up master %s", master->host); - free(qinfo.qname); return 0; } - free(qinfo.qname); + lock_basic_lock(&xfr->lock); return 1; } @@ -4069,10 +4076,13 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env) memmove(&addr, &xfr->task_transfer->scan_addr->addr, addrlen); } else { if(!extstrtoaddr(master->host, &addr, &addrlen)) { + /* the ones that are not in addr format are supposed + * to be looked up. The lookup has failed however, + * so skip them */ char zname[255+1]; dname_str(xfr->name, zname); - log_err("%s: cannot parse master %s", zname, - master->host); + log_err("%s: failed lookup, cannot transfer from master %s", + zname, master->host); return 0; } } @@ -4184,6 +4194,12 @@ xfr_master_add_addrs(struct auth_master* m, struct ub_packed_rrset_key* rrset, sa->sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); memmove(&sa->sin6_addr, rdata, INET6_SIZE); } + if(verbosity >= VERB_ALGO) { + char s[64]; + addr_to_str(&a->addr, a->addrlen, s, sizeof(s)); + verbose(VERB_ALGO, "auth host %s lookup %s", + m->host, s); + } /* append to list */ a->next = m->list; m->list = a; @@ -4221,6 +4237,9 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, } } } + if(xfr->task_transfer->lookup_target->list && + xfr->task_transfer->lookup_target == xfr_transfer_current_master(xfr)) + xfr->task_transfer->scan_addr = xfr->task_transfer->lookup_target->list; /* move to lookup AAAA after A lookup, move to next hostname lookup, * or move to fetch the zone, or, if nothing to do, end task_transfer */ @@ -4690,10 +4709,13 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env, memmove(&addr, &xfr->task_probe->scan_addr->addr, addrlen); } else { if(!extstrtoaddr(master->host, &addr, &addrlen)) { + /* the ones that are not in addr format are supposed + * to be looked up. The lookup has failed however, + * so skip them */ char zname[255+1]; dname_str(xfr->name, zname); - log_err("%s: cannot parse master %s", zname, - master->host); + log_err("%s: failed lookup, cannot probe to master %s", + zname, master->host); return 0; } } @@ -4894,13 +4916,16 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); else edns.udp_size = 65535; + /* unlock xfr during mesh_new_callback() because the callback can be + * called straight away */ + lock_basic_unlock(&xfr->lock); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, &auth_xfer_probe_lookup_callback, xfr)) { + lock_basic_lock(&xfr->lock); log_err("out of memory lookup up master %s", master->host); - free(qinfo.qname); return 0; } - free(qinfo.qname); + lock_basic_lock(&xfr->lock); return 1; } @@ -4916,6 +4941,7 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) * and we may then get an instant cache response, * and that calls the callback just like a full * lookup and lookup failures also call callback */ + lock_basic_unlock(&xfr->lock); return; } xfr_probe_move_to_next_lookup(xfr, env); @@ -4925,6 +4951,7 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) while(!xfr_probe_end_of_list(xfr)) { if(xfr_probe_send_probe(xfr, env, AUTH_PROBE_TIMEOUT)) { /* successfully sent probe, wait for callback */ + lock_basic_unlock(&xfr->lock); return; } /* failed to send probe, next master */ @@ -4947,6 +4974,7 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, struct auth_xfer* xfr = (struct auth_xfer*)arg; struct module_env* env; log_assert(xfr->task_probe); + lock_basic_lock(&xfr->lock); env = xfr->task_probe->env; /* process result */ @@ -4970,6 +4998,9 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, } } } + if(xfr->task_probe->lookup_target->list && + xfr->task_probe->lookup_target == xfr_probe_current_master(xfr)) + xfr->task_probe->scan_addr = xfr->task_probe->lookup_target->list; /* move to lookup AAAA after A lookup, move to next hostname lookup, * or move to send the probes, or, if nothing to do, end task_probe */ @@ -5017,7 +5048,6 @@ auth_xfer_timer(void* arg) /* pick up the probe task ourselves */ xfr->task_probe->worker = env->worker; xfr->task_probe->env = env; - lock_basic_unlock(&xfr->lock); xfr->task_probe->cp = NULL; /* start the task */ diff --git a/testdata/auth_xfr_host.rpl b/testdata/auth_xfr_host.rpl new file mode 100644 index 000000000..4b3b1879e --- /dev/null +++ b/testdata/auth_xfr_host.rpl @@ -0,0 +1,247 @@ +; config options +server: + target-fetch-policy: "0 0 0 0 0" + +auth-zone: + name: "example.com." + ## zonefile (or none). + ## zonefile: "example.com.zone" + ## master by IP address or hostname + ## can list multiple masters, each on one line. + ## master: + master: ns.example.net. + #master: 1.2.3.44 + ## url for http fetch + ## url: + ## queries from downstream clients get authoritative answers. + ## for-downstream: yes + for-downstream: yes + ## queries are used to fetch authoritative answers from this zone, + ## instead of unbound itself sending queries there. + ## for-upstream: yes + for-upstream: yes + ## on failures with for-upstream, fallback to sending queries to + ## the authority servers + ## fallback-enabled: no + + ## this line generates zonefile: \n"/tmp/xxx.example.com"\n + zonefile: +TEMPFILE_NAME example.com + ## this is the inline file /tmp/xxx.example.com + ## the tempfiles are deleted when the testrun is over. +TEMPFILE_CONTENTS example.com +TEMPFILE_END + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test authority zone that needs host name lookup + +; 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 qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.net. IN A +SECTION ANSWER +ns.example.net. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.net. IN AAAA +SECTION ANSWER +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.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.44 +ENTRY_END +RANGE_END + +; ns.example.com. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.44 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.com. IN A +SECTION ANSWER +ns.example.com. IN A 1.2.3.44 +SECTION AUTHORITY +example.com. IN NS ns.example.com. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.com. IN AAAA +SECTION AUTHORITY +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +www.example.com. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +example.com. IN NS ns.example.com. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN SOA +SECTION ANSWER +; serial, refresh, retry, expire, minimum +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.com. IN AXFR +SECTION ANSWER +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +example.com. IN NS ns.example.com. +www.example.com. IN A 1.2.3.4 +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +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 AA RD RA SERVFAIL +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +ENTRY_END + +STEP 30 TIME_PASSES ELAPSE 10 +STEP 40 TRAFFIC + +STEP 50 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 60 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 1.2.3.4 +ENTRY_END + +; the zonefile was updated with new contents +STEP 70 CHECK_TEMPFILE example.com +FILE_BEGIN +example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +example.com. 3600 IN NS ns.example.com. +www.example.com. 3600 IN A 1.2.3.4 +FILE_END + +SCENARIO_END