From: Yuri Schaeffer Date: Thu, 13 Sep 2012 12:59:13 +0000 (+0000) Subject: Add testbound test. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f270bab77112ffa1fb27db8fd825c769eb976a9;p=thirdparty%2Funbound.git Add testbound test. git-svn-id: file:///svn/unbound/branches/edns-subnet@2758 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 3848cf034..5d8c40bcf 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -725,6 +725,8 @@ struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, if(!e->qsent) { return NULL; } + if(e->qstate->mesh_info->reply_list) + e->qsent->client = &e->qstate->mesh_info->reply_list->query_reply; return e; } diff --git a/testcode/fake_event.c b/testcode/fake_event.c index c736fba4b..baa9bb662 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -56,10 +56,12 @@ #include "services/listen_dnsport.h" #include "services/outside_network.h" #include "services/cache/infra.h" +#include "services/outbound_list.h" #include "testcode/replay.h" #include "testcode/ldns-testpkts.h" #include "util/log.h" #include "util/fptr_wlist.h" +#include "edns-subnet/edns-subnet.h" #include struct worker; struct daemon_remote; @@ -909,6 +911,7 @@ outside_network_create(struct comm_base* base, size_t bufsize, return NULL; runtime->infra = infra; outnet->base = base; + outnet->edns_subnet_upstreams = edns_subnet_upstreams; outnet->udp_buff = ldns_buffer_new(bufsize); if(!outnet->udp_buff) return NULL; @@ -1044,6 +1047,10 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet, size_t zonelen, comm_point_callback_t* callback, void* callback_arg, ldns_buffer* ATTR_UNUSED(buff)) { + struct sockaddr_in target_addr; + struct mesh_reply* reply_list; + struct sockaddr_storage *ss; + void* sinaddr; struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; struct fake_pending* pend = (struct fake_pending*)calloc(1, sizeof(struct fake_pending)); @@ -1078,7 +1085,45 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet, edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits = 0; - edns.subnet_option_add = 0; + /* begin EDNS subnet option + * Is this a client initiated query? Make clients available + * to serviced query. */ + reply_list = ((struct outbound_entry*)callback_arg) + ->qstate->mesh_info->reply_list; + if(reply_list) + pend->client = &reply_list->query_reply; + + /* The testcode does not do networking and thus has no target. + * But the subnet code depends on it. Lets pretend 5.0.15.10 is + * our target. */ + inet_pton(AF_INET, "5.0.15.10", &(target_addr.sin_addr)); + memcpy(&pend->addr, (struct sockaddr_storage*)&target_addr, + sizeof(struct sockaddr_storage)); + pend->addrlen = 16; + edns.subnet_option_add = pend->client && upstream_lookup( + outnet->edns_subnet_upstreams, &pend->addr, pend->addrlen); + if(edns.subnet_option_add) { + ss = &pend->client->addr; + if(((struct sockaddr_in*)ss)->sin_family == AF_INET) { + edns.subnet_addr_fam = IANA_ADDRFAM_IP4; + sinaddr = &((struct sockaddr_in*)ss)->sin_addr; + memcpy(edns.subnet_addr, (uint8_t *)sinaddr, INET_SIZE); + /* YBS TODO: source mask must come from original query if + * any. Some default otherwise. But not more than + * configured maximum */ + edns.subnet_source_mask = MAX_CLIENT_SUBNET_IP4; + } +#ifdef INET6 + else { + edns.subnet_addr_fam = IANA_ADDRFAM_IP6; + sinaddr = &((struct sockaddr_in6*)ss)->sin6_addr; + memcpy(edns.subnet_addr, (uint8_t *)sinaddr, INET6_SIZE); + edns.subnet_source_mask = MAX_CLIENT_SUBNET_IP6; + } +#endif + edns.subnet_scope_mask = 0; + } + /* end EDNS subnet option */ if(dnssec) edns.bits = EDNS_DO; attach_edns_record(pend->buffer, &edns); diff --git a/testcode/ldns-testpkts.c b/testcode/ldns-testpkts.c index d8139511a..e09fe4f23 100644 --- a/testcode/ldns-testpkts.c +++ b/testcode/ldns-testpkts.c @@ -118,6 +118,8 @@ static void matchline(char* line, struct entry* e) e->match_do = true; } else if(str_keyword(&parse, "noedns")) { e->match_noedns = true; + } else if(str_keyword(&parse, "ednsdata")) { + e->match_ednsdata_raw = true; } else if(str_keyword(&parse, "UDP")) { e->match_transport = transport_udp; } else if(str_keyword(&parse, "TCP")) { @@ -423,7 +425,9 @@ read_entry(FILE* in, const char* name, int *lineno, uint32_t* default_ttl, ldns_pkt_section add_section = LDNS_SECTION_QUESTION; struct reply_packet *cur_reply = NULL; bool reading_hex = false; + bool reading_hex_ednsdata = false; ldns_buffer* hex_data_buffer = NULL; + ldns_buffer* hex_ednsdata_buffer = NULL; while(fgets(line, (int)sizeof(line), in) != NULL) { line[MAX_LINE-1] = 0; @@ -485,10 +489,23 @@ read_entry(FILE* in, const char* name, int *lineno, uint32_t* default_ttl, reading_hex = false; cur_reply->reply_from_hex = data_buffer2wire(hex_data_buffer); ldns_buffer_free(hex_data_buffer); - } else if(str_keyword(&parse, "ENTRY_END")) { - return current; } else if(reading_hex) { ldns_buffer_printf(hex_data_buffer, line); + } else if(str_keyword(&parse, "HEX_EDNSDATA_BEGIN")) { + hex_ednsdata_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); + reading_hex_ednsdata = true; + } else if(str_keyword(&parse, "HEX_EDNSDATA_END")) { + if (!reading_hex_ednsdata) { + error("%s line %d: HEX_EDNSDATA_END read but no" + "HEX_EDNSDATA_BEGIN keyword seen", name, *lineno); + } + reading_hex_ednsdata = false; + cur_reply->raw_ednsdata = data_buffer2wire(hex_ednsdata_buffer); + ldns_buffer_free(hex_ednsdata_buffer); + } else if(reading_hex_ednsdata) { + ldns_buffer_printf(hex_ednsdata_buffer, line); + } else if(str_keyword(&parse, "ENTRY_END")) { + return current; } else { /* it must be a RR, parse and add to packet. */ ldns_rr* n = NULL; @@ -657,6 +674,28 @@ match_all(ldns_pkt* q, ldns_pkt* p, bool mttl) return 1; } +/** Match q edns data to p raw edns data */ +static int +match_ednsdata(ldns_pkt* q, struct reply_packet* p) +{ + size_t qdlen; + ldns_rdf *edns_data; + if(!ldns_pkt_edns(q) || !ldns_pkt_edns_data(q)) { + verbose(3, "No EDNS data\n"); + return 0; + } + edns_data = ldns_pkt_edns_data(q); + qdlen = ldns_rdf_size(edns_data); + if( qdlen != ldns_buffer_limit(p->raw_ednsdata) || + 0 != memcmp(ldns_rdf_data(edns_data), + ldns_buffer_begin(p->raw_ednsdata), + qdlen) ) { + verbose(3, "EDNS data does not match.\n"); + return 0; + } + return 1; +} + /* finds entry in list, or returns NULL */ struct entry* find_match(struct entry* entries, ldns_pkt* query_pkt, @@ -707,6 +746,11 @@ find_match(struct entry* entries, ldns_pkt* query_pkt, verbose(3, "bad; EDNS OPT present\n"); continue; } + if(p->match_ednsdata_raw && + !match_ednsdata(query_pkt, p->reply_list)) { + verbose(3, "bad EDNS data match.\n"); + continue; + } if(p->match_transport != transport_any && p->match_transport != transport) { verbose(3, "bad transport\n"); continue; diff --git a/testcode/ldns-testpkts.h b/testcode/ldns-testpkts.h index 59e428952..b4d1c4b8e 100644 --- a/testcode/ldns-testpkts.h +++ b/testcode/ldns-testpkts.h @@ -48,6 +48,7 @@ ; 'ttl' used with all, rrs in packet must also have matching TTLs. ; 'DO' will match only queries with DO bit set. ; 'noedns' matches queries without EDNS OPT records. + ; 'ednsdata' matches queries to HEX_EDNS section. MATCH [opcode] [qtype] [qname] [serial=] [all] [ttl] MATCH [UDP|TCP] DO MATCH ... @@ -82,6 +83,11 @@ ; be parsed, ADJUST rules for the answer packet ; are ignored. Only copy_id is done. HEX_ANSWER_END + HEX_EDNS_BEGIN ; follow with hex data. + ; Raw EDNS data to match against. It must be an + ; exact match (all options are matched) and will be + ; evaluated only when 'MATCH ednsdata' given. + HEX_EDNS_END ENTRY_END @@ -142,6 +148,8 @@ struct reply_packet { struct reply_packet* next; /** the reply pkt */ ldns_pkt* reply; + /** Additional EDNS data for matching queries. */ + ldns_buffer* raw_ednsdata; /** or reply pkt in hex if not parsable */ ldns_buffer* reply_from_hex; /** seconds to sleep before giving packet */ @@ -171,6 +179,8 @@ struct entry { bool match_do; /** match absence of EDNS OPT record in query */ bool match_noedns; + /** match edns data field given in hex */ + bool match_ednsdata_raw; /** match query serial with this value. */ uint32_t ixfr_soa_serial; /** match on UDP/TCP */ diff --git a/testcode/replay.h b/testcode/replay.h index 049db4e80..1662bfbf2 100644 --- a/testcode/replay.h +++ b/testcode/replay.h @@ -346,6 +346,8 @@ struct fake_pending { int serviced; /** the runtime structure this is part of */ struct replay_runtime* runtime; + /** Clients initiating lookup. Not owned by serviced_query */ + struct comm_reply *client; }; /** diff --git a/testdata/edns_subnet_format.tpkg b/testdata/edns_subnet_format.tpkg deleted file mode 100644 index 8c56b82f3..000000000 Binary files a/testdata/edns_subnet_format.tpkg and /dev/null differ diff --git a/testdata/subnet_format_ip4.rpl b/testdata/subnet_format_ip4.rpl new file mode 100644 index 000000000..9e0e81639 --- /dev/null +++ b/testdata/subnet_format_ip4.rpl @@ -0,0 +1,161 @@ +server: + send-client-subnet: 5.0.15.10 + client-subnet-opc: 20730 + max-client-subnet-ipv4: 21 + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test formatting of edns subnet option + +; 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 qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +a.gtld-servers.net. IN AAAA +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.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 qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +a.gtld-servers.net. IN AAAA +SECTION ANSWER +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.com. IN A +SECTION AUTHORITY +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 5.0.15.10 +ENTRY_END +RANGE_END + +; ns.example.com. +RANGE_BEGIN 0 100 + ADDRESS 5.0.15.10 +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 5.0.15.10 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.com. IN AAAA +SECTION ANSWER +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 4.3.2.1 +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; query sent to .com server +STEP 5 CHECK_OUT_QUERY +ENTRY_BEGIN +MATCH qname qtype opcode ednsdata +SECTION QUESTION +www.example.com. IN A +SECTION ADDITIONAL +HEX_EDNSDATA_BEGIN + ; client is 127.0.0.1 + 50 fa ; OPC + 00 07 ; option length + 00 01 ; Family + 15 00 ; source mask, scopemask + 7f 00 00 ; address +HEX_EDNSDATA_END +ENTRY_END + +STEP 10 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 4.3.2.1 +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END + +SCENARIO_END diff --git a/util/data/msgencode.c b/util/data/msgencode.c index 94c2c397b..97fe83f75 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -863,6 +863,7 @@ error_encode(ldns_buffer* buf, int r, struct query_info* qinfo, es.udp_size = EDNS_ADVERTISED_SIZE; es.ext_rcode = 0; es.bits &= EDNS_DO; + es.subnet_option_add = 0; if(ldns_buffer_limit(buf) + calc_edns_field_size(&es) > edns->udp_size) return;