1/*
2 * testcode/replay.h - store and use a replay of events for the DNS resolver.
3 *
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5 *
6 * This software is open source.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36/**
37 * \file
38 * Store and use a replay of events for the DNS resolver.
39 * Used to test known scenarios to get known outcomes.
40 *
41 * <pre>
42 * File format for replay files.
43 *
44 * ; unbound.conf options.
45 * ; ...
46 * ; additional commandline options to pass to unbound
47 * COMMANDLINE cmdline_option
48 * ; autotrust key file contents, also adds auto-trust-anchor-file: "x" to cfg
49 * AUTOTRUST_FILE id
50 * ; contents of that file
51 * AUTOTRUST_END
52 * ; temp file names are echoed as "tmp/xxx.fname"
53 * TEMPFILE_NAME fname
54 * ; temp file contents, inline, deleted at end of run
55 * TEMPFILE_CONTENTS fname
56 * ; contents of that file
57 * ; this creates $INCLUDE /tmp/xxx.fname
58 * $INCLUDE_TEMPFILE fname
59 * TEMPFILE_END
60 * CONFIG_END
61 * ; comment line.
62 * SCENARIO_BEGIN name_of_scenario
63 * RANGE_BEGIN start_time end_time
64 *    ; give ip of the virtual server, it matches any ip if not present.
65 *    ADDRESS ip_address
66 *    match_entries
67 * RANGE_END
68 * ; more RANGE items.
69 * ; go to the next moment
70 * STEP time_step event_type [ADDRESS ip_address]
71 * ; event_type can be:
72 *	o NOTHING - nothing
73 *	o QUERY - followed by entry
74 *	o CHECK_ANSWER - followed by entry
75 *	o CHECK_OUT_QUERY - followed by entry (if copy-id it is also reply).
76 *	o REPLY - followed by entry
77 *	o TIMEOUT
78 *	o TIME_PASSES ELAPSE [seconds] - increase 'now' time counter, can be
79 *		a floating point number.
80 *	  TIME_PASSES EVAL [macro] - expanded for seconds to move time.
81 *	o TRAFFIC - like CHECK_ANSWER, causes traffic to flow.
82 *		actually the traffic flows before this step is taken.
83 *		the step waits for traffic to stop.
84 *	o CHECK_AUTOTRUST [id] - followed by FILE_BEGIN [to match] FILE_END.
85 *		The file contents is macro expanded before match.
86 *	o CHECK_TEMPFILE [fname] - followed by FILE_BEGIN [to match] FILE_END
87 *	o INFRA_RTT [ip] [dp] [rtt] - update infra cache entry with rtt.
88 *	o FLUSH_MESSAGE name type class - flushes entry in message cache.
89 *	o EXPIRE_MESSAGE name type class - expires entry in message cache.
90 *	o ERROR
91 * ; following entry starts on the next line, ENTRY_BEGIN.
92 * ; more STEP items
93 * SCENARIO_END
94 *
95 * Calculations, a macro-like system: ${$myvar + 3600}
96 * STEP 10 ASSIGN myvar = 3600
97 * 	; ASSIGN event. '=' is syntactic sugar here. 3600 is some expression.
98 * ${..} is macro expanded from its expression.  Text substitution.
99 * 	o $var replaced with its value.  var is identifier [azAZ09_]*
100 * 	o number is that number.
101 * 	o ${variables and arithmetic }
102 * 	o +, -, / and *.  Note, evaluated left-to-right. Use ${} for brackets.
103 * 	  So again, no precedence rules, so 2+3*4 == ${2+3}*4 = 20.
104 * 	  Do 2+${3*4} to get 24.
105 * 	o ${function params}
106 *		o ${time} is the current time for the simulated unbound.
107 *		o ${ctime value} is the text ctime(value), Fri 3 Aug 2009, ...
108 *		o ${timeout} is the time until next timeout in comm_timer list.
109 *		o ${range lower value upper} checks if lower<=value<=upper
110 *			returns value if check succeeds.
111 *
112 * ; Example file
113 * SCENARIO_BEGIN Example scenario
114 * RANGE_BEGIN 0 100
115 *   ENTRY_BEGIN
116 *   ; precoded answers to queries.
117 *   ENTRY_END
118 * END_RANGE
119 * STEP 0 QUERY
120 *   ENTRY_BEGIN
121 *   ; query
122 *   ENTRY_END
123 * ; a query is sent out to the network by resolver.
124 * ; precoded answer from range is returned.
125 * ; algorithm will do precoded answers from RANGE immediately, except if
126 * ; the next step specifically checks for that OUT_QUERY.
127 * ; or if none of the precoded answers match.
128 * STEP 1 CHECK_ANSWER
129 *   ENTRY_BEGIN
130 *   ; what the reply should look like
131 *   ENTRY_END
132 * ; successful termination. (if the answer was OK).
133 * ; also, all answers must have been checked with CHECK_ANSWER.
134 * ; and, no more pending out_queries (that have not been checked).
135 * SCENARIO_END
136 *
137 * </pre>
138 */
139
140#ifndef TESTCODE_REPLAY_H
141#define TESTCODE_REPLAY_H
142#include "util/netevent.h"
143#include "testcode/testpkts.h"
144#include "util/rbtree.h"
145struct replay_answer;
146struct replay_moment;
147struct replay_range;
148struct fake_pending;
149struct fake_timer;
150struct replay_var;
151struct infra_cache;
152struct sldns_buffer;
153struct daemon;
154
155/**
156 * A replay scenario.
157 */
158struct replay_scenario {
159	/** name of replay scenario. malloced string. */
160	char* title;
161
162	/** The list of replay moments. Linked list. Time increases in list. */
163	struct replay_moment* mom_first;
164	/** The last element in list of replay moments. */
165	struct replay_moment* mom_last;
166
167	/**
168	 * List of matching answers. This is to ease replay scenario
169	 * creation. It lists queries (to the network) and what answer
170	 * should be returned. The matching answers are valid for a range
171	 * of time steps.
172	 * So: timestep, parts of query, destination --> answer.
173	 */
174	struct replay_range* range_list;
175};
176
177/**
178 * A replay moment.
179 * Basically, it consists of events to a fake select() call.
180 * This is a recording of an event that happens.
181 * And if output is presented, what is done with that.
182 */
183struct replay_moment {
184	/**
185	 * The replay time step number. Starts at 0, time is incremented
186	 * every time the fake select() is run.
187	 */
188	int time_step;
189	/** Next replay moment in list of replay moments. */
190	struct replay_moment* mom_next;
191
192	/** what happens this moment? */
193	enum replay_event_type {
194		/** nothing happens, as if this event is not there. */
195		repevt_nothing,
196		/** incoming query */
197		repevt_front_query,
198		/** test fails if reply to query does not match */
199		repevt_front_reply,
200		/** timeout */
201		repevt_timeout,
202		/** time passes */
203		repevt_time_passes,
204		/** reply arrives from the network */
205		repevt_back_reply,
206		/** test fails if query to the network does not match */
207		repevt_back_query,
208		/** check autotrust key file */
209		repevt_autotrust_check,
210		/** check a temp file */
211		repevt_tempfile_check,
212		/** an error happens to outbound query */
213		repevt_error,
214		/** assignment to a variable */
215		repevt_assign,
216		/** store infra rtt cache entry: addr and string (int) */
217		repevt_infra_rtt,
218		/** flush message cache entry */
219		repevt_flush_message,
220		/** expire message cache entry */
221		repevt_expire_message,
222		/** cause traffic to flow */
223		repevt_traffic
224	}
225		/** variable with what is to happen this moment */
226		evt_type;
227
228	/** The sent packet must match this. Incoming events, the data. */
229	struct entry* match;
230
231	/** the amount of time that passes */
232	struct timeval elapse;
233
234	/** address that must be matched, or packet remote host address. */
235	struct sockaddr_storage addr;
236	/** length of addr, if 0, then any address will do */
237	socklen_t addrlen;
238
239	/** macro name, for assign. */
240	char* variable;
241	/** string argument, for assign. */
242	char* string;
243
244	/** the autotrust file id to check */
245	char* autotrust_id;
246	/** file contents to match, one string per line */
247	struct config_strlist* file_content;
248};
249
250/**
251 * Range of timesteps, and canned replies to matching queries.
252 */
253struct replay_range {
254	/** time range when this is valid. Including start and end step. */
255	int start_step;
256	/** end step of time range. */
257	int end_step;
258	/** address of where this range is served. */
259	struct sockaddr_storage addr;
260	/** length of addr, if 0, then any address will do */
261	socklen_t addrlen;
262
263	/** Matching list */
264	struct entry* match;
265
266	/** next in list of time ranges. */
267	struct replay_range* next_range;
268};
269
270/**
271 * Replay storage of runtime information.
272 */
273struct replay_runtime {
274	/**
275	 * The scenario
276	 */
277	struct replay_scenario* scenario;
278	/**
279	 * Current moment.
280	 */
281	struct replay_moment* now;
282
283	/**
284	 * List of pending queries in order they were sent out. First
285	 * one has been sent out most recently. Last one in list is oldest.
286	 */
287	struct fake_pending* pending_list;
288
289	/**
290	 * List of answers to queries from clients. These need to be checked.
291	 */
292	struct replay_answer* answer_list;
293
294	/** last element in answer list. */
295	struct replay_answer* answer_last;
296
297	/** list of fake timer callbacks that are pending */
298	struct fake_timer* timer_list;
299
300	/** callback to call for incoming queries */
301	comm_point_callback_type* callback_query;
302	/** user argument for incoming query callback */
303	void *cb_arg;
304
305	/** ref the infra cache (was passed to outside_network_create) */
306	struct infra_cache* infra;
307	/** the daemon structure passed in worker call to remote accept open */
308	struct daemon* daemon;
309
310	/** the current time in seconds */
311	time_t now_secs;
312	/** the current time in microseconds */
313	struct timeval now_tv;
314
315	/** has TCP connection seen a keepalive? */
316	int tcp_seen_keepalive;
317
318	/** signal handler callback */
319	void (*sig_cb)(int, void*);
320	/** signal handler user arg */
321	void *sig_cb_arg;
322	/** time to exit cleanly */
323	int exit_cleanly;
324
325	/** size of buffers */
326	size_t bufsize;
327
328	/**
329	 * Tree of macro values. Of type replay_var
330	 */
331	rbtree_type* vars;
332};
333
334/**
335 * Pending queries to network, fake replay version.
336 */
337struct fake_pending {
338	/** what is important only that we remember the query, copied here. */
339	struct sldns_buffer* buffer;
340	/** and to what address this is sent to. */
341	struct sockaddr_storage addr;
342	/** len of addr */
343	socklen_t addrlen;
344	/** zone name, uncompressed wire format (as used when sent) */
345	uint8_t* zone;
346	/** length of zone name */
347	size_t zonelen;
348	/** qtype */
349	int qtype;
350	/** The callback function to call when answer arrives (or timeout) */
351	comm_point_callback_type* callback;
352	/** callback user argument */
353	void* cb_arg;
354	/** original timeout in seconds from 'then' */
355	int timeout;
356
357	/** next in pending list */
358	struct fake_pending* next;
359	/** the buffer parsed into a sldns_pkt */
360	uint8_t* pkt;
361	size_t pkt_len;
362	/** by what transport was the query sent out */
363	enum transport_type transport;
364	/** if this is a serviced query */
365	int serviced;
366	/** if we are handling a multi pkt tcp stream, non 0 and the pkt nr*/
367	int tcp_pkt_counter;
368	/** the runtime structure this is part of */
369	struct replay_runtime* runtime;
370};
371
372/**
373 * An answer that is pending to happen.
374 */
375struct replay_answer {
376	/** Next in list */
377	struct replay_answer* next;
378	/** reply information */
379	struct comm_reply repinfo;
380	/** the answer preparsed as ldns pkt */
381	uint8_t* pkt;
382	size_t pkt_len;
383};
384
385/**
386 * Timers with callbacks, fake replay version.
387 */
388struct fake_timer {
389	/** next in list */
390	struct fake_timer* next;
391	/** the runtime structure this is part of */
392	struct replay_runtime* runtime;
393	/** the callback to call */
394	void (*cb)(void*);
395	/** the callback user argument */
396	void* cb_arg;
397	/** if timer is enabled */
398	int enabled;
399	/** when the timer expires */
400	struct timeval tv;
401};
402
403/**
404 * Replay macro variable.  And its value.
405 */
406struct replay_var {
407	/** rbtree node. Key is this structure. Sorted by name. */
408	rbnode_type node;
409	/** the variable name */
410	char* name;
411	/** the variable value */
412	char* value;
413};
414
415/**
416 * Read a replay scenario from the file.
417 * @param in: file to read from.
418 * @param name: name to print in errors.
419 * @param lineno: incremented for every line read.
420 * @return: Scenario. NULL if no scenario read.
421 */
422struct replay_scenario* replay_scenario_read(FILE* in, const char* name,
423	int* lineno);
424
425/**
426 * Delete scenario.
427 * @param scen: to delete.
428 */
429void replay_scenario_delete(struct replay_scenario* scen);
430
431/** compare two replay_vars */
432int replay_var_compare(const void* a, const void* b);
433
434/** get oldest enabled fake timer */
435struct fake_timer* replay_get_oldest_timer(struct replay_runtime* runtime);
436
437/** strip whitespace from end of string */
438void strip_end_white(char* p);
439
440/**
441 * Create variable storage
442 * @return new or NULL on failure.
443 */
444rbtree_type* macro_store_create(void);
445
446/**
447 * Delete variable storage
448 * @param store: the macro storage to free up.
449 */
450void macro_store_delete(rbtree_type* store);
451
452/**
453 * Apply macro substitution to string.
454 * @param store: variable store.
455 * @param runtime: the runtime to look up values as needed.
456 * @param text: string to work on.
457 * @return newly malloced string with result.
458 */
459char* macro_process(rbtree_type* store, struct replay_runtime* runtime,
460	char* text);
461
462/**
463 * Look up a macro value. Like calling ${$name}.
464 * @param store: variable store
465 * @param name: macro name
466 * @return newly malloced string with result or strdup("") if not found.
467 * 	or NULL on malloc failure.
468 */
469char* macro_lookup(rbtree_type* store, char* name);
470
471/**
472 * Set macro value.
473 * @param store: variable store
474 * @param name: macro name
475 * @param value: text to set it to.  Not expanded.
476 * @return false on failure.
477 */
478int macro_assign(rbtree_type* store, char* name, char* value);
479
480/** Print macro variables stored as debug info */
481void macro_print_debug(rbtree_type* store);
482
483/** testbounds self test */
484void testbound_selftest(void);
485
486#endif /* TESTCODE_REPLAY_H */
487