From: George Thessalonikefs Date: Wed, 13 Oct 2021 09:59:36 +0000 (+0200) Subject: - Introduce 'ede=' and 'all_noedns' as options in the MATCH line for X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9bff0b94dd79e2caa99c8b07c390842b6eafd582;p=thirdparty%2Funbound.git - Introduce 'ede=' and 'all_noedns' as options in the MATCH line for replay test packets. --- diff --git a/testcode/testpkts.c b/testcode/testpkts.c index dee451761..4a5cf69ca 100644 --- a/testcode/testpkts.c +++ b/testcode/testpkts.c @@ -128,6 +128,8 @@ static void matchline(char* line, struct entry* e) e->match_answer = 1; } else if(str_keyword(&parse, "subdomain")) { e->match_subdomain = 1; + } else if(str_keyword(&parse, "all_noedns")) { + e->match_all_noedns = 1; } else if(str_keyword(&parse, "all")) { e->match_all = 1; } else if(str_keyword(&parse, "ttl")) { @@ -148,7 +150,15 @@ static void matchline(char* line, struct entry* e) error("expected = or : in MATCH: %s", line); parse++; e->ixfr_soa_serial = (uint32_t)strtol(parse, (char**)&parse, 10); - while(isspace((unsigned char)*parse)) + while(isspace((unsigned char)*parse)) + parse++; + } else if(str_keyword(&parse, "ede")) { + e->match_ede = 1; + if(*parse != '=' && *parse != ':') + error("expected = or : in MATCH: %s", line); + parse++; + e->ede_info_code = (uint16_t)strtol(parse, (char**)&parse, 10); + while(isspace((unsigned char)*parse)) parse++; } else { error("could not parse MATCH: '%s'", parse); @@ -266,11 +276,14 @@ static struct entry* new_entry(void) e->match_answer = 0; e->match_subdomain = 0; e->match_all = 0; + e->match_all_noedns = 0; e->match_ttl = 0; e->match_do = 0; e->match_noedns = 0; e->match_serial = 0; e->ixfr_soa_serial = 0; + e->match_ede = 0; + e->ede_info_code = 0; e->match_transport = transport_any; e->reply_list = NULL; e->copy_id = 0; @@ -817,7 +830,7 @@ static uint32_t get_serial(uint8_t* p, size_t plen) return 0; } -/** get ptr to EDNS OPT record (and remaining length); behind the type u16 */ +/** get ptr to EDNS OPT record (and remaining length); after the type u16 */ static int pkt_find_edns_opt(uint8_t** p, size_t* plen) { @@ -884,6 +897,30 @@ get_do_flag(uint8_t* pkt, size_t len) return (int)(edns_bits&LDNS_EDNS_MASK_DO_BIT); } +/** return the EDNS EDE INFO-CODE if found, else 0 */ +static uint16_t +get_ede_info_code(uint8_t* pkt, size_t len) +{ + uint8_t *rdata; + uint16_t rdlen, optlen; + /* use arguments as temporary variables */ + if(!pkt_find_edns_opt(&pkt, &len)) return 0; + if(len < 8) return 0; /* malformed */ + rdlen = sldns_read_uint16(pkt+6); + rdata = pkt + 8; + while(rdlen > 0) { + if(rdlen < 4) return 0; /* malformed */ + if(sldns_read_uint16(rdata) == LDNS_EDNS_EDE) { + if(rdlen < 6) return 0; /* malformed */ + return sldns_read_uint16(rdata+4); + } + optlen = sldns_read_uint16(rdata+2); + rdlen -= optlen; + rdata += 4 + optlen; + } + return 0; +} + /** zero TTLs in packet */ static void zerottls(uint8_t* pkt, size_t pktlen) @@ -1201,7 +1238,7 @@ match_question(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl) return 0; } - /* remove after answer section, (;; AUTH, ;; ADD, ;; MSG size ..) */ + /* remove after answer section, (;; ANS, ;; AUTH, ;; ADD ..) */ s = strstr(qcmpstr, ";; ANSWER SECTION"); if(!s) s = strstr(qcmpstr, ";; AUTHORITY SECTION"); if(!s) s = strstr(qcmpstr, ";; ADDITIONAL SECTION"); @@ -1292,10 +1329,28 @@ match_answer(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl) return r; } +/** ignore EDNS lines in the string by overwriting them with what's left or + * zero out if at end of the string */ +static int +ignore_edns_lines(char* str) { + char* current = str, *edns = str, *n; + size_t str_len = strlen(str); + while((edns = strstr(edns, "; EDNS"))) { + n = strchr(edns, '\n'); + if(!n) { + /* EDNS at end of string; zero */ + *edns = 0; + break; + } + memmove(edns, n+1, str_len-(n-str)); + } + return 1; +} + /** match all of the packet */ int match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl, - int noloc) + int noloc, int noedns) { char* qstr, *pstr; uint8_t* qb = q, *pb = p; @@ -1313,6 +1368,11 @@ match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl, qstr = sldns_wire2str_pkt(qb, qlen); pstr = sldns_wire2str_pkt(pb, plen); if(!qstr || !pstr) error("cannot pkt2string"); + /* should we ignore EDNS lines? */ + if(noedns) { + ignore_edns_lines(qstr); + ignore_edns_lines(pstr); + } r = (strcmp(qstr, pstr) == 0); if(!r) { /* remove ;; MSG SIZE (at end of string) */ @@ -1321,8 +1381,8 @@ match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl, s = strstr(pstr, ";; MSG SIZE"); if(s) *s=0; r = (strcmp(qstr, pstr) == 0); - if(!r && !noloc) { - /* we are going to fail see if it is because of EDNS */ + if(!r && !noloc && !noedns) { + /* we are going to fail, see if the cause is EDNS */ char* a = strstr(qstr, "; EDNS"); char* b = strstr(pstr, "; EDNS"); if( (a&&!b) || (b&&!a) ) { @@ -1434,7 +1494,7 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len, verbose(3, "comparepkt: "); reply = p->reply_list->reply_pkt; rlen = p->reply_list->reply_len; - if(p->match_opcode && get_opcode(query_pkt, len) != + if(p->match_opcode && get_opcode(query_pkt, len) != get_opcode(reply, rlen)) { verbose(3, "bad opcode\n"); continue; @@ -1485,6 +1545,10 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len, verbose(3, "bad serial\n"); continue; } + if(p->match_ede && get_ede_info_code(query_pkt, len) != p->ede_info_code) { + verbose(3, "bad EDE INFO-CODE\n"); + continue; + } if(p->match_do && !get_do_flag(query_pkt, len)) { verbose(3, "no DO bit set\n"); continue; @@ -1502,8 +1566,13 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len, verbose(3, "bad transport\n"); continue; } + if(p->match_all_noedns && !match_all(query_pkt, len, reply, + rlen, (int)p->match_ttl, 0, 1)) { + verbose(3, "bad all_noedns match\n"); + continue; + } if(p->match_all && !match_all(query_pkt, len, reply, rlen, - (int)p->match_ttl, 0)) { + (int)p->match_ttl, 0, 0)) { verbose(3, "bad allmatch\n"); continue; } diff --git a/testcode/testpkts.h b/testcode/testpkts.h index 6e032fa90..d9dd043df 100644 --- a/testcode/testpkts.h +++ b/testcode/testpkts.h @@ -40,20 +40,25 @@ struct sldns_file_parse_state; ENTRY_BEGIN ; first give MATCH lines, that say what queries are matched ; by this entry. - ; 'opcode' makes the query match the opcode from the reply - ; if you leave it out, any opcode matches this entry. - ; 'qtype' makes the query match the qtype from the reply - ; 'qname' makes the query match the qname from the reply - ; 'subdomain' makes the query match subdomains of qname from the reply - ; 'serial=1023' makes the query match if ixfr serial is 1023. + ; 'opcode' makes the query match the opcode from the reply; + ; if you leave it out, any opcode matches this entry. + ; 'qtype' makes the query match the qtype from the reply. + ; 'qname' makes the query match the qname from the reply. + ; 'subdomain' makes the query match subdomains of qname from the reply. + ; 'serial=1023' makes the query match if ixfr serial is 1023. ; 'all' has to match header byte for byte and all rrs in packet. + ; 'all_noedns' has to match header byte for byte and all rrs in packet; + ; ignoring EDNS. ; '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. - ; 'rcode' makes the query match the rcode from the reply - ; 'question' makes the query match the question section - ; 'answer' makes the query match the answer section + ; 'rcode' makes the query match the rcode from the reply. + ; 'question' makes the query match the question section. + ; 'answer' makes the query match the answer section. ; 'ednsdata' matches queries to HEX_EDNS section. + ; 'UDP' matches if the transport is UDP. + ; 'TCP' matches if the transport is TCP. + ; 'ede=2' makes the query match if the EDNS EDE info-code is 2. MATCH [opcode] [qtype] [qname] [serial=] [all] [ttl] MATCH [UDP|TCP] DO MATCH ... @@ -72,6 +77,12 @@ struct sldns_file_parse_state; ; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open) ADJUST [sleep=] ; sleep before giving any reply ADJUST [packet_sleep=] ; sleep before this packet in sequence + ; 'copy_ednsdata_assume_clientsubnet' copies ednsdata to reply, assumes + ; it is clientsubnet and adjusts scopemask to match sourcemask. + ADJUST copy_ednsdata_assume_clientsubnet + ; 'increment_ecs_scope' increments the ECS scope copied from the + ; sourcemask by one. + ADJUST increment_ecs_scope SECTION QUESTION ; the RRcount is determined automatically. SECTION ANSWER @@ -167,11 +178,11 @@ struct entry { /* match */ /* How to match an incoming query with this canned reply */ /** match query opcode with answer opcode */ - uint8_t match_opcode; + uint8_t match_opcode; /** match qtype with answer qtype */ - uint8_t match_qtype; + uint8_t match_qtype; /** match qname with answer qname */ - uint8_t match_qname; + uint8_t match_qname; /** match rcode with answer rcode */ uint8_t match_rcode; /** match question section */ @@ -179,11 +190,15 @@ struct entry { /** match answer section */ uint8_t match_answer; /** match qname as subdomain of answer qname */ - uint8_t match_subdomain; + uint8_t match_subdomain; /** match SOA serial number, from auth section */ - uint8_t match_serial; + uint8_t match_serial; + /** match EDNS EDE info-code */ + uint8_t match_ede; /** match all of the packet */ uint8_t match_all; + /** match all of the packet; ignore EDNS */ + uint8_t match_all_noedns; /** match ttls in the packet */ uint8_t match_ttl; /** match DO bit */ @@ -193,9 +208,11 @@ struct entry { /** match edns data field given in hex */ uint8_t match_ednsdata_raw; /** match query serial with this value. */ - uint32_t ixfr_soa_serial; + uint32_t ixfr_soa_serial; /** match on UDP/TCP */ - enum transport_type match_transport; + enum transport_type match_transport; + /** match EDNS EDE info-code with this value. */ + uint16_t ede_info_code; /** pre canned reply */ struct reply_packet *reply_list; @@ -260,10 +277,11 @@ struct entry* find_match(struct entry* entries, uint8_t* query_pkt, * @param mttl: if true, ttls must match, if false, ttls do not need to match * @param noloc: if true, rrs may be reordered in their packet-section. * rrs are then matches without location of the rr being important. + * @param noedns: if true, edns is not compared, if false, edns must match. * @return true if matched. */ int match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl, - int noloc); + int noloc, int noedns); /** * copy & adjust packet, mallocs a copy. diff --git a/testcode/unitmsgparse.c b/testcode/unitmsgparse.c index 6f1edc6e9..a87314019 100644 --- a/testcode/unitmsgparse.c +++ b/testcode/unitmsgparse.c @@ -137,7 +137,7 @@ test_buffers(sldns_buffer* pkt, sldns_buffer* out) /* compare packets */ unit_assert(match_all(sldns_buffer_begin(pkt), sldns_buffer_limit(pkt), sldns_buffer_begin(out), sldns_buffer_limit(out), 1, - matches_nolocation)); + matches_nolocation, 0)); return 0; } diff --git a/testdata/autotrust_init_fail.rpl b/testdata/autotrust_init_fail.rpl index b7507e8eb..8c2ac6827 100644 --- a/testdata/autotrust_init_fail.rpl +++ b/testdata/autotrust_init_fail.rpl @@ -150,15 +150,11 @@ ENTRY_END STEP 20 CHECK_ANSWER ENTRY_BEGIN -MATCH all +MATCH all_noedns ede=6 REPLY QR RD RA DO SERVFAIL SECTION QUESTION www.example.com. IN A SECTION ANSWER -SECTION ADDITIONAL -HEX_EDNSDATA_BEGIN -000F 0079 000676616C69646174696F6E206661696C757265203C7777772E6578616D706C652E636F6D2E204120494E3E3A206E6F20444E534B455920727273657420666F7220747275737420616E63686F72206578616D706C652E636F6D2E207768696C65206275696C64696E6720636861696E206F66207472757374 -HEX_EDNSDATA_END ENTRY_END ; The autotrust anchor was probed due to the query.