1 /*
2  * ldns-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 LDNS_TESTPKTS_H
11 #define LDNS_TESTPKTS_H
12 
13 /**
14  * \file
15  *
16  * This is a debugging aid. It is not efficient, especially
17  * with a long config file, but it can give any reply to any query.
18  * This can help the developer pre-script replies for queries.
19  *
20  * You can specify a packet RR by RR with header flags to return.
21  *
22  * Missing features:
23  *		- matching content different from reply content.
24  *		- find way to adjust mangled packets?
25  *
26  */
27 
28  /*
29 	The data file format is as follows:
30 
31 	; comment.
32 	; a number of entries, these are processed first to last.
33 	; a line based format.
34 
35 	$ORIGIN origin
36 	$TTL default_ttl
37 
38 	ENTRY_BEGIN
39 	; first give MATCH lines, that say what queries are matched
40 	; by this entry.
41 	; 'opcode' makes the query match the opcode from the reply
42 	; if you leave it out, any opcode matches this entry.
43 	; 'qtype' makes the query match the qtype from the reply
44 	; 'qname' makes the query match the qname from the reply
45 	; 'subdomain' makes the query match subdomains of qname from the reply
46 	; 'serial=1023' makes the query match if ixfr serial is 1023.
47 	; 'all' has to match header byte for byte and all rrs in packet.
48 	; 'ttl' used with all, rrs in packet must also have matching TTLs.
49 	; 'DO' will match only queries with DO bit set.
50 	; 'noedns' matches queries without EDNS OPT records.
51 	; 'ednsdata' matches queries to HEX_EDNS section.
52 	MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
53 	MATCH [UDP|TCP] DO
54 	MATCH ...
55 	; Then the REPLY header is specified.
56 	REPLY opcode, rcode or flags.
57 		(opcode)  QUERY IQUERY STATUS NOTIFY UPDATE
58 		(rcode)   NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN
59 		 		YXRRSET NXRRSET NOTAUTH NOTZONE
60 		(flags)   QR AA TC RD CD RA AD DO
61 	REPLY ...
62 	; any additional actions to do.
63 	; 'copy_id' copies the ID from the query to the answer.
64 	ADJUST copy_id
65 	; 'copy_query' copies the query name, type and class to the answer.
66 	ADJUST copy_query
67 	; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open)
68 	ADJUST [sleep=<num>]    ; sleep before giving any reply
69 	ADJUST [packet_sleep=<num>]  ; sleep before this packet in sequence
70 	SECTION QUESTION
71 	<RRs, one per line>    ; the RRcount is determined automatically.
72 	SECTION ANSWER
73 	<RRs, one per line>
74 	SECTION AUTHORITY
75 	<RRs, one per line>
76 	SECTION ADDITIONAL
77 	<RRs, one per line>
78 	EXTRA_PACKET		; follow with SECTION, REPLY for more packets.
79 	HEX_ANSWER_BEGIN	; follow with hex data
80 				; this replaces any answer packet constructed
81 				; with the SECTION keywords (only SECTION QUERY
82 				; is used to match queries). If the data cannot
83 				; be parsed, ADJUST rules for the answer packet
84 				; are ignored. Only copy_id is done.
85 	HEX_ANSWER_END
86 	HEX_EDNS_BEGIN	; follow with hex data.
87 					; Raw EDNS data to match against. It must be an
88 					; exact match (all options are matched) and will be
89 					; evaluated only when 'MATCH ednsdata' given.
90 	HEX_EDNS_END
91 	ENTRY_END
92 
93 
94  	Example data file:
95 $ORIGIN nlnetlabs.nl
96 $TTL 3600
97 
98 ENTRY_BEGIN
99 MATCH qname
100 REPLY NOERROR
101 ADJUST copy_id
102 SECTION QUESTION
103 www.nlnetlabs.nl.	IN	A
104 SECTION ANSWER
105 www.nlnetlabs.nl.	IN	A	195.169.215.155
106 SECTION AUTHORITY
107 nlnetlabs.nl.		IN	NS	www.nlnetlabs.nl.
108 ENTRY_END
109 
110 ENTRY_BEGIN
111 MATCH qname
112 REPLY NOERROR
113 ADJUST copy_id
114 SECTION QUESTION
115 www2.nlnetlabs.nl.	IN	A
116 HEX_ANSWER_BEGIN
117 ; 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
118 ;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
119  00 bf 81 80 00 01 00 01 00 02 00 02 03 77 77 77 0b 6b 61 6e	;	   1-  20
120  61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 00 01 03 77 77	;	  21-  40
121  77 0b 6b 61 6e 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01	;	  41-  60
122  00 01 00 01 50 8b 00 04 52 5e ed 32 0b 6b 61 6e 61 72 69 65	;	  61-  80
123  70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 8b 00 11 03	;	  81- 100
124  6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 0b 6b 61 6e	;	 101- 120
125  61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50	;	 121- 140
126  8b 00 11 03 6e 73 32 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00	;	 141- 160
127  03 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 00 01 00	;	 161- 180
128  01 00 00 46 53 00 04 52 5e ed 02 03 6e 73 32 08 68 65 78 6f	;	 181- 200
129  6e 2d 69 73 02 6e 6c 00 00 01 00 01 00 00 46 53 00 04 d4 cc	;	 201- 220
130  db 5b
131 HEX_ANSWER_END
132 ENTRY_END
133 
134 
135 
136    note that this file will link with your
137    void verbose(int level, char* format, ...); output function.
138 */
139 
140 #include <ldns/ldns.h>
141 
142 /** Type of transport, since some entries match based on UDP or TCP of query */
143 enum transport_type {transport_any = 0, transport_udp, transport_tcp };
144 
145 /** struct to keep a linked list of reply packets for a query */
146 struct reply_packet {
147 	/** next in list of reply packets, for TCP multiple pkts on wire */
148 	struct reply_packet* next;
149 	/** the reply pkt */
150 	ldns_pkt* reply;
151 	/** Additional EDNS data for matching queries. */
152 	ldns_buffer* raw_ednsdata;
153 	/** or reply pkt in hex if not parsable */
154 	ldns_buffer* reply_from_hex;
155 	/** seconds to sleep before giving packet */
156 	unsigned int packet_sleep;
157 };
158 
159 /** data structure to keep the canned queries in.
160    format is the 'matching query' and the 'canned answer' */
161 struct entry {
162 	/* match */
163 	/* How to match an incoming query with this canned reply */
164 	/** match query opcode with answer opcode */
165 	bool match_opcode;
166 	/** match qtype with answer qtype */
167 	bool match_qtype;
168 	/** match qname with answer qname */
169 	bool match_qname;
170 	/** match qname as subdomain of answer qname */
171 	bool match_subdomain;
172 	/** match SOA serial number, from auth section */
173 	bool match_serial;
174 	/** match all of the packet */
175 	bool match_all;
176 	/** match ttls in the packet */
177 	bool match_ttl;
178 	/** match DO bit */
179 	bool match_do;
180 	/** match absence of EDNS OPT record in query */
181 	bool match_noedns;
182 	/** match edns data field given in hex */
183 	bool match_ednsdata_raw;
184 	/** match query serial with this value. */
185 	uint32_t ixfr_soa_serial;
186 	/** match on UDP/TCP */
187 	enum transport_type match_transport;
188 
189 	/** pre canned reply */
190 	struct reply_packet *reply_list;
191 
192 	/** how to adjust the reply packet */
193 	/** copy over the ID from the query into the answer */
194 	bool copy_id;
195 	/** copy the query nametypeclass from query into the answer */
196 	bool copy_query;
197 	/** in seconds */
198 	unsigned int sleeptime;
199 
200 	/** some number that names this entry, line number in file or so */
201 	int lineno;
202 
203 	/** next in list */
204 	struct entry* next;
205 };
206 
207 /**
208  * reads the canned reply file and returns a list of structs
209  * does an exit on error.
210  * @param name: name of the file to read.
211  * @param skip_whitespace: skip leftside whitespace.
212  */
213 struct entry* read_datafile(const char* name, int skip_whitespace);
214 
215 /**
216  * Delete linked list of entries.
217  */
218 void delete_entry(struct entry* list);
219 
220 /**
221  * Read one entry from the data file.
222  * @param in: file to read from. Filepos must be at the start of a new line.
223  * @param name: name of the file for prettier errors.
224  * @param lineno: line number in file, incremented as lines are read.
225  *	for prettier errors.
226  * @param default_ttl: on first call set to default TTL for entries,
227  *	later it stores the $TTL value last seen. Try 3600 first call.
228  * @param origin: domain name for origin appending. Can be &NULL on first call.
229  *	later it stores the $ORIGIN value last seen. Often &NULL or the zone
230  *	name on first call.
231  * @param prev_rr: previous rr name for correcter parsing. &NULL on first call.
232  * @param skip_whitespace: skip leftside whitespace.
233  * @return: The entry read (malloced) or NULL if no entry could be read.
234  */
235 struct entry* read_entry(FILE* in, const char* name, int *lineno,
236 	uint32_t* default_ttl, ldns_rdf** origin, ldns_rdf** prev_rr,
237 	int skip_whitespace);
238 
239 /**
240  * finds entry in list, or returns NULL.
241  */
242 struct entry* find_match(struct entry* entries, ldns_pkt* query_pkt,
243 	enum transport_type transport);
244 
245 /**
246  * copy & adjust packet
247  */
248 void adjust_packet(struct entry* match, ldns_pkt* answer_pkt,
249 	ldns_pkt* query_pkt);
250 
251 /**
252  * Parses data buffer to a query, finds the correct answer
253  * and calls the given function for every packet to send.
254  * if verbose_out filename is given, packets are dumped there.
255  * @param inbuf: the packet that came in
256  * @param inlen: length of packet.
257  * @param entries: entries read in from datafile.
258  * @param count: is increased to count number of queries answered.
259  * @param transport: set to UDP or TCP to match some types of entries.
260  * @param sendfunc: called to send answer (buffer, size, userarg).
261  * @param userdata: userarg to give to sendfunc.
262  * @param verbose_out: if not NULL, verbose messages are printed there.
263  */
264 void handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries,
265 	int* count, enum transport_type transport,
266 	void (*sendfunc)(uint8_t*, size_t, void*), void* userdata,
267 	FILE* verbose_out);
268 
269 #endif /* LDNS_TESTPKTS_H */
270