]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Add testbound test.
authorYuri Schaeffer <yuri@nlnetlabs.nl>
Thu, 13 Sep 2012 12:59:13 +0000 (12:59 +0000)
committerYuri Schaeffer <yuri@nlnetlabs.nl>
Thu, 13 Sep 2012 12:59:13 +0000 (12:59 +0000)
git-svn-id: file:///svn/unbound/branches/edns-subnet@2758 be551aaa-1e26-0410-a405-d3ace91eadb9

libunbound/libworker.c
testcode/fake_event.c
testcode/ldns-testpkts.c
testcode/ldns-testpkts.h
testcode/replay.h
testdata/edns_subnet_format.tpkg [deleted file]
testdata/subnet_format_ip4.rpl [new file with mode: 0644]
util/data/msgencode.c

index 3848cf034fa495fd22a30c09f382871402518597..5d8c40bcfa66dab67827fdfcfe70683cf44086f2 100644 (file)
@@ -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;
 }
 
index c736fba4b9e6259c88c3a18a82eac64d77da0632..baa9bb66252c5631b0e93995b756d9091aa6a973 100644 (file)
 #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 <signal.h>
 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);
index d8139511ab5cbcd755e1aa77328afccbd82fbb9b..e09fe4f23d1fbc6c54fa4cc20469a562a7059f6b 100644 (file)
@@ -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;
index 59e428952759328882c1c438e05f6a8acb62f96b..b4d1c4b8e6156d542c434648d063160a4e6b0f4f 100644 (file)
@@ -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=<value>] [all] [ttl]
        MATCH [UDP|TCP] DO
        MATCH ...
                                ; 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 */
index 049db4e800b551cc5d12698f4f6c75b7b41af2a8..1662bfbf29356e1dad4d20d1886df903c79fe681 100644 (file)
@@ -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 (file)
index 8c56b82..0000000
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 (file)
index 0000000..9e0e816
--- /dev/null
@@ -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
index 94c2c397bf2803edee340c01e80e9baa5d1e89c9..97fe83f7561469b8312d0040094b0cf42f035c5f 100644 (file)
@@ -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;