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 ERROR 89 * ; following entry starts on the next line, ENTRY_BEGIN. 90 * ; more STEP items 91 * SCENARIO_END 92 * 93 * Calculations, a macro-like system: ${$myvar + 3600} 94 * STEP 10 ASSIGN myvar = 3600 95 * ; ASSIGN event. '=' is syntactic sugar here. 3600 is some expression. 96 * ${..} is macro expanded from its expression. Text substitution. 97 * o $var replaced with its value. var is identifier [azAZ09_]* 98 * o number is that number. 99 * o ${variables and arithmetic } 100 * o +, -, / and *. Note, evaluated left-to-right. Use ${} for brackets. 101 * So again, no precedence rules, so 2+3*4 == ${2+3}*4 = 20. 102 * Do 2+${3*4} to get 24. 103 * o ${function params} 104 * o ${time} is the current time for the simulated unbound. 105 * o ${ctime value} is the text ctime(value), Fri 3 Aug 2009, ... 106 * o ${timeout} is the time until next timeout in comm_timer list. 107 * o ${range lower value upper} checks if lower<=value<=upper 108 * returns value if check succeeds. 109 * 110 * ; Example file 111 * SCENARIO_BEGIN Example scenario 112 * RANGE_BEGIN 0 100 113 * ENTRY_BEGIN 114 * ; precoded answers to queries. 115 * ENTRY_END 116 * END_RANGE 117 * STEP 0 QUERY 118 * ENTRY_BEGIN 119 * ; query 120 * ENTRY_END 121 * ; a query is sent out to the network by resolver. 122 * ; precoded answer from range is returned. 123 * ; algorithm will do precoded answers from RANGE immediately, except if 124 * ; the next step specifically checks for that OUT_QUERY. 125 * ; or if none of the precoded answers match. 126 * STEP 1 CHECK_ANSWER 127 * ENTRY_BEGIN 128 * ; what the reply should look like 129 * ENTRY_END 130 * ; successful termination. (if the answer was OK). 131 * ; also, all answers must have been checked with CHECK_ANSWER. 132 * ; and, no more pending out_queries (that have not been checked). 133 * SCENARIO_END 134 * 135 * </pre> 136 */ 137 138 #ifndef TESTCODE_REPLAY_H 139 #define TESTCODE_REPLAY_H 140 #include "util/netevent.h" 141 #include "testcode/testpkts.h" 142 #include "util/rbtree.h" 143 struct replay_answer; 144 struct replay_moment; 145 struct replay_range; 146 struct fake_pending; 147 struct fake_timer; 148 struct replay_var; 149 struct infra_cache; 150 struct sldns_buffer; 151 152 /** 153 * A replay scenario. 154 */ 155 struct replay_scenario { 156 /** name of replay scenario. malloced string. */ 157 char* title; 158 159 /** The list of replay moments. Linked list. Time increases in list. */ 160 struct replay_moment* mom_first; 161 /** The last element in list of replay moments. */ 162 struct replay_moment* mom_last; 163 164 /** 165 * List of matching answers. This is to ease replay scenario 166 * creation. It lists queries (to the network) and what answer 167 * should be returned. The matching answers are valid for a range 168 * of time steps. 169 * So: timestep, parts of query, destination --> answer. 170 */ 171 struct replay_range* range_list; 172 }; 173 174 /** 175 * A replay moment. 176 * Basically, it consists of events to a fake select() call. 177 * This is a recording of an event that happens. 178 * And if output is presented, what is done with that. 179 */ 180 struct replay_moment { 181 /** 182 * The replay time step number. Starts at 0, time is incremented 183 * every time the fake select() is run. 184 */ 185 int time_step; 186 /** Next replay moment in list of replay moments. */ 187 struct replay_moment* mom_next; 188 189 /** what happens this moment? */ 190 enum replay_event_type { 191 /** nothing happens, as if this event is not there. */ 192 repevt_nothing, 193 /** incoming query */ 194 repevt_front_query, 195 /** test fails if reply to query does not match */ 196 repevt_front_reply, 197 /** timeout */ 198 repevt_timeout, 199 /** time passes */ 200 repevt_time_passes, 201 /** reply arrives from the network */ 202 repevt_back_reply, 203 /** test fails if query to the network does not match */ 204 repevt_back_query, 205 /** check autotrust key file */ 206 repevt_autotrust_check, 207 /** check a temp file */ 208 repevt_tempfile_check, 209 /** an error happens to outbound query */ 210 repevt_error, 211 /** assignment to a variable */ 212 repevt_assign, 213 /** store infra rtt cache entry: addr and string (int) */ 214 repevt_infra_rtt, 215 /** cause traffic to flow */ 216 repevt_traffic 217 } 218 /** variable with what is to happen this moment */ 219 evt_type; 220 221 /** The sent packet must match this. Incoming events, the data. */ 222 struct entry* match; 223 224 /** the amount of time that passes */ 225 struct timeval elapse; 226 227 /** address that must be matched, or packet remote host address. */ 228 struct sockaddr_storage addr; 229 /** length of addr, if 0, then any address will do */ 230 socklen_t addrlen; 231 232 /** macro name, for assign. */ 233 char* variable; 234 /** string argument, for assign. */ 235 char* string; 236 237 /** the autotrust file id to check */ 238 char* autotrust_id; 239 /** file contents to match, one string per line */ 240 struct config_strlist* file_content; 241 }; 242 243 /** 244 * Range of timesteps, and canned replies to matching queries. 245 */ 246 struct replay_range { 247 /** time range when this is valid. Including start and end step. */ 248 int start_step; 249 /** end step of time range. */ 250 int end_step; 251 /** address of where this range is served. */ 252 struct sockaddr_storage addr; 253 /** length of addr, if 0, then any address will do */ 254 socklen_t addrlen; 255 256 /** Matching list */ 257 struct entry* match; 258 259 /** next in list of time ranges. */ 260 struct replay_range* next_range; 261 }; 262 263 /** 264 * Replay storage of runtime information. 265 */ 266 struct replay_runtime { 267 /** 268 * The scenario 269 */ 270 struct replay_scenario* scenario; 271 /** 272 * Current moment. 273 */ 274 struct replay_moment* now; 275 276 /** 277 * List of pending queries in order they were sent out. First 278 * one has been sent out most recently. Last one in list is oldest. 279 */ 280 struct fake_pending* pending_list; 281 282 /** 283 * List of answers to queries from clients. These need to be checked. 284 */ 285 struct replay_answer* answer_list; 286 287 /** last element in answer list. */ 288 struct replay_answer* answer_last; 289 290 /** list of fake timer callbacks that are pending */ 291 struct fake_timer* timer_list; 292 293 /** callback to call for incoming queries */ 294 comm_point_callback_type* callback_query; 295 /** user argument for incoming query callback */ 296 void *cb_arg; 297 298 /** ref the infra cache (was passed to outside_network_create) */ 299 struct infra_cache* infra; 300 301 /** the current time in seconds */ 302 time_t now_secs; 303 /** the current time in microseconds */ 304 struct timeval now_tv; 305 306 /** has TCP connection seen a keepalive? */ 307 int tcp_seen_keepalive; 308 309 /** signal handler callback */ 310 void (*sig_cb)(int, void*); 311 /** signal handler user arg */ 312 void *sig_cb_arg; 313 /** time to exit cleanly */ 314 int exit_cleanly; 315 316 /** size of buffers */ 317 size_t bufsize; 318 319 /** 320 * Tree of macro values. Of type replay_var 321 */ 322 rbtree_type* vars; 323 }; 324 325 /** 326 * Pending queries to network, fake replay version. 327 */ 328 struct fake_pending { 329 /** what is important only that we remember the query, copied here. */ 330 struct sldns_buffer* buffer; 331 /** and to what address this is sent to. */ 332 struct sockaddr_storage addr; 333 /** len of addr */ 334 socklen_t addrlen; 335 /** zone name, uncompressed wire format (as used when sent) */ 336 uint8_t* zone; 337 /** length of zone name */ 338 size_t zonelen; 339 /** qtype */ 340 int qtype; 341 /** The callback function to call when answer arrives (or timeout) */ 342 comm_point_callback_type* callback; 343 /** callback user argument */ 344 void* cb_arg; 345 /** original timeout in seconds from 'then' */ 346 int timeout; 347 348 /** next in pending list */ 349 struct fake_pending* next; 350 /** the buffer parsed into a sldns_pkt */ 351 uint8_t* pkt; 352 size_t pkt_len; 353 /** by what transport was the query sent out */ 354 enum transport_type transport; 355 /** if this is a serviced query */ 356 int serviced; 357 /** if we are handling a multi pkt tcp stream, non 0 and the pkt nr*/ 358 int tcp_pkt_counter; 359 /** the runtime structure this is part of */ 360 struct replay_runtime* runtime; 361 }; 362 363 /** 364 * An answer that is pending to happen. 365 */ 366 struct replay_answer { 367 /** Next in list */ 368 struct replay_answer* next; 369 /** reply information */ 370 struct comm_reply repinfo; 371 /** the answer preparsed as ldns pkt */ 372 uint8_t* pkt; 373 size_t pkt_len; 374 }; 375 376 /** 377 * Timers with callbacks, fake replay version. 378 */ 379 struct fake_timer { 380 /** next in list */ 381 struct fake_timer* next; 382 /** the runtime structure this is part of */ 383 struct replay_runtime* runtime; 384 /** the callback to call */ 385 void (*cb)(void*); 386 /** the callback user argument */ 387 void* cb_arg; 388 /** if timer is enabled */ 389 int enabled; 390 /** when the timer expires */ 391 struct timeval tv; 392 }; 393 394 /** 395 * Replay macro variable. And its value. 396 */ 397 struct replay_var { 398 /** rbtree node. Key is this structure. Sorted by name. */ 399 rbnode_type node; 400 /** the variable name */ 401 char* name; 402 /** the variable value */ 403 char* value; 404 }; 405 406 /** 407 * Read a replay scenario from the file. 408 * @param in: file to read from. 409 * @param name: name to print in errors. 410 * @param lineno: incremented for every line read. 411 * @return: Scenario. NULL if no scenario read. 412 */ 413 struct replay_scenario* replay_scenario_read(FILE* in, const char* name, 414 int* lineno); 415 416 /** 417 * Delete scenario. 418 * @param scen: to delete. 419 */ 420 void replay_scenario_delete(struct replay_scenario* scen); 421 422 /** compare two replay_vars */ 423 int replay_var_compare(const void* a, const void* b); 424 425 /** get oldest enabled fake timer */ 426 struct fake_timer* replay_get_oldest_timer(struct replay_runtime* runtime); 427 428 /** strip whitespace from end of string */ 429 void strip_end_white(char* p); 430 431 /** 432 * Create variable storage 433 * @return new or NULL on failure. 434 */ 435 rbtree_type* macro_store_create(void); 436 437 /** 438 * Delete variable storage 439 * @param store: the macro storage to free up. 440 */ 441 void macro_store_delete(rbtree_type* store); 442 443 /** 444 * Apply macro substitution to string. 445 * @param store: variable store. 446 * @param runtime: the runtime to look up values as needed. 447 * @param text: string to work on. 448 * @return newly malloced string with result. 449 */ 450 char* macro_process(rbtree_type* store, struct replay_runtime* runtime, 451 char* text); 452 453 /** 454 * Look up a macro value. Like calling ${$name}. 455 * @param store: variable store 456 * @param name: macro name 457 * @return newly malloced string with result or strdup("") if not found. 458 * or NULL on malloc failure. 459 */ 460 char* macro_lookup(rbtree_type* store, char* name); 461 462 /** 463 * Set macro value. 464 * @param store: variable store 465 * @param name: macro name 466 * @param value: text to set it to. Not expanded. 467 * @return false on failure. 468 */ 469 int macro_assign(rbtree_type* store, char* name, char* value); 470 471 /** Print macro variables stored as debug info */ 472 void macro_print_debug(rbtree_type* store); 473 474 /** testbounds self test */ 475 void testbound_selftest(void); 476 477 #endif /* TESTCODE_REPLAY_H */ 478