]>
Commit | Line | Data |
---|---|---|
89c4ed63 A |
1 | /* |
2 | * testcode/fake_event.c - fake event handling that replays existing scenario. | |
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 | * Event service that replays a scenario. | |
39 | * This implements the same exported symbols as the files: | |
40 | * util/netevent.c | |
41 | * services/listen_dnsport.c | |
42 | * services/outside_network.c | |
43 | * But these do not actually access the network or events, instead | |
44 | * the scenario is played. | |
45 | */ | |
46 | ||
47 | #include "config.h" | |
48 | #include "testcode/fake_event.h" | |
49 | #include "util/netevent.h" | |
50 | #include "util/net_help.h" | |
51 | #include "util/data/msgparse.h" | |
52 | #include "util/data/msgreply.h" | |
53 | #include "util/data/msgencode.h" | |
54 | #include "util/data/dname.h" | |
55 | #include "util/config_file.h" | |
56 | #include "services/listen_dnsport.h" | |
57 | #include "services/outside_network.h" | |
58 | #include "services/cache/infra.h" | |
59 | #include "testcode/replay.h" | |
60 | #include "testcode/testpkts.h" | |
61 | #include "util/log.h" | |
62 | #include "util/fptr_wlist.h" | |
63 | #include "ldns/sbuffer.h" | |
64 | #include "ldns/wire2str.h" | |
65 | #include "ldns/str2wire.h" | |
66 | #include <signal.h> | |
67 | struct worker; | |
68 | struct daemon_remote; | |
69 | ||
70 | /** Global variable: the scenario. Saved here for when event_init is done. */ | |
71 | static struct replay_scenario* saved_scenario = NULL; | |
72 | ||
73 | /** add timers and the values do not overflow or become negative */ | |
74 | static void | |
75 | timeval_add(struct timeval* d, const struct timeval* add) | |
76 | { | |
77 | #ifndef S_SPLINT_S | |
78 | d->tv_sec += add->tv_sec; | |
79 | d->tv_usec += add->tv_usec; | |
80 | if(d->tv_usec > 1000000) { | |
81 | d->tv_usec -= 1000000; | |
82 | d->tv_sec++; | |
83 | } | |
84 | #endif | |
85 | } | |
86 | ||
87 | void | |
88 | fake_temp_file(const char* adj, const char* id, char* buf, size_t len) | |
89 | { | |
90 | #ifdef USE_WINSOCK | |
91 | snprintf(buf, len, "testbound_%u%s%s.tmp", | |
92 | (unsigned)getpid(), adj, id); | |
93 | #else | |
94 | snprintf(buf, len, "/tmp/testbound_%u%s%s.tmp", | |
95 | (unsigned)getpid(), adj, id); | |
96 | #endif | |
97 | } | |
98 | ||
99 | void | |
100 | fake_event_init(struct replay_scenario* scen) | |
101 | { | |
102 | saved_scenario = scen; | |
103 | } | |
104 | ||
105 | void | |
106 | fake_event_cleanup(void) | |
107 | { | |
108 | replay_scenario_delete(saved_scenario); | |
109 | saved_scenario = NULL; | |
110 | } | |
111 | ||
112 | /** helper function that logs a sldns_pkt packet to logfile */ | |
113 | static void | |
114 | log_pkt(const char* desc, uint8_t* pkt, size_t len) | |
115 | { | |
116 | char* str = sldns_wire2str_pkt(pkt, len); | |
117 | if(!str) | |
118 | fatal_exit("%s: (failed out of memory wire2str_pkt)", desc); | |
119 | else { | |
120 | log_info("%s%s", desc, str); | |
121 | free(str); | |
122 | } | |
123 | } | |
124 | ||
125 | /** | |
126 | * Returns a string describing the event type. | |
127 | */ | |
128 | static const char* | |
129 | repevt_string(enum replay_event_type t) | |
130 | { | |
131 | switch(t) { | |
132 | case repevt_nothing: return "NOTHING"; | |
133 | case repevt_front_query: return "QUERY"; | |
134 | case repevt_front_reply: return "CHECK_ANSWER"; | |
135 | case repevt_timeout: return "TIMEOUT"; | |
136 | case repevt_time_passes: return "TIME_PASSES"; | |
137 | case repevt_back_reply: return "REPLY"; | |
138 | case repevt_back_query: return "CHECK_OUT_QUERY"; | |
139 | case repevt_autotrust_check: return "CHECK_AUTOTRUST"; | |
140 | case repevt_error: return "ERROR"; | |
141 | case repevt_assign: return "ASSIGN"; | |
142 | case repevt_traffic: return "TRAFFIC"; | |
143 | case repevt_infra_rtt: return "INFRA_RTT"; | |
144 | default: return "UNKNOWN"; | |
145 | } | |
146 | } | |
147 | ||
148 | /** delete a fake pending */ | |
149 | static void | |
150 | delete_fake_pending(struct fake_pending* pend) | |
151 | { | |
152 | if(!pend) | |
153 | return; | |
154 | free(pend->zone); | |
155 | sldns_buffer_free(pend->buffer); | |
156 | free(pend->pkt); | |
157 | free(pend); | |
158 | } | |
159 | ||
160 | /** delete a replay answer */ | |
161 | static void | |
162 | delete_replay_answer(struct replay_answer* a) | |
163 | { | |
164 | if(!a) | |
165 | return; | |
166 | if(a->repinfo.c) { | |
167 | sldns_buffer_free(a->repinfo.c->buffer); | |
168 | free(a->repinfo.c); | |
169 | } | |
170 | free(a->pkt); | |
171 | free(a); | |
172 | } | |
173 | ||
174 | /** | |
175 | * return: true if pending query matches the now event. | |
176 | */ | |
177 | static int | |
178 | pending_matches_current(struct replay_runtime* runtime, | |
179 | struct entry** entry, struct fake_pending **pend) | |
180 | { | |
181 | struct fake_pending* p; | |
182 | struct entry* e; | |
183 | if(!runtime->now || runtime->now->evt_type != repevt_back_query | |
184 | || !runtime->pending_list) | |
185 | return 0; | |
186 | /* see if any of the pending queries matches */ | |
187 | for(p = runtime->pending_list; p; p = p->next) { | |
188 | if(runtime->now->addrlen != 0 && | |
189 | sockaddr_cmp(&p->addr, p->addrlen, &runtime->now->addr, | |
190 | runtime->now->addrlen) != 0) | |
191 | continue; | |
192 | if((e=find_match(runtime->now->match, p->pkt, p->pkt_len, | |
193 | p->transport))) { | |
194 | *entry = e; | |
195 | *pend = p; | |
196 | return 1; | |
197 | } | |
198 | } | |
199 | return 0; | |
200 | } | |
201 | ||
202 | /** | |
203 | * Find the range that matches this pending message. | |
204 | * @param runtime: runtime with current moment, and range list. | |
205 | * @param entry: returns the pointer to entry that matches. | |
206 | * @param pend: the pending that the entry must match. | |
207 | * @return: true if a match is found. | |
208 | */ | |
209 | static int | |
210 | pending_find_match(struct replay_runtime* runtime, struct entry** entry, | |
211 | struct fake_pending* pend) | |
212 | { | |
213 | int timenow = runtime->now->time_step; | |
214 | struct replay_range* p = runtime->scenario->range_list; | |
215 | while(p) { | |
216 | if(p->start_step <= timenow && timenow <= p->end_step && | |
217 | (p->addrlen == 0 || sockaddr_cmp(&p->addr, p->addrlen, | |
218 | &pend->addr, pend->addrlen) == 0) && | |
219 | (*entry = find_match(p->match, pend->pkt, pend->pkt_len, | |
220 | pend->transport))) { | |
221 | log_info("matched query time %d in range [%d, %d] " | |
222 | "with entry line %d", timenow, | |
223 | p->start_step, p->end_step, (*entry)->lineno); | |
224 | if(p->addrlen != 0) | |
225 | log_addr(0, "matched ip", &p->addr, p->addrlen); | |
226 | log_pkt("matched pkt: ", | |
227 | (*entry)->reply_list->reply_pkt, | |
228 | (*entry)->reply_list->reply_len); | |
229 | return 1; | |
230 | } | |
231 | p = p->next_range; | |
232 | } | |
233 | return 0; | |
234 | } | |
235 | ||
236 | /** | |
237 | * See if outgoing pending query matches an entry. | |
238 | * @param runtime: runtime. | |
239 | * @param entry: if true, the entry that matches is returned. | |
240 | * @param pend: if true, the outgoing message that matches is returned. | |
241 | * @return: true if pending query matches the now event. | |
242 | */ | |
243 | static int | |
244 | pending_matches_range(struct replay_runtime* runtime, | |
245 | struct entry** entry, struct fake_pending** pend) | |
246 | { | |
247 | struct fake_pending* p = runtime->pending_list; | |
248 | /* slow, O(N*N), but it works as advertised with weird matching */ | |
249 | while(p) { | |
250 | log_info("check of pending"); | |
251 | if(pending_find_match(runtime, entry, p)) { | |
252 | *pend = p; | |
253 | return 1; | |
254 | } | |
255 | p = p->next; | |
256 | } | |
257 | return 0; | |
258 | } | |
259 | ||
260 | /** | |
261 | * Remove the item from the pending list. | |
262 | */ | |
263 | static void | |
264 | pending_list_delete(struct replay_runtime* runtime, struct fake_pending* pend) | |
265 | { | |
266 | struct fake_pending** prev = &runtime->pending_list; | |
267 | struct fake_pending* p = runtime->pending_list; | |
268 | ||
269 | while(p) { | |
270 | if(p == pend) { | |
271 | *prev = p->next; | |
272 | delete_fake_pending(pend); | |
273 | return; | |
274 | } | |
275 | ||
276 | prev = &p->next; | |
277 | p = p->next; | |
278 | } | |
279 | } | |
280 | ||
281 | /** | |
282 | * Fill buffer with reply from the entry. | |
283 | */ | |
284 | static void | |
285 | fill_buffer_with_reply(sldns_buffer* buffer, struct entry* entry, uint8_t* q, | |
286 | size_t qlen) | |
287 | { | |
288 | uint8_t* c; | |
289 | size_t clen; | |
290 | log_assert(entry && entry->reply_list); | |
291 | sldns_buffer_clear(buffer); | |
292 | if(entry->reply_list->reply_from_hex) { | |
293 | c = sldns_buffer_begin(entry->reply_list->reply_from_hex); | |
294 | clen = sldns_buffer_limit(entry->reply_list->reply_from_hex); | |
295 | if(!c) fatal_exit("out of memory"); | |
296 | } else { | |
297 | c = entry->reply_list->reply_pkt; | |
298 | clen = entry->reply_list->reply_len; | |
299 | } | |
300 | if(c) { | |
301 | if(q) adjust_packet(entry, &c, &clen, q, qlen); | |
302 | sldns_buffer_write(buffer, c, clen); | |
303 | if(q) free(c); | |
304 | } | |
305 | sldns_buffer_flip(buffer); | |
306 | } | |
307 | ||
308 | /** | |
309 | * Perform range entry on pending message. | |
310 | * @param runtime: runtime buffer size preference. | |
311 | * @param entry: entry that codes for the reply to do. | |
312 | * @param pend: pending query that is answered, callback called. | |
313 | */ | |
314 | static void | |
315 | answer_callback_from_entry(struct replay_runtime* runtime, | |
316 | struct entry* entry, struct fake_pending* pend) | |
317 | { | |
318 | struct comm_point c; | |
319 | struct comm_reply repinfo; | |
320 | void* cb_arg = pend->cb_arg; | |
321 | comm_point_callback_t* cb = pend->callback; | |
322 | ||
323 | memset(&c, 0, sizeof(c)); | |
324 | c.fd = -1; | |
325 | c.buffer = sldns_buffer_new(runtime->bufsize); | |
326 | c.type = comm_udp; | |
327 | if(pend->transport == transport_tcp) | |
328 | c.type = comm_tcp; | |
329 | fill_buffer_with_reply(c.buffer, entry, pend->pkt, pend->pkt_len); | |
330 | repinfo.c = &c; | |
331 | repinfo.addrlen = pend->addrlen; | |
332 | memcpy(&repinfo.addr, &pend->addr, pend->addrlen); | |
333 | if(!pend->serviced) | |
334 | pending_list_delete(runtime, pend); | |
335 | if((*cb)(&c, cb_arg, NETEVENT_NOERROR, &repinfo)) { | |
336 | fatal_exit("testbound: unexpected: callback returned 1"); | |
337 | } | |
338 | sldns_buffer_free(c.buffer); | |
339 | } | |
340 | ||
341 | /** Check the now moment answer check event */ | |
342 | static void | |
343 | answer_check_it(struct replay_runtime* runtime) | |
344 | { | |
345 | struct replay_answer* ans = runtime->answer_list, | |
346 | *prev = NULL; | |
347 | log_assert(runtime && runtime->now && | |
348 | runtime->now->evt_type == repevt_front_reply); | |
349 | while(ans) { | |
350 | enum transport_type tr = transport_tcp; | |
351 | if(ans->repinfo.c->type == comm_udp) | |
352 | tr = transport_udp; | |
353 | if((runtime->now->addrlen == 0 || sockaddr_cmp( | |
354 | &runtime->now->addr, runtime->now->addrlen, | |
355 | &ans->repinfo.addr, ans->repinfo.addrlen) == 0) && | |
356 | find_match(runtime->now->match, ans->pkt, | |
357 | ans->pkt_len, tr)) { | |
358 | log_info("testbound matched event entry from line %d", | |
359 | runtime->now->match->lineno); | |
360 | log_info("testbound: do STEP %d %s", | |
361 | runtime->now->time_step, | |
362 | repevt_string(runtime->now->evt_type)); | |
363 | if(prev) | |
364 | prev->next = ans->next; | |
365 | else runtime->answer_list = ans->next; | |
366 | if(!ans->next) | |
367 | runtime->answer_last = prev; | |
368 | delete_replay_answer(ans); | |
369 | return; | |
370 | } else { | |
371 | prev = ans; | |
372 | ans = ans->next; | |
373 | } | |
374 | } | |
375 | log_info("testbound: do STEP %d %s", runtime->now->time_step, | |
376 | repevt_string(runtime->now->evt_type)); | |
377 | fatal_exit("testbound: not matched"); | |
378 | } | |
379 | ||
380 | /** | |
381 | * Create commpoint (as return address) for a fake incoming query. | |
382 | */ | |
383 | static void | |
384 | fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo) | |
385 | { | |
386 | struct comm_reply repinfo; | |
387 | memset(&repinfo, 0, sizeof(repinfo)); | |
388 | repinfo.c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); | |
389 | repinfo.addrlen = (socklen_t)sizeof(struct sockaddr_in); | |
390 | if(todo->addrlen != 0) { | |
391 | repinfo.addrlen = todo->addrlen; | |
392 | memcpy(&repinfo.addr, &todo->addr, todo->addrlen); | |
393 | } | |
394 | repinfo.c->fd = -1; | |
395 | repinfo.c->ev = (struct internal_event*)runtime; | |
396 | repinfo.c->buffer = sldns_buffer_new(runtime->bufsize); | |
397 | if(todo->match->match_transport == transport_tcp) | |
398 | repinfo.c->type = comm_tcp; | |
399 | else repinfo.c->type = comm_udp; | |
400 | fill_buffer_with_reply(repinfo.c->buffer, todo->match, NULL, 0); | |
401 | log_info("testbound: incoming QUERY"); | |
402 | log_pkt("query pkt", todo->match->reply_list->reply_pkt, | |
403 | todo->match->reply_list->reply_len); | |
404 | /* call the callback for incoming queries */ | |
405 | if((*runtime->callback_query)(repinfo.c, runtime->cb_arg, | |
406 | NETEVENT_NOERROR, &repinfo)) { | |
407 | /* send immediate reply */ | |
408 | comm_point_send_reply(&repinfo); | |
409 | } | |
410 | /* clear it again, in case copy not done properly */ | |
411 | memset(&repinfo, 0, sizeof(repinfo)); | |
412 | } | |
413 | ||
414 | /** | |
415 | * Perform callback for fake pending message. | |
416 | */ | |
417 | static void | |
418 | fake_pending_callback(struct replay_runtime* runtime, | |
419 | struct replay_moment* todo, int error) | |
420 | { | |
421 | struct fake_pending* p = runtime->pending_list; | |
422 | struct comm_reply repinfo; | |
423 | struct comm_point c; | |
424 | void* cb_arg; | |
425 | comm_point_callback_t* cb; | |
426 | ||
427 | memset(&c, 0, sizeof(c)); | |
428 | if(!p) fatal_exit("No pending queries."); | |
429 | cb_arg = p->cb_arg; | |
430 | cb = p->callback; | |
431 | c.buffer = sldns_buffer_new(runtime->bufsize); | |
432 | c.type = comm_udp; | |
433 | if(p->transport == transport_tcp) | |
434 | c.type = comm_tcp; | |
435 | if(todo->evt_type == repevt_back_reply && todo->match) { | |
436 | fill_buffer_with_reply(c.buffer, todo->match, p->pkt, | |
437 | p->pkt_len); | |
438 | } | |
439 | repinfo.c = &c; | |
440 | repinfo.addrlen = p->addrlen; | |
441 | memcpy(&repinfo.addr, &p->addr, p->addrlen); | |
442 | if(!p->serviced) | |
443 | pending_list_delete(runtime, p); | |
444 | if((*cb)(&c, cb_arg, error, &repinfo)) { | |
445 | fatal_exit("unexpected: pending callback returned 1"); | |
446 | } | |
447 | /* delete the pending item. */ | |
448 | sldns_buffer_free(c.buffer); | |
449 | } | |
450 | ||
451 | /** pass time */ | |
452 | static void | |
453 | moment_assign(struct replay_runtime* runtime, struct replay_moment* mom) | |
454 | { | |
455 | char* value = macro_process(runtime->vars, runtime, mom->string); | |
456 | if(!value) | |
457 | fatal_exit("could not process macro step %d", mom->time_step); | |
458 | log_info("assign %s = %s", mom->variable, value); | |
459 | if(!macro_assign(runtime->vars, mom->variable, value)) | |
460 | fatal_exit("out of memory storing macro"); | |
461 | free(value); | |
462 | if(verbosity >= VERB_ALGO) | |
463 | macro_print_debug(runtime->vars); | |
464 | } | |
465 | ||
466 | /** pass time */ | |
467 | static void | |
468 | time_passes(struct replay_runtime* runtime, struct replay_moment* mom) | |
469 | { | |
470 | struct fake_timer *t; | |
471 | struct timeval tv = mom->elapse; | |
472 | if(mom->string) { | |
473 | char* xp = macro_process(runtime->vars, runtime, mom->string); | |
474 | double sec; | |
475 | if(!xp) fatal_exit("could not macro expand %s", mom->string); | |
476 | verbose(VERB_ALGO, "EVAL %s", mom->string); | |
477 | sec = atof(xp); | |
478 | free(xp); | |
479 | #ifndef S_SPLINT_S | |
480 | tv.tv_sec = sec; | |
481 | tv.tv_usec = (int)((sec - (double)tv.tv_sec) *1000000. + 0.5); | |
482 | #endif | |
483 | } | |
484 | timeval_add(&runtime->now_tv, &tv); | |
485 | runtime->now_secs = (time_t)runtime->now_tv.tv_sec; | |
486 | #ifndef S_SPLINT_S | |
487 | log_info("elapsed %d.%6.6d now %d.%6.6d", | |
488 | (int)tv.tv_sec, (int)tv.tv_usec, | |
489 | (int)runtime->now_tv.tv_sec, (int)runtime->now_tv.tv_usec); | |
490 | #endif | |
491 | /* see if any timers have fired; and run them */ | |
492 | while( (t=replay_get_oldest_timer(runtime)) ) { | |
493 | t->enabled = 0; | |
494 | log_info("fake_timer callback"); | |
495 | fptr_ok(fptr_whitelist_comm_timer(t->cb)); | |
496 | (*t->cb)(t->cb_arg); | |
497 | } | |
498 | } | |
499 | ||
500 | /** check autotrust file contents */ | |
501 | static void | |
502 | autotrust_check(struct replay_runtime* runtime, struct replay_moment* mom) | |
503 | { | |
504 | char name[1024], line[1024]; | |
505 | FILE *in; | |
506 | int lineno = 0, oke=1; | |
507 | char* expanded; | |
508 | struct config_strlist* p; | |
509 | line[sizeof(line)-1] = 0; | |
510 | log_assert(mom->autotrust_id); | |
511 | fake_temp_file("_auto_", mom->autotrust_id, name, sizeof(name)); | |
512 | in = fopen(name, "r"); | |
513 | if(!in) fatal_exit("could not open %s: %s", name, strerror(errno)); | |
514 | for(p=mom->file_content; p; p=p->next) { | |
515 | lineno++; | |
516 | if(!fgets(line, (int)sizeof(line)-1, in)) { | |
517 | log_err("autotrust check failed, could not read line"); | |
518 | log_err("file %s, line %d", name, lineno); | |
519 | log_err("should be: %s", p->str); | |
520 | fatal_exit("autotrust_check failed"); | |
521 | } | |
522 | if(line[0]) line[strlen(line)-1] = 0; /* remove newline */ | |
523 | expanded = macro_process(runtime->vars, runtime, p->str); | |
524 | if(!expanded) | |
525 | fatal_exit("could not expand macro line %d", lineno); | |
526 | if(verbosity >= 7 && strcmp(p->str, expanded) != 0) | |
527 | log_info("expanded '%s' to '%s'", p->str, expanded); | |
528 | if(strcmp(expanded, line) != 0) { | |
529 | log_err("mismatch in file %s, line %d", name, lineno); | |
530 | log_err("file has : %s", line); | |
531 | log_err("should be: %s", expanded); | |
532 | free(expanded); | |
533 | oke = 0; | |
534 | continue; | |
535 | } | |
536 | free(expanded); | |
537 | fprintf(stderr, "%s:%2d ok : %s\n", name, lineno, line); | |
538 | } | |
539 | if(fgets(line, (int)sizeof(line)-1, in)) { | |
540 | log_err("autotrust check failed, extra lines in %s after %d", | |
541 | name, lineno); | |
542 | do { | |
543 | fprintf(stderr, "file has: %s", line); | |
544 | } while(fgets(line, (int)sizeof(line)-1, in)); | |
545 | oke = 0; | |
546 | } | |
547 | fclose(in); | |
548 | if(!oke) | |
549 | fatal_exit("autotrust_check STEP %d failed", mom->time_step); | |
550 | log_info("autotrust %s is OK", mom->autotrust_id); | |
551 | } | |
552 | ||
553 | /** Store RTT in infra cache */ | |
554 | static void | |
555 | do_infra_rtt(struct replay_runtime* runtime) | |
556 | { | |
557 | struct replay_moment* now = runtime->now; | |
558 | int rto; | |
559 | size_t dplen = 0; | |
560 | uint8_t* dp = sldns_str2wire_dname(now->variable, &dplen); | |
561 | if(!dp) fatal_exit("cannot parse %s", now->variable); | |
562 | rto = infra_rtt_update(runtime->infra, &now->addr, now->addrlen, | |
563 | dp, dplen, LDNS_RR_TYPE_A, atoi(now->string), | |
564 | -1, runtime->now_secs); | |
565 | log_addr(0, "INFRA_RTT for", &now->addr, now->addrlen); | |
566 | log_info("INFRA_RTT(%s roundtrip %d): rto of %d", now->variable, | |
567 | atoi(now->string), rto); | |
568 | if(rto == 0) fatal_exit("infra_rtt_update failed"); | |
569 | free(dp); | |
570 | } | |
571 | ||
572 | /** perform exponential backoff on the timout */ | |
573 | static void | |
574 | expon_timeout_backoff(struct replay_runtime* runtime) | |
575 | { | |
576 | struct fake_pending* p = runtime->pending_list; | |
577 | int rtt, vs; | |
578 | uint8_t edns_lame_known; | |
579 | int last_rtt, rto; | |
580 | if(!p) return; /* no pending packet to backoff */ | |
581 | if(!infra_host(runtime->infra, &p->addr, p->addrlen, p->zone, | |
582 | p->zonelen, runtime->now_secs, &vs, &edns_lame_known, &rtt)) | |
583 | return; | |
584 | last_rtt = rtt; | |
585 | rto = infra_rtt_update(runtime->infra, &p->addr, p->addrlen, p->zone, | |
586 | p->zonelen, p->qtype, -1, last_rtt, runtime->now_secs); | |
587 | log_info("infra_rtt_update returned rto %d", rto); | |
588 | } | |
589 | ||
590 | /** | |
591 | * Advance to the next moment. | |
592 | */ | |
593 | static void | |
594 | advance_moment(struct replay_runtime* runtime) | |
595 | { | |
596 | if(!runtime->now) | |
597 | runtime->now = runtime->scenario->mom_first; | |
598 | else runtime->now = runtime->now->mom_next; | |
599 | } | |
600 | ||
601 | /** | |
602 | * Perform actions or checks determined by the moment. | |
603 | * Also advances the time by one step. | |
604 | * @param runtime: scenario runtime information. | |
605 | */ | |
606 | static void | |
607 | do_moment_and_advance(struct replay_runtime* runtime) | |
608 | { | |
609 | struct replay_moment* mom; | |
610 | if(!runtime->now) { | |
611 | advance_moment(runtime); | |
612 | return; | |
613 | } | |
614 | log_info("testbound: do STEP %d %s", runtime->now->time_step, | |
615 | repevt_string(runtime->now->evt_type)); | |
616 | switch(runtime->now->evt_type) { | |
617 | case repevt_nothing: | |
618 | advance_moment(runtime); | |
619 | break; | |
620 | case repevt_front_query: | |
621 | /* advance moment before doing the step, so that the next | |
622 | moment which may check some result of the mom step | |
623 | can catch those results. */ | |
624 | mom = runtime->now; | |
625 | advance_moment(runtime); | |
626 | fake_front_query(runtime, mom); | |
627 | break; | |
628 | case repevt_front_reply: | |
629 | if(runtime->answer_list) | |
630 | log_err("testbound: There are unmatched answers."); | |
631 | fatal_exit("testbound: query answer not matched"); | |
632 | break; | |
633 | case repevt_timeout: | |
634 | mom = runtime->now; | |
635 | advance_moment(runtime); | |
636 | expon_timeout_backoff(runtime); | |
637 | fake_pending_callback(runtime, mom, NETEVENT_TIMEOUT); | |
638 | break; | |
639 | case repevt_back_reply: | |
640 | mom = runtime->now; | |
641 | advance_moment(runtime); | |
642 | fake_pending_callback(runtime, mom, NETEVENT_NOERROR); | |
643 | break; | |
644 | case repevt_back_query: | |
645 | /* Back queries are matched when they are sent out. */ | |
646 | log_err("No query matching the current moment was sent."); | |
647 | fatal_exit("testbound: back query not matched"); | |
648 | break; | |
649 | case repevt_error: | |
650 | mom = runtime->now; | |
651 | advance_moment(runtime); | |
652 | fake_pending_callback(runtime, mom, NETEVENT_CLOSED); | |
653 | break; | |
654 | case repevt_time_passes: | |
655 | time_passes(runtime, runtime->now); | |
656 | advance_moment(runtime); | |
657 | break; | |
658 | case repevt_autotrust_check: | |
659 | autotrust_check(runtime, runtime->now); | |
660 | advance_moment(runtime); | |
661 | break; | |
662 | case repevt_assign: | |
663 | moment_assign(runtime, runtime->now); | |
664 | advance_moment(runtime); | |
665 | break; | |
666 | case repevt_traffic: | |
667 | advance_moment(runtime); | |
668 | break; | |
669 | case repevt_infra_rtt: | |
670 | do_infra_rtt(runtime); | |
671 | advance_moment(runtime); | |
672 | break; | |
673 | default: | |
674 | fatal_exit("testbound: unknown event type %d", | |
675 | runtime->now->evt_type); | |
676 | } | |
677 | } | |
678 | ||
679 | /** run the scenario in event callbacks */ | |
680 | static void | |
681 | run_scenario(struct replay_runtime* runtime) | |
682 | { | |
683 | struct entry* entry = NULL; | |
684 | struct fake_pending* pending = NULL; | |
685 | int max_rounds = 5000; | |
686 | int rounds = 0; | |
687 | runtime->now = runtime->scenario->mom_first; | |
688 | log_info("testbound: entering fake runloop"); | |
689 | do { | |
690 | /* if moment matches pending query do it. */ | |
691 | /* else if moment matches given answer, do it */ | |
692 | /* else if precoded_range matches pending, do it */ | |
693 | /* else do the current moment */ | |
694 | if(pending_matches_current(runtime, &entry, &pending)) { | |
695 | log_info("testbound: do STEP %d CHECK_OUT_QUERY", | |
696 | runtime->now->time_step); | |
697 | advance_moment(runtime); | |
698 | if(entry->copy_id) | |
699 | answer_callback_from_entry(runtime, entry, | |
700 | pending); | |
701 | } else if(runtime->answer_list && runtime->now && | |
702 | runtime->now->evt_type == repevt_front_reply) { | |
703 | answer_check_it(runtime); | |
704 | advance_moment(runtime); | |
705 | } else if(pending_matches_range(runtime, &entry, &pending)) { | |
706 | answer_callback_from_entry(runtime, entry, pending); | |
707 | } else { | |
708 | do_moment_and_advance(runtime); | |
709 | } | |
710 | log_info("testbound: end of event stage"); | |
711 | rounds++; | |
712 | if(rounds > max_rounds) | |
713 | fatal_exit("testbound: too many rounds, it loops."); | |
714 | } while(runtime->now); | |
715 | ||
716 | if(runtime->pending_list) { | |
717 | struct fake_pending* p; | |
718 | log_err("testbound: there are still messages pending."); | |
719 | for(p = runtime->pending_list; p; p=p->next) { | |
720 | log_pkt("pending msg", p->pkt, p->pkt_len); | |
721 | log_addr(0, "pending to", &p->addr, p->addrlen); | |
722 | } | |
723 | fatal_exit("testbound: there are still messages pending."); | |
724 | } | |
725 | if(runtime->answer_list) { | |
726 | fatal_exit("testbound: there are unmatched answers."); | |
727 | } | |
728 | log_info("testbound: exiting fake runloop."); | |
729 | runtime->exit_cleanly = 1; | |
730 | } | |
731 | ||
732 | /*********** Dummy routines ***********/ | |
733 | ||
734 | struct listen_dnsport* | |
735 | listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports), | |
736 | size_t bufsize, int ATTR_UNUSED(tcp_accept_count), | |
737 | void* ATTR_UNUSED(sslctx), struct dt_env* ATTR_UNUSED(dtenv), | |
738 | comm_point_callback_t* cb, void* cb_arg) | |
739 | { | |
740 | struct replay_runtime* runtime = (struct replay_runtime*)base; | |
741 | struct listen_dnsport* l= calloc(1, sizeof(struct listen_dnsport)); | |
742 | if(!l) | |
743 | return NULL; | |
744 | l->base = base; | |
745 | l->udp_buff = sldns_buffer_new(bufsize); | |
746 | if(!l->udp_buff) { | |
747 | free(l); | |
748 | return NULL; | |
749 | } | |
750 | runtime->callback_query = cb; | |
751 | runtime->cb_arg = cb_arg; | |
752 | runtime->bufsize = bufsize; | |
753 | return l; | |
754 | } | |
755 | ||
756 | void | |
757 | listen_delete(struct listen_dnsport* listen) | |
758 | { | |
759 | if(!listen) | |
760 | return; | |
761 | sldns_buffer_free(listen->udp_buff); | |
762 | free(listen); | |
763 | } | |
764 | ||
765 | struct comm_base* | |
766 | comm_base_create(int ATTR_UNUSED(sigs)) | |
767 | { | |
768 | /* we return the runtime structure instead. */ | |
769 | struct replay_runtime* runtime = (struct replay_runtime*) | |
770 | calloc(1, sizeof(struct replay_runtime)); | |
771 | runtime->scenario = saved_scenario; | |
772 | runtime->vars = macro_store_create(); | |
773 | if(!runtime->vars) fatal_exit("out of memory"); | |
774 | return (struct comm_base*)runtime; | |
775 | } | |
776 | ||
777 | void | |
778 | comm_base_delete(struct comm_base* b) | |
779 | { | |
780 | struct replay_runtime* runtime = (struct replay_runtime*)b; | |
781 | struct fake_pending* p, *np; | |
782 | struct replay_answer* a, *na; | |
783 | struct fake_timer* t, *nt; | |
784 | if(!runtime) | |
785 | return; | |
786 | runtime->scenario= NULL; | |
787 | p = runtime->pending_list; | |
788 | while(p) { | |
789 | np = p->next; | |
790 | delete_fake_pending(p); | |
791 | p = np; | |
792 | } | |
793 | a = runtime->answer_list; | |
794 | while(a) { | |
795 | na = a->next; | |
796 | delete_replay_answer(a); | |
797 | a = na; | |
798 | } | |
799 | t = runtime->timer_list; | |
800 | while(t) { | |
801 | nt = t->next; | |
802 | free(t); | |
803 | t = nt; | |
804 | } | |
805 | macro_store_delete(runtime->vars); | |
806 | free(runtime); | |
807 | } | |
808 | ||
809 | void | |
810 | comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv) | |
811 | { | |
812 | struct replay_runtime* runtime = (struct replay_runtime*)b; | |
813 | *tt = &runtime->now_secs; | |
814 | *tv = &runtime->now_tv; | |
815 | } | |
816 | ||
817 | void | |
818 | comm_base_dispatch(struct comm_base* b) | |
819 | { | |
820 | struct replay_runtime* runtime = (struct replay_runtime*)b; | |
821 | run_scenario(runtime); | |
822 | if(runtime->sig_cb) | |
823 | (*runtime->sig_cb)(SIGTERM, runtime->sig_cb_arg); | |
824 | else exit(0); /* OK exit when LIBEVENT_SIGNAL_PROBLEM exists */ | |
825 | } | |
826 | ||
827 | void | |
828 | comm_base_exit(struct comm_base* b) | |
829 | { | |
830 | struct replay_runtime* runtime = (struct replay_runtime*)b; | |
831 | if(!runtime->exit_cleanly) { | |
832 | /* some sort of failure */ | |
833 | fatal_exit("testbound: comm_base_exit was called."); | |
834 | } | |
835 | } | |
836 | ||
837 | struct comm_signal* | |
838 | comm_signal_create(struct comm_base* base, | |
839 | void (*callback)(int, void*), void* cb_arg) | |
840 | { | |
841 | struct replay_runtime* runtime = (struct replay_runtime*)base; | |
842 | runtime->sig_cb = callback; | |
843 | runtime->sig_cb_arg = cb_arg; | |
844 | return calloc(1, sizeof(struct comm_signal)); | |
845 | } | |
846 | ||
847 | int | |
848 | comm_signal_bind(struct comm_signal* ATTR_UNUSED(comsig), int | |
849 | ATTR_UNUSED(sig)) | |
850 | { | |
851 | return 1; | |
852 | } | |
853 | ||
854 | void | |
855 | comm_signal_delete(struct comm_signal* comsig) | |
856 | { | |
857 | free(comsig); | |
858 | } | |
859 | ||
860 | void | |
861 | comm_point_send_reply(struct comm_reply* repinfo) | |
862 | { | |
863 | struct replay_answer* ans = (struct replay_answer*)calloc(1, | |
864 | sizeof(struct replay_answer)); | |
865 | struct replay_runtime* runtime = (struct replay_runtime*)repinfo->c->ev; | |
866 | log_info("testbound: comm_point_send_reply fake"); | |
867 | /* dump it into the todo list */ | |
868 | log_assert(ans); | |
869 | memcpy(&ans->repinfo, repinfo, sizeof(struct comm_reply)); | |
870 | ans->next = NULL; | |
871 | if(runtime->answer_last) | |
872 | runtime->answer_last->next = ans; | |
873 | else runtime->answer_list = ans; | |
874 | runtime->answer_last = ans; | |
875 | ||
876 | /* try to parse packet */ | |
877 | ans->pkt = memdup(sldns_buffer_begin(ans->repinfo.c->buffer), | |
878 | sldns_buffer_limit(ans->repinfo.c->buffer)); | |
879 | ans->pkt_len = sldns_buffer_limit(ans->repinfo.c->buffer); | |
880 | if(!ans->pkt) fatal_exit("out of memory"); | |
881 | log_pkt("reply pkt: ", ans->pkt, ans->pkt_len); | |
882 | } | |
883 | ||
884 | void | |
885 | comm_point_drop_reply(struct comm_reply* repinfo) | |
886 | { | |
887 | log_info("comm_point_drop_reply fake"); | |
888 | if(repinfo->c) { | |
889 | sldns_buffer_free(repinfo->c->buffer); | |
890 | free(repinfo->c); | |
891 | } | |
892 | } | |
893 | ||
894 | struct outside_network* | |
895 | outside_network_create(struct comm_base* base, size_t bufsize, | |
896 | size_t ATTR_UNUSED(num_ports), char** ATTR_UNUSED(ifs), | |
897 | int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4), | |
898 | int ATTR_UNUSED(do_ip6), size_t ATTR_UNUSED(num_tcp), | |
899 | struct infra_cache* infra, | |
900 | struct ub_randstate* ATTR_UNUSED(rnd), | |
901 | int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports), | |
902 | int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold), | |
903 | void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param), | |
904 | int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx), | |
905 | int ATTR_UNUSED(delayclose), struct dt_env* ATTR_UNUSED(dtenv)) | |
906 | { | |
907 | struct replay_runtime* runtime = (struct replay_runtime*)base; | |
908 | struct outside_network* outnet = calloc(1, | |
909 | sizeof(struct outside_network)); | |
910 | (void)unwanted_action; | |
911 | if(!outnet) | |
912 | return NULL; | |
913 | runtime->infra = infra; | |
914 | outnet->base = base; | |
915 | outnet->udp_buff = sldns_buffer_new(bufsize); | |
916 | if(!outnet->udp_buff) { | |
917 | free(outnet); | |
918 | return NULL; | |
919 | } | |
920 | return outnet; | |
921 | } | |
922 | ||
923 | void | |
924 | outside_network_delete(struct outside_network* outnet) | |
925 | { | |
926 | if(!outnet) | |
927 | return; | |
928 | sldns_buffer_free(outnet->udp_buff); | |
929 | free(outnet); | |
930 | } | |
931 | ||
932 | void | |
933 | outside_network_quit_prepare(struct outside_network* ATTR_UNUSED(outnet)) | |
934 | { | |
935 | } | |
936 | ||
937 | struct pending* | |
938 | pending_udp_query(struct serviced_query* sq, sldns_buffer* packet, | |
939 | int timeout, comm_point_callback_t* callback, void* callback_arg) | |
940 | { | |
941 | struct replay_runtime* runtime = (struct replay_runtime*) | |
942 | sq->outnet->base; | |
943 | struct fake_pending* pend = (struct fake_pending*)calloc(1, | |
944 | sizeof(struct fake_pending)); | |
945 | log_assert(pend); | |
946 | pend->buffer = sldns_buffer_new(sldns_buffer_capacity(packet)); | |
947 | log_assert(pend->buffer); | |
948 | sldns_buffer_write(pend->buffer, sldns_buffer_begin(packet), | |
949 | sldns_buffer_limit(packet)); | |
950 | sldns_buffer_flip(pend->buffer); | |
951 | memcpy(&pend->addr, &sq->addr, sq->addrlen); | |
952 | pend->addrlen = sq->addrlen; | |
953 | pend->callback = callback; | |
954 | pend->cb_arg = callback_arg; | |
955 | pend->timeout = timeout/1000; | |
956 | pend->transport = transport_udp; | |
957 | pend->pkt = NULL; | |
958 | pend->zone = NULL; | |
959 | pend->serviced = 0; | |
960 | pend->runtime = runtime; | |
961 | pend->pkt_len = sldns_buffer_limit(packet); | |
962 | pend->pkt = memdup(sldns_buffer_begin(packet), pend->pkt_len); | |
963 | if(!pend->pkt) fatal_exit("out of memory"); | |
964 | log_pkt("pending udp pkt: ", pend->pkt, pend->pkt_len); | |
965 | ||
966 | /* see if it matches the current moment */ | |
967 | if(runtime->now && runtime->now->evt_type == repevt_back_query && | |
968 | (runtime->now->addrlen == 0 || sockaddr_cmp( | |
969 | &runtime->now->addr, runtime->now->addrlen, | |
970 | &pend->addr, pend->addrlen) == 0) && | |
971 | find_match(runtime->now->match, pend->pkt, pend->pkt_len, | |
972 | pend->transport)) { | |
973 | log_info("testbound: matched pending to event. " | |
974 | "advance time between events."); | |
975 | log_info("testbound: do STEP %d %s", runtime->now->time_step, | |
976 | repevt_string(runtime->now->evt_type)); | |
977 | advance_moment(runtime); | |
978 | /* still create the pending, because we need it to callback */ | |
979 | } | |
980 | log_info("testbound: created fake pending"); | |
981 | /* add to list */ | |
982 | pend->next = runtime->pending_list; | |
983 | runtime->pending_list = pend; | |
984 | return (struct pending*)pend; | |
985 | } | |
986 | ||
987 | struct waiting_tcp* | |
988 | pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet, | |
989 | int timeout, comm_point_callback_t* callback, void* callback_arg) | |
990 | { | |
991 | struct replay_runtime* runtime = (struct replay_runtime*) | |
992 | sq->outnet->base; | |
993 | struct fake_pending* pend = (struct fake_pending*)calloc(1, | |
994 | sizeof(struct fake_pending)); | |
995 | log_assert(pend); | |
996 | pend->buffer = sldns_buffer_new(sldns_buffer_capacity(packet)); | |
997 | log_assert(pend->buffer); | |
998 | sldns_buffer_write(pend->buffer, sldns_buffer_begin(packet), | |
999 | sldns_buffer_limit(packet)); | |
1000 | sldns_buffer_flip(pend->buffer); | |
1001 | memcpy(&pend->addr, &sq->addr, sq->addrlen); | |
1002 | pend->addrlen = sq->addrlen; | |
1003 | pend->callback = callback; | |
1004 | pend->cb_arg = callback_arg; | |
1005 | pend->timeout = timeout; | |
1006 | pend->transport = transport_tcp; | |
1007 | pend->pkt = NULL; | |
1008 | pend->zone = NULL; | |
1009 | pend->runtime = runtime; | |
1010 | pend->serviced = 0; | |
1011 | pend->pkt_len = sldns_buffer_limit(packet); | |
1012 | pend->pkt = memdup(sldns_buffer_begin(packet), pend->pkt_len); | |
1013 | if(!pend->pkt) fatal_exit("out of memory"); | |
1014 | log_pkt("pending tcp pkt: ", pend->pkt, pend->pkt_len); | |
1015 | ||
1016 | /* see if it matches the current moment */ | |
1017 | if(runtime->now && runtime->now->evt_type == repevt_back_query && | |
1018 | (runtime->now->addrlen == 0 || sockaddr_cmp( | |
1019 | &runtime->now->addr, runtime->now->addrlen, | |
1020 | &pend->addr, pend->addrlen) == 0) && | |
1021 | find_match(runtime->now->match, pend->pkt, pend->pkt_len, | |
1022 | pend->transport)) { | |
1023 | log_info("testbound: matched pending to event. " | |
1024 | "advance time between events."); | |
1025 | log_info("testbound: do STEP %d %s", runtime->now->time_step, | |
1026 | repevt_string(runtime->now->evt_type)); | |
1027 | advance_moment(runtime); | |
1028 | /* still create the pending, because we need it to callback */ | |
1029 | } | |
1030 | log_info("testbound: created fake pending"); | |
1031 | /* add to list */ | |
1032 | pend->next = runtime->pending_list; | |
1033 | runtime->pending_list = pend; | |
1034 | return (struct waiting_tcp*)pend; | |
1035 | } | |
1036 | ||
1037 | struct serviced_query* outnet_serviced_query(struct outside_network* outnet, | |
1038 | uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, | |
1039 | uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec), | |
1040 | int ATTR_UNUSED(nocaps), int ATTR_UNUSED(tcp_upstream), | |
1041 | int ATTR_UNUSED(ssl_upstream), struct sockaddr_storage* addr, | |
1042 | socklen_t addrlen, uint8_t* zone, size_t zonelen, | |
1043 | comm_point_callback_t* callback, void* callback_arg, | |
1044 | sldns_buffer* ATTR_UNUSED(buff)) | |
1045 | { | |
1046 | struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; | |
1047 | struct fake_pending* pend = (struct fake_pending*)calloc(1, | |
1048 | sizeof(struct fake_pending)); | |
1049 | char z[256]; | |
1050 | log_assert(pend); | |
1051 | log_nametypeclass(VERB_OPS, "pending serviced query", | |
1052 | qname, qtype, qclass); | |
1053 | dname_str(zone, z); | |
1054 | verbose(VERB_OPS, "pending serviced query zone %s flags%s%s%s%s", | |
1055 | z, (flags&BIT_RD)?" RD":"", (flags&BIT_CD)?" CD":"", | |
1056 | (flags&~(BIT_RD|BIT_CD))?" MORE":"", (dnssec)?" DO":""); | |
1057 | ||
1058 | /* create packet with EDNS */ | |
1059 | pend->buffer = sldns_buffer_new(512); | |
1060 | log_assert(pend->buffer); | |
1061 | sldns_buffer_write_u16(pend->buffer, 0); /* id */ | |
1062 | sldns_buffer_write_u16(pend->buffer, flags); | |
1063 | sldns_buffer_write_u16(pend->buffer, 1); /* qdcount */ | |
1064 | sldns_buffer_write_u16(pend->buffer, 0); /* ancount */ | |
1065 | sldns_buffer_write_u16(pend->buffer, 0); /* nscount */ | |
1066 | sldns_buffer_write_u16(pend->buffer, 0); /* arcount */ | |
1067 | sldns_buffer_write(pend->buffer, qname, qnamelen); | |
1068 | sldns_buffer_write_u16(pend->buffer, qtype); | |
1069 | sldns_buffer_write_u16(pend->buffer, qclass); | |
1070 | sldns_buffer_flip(pend->buffer); | |
1071 | if(1) { | |
1072 | /* add edns */ | |
1073 | struct edns_data edns; | |
1074 | edns.edns_present = 1; | |
1075 | edns.ext_rcode = 0; | |
1076 | edns.edns_version = EDNS_ADVERTISED_VERSION; | |
1077 | edns.udp_size = EDNS_ADVERTISED_SIZE; | |
1078 | edns.bits = 0; | |
1079 | if(dnssec) | |
1080 | edns.bits = EDNS_DO; | |
1081 | attach_edns_record(pend->buffer, &edns); | |
1082 | } | |
1083 | memcpy(&pend->addr, addr, addrlen); | |
1084 | pend->addrlen = addrlen; | |
1085 | pend->zone = memdup(zone, zonelen); | |
1086 | pend->zonelen = zonelen; | |
1087 | pend->qtype = (int)qtype; | |
1088 | log_assert(pend->zone); | |
1089 | pend->callback = callback; | |
1090 | pend->cb_arg = callback_arg; | |
1091 | pend->timeout = UDP_AUTH_QUERY_TIMEOUT; | |
1092 | pend->transport = transport_udp; /* pretend UDP */ | |
1093 | pend->pkt = NULL; | |
1094 | pend->runtime = runtime; | |
1095 | pend->serviced = 1; | |
1096 | pend->pkt_len = sldns_buffer_limit(pend->buffer); | |
1097 | pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len); | |
1098 | if(!pend->pkt) fatal_exit("out of memory"); | |
1099 | /*log_pkt("pending serviced query: ", pend->pkt, pend->pkt_len);*/ | |
1100 | ||
1101 | /* see if it matches the current moment */ | |
1102 | if(runtime->now && runtime->now->evt_type == repevt_back_query && | |
1103 | (runtime->now->addrlen == 0 || sockaddr_cmp( | |
1104 | &runtime->now->addr, runtime->now->addrlen, | |
1105 | &pend->addr, pend->addrlen) == 0) && | |
1106 | find_match(runtime->now->match, pend->pkt, pend->pkt_len, | |
1107 | pend->transport)) { | |
1108 | log_info("testbound: matched pending to event. " | |
1109 | "advance time between events."); | |
1110 | log_info("testbound: do STEP %d %s", runtime->now->time_step, | |
1111 | repevt_string(runtime->now->evt_type)); | |
1112 | advance_moment(runtime); | |
1113 | /* still create the pending, because we need it to callback */ | |
1114 | } | |
1115 | log_info("testbound: created fake pending"); | |
1116 | /* add to list */ | |
1117 | pend->next = runtime->pending_list; | |
1118 | runtime->pending_list = pend; | |
1119 | return (struct serviced_query*)pend; | |
1120 | } | |
1121 | ||
1122 | void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg) | |
1123 | { | |
1124 | struct fake_pending* pend = (struct fake_pending*)sq; | |
1125 | struct replay_runtime* runtime = pend->runtime; | |
1126 | /* delete from the list */ | |
1127 | struct fake_pending* p = runtime->pending_list, *prev=NULL; | |
1128 | while(p) { | |
1129 | if(p == pend) { | |
1130 | log_assert(p->cb_arg == cb_arg); | |
1131 | log_info("serviced pending delete"); | |
1132 | if(prev) | |
1133 | prev->next = p->next; | |
1134 | else runtime->pending_list = p->next; | |
1135 | sldns_buffer_free(p->buffer); | |
1136 | free(p->pkt); | |
1137 | free(p->zone); | |
1138 | free(p); | |
1139 | return; | |
1140 | } | |
1141 | prev = p; | |
1142 | p = p->next; | |
1143 | } | |
1144 | log_info("double delete of pending serviced query"); | |
1145 | } | |
1146 | ||
1147 | struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg), | |
1148 | int* ATTR_UNUSED(reuseport)) | |
1149 | { | |
1150 | return calloc(1, 1); | |
1151 | } | |
1152 | ||
1153 | void listening_ports_free(struct listen_port* list) | |
1154 | { | |
1155 | free(list); | |
1156 | } | |
1157 | ||
1158 | struct comm_point* comm_point_create_local(struct comm_base* ATTR_UNUSED(base), | |
1159 | int ATTR_UNUSED(fd), size_t ATTR_UNUSED(bufsize), | |
1160 | comm_point_callback_t* ATTR_UNUSED(callback), | |
1161 | void* ATTR_UNUSED(callback_arg)) | |
1162 | { | |
1163 | return calloc(1, 1); | |
1164 | } | |
1165 | ||
1166 | struct comm_point* comm_point_create_raw(struct comm_base* ATTR_UNUSED(base), | |
1167 | int ATTR_UNUSED(fd), int ATTR_UNUSED(writing), | |
1168 | comm_point_callback_t* ATTR_UNUSED(callback), | |
1169 | void* ATTR_UNUSED(callback_arg)) | |
1170 | { | |
1171 | /* no pipe comm possible */ | |
1172 | return calloc(1, 1); | |
1173 | } | |
1174 | ||
1175 | void comm_point_start_listening(struct comm_point* ATTR_UNUSED(c), | |
1176 | int ATTR_UNUSED(newfd), int ATTR_UNUSED(sec)) | |
1177 | { | |
1178 | /* no bg write pipe comm possible */ | |
1179 | } | |
1180 | ||
1181 | void comm_point_stop_listening(struct comm_point* ATTR_UNUSED(c)) | |
1182 | { | |
1183 | /* no bg write pipe comm possible */ | |
1184 | } | |
1185 | ||
1186 | /* only cmd com _local gets deleted */ | |
1187 | void comm_point_delete(struct comm_point* c) | |
1188 | { | |
1189 | free(c); | |
1190 | } | |
1191 | ||
1192 | size_t listen_get_mem(struct listen_dnsport* ATTR_UNUSED(listen)) | |
1193 | { | |
1194 | return 0; | |
1195 | } | |
1196 | ||
1197 | size_t outnet_get_mem(struct outside_network* ATTR_UNUSED(outnet)) | |
1198 | { | |
1199 | return 0; | |
1200 | } | |
1201 | ||
1202 | size_t comm_point_get_mem(struct comm_point* ATTR_UNUSED(c)) | |
1203 | { | |
1204 | return 0; | |
1205 | } | |
1206 | ||
1207 | size_t serviced_get_mem(struct serviced_query* ATTR_UNUSED(c)) | |
1208 | { | |
1209 | return 0; | |
1210 | } | |
1211 | ||
1212 | /* fake for fptr wlist */ | |
1213 | int outnet_udp_cb(struct comm_point* ATTR_UNUSED(c), | |
1214 | void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), | |
1215 | struct comm_reply *ATTR_UNUSED(reply_info)) | |
1216 | { | |
1217 | log_assert(0); | |
1218 | return 0; | |
1219 | } | |
1220 | ||
1221 | int outnet_tcp_cb(struct comm_point* ATTR_UNUSED(c), | |
1222 | void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), | |
1223 | struct comm_reply *ATTR_UNUSED(reply_info)) | |
1224 | { | |
1225 | log_assert(0); | |
1226 | return 0; | |
1227 | } | |
1228 | ||
1229 | void pending_udp_timer_cb(void *ATTR_UNUSED(arg)) | |
1230 | { | |
1231 | log_assert(0); | |
1232 | } | |
1233 | ||
1234 | void pending_udp_timer_delay_cb(void *ATTR_UNUSED(arg)) | |
1235 | { | |
1236 | log_assert(0); | |
1237 | } | |
1238 | ||
1239 | void outnet_tcptimer(void* ATTR_UNUSED(arg)) | |
1240 | { | |
1241 | log_assert(0); | |
1242 | } | |
1243 | ||
1244 | void comm_point_udp_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event), | |
1245 | void* ATTR_UNUSED(arg)) | |
1246 | { | |
1247 | log_assert(0); | |
1248 | } | |
1249 | ||
1250 | void comm_point_udp_ancil_callback(int ATTR_UNUSED(fd), | |
1251 | short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) | |
1252 | { | |
1253 | log_assert(0); | |
1254 | } | |
1255 | ||
1256 | void comm_point_tcp_accept_callback(int ATTR_UNUSED(fd), | |
1257 | short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) | |
1258 | { | |
1259 | log_assert(0); | |
1260 | } | |
1261 | ||
1262 | void comm_point_tcp_handle_callback(int ATTR_UNUSED(fd), | |
1263 | short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) | |
1264 | { | |
1265 | log_assert(0); | |
1266 | } | |
1267 | ||
1268 | void comm_timer_callback(int ATTR_UNUSED(fd), | |
1269 | short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) | |
1270 | { | |
1271 | log_assert(0); | |
1272 | } | |
1273 | ||
1274 | void comm_signal_callback(int ATTR_UNUSED(fd), | |
1275 | short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) | |
1276 | { | |
1277 | log_assert(0); | |
1278 | } | |
1279 | ||
1280 | void comm_point_local_handle_callback(int ATTR_UNUSED(fd), | |
1281 | short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) | |
1282 | { | |
1283 | log_assert(0); | |
1284 | } | |
1285 | ||
1286 | void comm_point_raw_handle_callback(int ATTR_UNUSED(fd), | |
1287 | short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) | |
1288 | { | |
1289 | log_assert(0); | |
1290 | } | |
1291 | ||
1292 | void comm_base_handle_slow_accept(int ATTR_UNUSED(fd), | |
1293 | short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) | |
1294 | { | |
1295 | log_assert(0); | |
1296 | } | |
1297 | ||
1298 | int serviced_udp_callback(struct comm_point* ATTR_UNUSED(c), | |
1299 | void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), | |
1300 | struct comm_reply* ATTR_UNUSED(reply_info)) | |
1301 | { | |
1302 | log_assert(0); | |
1303 | return 0; | |
1304 | } | |
1305 | ||
1306 | int serviced_tcp_callback(struct comm_point* ATTR_UNUSED(c), | |
1307 | void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), | |
1308 | struct comm_reply* ATTR_UNUSED(reply_info)) | |
1309 | { | |
1310 | log_assert(0); | |
1311 | return 0; | |
1312 | } | |
1313 | ||
1314 | int pending_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) | |
1315 | { | |
1316 | log_assert(0); | |
1317 | return 0; | |
1318 | } | |
1319 | ||
1320 | int serviced_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) | |
1321 | { | |
1322 | log_assert(0); | |
1323 | return 0; | |
1324 | } | |
1325 | ||
1326 | /* timers in testbound for autotrust. statistics tested in tpkg. */ | |
1327 | struct comm_timer* comm_timer_create(struct comm_base* base, | |
1328 | void (*cb)(void*), void* cb_arg) | |
1329 | { | |
1330 | struct replay_runtime* runtime = (struct replay_runtime*)base; | |
1331 | struct fake_timer* t = (struct fake_timer*)calloc(1, sizeof(*t)); | |
1332 | t->cb = cb; | |
1333 | t->cb_arg = cb_arg; | |
1334 | fptr_ok(fptr_whitelist_comm_timer(t->cb)); /* check in advance */ | |
1335 | t->runtime = runtime; | |
1336 | t->next = runtime->timer_list; | |
1337 | runtime->timer_list = t; | |
1338 | return (struct comm_timer*)t; | |
1339 | } | |
1340 | ||
1341 | void comm_timer_disable(struct comm_timer* timer) | |
1342 | { | |
1343 | struct fake_timer* t = (struct fake_timer*)timer; | |
1344 | log_info("fake timer disabled"); | |
1345 | t->enabled = 0; | |
1346 | } | |
1347 | ||
1348 | void comm_timer_set(struct comm_timer* timer, struct timeval* tv) | |
1349 | { | |
1350 | struct fake_timer* t = (struct fake_timer*)timer; | |
1351 | t->enabled = 1; | |
1352 | t->tv = *tv; | |
1353 | log_info("fake timer set %d.%6.6d", | |
1354 | (int)t->tv.tv_sec, (int)t->tv.tv_usec); | |
1355 | timeval_add(&t->tv, &t->runtime->now_tv); | |
1356 | } | |
1357 | ||
1358 | void comm_timer_delete(struct comm_timer* timer) | |
1359 | { | |
1360 | struct fake_timer* t = (struct fake_timer*)timer; | |
1361 | struct fake_timer** pp, *p; | |
1362 | if(!t) return; | |
1363 | ||
1364 | /* remove from linked list */ | |
1365 | pp = &t->runtime->timer_list; | |
1366 | p = t->runtime->timer_list; | |
1367 | while(p) { | |
1368 | if(p == t) { | |
1369 | /* snip from list */ | |
1370 | *pp = p->next; | |
1371 | break; | |
1372 | } | |
1373 | pp = &p->next; | |
1374 | p = p->next; | |
1375 | } | |
1376 | ||
1377 | free(timer); | |
1378 | } | |
1379 | ||
1380 | void comm_base_set_slow_accept_handlers(struct comm_base* ATTR_UNUSED(b), | |
1381 | void (*stop_acc)(void*), void (*start_acc)(void*), | |
1382 | void* ATTR_UNUSED(arg)) | |
1383 | { | |
1384 | /* ignore this */ | |
1385 | (void)stop_acc; | |
1386 | (void)start_acc; | |
1387 | } | |
1388 | ||
1389 | struct event_base* comm_base_internal(struct comm_base* ATTR_UNUSED(b)) | |
1390 | { | |
1391 | /* no pipe comm possible in testbound */ | |
1392 | return NULL; | |
1393 | } | |
1394 | ||
1395 | void daemon_remote_exec(struct worker* ATTR_UNUSED(worker)) | |
1396 | { | |
1397 | } | |
1398 | ||
1399 | void listen_start_accept(struct listen_dnsport* ATTR_UNUSED(listen)) | |
1400 | { | |
1401 | } | |
1402 | ||
1403 | void listen_stop_accept(struct listen_dnsport* ATTR_UNUSED(listen)) | |
1404 | { | |
1405 | } | |
1406 | ||
1407 | void daemon_remote_start_accept(struct daemon_remote* ATTR_UNUSED(rc)) | |
1408 | { | |
1409 | } | |
1410 | ||
1411 | void daemon_remote_stop_accept(struct daemon_remote* ATTR_UNUSED(rc)) | |
1412 | { | |
1413 | } | |
1414 | ||
1415 | /*********** End of Dummy routines ***********/ |