Home | History | Annotate | Line # | Download | only in testcode
      1 /*
      2  * testpkts. Data file parse for test packets, and query matching.
      3  *
      4  * Data storage for specially crafted replies for testing purposes.
      5  *
      6  * (c) NLnet Labs, 2005, 2006, 2007
      7  * See the file LICENSE for the license
      8  */
      9 
     10 #ifndef TESTPKTS_H
     11 #define TESTPKTS_H
     12 struct sldns_buffer;
     13 struct sldns_file_parse_state;
     14 
     15 /**
     16  * \file
     17  *
     18  * This is a debugging aid. It is not efficient, especially
     19  * with a long config file, but it can give any reply to any query.
     20  * This can help the developer pre-script replies for queries.
     21  *
     22  * You can specify a packet RR by RR with header flags to return.
     23  *
     24  * Missing features:
     25  *		- matching content different from reply content.
     26  *		- find way to adjust mangled packets?
     27  *
     28  */
     29 
     30  /*
     31 	The data file format is as follows:
     32 
     33 	; comment.
     34 	; a number of entries, these are processed first to last.
     35 	; a line based format.
     36 
     37 	$ORIGIN origin
     38 	$TTL default_ttl
     39 
     40 	ENTRY_BEGIN
     41 	; first give MATCH lines, that say what queries are matched
     42 	; by this entry.
     43 	; 'opcode' makes the query match the opcode from the reply;
     44 	;	if you leave it out, any opcode matches this entry.
     45 	; 'qtype' makes the query match the qtype from the reply.
     46 	; 'qname' makes the query match the qname from the reply.
     47 	; 'subdomain' makes the query match subdomains of qname from the reply.
     48 	; 'serial=1023' makes the query match if ixfr serial is 1023.
     49 	; 'all' has to match header byte for byte and all rrs in packet.
     50 	; 'all_noedns' has to match header byte for byte and all rrs in packet;
     51 	;	ignoring EDNS.
     52 	; 'ttl' used with all, rrs in packet must also have matching TTLs.
     53 	; 'DO' will match only queries with DO bit set.
     54 	; 'noedns' matches queries without EDNS OPT records.
     55 	; 'rcode' makes the query match the rcode from the reply.
     56 	; 'question' makes the query match the question section.
     57 	; 'answer' makes the query match the answer section.
     58 	; 'ednsdata' matches queries to HEX_EDNS section.
     59 	; 'UDP' matches if the transport is UDP.
     60 	; 'TCP' matches if the transport is TCP.
     61 	; 'ede=2' makes the query match if the EDNS EDE info-code is 2.
     62 	;	It also snips the EDE record out of the packet to facilitate
     63 	;	other matches.
     64 	; 'ede=any' makes the query match any EDNS EDE info-code.
     65 	;	It also snips the EDE record out of the packet to facilitate
     66 	;	other matches.
     67 	; 'client_cookie' makes the query match any DNS Cookie option with
     68 	;	with a length of 8 octets.
     69 	;	It also snips the DNS Cookie record out of the packet to
     70 	;	facilitate other matches.
     71 	; 'server_cookie' makes the query match any DNS Cookie option with
     72 	;	with a length of 24 octets.
     73 	;	It also snips the DNS Cookie record out of the packet to
     74 	;	facilitate other matches.
     75 	MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
     76 	MATCH [UDP|TCP] DO
     77 	MATCH ...
     78 	; Then the REPLY header is specified.
     79 	REPLY opcode, rcode or flags.
     80 		(opcode)  QUERY IQUERY STATUS NOTIFY UPDATE
     81 		(rcode)   NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN
     82 		 		YXRRSET NXRRSET NOTAUTH NOTZONE
     83 		(flags)   QR AA TC RD CD RA AD DO
     84 	REPLY ...
     85 	; any additional actions to do.
     86 	; 'copy_id' copies the ID from the query to the answer.
     87 	ADJUST copy_id
     88 	; 'copy_query' copies the query name, type and class to the answer.
     89 	ADJUST copy_query
     90 	; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open)
     91 	ADJUST [sleep=<num>]    ; sleep before giving any reply
     92 	ADJUST [packet_sleep=<num>]  ; sleep before this packet in sequence
     93 	; 'copy_ednsdata_assume_clientsubnet' copies ednsdata to reply, assumes
     94 	; it is clientsubnet and adjusts scopemask to match sourcemask.
     95 	ADJUST copy_ednsdata_assume_clientsubnet
     96 	; 'increment_ecs_scope' increments the ECS scope copied from the
     97 	;  sourcemask by one.
     98 	ADJUST increment_ecs_scope
     99 	SECTION QUESTION
    100 	<RRs, one per line>    ; the RRcount is determined automatically.
    101 	SECTION ANSWER
    102 	<RRs, one per line>
    103 	SECTION AUTHORITY
    104 	<RRs, one per line>
    105 	SECTION ADDITIONAL
    106 	<RRs, one per line>
    107 	EXTRA_PACKET		; follow with SECTION, REPLY for more packets.
    108 	HEX_ANSWER_BEGIN	; follow with hex data
    109 				; this replaces any answer packet constructed
    110 				; with the SECTION keywords (only SECTION QUERY
    111 				; is used to match queries). If the data cannot
    112 				; be parsed, ADJUST rules for the answer packet
    113 				; are ignored. Only copy_id is done.
    114 	HEX_ANSWER_END
    115 	HEX_EDNSDATA_BEGIN	; follow with hex data.
    116 				; Raw EDNS data to match against. It must be an
    117 				; exact match (all options are matched) and will be
    118 				; evaluated only when 'MATCH ednsdata' given.
    119 	HEX_EDNSDATA_END
    120 	ENTRY_END
    121 
    122 
    123  	Example data file:
    124 $ORIGIN nlnetlabs.nl
    125 $TTL 3600
    126 
    127 ENTRY_BEGIN
    128 MATCH qname
    129 REPLY NOERROR
    130 ADJUST copy_id
    131 SECTION QUESTION
    132 www.nlnetlabs.nl.	IN	A
    133 SECTION ANSWER
    134 www.nlnetlabs.nl.	IN	A	195.169.215.155
    135 SECTION AUTHORITY
    136 nlnetlabs.nl.		IN	NS	www.nlnetlabs.nl.
    137 ENTRY_END
    138 
    139 ENTRY_BEGIN
    140 MATCH qname
    141 REPLY NOERROR
    142 ADJUST copy_id
    143 SECTION QUESTION
    144 www2.nlnetlabs.nl.	IN	A
    145 HEX_ANSWER_BEGIN
    146 ; 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
    147 ;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    148  00 bf 81 80 00 01 00 01 00 02 00 02 03 77 77 77 0b 6b 61 6e	;	   1-  20
    149  61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 00 01 03 77 77	;	  21-  40
    150  77 0b 6b 61 6e 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01	;	  41-  60
    151  00 01 00 01 50 8b 00 04 52 5e ed 32 0b 6b 61 6e 61 72 69 65	;	  61-  80
    152  70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 8b 00 11 03	;	  81- 100
    153  6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 0b 6b 61 6e	;	 101- 120
    154  61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50	;	 121- 140
    155  8b 00 11 03 6e 73 32 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00	;	 141- 160
    156  03 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 00 01 00	;	 161- 180
    157  01 00 00 46 53 00 04 52 5e ed 02 03 6e 73 32 08 68 65 78 6f	;	 181- 200
    158  6e 2d 69 73 02 6e 6c 00 00 01 00 01 00 00 46 53 00 04 d4 cc	;	 201- 220
    159  db 5b
    160 HEX_ANSWER_END
    161 ENTRY_END
    162 
    163 
    164 
    165    note that this file will link with your
    166    void verbose(int level, char* format, ...); output function.
    167 */
    168 
    169 /** Type of transport, since some entries match based on UDP or TCP of query */
    170 enum transport_type {transport_any = 0, transport_udp, transport_tcp };
    171 
    172 /** struct to keep a linked list of reply packets for a query */
    173 struct reply_packet {
    174 	/** next in list of reply packets, for TCP multiple pkts on wire */
    175 	struct reply_packet* next;
    176 	/** the reply pkt */
    177 	uint8_t* reply_pkt;
    178 	/** length of reply pkt */
    179 	size_t reply_len;
    180 	/** Additional EDNS data for matching queries. */
    181 	struct sldns_buffer* raw_ednsdata;
    182 	/** or reply pkt in hex if not parsable */
    183 	struct sldns_buffer* reply_from_hex;
    184 	/** seconds to sleep before giving packet */
    185 	unsigned int packet_sleep;
    186 };
    187 
    188 /** data structure to keep the canned queries in.
    189    format is the 'matching query' and the 'canned answer' */
    190 struct entry {
    191 	/* match */
    192 	/* How to match an incoming query with this canned reply */
    193 	/** match query opcode with answer opcode */
    194 	uint8_t match_opcode;
    195 	/** match qtype with answer qtype */
    196 	uint8_t match_qtype;
    197 	/** match qname with answer qname */
    198 	uint8_t match_qname;
    199 	/** match rcode with answer rcode */
    200 	uint8_t match_rcode;
    201 	/** match question section */
    202 	uint8_t match_question;
    203 	/** match answer section */
    204 	uint8_t match_answer;
    205 	/** match qname as subdomain of answer qname */
    206 	uint8_t match_subdomain;
    207 	/** match SOA serial number, from auth section */
    208 	uint8_t match_serial;
    209 	/** match EDNS EDE info-code */
    210 	uint8_t match_ede;
    211 	/** match any EDNS EDE info-code */
    212 	uint8_t match_ede_any;
    213 	/** match all of the packet */
    214 	uint8_t match_all;
    215 	/** match all of the packet; ignore EDNS */
    216 	uint8_t match_all_noedns;
    217 	/** match ttls in the packet */
    218 	uint8_t match_ttl;
    219 	/** match DO bit */
    220 	uint8_t match_do;
    221 	/** match CO bit */
    222 	uint8_t match_co;
    223 	/** match absence of EDNS OPT record in query */
    224 	uint8_t match_noedns;
    225 	/** match edns data field given in hex */
    226 	uint8_t match_ednsdata_raw;
    227 	/** match an DNS cookie of length 8 */
    228 	uint8_t match_client_cookie;
    229 	/** match an DNS cookie of length 24 */
    230 	uint8_t match_server_cookie;
    231 	/** match query serial with this value. */
    232 	uint32_t ixfr_soa_serial;
    233 	/** match on UDP/TCP */
    234 	enum transport_type match_transport;
    235 	/** match EDNS EDE info-code with this value. */
    236 	uint16_t ede_info_code;
    237 
    238 	/** pre canned reply */
    239 	struct reply_packet *reply_list;
    240 
    241 	/** how to adjust the reply packet */
    242 	/** copy over the ID from the query into the answer */
    243 	uint8_t copy_id;
    244 	/** copy the query nametypeclass from query into the answer */
    245 	uint8_t copy_query;
    246 	/** copy ednsdata to reply, assume it is clientsubnet and
    247 	 * adjust scopemask to match sourcemask */
    248 	uint8_t copy_ednsdata_assume_clientsubnet;
    249 	/** increment the ECS scope copied from the sourcemask by one */
    250 	uint8_t increment_ecs_scope;
    251 	/** in seconds */
    252 	unsigned int sleeptime;
    253 
    254 	/** some number that names this entry, line number in file or so */
    255 	int lineno;
    256 
    257 	/** next in list */
    258 	struct entry* next;
    259 };
    260 
    261 /**
    262  * reads the canned reply file and returns a list of structs
    263  * does an exit on error.
    264  * @param name: name of the file to read.
    265  * @param skip_whitespace: skip leftside whitespace.
    266  */
    267 struct entry* read_datafile(const char* name, int skip_whitespace);
    268 
    269 /**
    270  * Delete linked list of entries.
    271  */
    272 void delete_entry(struct entry* list);
    273 
    274 /**
    275  * Read one entry from the data file.
    276  * @param in: file to read from. Filepos must be at the start of a new line.
    277  * @param name: name of the file for prettier errors.
    278  * @param pstate: file parse state with lineno, default_ttl,
    279  * 	origin and prev_rr name.
    280  * @param skip_whitespace: skip leftside whitespace.
    281  * @return: The entry read (malloced) or NULL if no entry could be read.
    282  */
    283 struct entry* read_entry(FILE* in, const char* name,
    284 	struct sldns_file_parse_state* pstate, int skip_whitespace);
    285 
    286 /**
    287  * finds entry in list, or returns NULL.
    288  */
    289 struct entry* find_match(struct entry* entries, uint8_t* query_pkt,
    290 	size_t query_pkt_len, enum transport_type transport);
    291 
    292 /**
    293  * match two packets, all must match
    294  * @param q: packet 1
    295  * @param qlen: length of q.
    296  * @param p: packet 2
    297  * @param plen: length of p.
    298  * @param mttl: if true, ttls must match, if false, ttls do not need to match
    299  * @param noloc: if true, rrs may be reordered in their packet-section.
    300  * 	rrs are then matches without location of the rr being important.
    301  * @param noedns: if true, edns is not compared, if false, edns must match.
    302  * @return true if matched.
    303  */
    304 int match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl,
    305 	int noloc, int noedns);
    306 
    307 /**
    308  * copy & adjust packet, mallocs a copy.
    309  */
    310 void adjust_packet(struct entry* match, uint8_t** answer_pkt,
    311 	size_t* answer_pkt_len, uint8_t* query_pkt, size_t query_pkt_len);
    312 
    313 /**
    314  * Parses data buffer to a query, finds the correct answer
    315  * and calls the given function for every packet to send.
    316  * if verbose_out filename is given, packets are dumped there.
    317  * @param inbuf: the packet that came in
    318  * @param inlen: length of packet.
    319  * @param entries: entries read in from datafile.
    320  * @param count: is increased to count number of queries answered.
    321  * @param transport: set to UDP or TCP to match some types of entries.
    322  * @param sendfunc: called to send answer (buffer, size, userarg).
    323  * @param userdata: userarg to give to sendfunc.
    324  * @param verbose_out: if not NULL, verbose messages are printed there.
    325  */
    326 void handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries,
    327 	int* count, enum transport_type transport,
    328 	void (*sendfunc)(uint8_t*, size_t, void*), void* userdata,
    329 	FILE* verbose_out);
    330 
    331 #endif /* TESTPKTS_H */
    332