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")) {
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);
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;
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)
{
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)
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");
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;
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) */
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) ) {
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;
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;
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;
}
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=<value>] [all] [ttl]
MATCH [UDP|TCP] DO
MATCH ...
; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open)
ADJUST [sleep=<num>] ; sleep before giving any reply
ADJUST [packet_sleep=<num>] ; 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
<RRs, one per line> ; the RRcount is determined automatically.
SECTION ANSWER
/* 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 */
/** 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 */
/** 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;
* @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.