1 /*
2 * sc_speedtrap
3 *
4 * $Id: sc_speedtrap.c,v 1.63 2021/08/22 08:11:53 mjl Exp $
5 *
6 * Matthew Luckie
7 * mjl@luckie.org.nz
8 *
9 * Copyright (C) 2013-2015 The Regents of the University of California
10 * Copyright (C) 2016,2020 The University of Waikato
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, version 2.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 #include "internal.h"
31
32 #ifdef HAVE_PTHREAD
33 #include <pthread.h>
34 #endif
35
36 #include "scamper_addr.h"
37 #include "scamper_list.h"
38 #include "ping/scamper_ping.h"
39 #include "dealias/scamper_dealias.h"
40 #include "scamper_linepoll.h"
41 #include "scamper_writebuf.h"
42 #include "scamper_file.h"
43 #include "mjl_list.h"
44 #include "mjl_splaytree.h"
45 #include "mjl_heap.h"
46 #include "mjl_threadpool.h"
47 #include "utils.h"
48
49 #define OPT_HELP 0x0001
50 #define OPT_ADDRFILE 0x0002
51 #define OPT_OUTFILE 0x0004
52 #define OPT_PORT 0x0008
53 #define OPT_STOP 0x0010
54 #define OPT_LOG 0x0020
55 #define OPT_UNIX 0x0040
56 #define OPT_DUMP 0x0200
57 #define OPT_INCR 0x0400
58 #define OPT_THREADC 0x0800
59 #define OPT_ALL 0xffff
60
61 typedef struct sc_targetipid sc_targetipid_t;
62 typedef struct sc_targetset sc_targetset_t;
63
64 /*
65 * sc_target
66 *
67 * keep a set of IPID samples for a given interface address.
68 */
69 typedef struct sc_target
70 {
71 scamper_addr_t *addr; /* the interface being probed */
72 slist_t *samples; /* collected samples */
73 uint32_t last; /* last IPID sample */
74 sc_targetset_t *ts; /* pointer to ts that has probing lock */
75 int attempt; /* how many times we've tried this probe */
76 splaytree_node_t *tree_node;
77 } sc_target_t;
78
79 /*
80 * sc_targetipid
81 *
82 * an IPID sample, including tx and rx timestamps.
83 */
84 struct sc_targetipid
85 {
86 sc_target_t *target;
87 struct timeval tx, rx;
88 uint32_t ipid;
89 };
90
91 /*
92 * sc_targetset
93 *
94 * state kept when probing a set of addresses.
95 */
96 struct sc_targetset
97 {
98 slist_t *targets;
99 slist_node_t *next; /* next is used in mode overlap */
100 struct timeval min, max; /* min + max are used in mode overlap */
101 slist_t *blocked; /* blocked is used in mode overlap and ally */
102 dlist_node_t *node;
103 int attempt; /* attempt is used in mode ally */
104 };
105
106 typedef struct sc_wait
107 {
108 struct timeval tv;
109 union
110 {
111 void *ptr;
112 sc_target_t *target;
113 sc_targetset_t *targetset;
114 } un;
115 } sc_wait_t;
116
117 /*
118 * sc_router_t
119 *
120 * collect a set of interfaces mapped to a router
121 */
122 typedef struct sc_router
123 {
124 slist_t *addrs;
125 dlist_node_t *node;
126 } sc_router_t;
127
128 /*
129 * sc_addr2router_t
130 *
131 * map an address to a router.
132 */
133 typedef struct sc_addr2router
134 {
135 scamper_addr_t *addr;
136 sc_router_t *router;
137 } sc_addr2router_t;
138
139 typedef struct sc_addr2ptr
140 {
141 scamper_addr_t *addr;
142 void *ptr;
143 } sc_addr2ptr_t;
144
145 typedef struct sc_pairwise
146 {
147 sc_target_t *ta; /* the node to consider */
148 slist_node_t *sb; /* other nodes after ta in the list */
149 } sc_pairwise_t;
150
151 typedef struct sc_notaliases
152 {
153 sc_router_t *r;
154 splaytree_node_t *tree_node;
155 splaytree_t *tree;
156 } sc_notaliases_t;
157
158 typedef struct sc_dump
159 {
160 char *descr;
161 int (*proc_ping)(const scamper_ping_t *ping);
162 int (*proc_ally)(const scamper_dealias_t *dealias);
163 void (*finish)(void);
164 } sc_dump_t;
165
166 /* declare dump functions used for dump_funcs[] below */
167 static int process_1_ping(const scamper_ping_t *);
168 static int process_1_ally(const scamper_dealias_t *);
169 static void finish_1(void);
170 static int process_2_ping(const scamper_ping_t *);
171 static int process_3_ping(const scamper_ping_t *);
172 static int process_3_ally(const scamper_dealias_t *);
173 static void finish_3(void);
174 static int process_4_ping(const scamper_ping_t *);
175 static void finish_4(void);
176
177 static uint32_t options = 0;
178 static char *addressfile = NULL;
179 static char *dst_addr = NULL;
180 static int dst_port = 0;
181 static char *unix_name = NULL;
182 static splaytree_t *targets = NULL;
183 static splaytree_t *addr2routers = NULL;
184 static dlist_t *routers = NULL;
185 static splaytree_t *notaliases = NULL;
186 static slist_t *probelist = NULL;
187 static heap_t *probeheap = NULL;
188 static slist_t *incr = NULL; /* descend and overlap */
189 static heap_t *waiting = NULL;
190 static int scamper_fd = -1;
191 static scamper_linepoll_t *scamper_lp = NULL;
192 static scamper_writebuf_t *scamper_wb = NULL;
193 static char *outfile_name = NULL;
194 static scamper_file_t *outfile = NULL;
195 static scamper_file_filter_t *ffilter = NULL;
196 static scamper_file_t *decode_in = NULL;
197 static int decode_in_fd = -1;
198 static int decode_out_fd = -1;
199 static scamper_writebuf_t *decode_wb = NULL;
200 static int data_left = 0;
201 static int more = 0;
202 static int probing = 0;
203 static int blocked = 0;
204 static int mode = 0;
205 static long threadc = -1;
206 static struct timeval now;
207 static FILE *logfile = NULL;
208 static uint32_t fudge = 65535;
209 static slist_t *descend = NULL;
210 static dlist_t *overlap_act = NULL;
211 static slist_t *candidates = NULL;
212 static const char *step_names[] = {"classify","descend","overlap",
213 "descend2","ally"};
214 static int step_namec = sizeof(step_names)/sizeof(char *);
215 static char *stop_stepname = NULL;
216 static int stop_stepid = 0;
217
218 static uint32_t *pairwise_uint32 = NULL;
219 static sc_targetipid_t **pairwise_tipid = NULL;
220 static int pairwise_max = 0;
221
222 #ifdef HAVE_PTHREAD
223 static pthread_mutex_t candidates_mutex;
224 #endif
225
226 static int dump_id = 0;
227 static int dump_stop = 0;
228 static char **dump_files;
229 static int dump_filec = 0;
230 static const sc_dump_t dump_funcs[] = {
231 {NULL, NULL, NULL, NULL},
232 {"dump transitive closure from ally probes",
233 process_1_ping, process_1_ally, finish_1},
234 {"dump interface classification",
235 process_2_ping, NULL, NULL},
236 {"summary table of per-stage statistics",
237 process_3_ping, process_3_ally, finish_3},
238 {"dump transitive closure from descend and overlap stages",
239 process_4_ping, NULL, finish_4},
240 };
241 static int dump_funcc = sizeof(dump_funcs) / sizeof(sc_dump_t);
242
243 #define MODE_CLASSIFY 0
244 #define MODE_DESCEND 1
245 #define MODE_OVERLAP 2
246 #define MODE_DESCEND2 3
247 #define MODE_ALLY 4
248
usage(uint32_t opt_mask)249 static void usage(uint32_t opt_mask)
250 {
251 int i;
252
253 fprintf(stderr,
254 "usage: sc_speedtrap [-a addr-file] [-o outfile] [-p [ip:]port] [-U unix]\n"
255 " [-I] [-l log] [-s stop]\n"
256 #ifdef HAVE_PTHREAD
257 " [-t thread-count]\n"
258 #endif
259 "\n"
260 " sc_speedtrap [-d dump] file1.warts .. fileN.warts\n"
261 "\n");
262
263 if(opt_mask == 0)
264 fprintf(stderr, " sc_speedtrap -?\n\n");
265
266 if(opt_mask & OPT_HELP)
267 fprintf(stderr, " -? give an overview of the usage of sc_speedtrap\n");
268
269 if(opt_mask & OPT_ADDRFILE)
270 fprintf(stderr, " -a input addressfile\n");
271
272 if(opt_mask & OPT_DUMP)
273 {
274 fprintf(stderr, " -d dump selection\n");
275 for(i=1; i<dump_funcc; i++)
276 printf(" %2d : %s\n", i, dump_funcs[i].descr);
277 }
278
279 if(opt_mask & OPT_INCR)
280 fprintf(stderr, " -I input addresses increment, skip classify step\n");
281
282 if(opt_mask & OPT_LOG)
283 fprintf(stderr, " -l output logfile\n");
284
285 if(opt_mask & OPT_OUTFILE)
286 fprintf(stderr, " -o output warts file\n");
287
288 if(opt_mask & OPT_PORT)
289 fprintf(stderr, " -p [ip:]port to find scamper on\n");
290
291 if(opt_mask & OPT_STOP)
292 {
293 fprintf(stderr,
294 " -s step to halt on completion of\n"
295 " [%s", step_names[0]);
296 for(i=1; i<step_namec; i++)
297 fprintf(stderr, "|%s", step_names[i]);
298 fprintf(stderr, "]\n");
299 }
300
301 #ifdef HAVE_PTHREAD
302 if(opt_mask & OPT_THREADC)
303 fprintf(stderr, " -t number of threads to infer candidate sets\n");
304 #endif
305
306 if(opt_mask & OPT_UNIX)
307 fprintf(stderr, " -U unix domain to find scamper on\n");
308
309 return;
310 }
311
check_options(int argc,char * argv[])312 static int check_options(int argc, char *argv[])
313 {
314 long lo;
315 char *opts = "?a:d:Il:o:p:s:"
316 #ifdef HAVE_PTHREAD
317 "t:"
318 #endif
319 "U:w:";
320 char *opt_port = NULL, *opt_unix = NULL, *opt_log = NULL, *opt_dump = NULL;
321 int i, ch;
322
323 #ifdef HAVE_PTHREAD
324 char *opt_threadc = NULL;
325 #endif
326
327 while((ch = getopt(argc, argv, opts)) != -1)
328 {
329 switch(ch)
330 {
331 case 'a':
332 options |= OPT_ADDRFILE;
333 addressfile = optarg;
334 break;
335
336 case 'd':
337 options |= OPT_DUMP;
338 opt_dump = optarg;
339 break;
340
341 case 'I':
342 options |= OPT_INCR;
343 break;
344
345 case 'l':
346 options |= OPT_LOG;
347 opt_log = optarg;
348 break;
349
350 case 'o':
351 options |= OPT_OUTFILE;
352 outfile_name = optarg;
353 break;
354
355 case 'p':
356 options |= OPT_PORT;
357 opt_port = optarg;
358 break;
359
360 case 's':
361 options |= OPT_STOP;
362 stop_stepname = optarg;
363 break;
364
365 #ifdef HAVE_PTHREAD
366 case 't':
367 options |= OPT_THREADC;
368 opt_threadc = optarg;
369 break;
370 #endif
371
372 case 'U':
373 options |= OPT_UNIX;
374 opt_unix = optarg;
375 break;
376
377 case '?':
378 usage(OPT_ALL);
379 return -1;
380
381 default:
382 usage(0);
383 return -1;
384 }
385 }
386
387 if((options & (OPT_ADDRFILE|OPT_OUTFILE|OPT_DUMP)) != (OPT_ADDRFILE|OPT_OUTFILE) &&
388 (options & (OPT_ADDRFILE|OPT_OUTFILE|OPT_DUMP)) != OPT_DUMP)
389 {
390 usage(0);
391 return -1;
392 }
393
394 if(options & (OPT_ADDRFILE|OPT_OUTFILE))
395 {
396 if((options & (OPT_PORT|OPT_UNIX)) == 0 ||
397 (options & (OPT_PORT|OPT_UNIX)) == (OPT_PORT|OPT_UNIX) ||
398 argc - optind > 0)
399 {
400 usage(OPT_ADDRFILE|OPT_OUTFILE|OPT_PORT|OPT_UNIX);
401 return -1;
402 }
403
404 if(options & OPT_PORT)
405 {
406 if(string_addrport(opt_port, &dst_addr, &dst_port) != 0)
407 {
408 usage(OPT_PORT);
409 return -1;
410 }
411 }
412 else if(options & OPT_UNIX)
413 {
414 unix_name = opt_unix;
415 }
416
417 #ifdef HAVE_PTHREAD
418 if(opt_threadc != NULL)
419 {
420 if(string_tolong(opt_threadc, &lo) != 0 || lo < 0)
421 {
422 usage(OPT_THREADC);
423 return -1;
424 }
425 threadc = lo;
426 }
427 #endif
428
429 if(stop_stepname != NULL)
430 {
431 for(i=0; i<step_namec; i++)
432 {
433 if(strcasecmp(stop_stepname, step_names[i]) == 0)
434 {
435 stop_stepid = i;
436 break;
437 }
438 }
439 if(i == step_namec)
440 {
441 usage(OPT_STOP);
442 return -1;
443 }
444 }
445
446 if(opt_log != NULL)
447 {
448 if(string_isdash(opt_log) != 0)
449 {
450 logfile = stdout;
451 }
452 else if((logfile = fopen(opt_log, "w")) == NULL)
453 {
454 usage(OPT_LOG);
455 fprintf(stderr, "could not open %s\n", opt_log);
456 return -1;
457 }
458 }
459 }
460 else
461 {
462 if(argc - optind < 1)
463 {
464 usage(0);
465 return -1;
466 }
467 if(string_tolong(opt_dump, &lo) != 0 || lo < 1 || lo > dump_funcc)
468 {
469 usage(OPT_DUMP);
470 return -1;
471 }
472 dump_id = lo;
473 dump_files = argv + optind;
474 dump_filec = argc - optind;
475 }
476
477 return 0;
478 }
479
mode_ok(int m)480 static int mode_ok(int m)
481 {
482 if(stop_stepname == NULL)
483 return 1;
484 if(m > stop_stepid)
485 return 0;
486 return 1;
487 }
488
ptrcmp(const void * a,const void * b)489 static int ptrcmp(const void *a, const void *b)
490 {
491 if(a < b) return -1;
492 if(a > b) return 1;
493 return 0;
494 }
495
tree_to_slist(void * ptr,void * entry)496 static int tree_to_slist(void *ptr, void *entry)
497 {
498 slist_tail_push((slist_t *)ptr, entry);
499 return 0;
500 }
501
hms(int x,int * h,int * m,int * s)502 static void hms(int x, int *h, int *m, int *s)
503 {
504 *s = x % 60; x -= *s; x /= 60;
505 *m = x % 60; x -= *m;
506 *h = x / 60;
507 return;
508 }
509
logprint(int st,char * format,...)510 static void logprint(int st, char *format, ...)
511 {
512 va_list ap;
513 char msg[131072];
514 int pl;
515
516 if(logfile != NULL)
517 {
518 if(st != 0)
519 {
520 if(probeheap != NULL && heap_count(probeheap) > 0)
521 pl = heap_count(probeheap);
522 else
523 pl = slist_count(probelist);
524 fprintf(logfile, "%ld: p %d, w %d, l %d, b %d : ",
525 (long int)now.tv_sec,
526 probing, heap_count(waiting), pl, blocked);
527 }
528
529 va_start(ap, format);
530 vsnprintf(msg, sizeof(msg), format, ap);
531 va_end(ap);
532 fprintf(logfile, "%s", msg);
533 fflush(logfile);
534 }
535
536 return;
537 }
538
uint32_cmp(const void * va,const void * vb)539 static int uint32_cmp(const void *va, const void *vb)
540 {
541 const uint32_t a = *((uint32_t *)va);
542 const uint32_t b = *((uint32_t *)vb);
543 if(a < b) return -1;
544 if(a > b) return 1;
545 return 0;
546 }
547
uint32_find(uint32_t * a,size_t len,uint32_t u32)548 static int uint32_find(uint32_t *a, size_t len, uint32_t u32)
549 {
550 if(bsearch(&u32, a, len, sizeof(uint32_t), uint32_cmp) != NULL)
551 return 1;
552 return 0;
553 }
554
ipid_inseq3(uint64_t a,uint64_t b,uint64_t c)555 static int ipid_inseq3(uint64_t a, uint64_t b, uint64_t c)
556 {
557 if(a == b || b == c || a == c)
558 return 0;
559 if(a > b)
560 b += 0x100000000ULL;
561 if(a > c)
562 c += 0x100000000ULL;
563 if(a > b || b > c)
564 return 0;
565 if(fudge != 0 && (b - a > fudge || c - b > fudge))
566 return 0;
567 return 1;
568 }
569
ipid_incr(uint32_t * ipids,int ipidc)570 static int ipid_incr(uint32_t *ipids, int ipidc)
571 {
572 int i;
573 if(ipidc < 3)
574 return 0;
575 for(i=2; i<ipidc; i++)
576 if(ipid_inseq3(ipids[i-2], ipids[i-1], ipids[i]) == 0)
577 return 0;
578 return 1;
579 }
580
sc_addr2router_human_cmp(sc_addr2router_t * a,sc_addr2router_t * b)581 static int sc_addr2router_human_cmp(sc_addr2router_t *a, sc_addr2router_t *b)
582 {
583 return scamper_addr_human_cmp(a->addr, b->addr);
584 }
585
sc_addr2router_cmp(sc_addr2router_t * a,sc_addr2router_t * b)586 static int sc_addr2router_cmp(sc_addr2router_t *a, sc_addr2router_t *b)
587 {
588 return scamper_addr_cmp(a->addr, b->addr);
589 }
590
sc_addr2router_free(sc_addr2router_t * a2r)591 static void sc_addr2router_free(sc_addr2router_t *a2r)
592 {
593 if(a2r->addr != NULL) scamper_addr_free(a2r->addr);
594 free(a2r);
595 return;
596 }
597
sc_addr2router_find(scamper_addr_t * addr)598 static sc_addr2router_t *sc_addr2router_find(scamper_addr_t *addr)
599 {
600 sc_addr2router_t fm; fm.addr = addr;
601 return splaytree_find(addr2routers, &fm);
602 }
603
sc_addr2router_alloc(scamper_addr_t * a,sc_router_t * r)604 static sc_addr2router_t *sc_addr2router_alloc(scamper_addr_t *a, sc_router_t *r)
605 {
606 sc_addr2router_t *a2r = NULL;
607 if((a2r = malloc_zero(sizeof(sc_addr2router_t))) == NULL)
608 goto err;
609 a2r->addr = scamper_addr_use(a);
610 a2r->router = r;
611 if(splaytree_insert(addr2routers, a2r) == NULL)
612 goto err;
613 return a2r;
614
615 err:
616 if(a2r != NULL) sc_addr2router_free(a2r);
617 return NULL;
618 }
619
sc_router_cmp(const sc_router_t * a,const sc_router_t * b)620 static int sc_router_cmp(const sc_router_t *a, const sc_router_t *b)
621 {
622 int al = slist_count(a->addrs), bl = slist_count(b->addrs);
623 sc_addr2router_t *aa, *ab;
624 if(al > bl) return -1;
625 if(al < bl) return 1;
626 aa = slist_head_item(a->addrs);
627 ab = slist_head_item(b->addrs);
628 return scamper_addr_human_cmp(aa->addr, ab->addr);
629 }
630
sc_router_free(sc_router_t * r)631 static void sc_router_free(sc_router_t *r)
632 {
633 if(r->node != NULL) dlist_node_pop(routers, r->node);
634 if(r->addrs != NULL) slist_free(r->addrs);
635 free(r);
636 return;
637 }
638
sc_router_node_setnull(sc_router_t * r,void * param)639 static int sc_router_node_setnull(sc_router_t *r, void *param)
640 {
641 r->node = NULL;
642 return 0;
643 }
644
sc_router_alloc(void)645 static sc_router_t *sc_router_alloc(void)
646 {
647 sc_router_t *r;
648 if((r = malloc_zero(sizeof(sc_router_t))) == NULL ||
649 (r->addrs = slist_alloc()) == NULL ||
650 (r->node = dlist_tail_push(routers, r)) == NULL)
651 goto err;
652 return r;
653
654 err:
655 if(r != NULL) sc_router_free(r);
656 return NULL;
657 }
658
sc_notaliases_cmp(sc_notaliases_t * a,sc_notaliases_t * b)659 static int sc_notaliases_cmp(sc_notaliases_t *a, sc_notaliases_t *b)
660 {
661 return ptrcmp(a->r, b->r);
662 }
663
sc_notaliases_find(sc_router_t * r)664 static sc_notaliases_t *sc_notaliases_find(sc_router_t *r)
665 {
666 sc_notaliases_t fm; fm.r = r;
667 return splaytree_find(notaliases, &fm);
668 }
669
sc_notaliases_free(sc_notaliases_t * na)670 static void sc_notaliases_free(sc_notaliases_t *na)
671 {
672 if(na->tree != NULL) splaytree_free(na->tree, NULL);
673 free(na);
674 return;
675 }
676
sc_notaliases_alloc(sc_router_t * r)677 static sc_notaliases_t *sc_notaliases_alloc(sc_router_t *r)
678 {
679 sc_notaliases_t *na;
680 if((na = malloc_zero(sizeof(sc_notaliases_t))) == NULL ||
681 (na->tree = splaytree_alloc(ptrcmp)) == NULL)
682 goto err;
683 na->r = r;
684 if((na->tree_node = splaytree_insert(notaliases, na)) == NULL)
685 goto err;
686 return na;
687 err:
688 if(na != NULL) sc_notaliases_free(na);
689 return NULL;
690 }
691
692 /*
693 * sc_notaliases_add
694 *
695 * two routers are inferred to not be aliases, record that.
696 */
sc_notaliases_add(sc_router_t * a,sc_router_t * b)697 static int sc_notaliases_add(sc_router_t *a, sc_router_t *b)
698 {
699 sc_notaliases_t *na;
700
701 /*
702 * get a notaliases node for router a.
703 * if b is already known to be not alias, move on.
704 * otherwise, record the not-alias information.
705 */
706 if((na = sc_notaliases_find(a)) == NULL &&
707 (na = sc_notaliases_alloc(a)) == NULL)
708 return -1;
709 if(splaytree_find(na->tree, b) == NULL &&
710 splaytree_insert(na->tree, b) == NULL)
711 return -1;
712
713 /*
714 * get a notaliases node for router b.
715 * if a is already known to be not alias, move on.
716 * otherwise, record the not-alias information.
717 */
718 if((na = sc_notaliases_find(b)) == NULL &&
719 (na = sc_notaliases_alloc(b)) == NULL)
720 return -1;
721 if(splaytree_find(na->tree, a) == NULL &&
722 splaytree_insert(na->tree, a) == NULL)
723 return -1;
724
725 return 0;
726 }
727
728 /*
729 * sc_notaliases_merge_r
730 *
731 * merge c into na, and update c's notaliases by replacing b with a.
732 */
sc_notaliases_merge_r(sc_notaliases_t * na,sc_router_t * b,sc_router_t * c)733 static int sc_notaliases_merge_r(sc_notaliases_t *na,
734 sc_router_t *b, sc_router_t *c)
735 {
736 sc_notaliases_t *nc;
737
738 /* add c to na */
739 if(splaytree_find(na->tree, c) == NULL &&
740 splaytree_insert(na->tree, c) == NULL)
741 return -1;
742
743 /* remove b, replace with a */
744 if((nc = sc_notaliases_find(c)) == NULL ||
745 splaytree_remove_item(nc->tree, b) != 0)
746 return -1;
747 if(splaytree_find(nc->tree, na->r) == NULL &&
748 splaytree_insert(nc->tree, na->r) == NULL)
749 return -1;
750
751 return 0;
752 }
753
754 /*
755 * sc_notaliases_merge
756 *
757 * two routers (a and b) are inferred to be aliases. merge their
758 * notalias state and free b.
759 */
sc_notaliases_merge(sc_router_t * a,sc_router_t * b)760 static int sc_notaliases_merge(sc_router_t *a, sc_router_t *b)
761 {
762 slist_t *list = NULL;
763 sc_notaliases_t *na, *nb;
764 sc_router_t *c;
765 int rc = -1;
766
767 /* if we haven't got "not aliases" nodes for b, move on */
768 if((nb = sc_notaliases_find(b)) == NULL)
769 return 0;
770
771 if((list = slist_alloc()) == NULL ||
772 ((na = sc_notaliases_find(a)) == NULL &&
773 (na = sc_notaliases_alloc(a)) == NULL))
774 goto done;
775
776 splaytree_inorder(nb->tree, tree_to_slist, list);
777 while((c = slist_head_pop(list)) != NULL)
778 {
779 if(sc_notaliases_merge_r(na, b, c) != 0)
780 goto done;
781 }
782 splaytree_remove_node(notaliases, nb->tree_node);
783 sc_notaliases_free(nb);
784 rc = 0;
785
786 done:
787 if(list != NULL) slist_free(list);
788 return rc;
789 }
790
791 /*
792 * sc_notaliases_check
793 *
794 * check to see if two routers are already known to not be aliases
795 */
sc_notaliases_check(sc_router_t * a,sc_router_t * b)796 static int sc_notaliases_check(sc_router_t *a, sc_router_t *b)
797 {
798 sc_notaliases_t *na;
799 if((na = sc_notaliases_find(a)) == NULL ||
800 splaytree_find(na->tree, b) == NULL)
801 return 0;
802 return 1;
803 }
804
sc_wait_target(struct timeval * tv,sc_target_t * target)805 static int sc_wait_target(struct timeval *tv, sc_target_t *target)
806 {
807 sc_wait_t *w;
808 if((w = malloc_zero(sizeof(sc_wait_t))) == NULL)
809 return -1;
810 timeval_cpy(&w->tv, tv);
811 w->un.target = target;
812 if(heap_insert(waiting, w) == NULL)
813 return -1;
814 return 0;
815 }
816
sc_wait_targetset(struct timeval * tv,sc_targetset_t * targetset)817 static int sc_wait_targetset(struct timeval *tv, sc_targetset_t *targetset)
818 {
819 sc_wait_t *w;
820 if((w = malloc_zero(sizeof(sc_wait_t))) == NULL)
821 return -1;
822 timeval_cpy(&w->tv, tv);
823 w->un.targetset = targetset;
824 if(heap_insert(waiting, w) == NULL)
825 return -1;
826 return 0;
827 }
828
sc_wait_free(sc_wait_t * w)829 static void sc_wait_free(sc_wait_t *w)
830 {
831 free(w);
832 return;
833 }
834
sc_wait_cmp(const sc_wait_t * a,const sc_wait_t * b)835 static int sc_wait_cmp(const sc_wait_t *a, const sc_wait_t *b)
836 {
837 return timeval_cmp(&b->tv, &a->tv);
838 }
839
sc_target_addr_cmp(const sc_target_t * a,const sc_target_t * b)840 static int sc_target_addr_cmp(const sc_target_t *a, const sc_target_t *b)
841 {
842 return scamper_addr_cmp(a->addr, b->addr);
843 }
844
sc_target_ipid_cmp(const sc_target_t * a,const sc_target_t * b)845 static int sc_target_ipid_cmp(const sc_target_t *a, const sc_target_t *b)
846 {
847 if(a->last > b->last) return -1;
848 if(a->last < b->last) return 1;
849 return 0;
850 }
851
sc_target_findtree(scamper_addr_t * addr)852 static sc_target_t *sc_target_findtree(scamper_addr_t *addr)
853 {
854 sc_target_t fm;
855 fm.addr = addr;
856 return splaytree_find(targets, &fm);
857 }
858
sc_target_detachtree(sc_target_t * tg)859 static void sc_target_detachtree(sc_target_t *tg)
860 {
861 if(tg->tree_node != NULL)
862 {
863 splaytree_remove_node(targets, tg->tree_node);
864 tg->tree_node = NULL;
865 }
866 return;
867 }
868
sc_target_sample(sc_target_t * tg,sc_targetipid_t * x)869 static sc_targetipid_t *sc_target_sample(sc_target_t *tg, sc_targetipid_t *x)
870 {
871 sc_targetipid_t *ti;
872 if((ti = memdup(x, sizeof(sc_targetipid_t))) == NULL)
873 {
874 fprintf(stderr, "%s: could not memdup sample: %s\n",
875 __func__, strerror(errno));
876 return NULL;
877 }
878 ti->target = tg;
879 if(slist_tail_push(tg->samples, ti) == NULL)
880 {
881 fprintf(stderr, "%s: could not push sample: %s\n",
882 __func__, strerror(errno));
883 free(ti);
884 return NULL;
885 }
886 tg->last = ti->ipid;
887 return ti;
888 }
889
sc_target_free(sc_target_t * tg)890 static sc_target_t *sc_target_free(sc_target_t *tg)
891 {
892 if(tg == NULL)
893 return NULL;
894
895 if(tg->samples != NULL)
896 slist_free_cb(tg->samples, free);
897 if(tg->tree_node != NULL)
898 splaytree_remove_node(targets, tg->tree_node);
899 if(tg->addr != NULL)
900 scamper_addr_free(tg->addr);
901
902 free(tg);
903 return NULL;
904 }
905
sc_target_alloc(scamper_addr_t * addr)906 static sc_target_t *sc_target_alloc(scamper_addr_t *addr)
907 {
908 sc_target_t *target = NULL;
909
910 if((target = malloc_zero(sizeof(sc_target_t))) == NULL ||
911 (target->samples = slist_alloc()) == NULL)
912 goto err;
913 target->addr = scamper_addr_use(addr);
914 return target;
915
916 err:
917 if(target != NULL) sc_target_free(target);
918 return NULL;
919 }
920
sc_targetipid_tx_cmp(const sc_targetipid_t * a,const sc_targetipid_t * b)921 static int sc_targetipid_tx_cmp(const sc_targetipid_t *a,
922 const sc_targetipid_t *b)
923 {
924 return timeval_cmp(&a->tx, &b->tx);
925 }
926
sc_targetset_logprint(const sc_targetset_t * ts)927 static void sc_targetset_logprint(const sc_targetset_t *ts)
928 {
929 sc_target_t *tg;
930 slist_node_t *ss;
931 size_t off = 0;
932 char a[64], buf[131072];
933 string_concat(buf, sizeof(buf), &off, "%p:", ts);
934 for(ss=slist_head_node(ts->targets); ss != NULL; ss=slist_node_next(ss))
935 {
936 tg = slist_node_item(ss);
937 string_concat(buf, sizeof(buf), &off, " %s",
938 scamper_addr_tostr(tg->addr, a, sizeof(a)));
939 }
940 logprint(0, "%s\n", buf);
941 return;
942 }
943
sc_targetset_targetc_asc_cmp(const sc_targetset_t * a,const sc_targetset_t * b)944 static int sc_targetset_targetc_asc_cmp(const sc_targetset_t *a,
945 const sc_targetset_t *b)
946 {
947 int ac = slist_count(a->targets);
948 int bc = slist_count(b->targets);
949 if(ac < bc) return -1;
950 if(ac > bc) return 1;
951 return 0;
952 }
953
sc_targetset_targetc_desc_cmp(const sc_targetset_t * a,const sc_targetset_t * b)954 static int sc_targetset_targetc_desc_cmp(const sc_targetset_t *a,
955 const sc_targetset_t *b)
956 {
957 int ac = slist_count(a->targets);
958 int bc = slist_count(b->targets);
959 if(ac > bc) return -1;
960 if(ac < bc) return 1;
961 return 0;
962 }
963
sc_targetset_length_cmp(const sc_targetset_t * a,const sc_targetset_t * b)964 static int sc_targetset_length_cmp(const sc_targetset_t *a,
965 const sc_targetset_t *b)
966 {
967 struct timeval a_len, b_len;
968 timeval_diff_tv(&a_len, &a->min, &a->max);
969 timeval_diff_tv(&b_len, &b->min, &b->max);
970 return timeval_cmp(&b_len, &a_len);
971 }
972
sc_targetset_free(sc_targetset_t * ts)973 static void sc_targetset_free(sc_targetset_t *ts)
974 {
975 if(ts == NULL)
976 return;
977 if(ts->targets != NULL) slist_free(ts->targets);
978 if(ts->blocked != NULL) slist_free(ts->blocked);
979 free(ts);
980 return;
981 }
982
sc_targetset_alloc(void)983 static sc_targetset_t *sc_targetset_alloc(void)
984 {
985 sc_targetset_t *ts;
986 if((ts = malloc_zero(sizeof(sc_targetset_t))) == NULL ||
987 (ts->targets = slist_alloc()) == NULL ||
988 (ts->blocked = slist_alloc()) == NULL)
989 {
990 sc_targetset_free(ts);
991 return NULL;
992 }
993 return ts;
994 }
995
timeval_overlap(const struct timeval * a1,const struct timeval * a2,const struct timeval * b1,const struct timeval * b2)996 static int timeval_overlap(const struct timeval *a1, const struct timeval *a2,
997 const struct timeval *b1, const struct timeval *b2)
998 {
999 int rc = timeval_cmp(a1, b1);
1000
1001 if(rc < 0)
1002 {
1003 if(timeval_cmp(a2, b1) < 0)
1004 return 0; /* a=0,1 b=2,3 */
1005 else
1006 return 1; /* a=1,3 b=2,4 + a=0,6 b=1,5 */
1007 }
1008 else if(rc > 0)
1009 {
1010 if(timeval_cmp(b2, a1) < 0)
1011 return 0; /* a=2,3 b=0,1 */
1012 else
1013 return 1; /* a=2,4 b=1,3 + a=1,5 b=0,6 */
1014 }
1015
1016 return 1;
1017 }
1018
sample_overlap(const sc_targetipid_t * a,const sc_targetipid_t * b)1019 static int sample_overlap(const sc_targetipid_t *a, const sc_targetipid_t *b)
1020 {
1021 return timeval_overlap(&a->tx, &a->rx, &b->tx, &b->rx);
1022 }
1023
pairwise_test(sc_targetipid_t ** tis,int tc,uint32_t * pairwise_u32)1024 static int pairwise_test(sc_targetipid_t **tis, int tc, uint32_t *pairwise_u32)
1025 {
1026 sc_targetipid_t *ti, *st[2][2];
1027 sc_target_t *x = tis[0]->target;
1028 int si, sj, ipidc = 0;
1029 int i, rc = 0;
1030
1031 st[0][0] = NULL; st[0][1] = NULL;
1032 st[1][0] = NULL; st[1][1] = NULL;
1033
1034 for(i=0; i<tc; i++)
1035 {
1036 /* first, check if this IPID has already been observed */
1037 ti = tis[i];
1038 if(uint32_find(pairwise_u32, ipidc, ti->ipid) != 0)
1039 return 0;
1040 pairwise_u32[ipidc++] = ti->ipid;
1041 qsort(pairwise_u32, ipidc, sizeof(uint32_t), uint32_cmp);
1042
1043 if(ti->target == x) { si = 0; sj = 1; }
1044 else { si = 1; sj = 0; }
1045
1046 if(st[si][1] == NULL || st[sj][1] == NULL)
1047 goto next;
1048
1049 if(timeval_cmp(&st[si][1]->tx, &st[sj][1]->tx) > 0)
1050 {
1051 if(ipid_inseq3(st[sj][1]->ipid, st[si][1]->ipid, ti->ipid) == 0 &&
1052 sample_overlap(st[sj][1], st[si][1]) == 0 &&
1053 sample_overlap(st[si][1], ti) == 0)
1054 return 0;
1055 goto next;
1056 }
1057
1058 if(sample_overlap(st[si][1], st[sj][1]) || sample_overlap(st[sj][1], ti))
1059 {
1060 if(sample_overlap(st[sj][1], ti) && st[sj][0] != NULL &&
1061 timeval_cmp(&st[si][1]->tx, &st[sj][0]->tx) < 0 &&
1062 sample_overlap(st[si][1], st[sj][0]) == 0 &&
1063 ipid_inseq3(st[si][1]->ipid, st[sj][0]->ipid, ti->ipid) == 0)
1064 return 0;
1065 goto next;
1066 }
1067
1068 if(ipid_inseq3(st[si][1]->ipid, st[sj][1]->ipid, ti->ipid) == 1)
1069 rc = 1;
1070 else
1071 return 0;
1072
1073 next:
1074 st[si][0] = st[si][1];
1075 st[si][1] = ti;
1076 }
1077
1078 return rc;
1079 }
1080
pairwise(sc_target_t * ta,sc_target_t * tb)1081 static int pairwise(sc_target_t *ta, sc_target_t *tb)
1082 {
1083 slist_node_t *ss;
1084 size_t len;
1085 int tc;
1086
1087 tc = slist_count(ta->samples) + slist_count(tb->samples);
1088 if(tc > pairwise_max)
1089 {
1090 len = tc * sizeof(sc_targetipid_t *);
1091 if(realloc_wrap((void **)&pairwise_tipid, len) != 0)
1092 return -1;
1093 len = tc * sizeof(uint32_t);
1094 if(realloc_wrap((void **)&pairwise_uint32, len) != 0)
1095 return -1;
1096 pairwise_max = tc;
1097 }
1098
1099 tc = 0;
1100 for(ss=slist_head_node(ta->samples); ss!=NULL; ss=slist_node_next(ss))
1101 pairwise_tipid[tc++] = slist_node_item(ss);
1102 for(ss=slist_head_node(tb->samples); ss!=NULL; ss=slist_node_next(ss))
1103 pairwise_tipid[tc++] = slist_node_item(ss);
1104 array_qsort((void **)pairwise_tipid, tc, (array_cmp_t)sc_targetipid_tx_cmp);
1105
1106 return pairwise_test(pairwise_tipid, tc, pairwise_uint32);
1107 }
1108
pairwise_all_thread(void * param)1109 static void pairwise_all_thread(void *param)
1110 {
1111 sc_pairwise_t *pw = param;
1112 sc_targetipid_t **pairwise_tipid = NULL;
1113 sc_targetset_t *ts = NULL;
1114 uint32_t *pairwise_uint32 = NULL;
1115 int pairwise_max = 0;
1116 slist_node_t *sb, *ss;
1117 sc_target_t *ta = pw->ta, *tb;
1118 slist_t *list = NULL;
1119 size_t len;
1120 int tc;
1121
1122 #if defined(HAVE_PTHREAD)
1123 int candidates_mutex_held = 0;
1124 #endif
1125
1126 if((list = slist_alloc()) == NULL)
1127 goto done;
1128
1129 for(sb=pw->sb; sb != NULL; sb=slist_node_next(sb))
1130 {
1131 tb = slist_node_item(sb);
1132 if(slist_count(tb->samples) == 0)
1133 continue;
1134
1135 tc = slist_count(ta->samples) + slist_count(tb->samples);
1136 if(tc > pairwise_max)
1137 {
1138 len = tc * sizeof(sc_targetipid_t *);
1139 if(realloc_wrap((void **)&pairwise_tipid, len) != 0)
1140 goto done;
1141 len = tc * sizeof(uint32_t);
1142 if(realloc_wrap((void **)&pairwise_uint32, len) != 0)
1143 goto done;
1144 pairwise_max = tc;
1145 }
1146
1147 tc = 0;
1148 for(ss=slist_head_node(ta->samples); ss!=NULL; ss=slist_node_next(ss))
1149 pairwise_tipid[tc++] = slist_node_item(ss);
1150 for(ss=slist_head_node(tb->samples); ss!=NULL; ss=slist_node_next(ss))
1151 pairwise_tipid[tc++] = slist_node_item(ss);
1152 array_qsort((void **)pairwise_tipid, tc,
1153 (array_cmp_t)sc_targetipid_tx_cmp);
1154
1155 if(pairwise_test(pairwise_tipid, tc, pairwise_uint32) != 0 &&
1156 slist_tail_push(list, tb) == NULL)
1157 goto done;
1158 }
1159
1160 if(slist_count(list) > 0)
1161 {
1162 /* merge the addresses into a targetset */
1163 if((ts = sc_targetset_alloc()) == NULL ||
1164 slist_tail_push(ts->targets, ta) == NULL)
1165 goto done;
1166 slist_concat(ts->targets, list);
1167
1168 #if defined(HAVE_PTHREAD)
1169 pthread_mutex_lock(&candidates_mutex);
1170 candidates_mutex_held = 1;
1171 #endif
1172 if(slist_tail_push(candidates, ts) == NULL)
1173 goto done;
1174 ts = NULL;
1175 #if defined(HAVE_PTHREAD)
1176 pthread_mutex_unlock(&candidates_mutex);
1177 candidates_mutex_held = 0;
1178 #endif
1179 }
1180
1181 done:
1182 #if defined(HAVE_PTHREAD)
1183 if(candidates_mutex_held != 0)
1184 pthread_mutex_unlock(&candidates_mutex);
1185 #endif
1186 if(pairwise_tipid != NULL)
1187 free(pairwise_tipid);
1188 if(pairwise_uint32 != NULL)
1189 free(pairwise_uint32);
1190 if(list != NULL)
1191 slist_free(list);
1192 if(ts != NULL)
1193 sc_targetset_free(ts);
1194 free(pw);
1195 return;
1196 }
1197
pairwise_all(slist_t * targets)1198 static int pairwise_all(slist_t *targets)
1199 {
1200 sc_pairwise_t *pw = NULL;
1201 threadpool_t *tp = NULL;
1202 slist_node_t *sa;
1203 sc_target_t *ta;
1204 int rc = -1;
1205
1206 #if defined(HAVE_PTHREAD)
1207 int candidates_mutex_ok = 0;
1208 #endif
1209
1210 if((tp = threadpool_alloc(threadc)) == NULL)
1211 goto done;
1212
1213 #if defined(HAVE_PTHREAD)
1214 if(pthread_mutex_init(&candidates_mutex, NULL) != 0)
1215 goto done;
1216 candidates_mutex_ok = 1;
1217 #endif
1218
1219 for(sa=slist_head_node(targets); sa != NULL; sa=slist_node_next(sa))
1220 {
1221 ta = slist_node_item(sa);
1222 if(slist_count(ta->samples) <= 0)
1223 continue;
1224 if((pw = malloc(sizeof(sc_pairwise_t))) == NULL)
1225 goto done;
1226 pw->sb = slist_node_next(sa);
1227 pw->ta = ta;
1228 if(threadpool_tail_push(tp, pairwise_all_thread, pw) != 0)
1229 goto done;
1230 pw = NULL;
1231 }
1232
1233 threadpool_join(tp); tp = NULL;
1234 rc = 0;
1235
1236 done:
1237 #if defined(HAVE_PTHREAD)
1238 if(candidates_mutex_ok != 0)
1239 pthread_mutex_destroy(&candidates_mutex);
1240 #endif
1241
1242 return rc;
1243 }
1244
test_ping6(sc_target_t * target,char * cmd,size_t len)1245 static int test_ping6(sc_target_t *target, char *cmd, size_t len)
1246 {
1247 size_t off = 0;
1248 char buf[64];
1249 string_concat(cmd, len, &off,
1250 "ping -O dl -U %d -c 6 -s 1300 -M 1280 %s\n",
1251 mode, scamper_addr_tostr(target->addr, buf, sizeof(buf)));
1252 return off;
1253 }
1254
test_ping1(sc_target_t * target,char * cmd,size_t len)1255 static int test_ping1(sc_target_t *target, char *cmd, size_t len)
1256 {
1257 size_t off = 0;
1258 char buf[64];
1259 string_concat(cmd, len, &off,
1260 "ping -O dl -O tbt -U %d -c 2 -o 1 -s 1300 -M 1280 %s\n",
1261 mode, scamper_addr_tostr(target->addr, buf, sizeof(buf)));
1262 return off;
1263 }
1264
target_classify(void)1265 static sc_target_t *target_classify(void)
1266 {
1267 return slist_head_pop(probelist);
1268 }
1269
target_descend(void)1270 static sc_target_t *target_descend(void)
1271 {
1272 return slist_head_pop(probelist);
1273 }
1274
target_overlap(void)1275 static sc_target_t *target_overlap(void)
1276 {
1277 sc_targetset_t *ts, *tt;
1278 sc_target_t *tg;
1279 dlist_node_t *dn;
1280 slist_node_t *sn;
1281
1282 for(;;)
1283 {
1284 if((ts = slist_head_pop(probelist)) == NULL)
1285 return NULL;
1286 for(dn=dlist_head_node(overlap_act); dn != NULL; dn=dlist_node_next(dn))
1287 {
1288 tt = dlist_node_item(dn);
1289 if(timeval_overlap(&ts->min, &ts->max, &tt->min, &tt->max) != 0)
1290 break;
1291 }
1292 if(dn == NULL)
1293 break;
1294 if(slist_tail_push(tt->blocked, ts) == NULL)
1295 return NULL;
1296 blocked++;
1297 }
1298
1299 if((ts->node = dlist_tail_push(overlap_act, ts)) == NULL)
1300 return NULL;
1301
1302 slist_qsort(ts->targets, (slist_cmp_t)sc_target_ipid_cmp);
1303 sn = slist_head_node(ts->targets);
1304 tg = slist_node_item(sn);
1305 tg->attempt = 0;
1306 tg->ts = ts;
1307 ts->next = slist_node_next(sn);
1308
1309 return tg;
1310 }
1311
target_descend2(void)1312 static sc_target_t *target_descend2(void)
1313 {
1314 return slist_head_pop(probelist);
1315 }
1316
targetset_ally(void)1317 static sc_targetset_t *targetset_ally(void)
1318 {
1319 sc_addr2router_t *a2r_a, *a2r_b;
1320 sc_targetset_t *ts;
1321 slist_node_t *sn;
1322 sc_target_t *tg;
1323 char addr[256];
1324
1325 while((ts = heap_remove(probeheap)) != NULL)
1326 {
1327 /*
1328 * check if something else is already probing an overlap of
1329 * these addresses
1330 */
1331 for(sn=slist_head_node(ts->targets); sn != NULL; sn=slist_node_next(sn))
1332 {
1333 tg = slist_node_item(sn);
1334 if(splaytree_find(targets, tg) != NULL)
1335 break;
1336 }
1337
1338 /*
1339 * if there is something else probing an address in this targetset,
1340 * we block this targetset and move onto the next
1341 */
1342 if(sn != NULL)
1343 {
1344 tg = slist_node_item(sn);
1345 if(slist_tail_push(tg->ts->blocked, ts) == NULL)
1346 {
1347 fprintf(stderr, "could not block on %s\n",
1348 scamper_addr_tostr(tg->addr, addr, sizeof(addr)));
1349 return NULL;
1350 }
1351 blocked++;
1352 continue;
1353 }
1354
1355 /* check to see if we already know the answers for this set */
1356 tg = slist_head_item(ts->targets);
1357 a2r_a = sc_addr2router_find(tg->addr); assert(a2r_a != NULL);
1358 sn = slist_node_next(slist_head_node(ts->targets)); assert(sn != NULL);
1359 while(sn != NULL)
1360 {
1361 tg = slist_node_item(sn);
1362 a2r_b = sc_addr2router_find(tg->addr); assert(a2r_b != NULL);
1363 if(a2r_a->router != a2r_b->router &&
1364 sc_notaliases_check(a2r_a->router, a2r_b->router) == 0)
1365 break;
1366 sn = slist_node_next(sn);
1367 }
1368
1369 /* if we already know the answer, we free the targetset and move on */
1370 if(sn == NULL)
1371 {
1372 sc_targetset_free(ts);
1373 continue;
1374 }
1375 break;
1376 }
1377 if(ts == NULL)
1378 return NULL;
1379
1380 /* install all of the addresses into the targets tree */
1381 for(sn=slist_head_node(ts->targets); sn != NULL; sn=slist_node_next(sn))
1382 {
1383 tg = slist_node_item(sn);
1384 if((tg->tree_node = splaytree_insert(targets, tg)) == NULL)
1385 {
1386 fprintf(stderr, "could not add %s to tree\n",
1387 scamper_addr_tostr(tg->addr, addr, sizeof(addr)));
1388 return NULL;
1389 }
1390 tg->ts = ts;
1391 }
1392
1393 ts->next = slist_node_next(slist_head_node(ts->targets));
1394 ts->attempt = 0;
1395 return ts;
1396 }
1397
do_method_ping(void)1398 static int do_method_ping(void)
1399 {
1400 static int (*const test_func[])(sc_target_t *, char *, size_t) = {
1401 test_ping6,
1402 test_ping1,
1403 test_ping1,
1404 test_ping1,
1405 };
1406 static sc_target_t * (*const target_func[])(void) = {
1407 target_classify,
1408 target_descend,
1409 target_overlap,
1410 target_descend2,
1411 };
1412
1413 sc_target_t *tg;
1414 sc_wait_t *w;
1415 char buf[128];
1416 size_t off;
1417
1418 if((w = heap_head_item(waiting)) != NULL && timeval_cmp(&now, &w->tv) >= 0)
1419 {
1420 heap_remove(waiting);
1421 tg = w->un.target;
1422 sc_wait_free(w);
1423 }
1424 else if((tg = target_func[mode]()) == NULL)
1425 return 0;
1426
1427 if((tg->tree_node = splaytree_insert(targets, tg)) == NULL)
1428 {
1429 fprintf(stderr, "could not add %s to tree\n",
1430 scamper_addr_tostr(tg->addr, buf, sizeof(buf)));
1431 return -1;
1432 }
1433
1434 if((off = test_func[mode](tg, buf, sizeof(buf))) == -1)
1435 {
1436 fprintf(stderr, "something went wrong\n");
1437 return -1;
1438 }
1439
1440 write_wrap(scamper_fd, buf, NULL, off);
1441 probing++;
1442 more--;
1443
1444 logprint(1, "%s", buf);
1445 return 0;
1446 }
1447
do_method_ally(void)1448 static int do_method_ally(void)
1449 {
1450 sc_targetset_t *ts;
1451 sc_target_t *tg;
1452 sc_wait_t *w;
1453 char cmd[192], addr[64];
1454 size_t off = 0;
1455
1456 if((w = heap_head_item(waiting)) != NULL && timeval_cmp(&now, &w->tv) >= 0)
1457 {
1458 heap_remove(waiting);
1459 ts = w->un.targetset;
1460 sc_wait_free(w);
1461 }
1462 else if((ts = targetset_ally()) == NULL)
1463 return 0;
1464
1465 tg = slist_head_item(ts->targets);
1466 string_concat(cmd, sizeof(cmd), &off,
1467 "dealias -U %d -m ally -f %u -w 2 -W 1000 -p '%s' %s",
1468 mode, fudge, "-P icmp-echo -s 1300 -M 1280",
1469 scamper_addr_tostr(tg->addr, addr, sizeof(addr)));
1470 tg = slist_node_item(ts->next);
1471 string_concat(cmd, sizeof(cmd), &off, " %s\n",
1472 scamper_addr_tostr(tg->addr, addr, sizeof(addr)));
1473
1474 write_wrap(scamper_fd, cmd, NULL, off);
1475 probing++;
1476 more--;
1477
1478 logprint(1, "%s", cmd);
1479 return 0;
1480 }
1481
do_method(void)1482 static int do_method(void)
1483 {
1484 int rc;
1485 if(more < 1)
1486 return 0;
1487 if(mode != MODE_ALLY)
1488 rc = do_method_ping();
1489 else
1490 rc = do_method_ally();
1491 return rc;
1492 }
1493
isdone(void)1494 static int isdone(void)
1495 {
1496 if(splaytree_count(targets) != 0 || slist_count(probelist) != 0 ||
1497 heap_count(waiting) != 0)
1498 return 0;
1499 return 1;
1500 }
1501
finish_classify(void)1502 static int finish_classify(void)
1503 {
1504 slist_node_t *sn;
1505 sc_target_t *target;
1506
1507 /*
1508 * can only move beyond classification stage if there is nothing
1509 * left to probe
1510 */
1511 if(isdone() == 0)
1512 return 0;
1513
1514 /*
1515 * can only move into descend mode if speedtrap is told to continue
1516 * after classification stage
1517 */
1518 if(mode_ok(MODE_DESCEND) == 0)
1519 return 0;
1520 mode = MODE_DESCEND;
1521
1522 /* put all the targets on the probelist, with their state re-set */
1523 for(sn=slist_head_node(incr); sn != NULL; sn=slist_node_next(sn))
1524 {
1525 target = slist_node_item(sn);
1526 target->attempt = 0;
1527 target->ts = NULL;
1528 slist_tail_push(probelist, target);
1529 }
1530
1531 /* probe in order of IPIDs observed */
1532 slist_qsort(probelist, (slist_cmp_t)sc_target_ipid_cmp);
1533 if((descend = slist_alloc()) == NULL)
1534 return -1;
1535 return 0;
1536 }
1537
reply_classify(sc_target_t * target,sc_targetipid_t * p,uint16_t ipidc,uint16_t rxd)1538 static int reply_classify(sc_target_t *target, sc_targetipid_t *p,
1539 uint16_t ipidc, uint16_t rxd)
1540 {
1541 char addr[64];
1542 uint16_t u16;
1543
1544 scamper_addr_tostr(target->addr, addr, sizeof(addr));
1545
1546 /* no responses at all: unresponsive */
1547 if(rxd == 0)
1548 {
1549 logprint(1, "%s unresponsive\n", addr);
1550 sc_target_free(target);
1551 goto done;
1552 }
1553
1554 /* less than three IPID samples, sort of unresponsive */
1555 if(ipidc < 3)
1556 {
1557 logprint(1, "%s ipidc %d\n", addr, ipidc);
1558 sc_target_free(target);
1559 goto done;
1560 }
1561
1562 /* check for an incrementing sequence: any break and we're done */
1563 for(u16=0; u16+2 < ipidc; u16++)
1564 {
1565 if(ipid_inseq3(p[u16].ipid, p[u16+1].ipid, p[u16+2].ipid) == 0)
1566 {
1567 logprint(1, "%s not inseq %d\n", addr, u16);
1568 sc_target_free(target);
1569 goto done;
1570 }
1571 }
1572
1573 logprint(1, "%s incr\n", addr);
1574 target->last = p[ipidc-1].ipid;
1575 slist_tail_push(incr, target);
1576
1577 done:
1578 return finish_classify();
1579 }
1580
finish_descend(void)1581 static int finish_descend(void)
1582 {
1583 sc_targetipid_t *ti;
1584 sc_targetset_t *ts;
1585 struct timeval tv;
1586
1587 /* can only move beyond descend stage if there is nothing left to probe */
1588 if(isdone() == 0)
1589 return 0;
1590
1591 /*
1592 * can only move into descend mode if speedtrap is told to continue
1593 * after descend stage
1594 */
1595 if(mode_ok(MODE_OVERLAP) == 0)
1596 return 0;
1597 mode = MODE_OVERLAP;
1598
1599 slist_qsort(descend, (slist_cmp_t)sc_targetipid_tx_cmp);
1600 ts = NULL;
1601 while((ti = slist_head_pop(descend)) != NULL)
1602 {
1603 if(ts == NULL || timeval_cmp(&tv, &ti->tx) <= 0)
1604 {
1605 timeval_cpy(&tv, &ti->rx);
1606 if((ts = sc_targetset_alloc()) == NULL ||
1607 slist_tail_push(probelist, ts) == NULL)
1608 return -1;
1609 timeval_cpy(&ts->min, &ti->tx);
1610 timeval_cpy(&ts->max, &ti->rx);
1611 }
1612 else
1613 {
1614 if(timeval_cmp(&ts->max, &ti->rx) < 0)
1615 timeval_cpy(&ts->max, &ti->rx);
1616 }
1617 slist_tail_push(ts->targets, ti->target);
1618 }
1619 slist_free(descend); descend = NULL;
1620
1621 /*
1622 * sort the probelist so that longer-length target sets are probed
1623 * first in an attempt to reduce the overall runtime
1624 */
1625 slist_qsort(probelist, (slist_cmp_t)sc_targetset_length_cmp);
1626 return 0;
1627 }
1628
reply_descend(sc_target_t * target,sc_targetipid_t * ipids,uint16_t ipidc,uint16_t rxd)1629 static int reply_descend(sc_target_t *target, sc_targetipid_t *ipids,
1630 uint16_t ipidc, uint16_t rxd)
1631 {
1632 sc_targetipid_t *ti;
1633 struct timeval tv;
1634
1635 if(ipidc == 0)
1636 {
1637 if(target->attempt >= 2)
1638 goto done;
1639 target->attempt++;
1640 timeval_add_s(&tv, &now, 1);
1641 if(sc_wait_target(&tv, target) != 0)
1642 return -1;
1643 return 0;
1644 }
1645
1646 if((ti = sc_target_sample(target, &ipids[0])) == NULL)
1647 return -1;
1648 if(slist_tail_push(descend, ti) == NULL)
1649 return -1;
1650
1651 done:
1652 return finish_descend();
1653 }
1654
finish_overlap(void)1655 static int finish_overlap(void)
1656 {
1657 sc_target_t *target;
1658 slist_node_t *sn;
1659
1660 /* can only move beyond overlap stage if there is nothing left to probe */
1661 if(isdone() == 0)
1662 return 0;
1663
1664 /*
1665 * can only move into descend2 mode if speedtrap is told to continue
1666 * after overlap stage
1667 */
1668 if(mode_ok(MODE_DESCEND2) == 0)
1669 return 0;
1670 mode = MODE_DESCEND2;
1671 for(sn=slist_head_node(incr); sn != NULL; sn=slist_node_next(sn))
1672 {
1673 target = slist_node_item(sn);
1674 target->attempt = 0;
1675 target->ts = NULL;
1676 slist_tail_push(probelist, target);
1677 }
1678 slist_qsort(probelist, (slist_cmp_t)sc_target_ipid_cmp);
1679 return 0;
1680 }
1681
reply_overlap(sc_target_t * target,sc_targetipid_t * ipids,uint16_t ipidc,uint16_t rxd)1682 static int reply_overlap(sc_target_t *target, sc_targetipid_t *ipids,
1683 uint16_t ipidc, uint16_t rxd)
1684 {
1685 sc_targetipid_t *ti;
1686 sc_targetset_t *ts, *tsb;
1687 sc_target_t *tg;
1688 struct timeval tv;
1689
1690 if(ipidc == 0)
1691 {
1692 if(target->attempt >= 2)
1693 goto done;
1694 target->attempt++;
1695 timeval_add_s(&tv, &now, 1);
1696 if(sc_wait_target(&tv, target) != 0)
1697 return -1;
1698 return 0;
1699 }
1700
1701 if((ti = sc_target_sample(target, &ipids[0])) == NULL)
1702 return -1;
1703
1704 done:
1705 ts = target->ts;
1706 if(ts->next != NULL)
1707 {
1708 tg = slist_node_item(ts->next);
1709 tg->attempt = 0;
1710 tg->ts = ts;
1711 ts->next = slist_node_next(ts->next);
1712 timeval_add_s(&tv, &now, 1);
1713 if(sc_wait_target(&tv, tg) != 0)
1714 return -1;
1715 }
1716 else
1717 {
1718 while((tsb = slist_head_pop(ts->blocked)) != NULL)
1719 {
1720 /* put the blocked items at the front of the probelist */
1721 if(slist_head_push(probelist, tsb) == NULL)
1722 return -1;
1723 blocked--;
1724 }
1725
1726 dlist_node_pop(overlap_act, ts->node);
1727 sc_targetset_free(ts);
1728 }
1729
1730 return finish_overlap();
1731 }
1732
finish_descend2(void)1733 static int finish_descend2(void)
1734 {
1735 slist_node_t *sa, *sb;
1736 sc_router_t *r;
1737 sc_addr2router_t *a2r;
1738 sc_targetset_t *ts;
1739 sc_target_t *tg;
1740
1741 if(isdone() == 0)
1742 return 0;
1743
1744 if(mode_ok(MODE_ALLY) == 0)
1745 return 0;
1746 mode = MODE_ALLY;
1747
1748 if(pairwise_all(incr) != 0)
1749 return -1;
1750 slist_qsort(candidates, (slist_cmp_t)sc_targetset_targetc_asc_cmp);
1751
1752 /* create router nodes for all addresses to probe */
1753 for(sa=slist_head_node(candidates); sa != NULL; sa=slist_node_next(sa))
1754 {
1755 ts = slist_node_item(sa);
1756 sc_targetset_logprint(ts);
1757 for(sb=slist_head_node(ts->targets); sb != NULL; sb=slist_node_next(sb))
1758 {
1759 tg = slist_node_item(sb);
1760 if((a2r = sc_addr2router_find(tg->addr)) != NULL)
1761 continue;
1762 if((r = sc_router_alloc()) == NULL ||
1763 (a2r = sc_addr2router_alloc(tg->addr, r)) == NULL ||
1764 slist_tail_push(r->addrs, a2r) == NULL)
1765 return -1;
1766 }
1767 }
1768
1769 if((probeheap=heap_alloc((heap_cmp_t)sc_targetset_targetc_desc_cmp)) == NULL)
1770 return -1;
1771 while((ts = slist_head_pop(candidates)) != NULL)
1772 {
1773 if(heap_insert(probeheap, ts) == NULL)
1774 return -1;
1775 }
1776
1777 return 0;
1778 }
1779
reply_descend2(sc_target_t * target,sc_targetipid_t * ipids,uint16_t ipidc,uint16_t rxd)1780 static int reply_descend2(sc_target_t *target, sc_targetipid_t *ipids,
1781 uint16_t ipidc, uint16_t rxd)
1782 {
1783 struct timeval tv;
1784
1785 if(ipidc == 0 && target->attempt < 2)
1786 {
1787 target->attempt++;
1788 timeval_add_s(&tv, &now, 1);
1789 if(sc_wait_target(&tv, target) != 0)
1790 return -1;
1791 return 0;
1792 }
1793
1794 if(ipidc > 0 && sc_target_sample(target, &ipids[0]) == NULL)
1795 return -1;
1796
1797 return finish_descend2();
1798 }
1799
do_decoderead_ping(scamper_ping_t * ping)1800 static int do_decoderead_ping(scamper_ping_t *ping)
1801 {
1802 static int (*const func[])(sc_target_t *, sc_targetipid_t *,
1803 uint16_t, uint16_t) = {
1804 reply_classify,
1805 reply_descend,
1806 reply_overlap,
1807 reply_descend2,
1808 };
1809 sc_target_t *target;
1810 char buf[64];
1811 scamper_ping_reply_t *reply;
1812 int rc = -1;
1813 sc_targetipid_t p[6];
1814 uint16_t u16;
1815 uint16_t probes_rxd = 0;
1816 uint16_t ipids_rxd = 0;
1817
1818 if((target = sc_target_findtree(ping->dst)) == NULL)
1819 {
1820 fprintf(stderr, "do_decoderead: could not find dst %s\n",
1821 scamper_addr_tostr(ping->dst, buf, sizeof(buf)));
1822 goto done;
1823 }
1824 sc_target_detachtree(target);
1825
1826 for(u16=0; u16<ping->ping_sent; u16++)
1827 {
1828 if((reply = ping->ping_replies[u16]) == NULL ||
1829 SCAMPER_PING_REPLY_IS_ICMP_ECHO_REPLY(reply) == 0)
1830 continue;
1831 probes_rxd++;
1832 if(reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_IPID)
1833 {
1834 timeval_cpy(&p[ipids_rxd].tx, &reply->tx);
1835 timeval_add_tv3(&p[ipids_rxd].rx, &reply->tx, &reply->rtt);
1836 p[ipids_rxd].ipid = reply->reply_ipid32;
1837 ipids_rxd++;
1838 }
1839 }
1840 scamper_ping_free(ping); ping = NULL;
1841
1842 rc = func[mode](target, p, ipids_rxd, probes_rxd);
1843
1844 done:
1845 if(ping != NULL) scamper_ping_free(ping);
1846 return rc;
1847 }
1848
do_decoderead_dealias(scamper_dealias_t * dealias)1849 static int do_decoderead_dealias(scamper_dealias_t *dealias)
1850 {
1851 scamper_dealias_ally_t *ally = dealias->data;
1852 sc_addr2router_t *a2r_a, *a2r_b, *a2r_c;
1853 scamper_addr_t *a, *b;
1854 sc_targetset_t *ts;
1855 sc_target_t *tg;
1856 struct timeval tv;
1857 char ab[64], bb[64], r[16];
1858 slist_node_t *sn;
1859 slist_t *list;
1860 int rc = -1;
1861
1862 assert(SCAMPER_DEALIAS_METHOD_IS_ALLY(dealias));
1863
1864 a = ally->probedefs[0].dst; scamper_addr_tostr(a, ab, sizeof(ab));
1865 b = ally->probedefs[1].dst; scamper_addr_tostr(b, bb, sizeof(bb));
1866
1867 a2r_a = sc_addr2router_find(a);
1868 assert(a2r_a != NULL); assert(a2r_a->router != NULL);
1869 a2r_b = sc_addr2router_find(b);
1870 assert(a2r_b != NULL); assert(a2r_b->router != NULL);
1871
1872 if((tg = sc_target_findtree(a)) == NULL)
1873 {
1874 fprintf(stderr, "do_decoderead: could not find dst %s\n", ab);
1875 goto done;
1876 }
1877 ts = tg->ts;
1878
1879 logprint(1, "%s %s %s\n", ab, bb,
1880 scamper_dealias_result_tostr(dealias, r, sizeof(r)));
1881
1882 if(dealias->result == SCAMPER_DEALIAS_RESULT_ALIASES)
1883 {
1884 /* merge two routers together */
1885 if(a2r_a->router != a2r_b->router)
1886 {
1887 /* merge the sets of "not aliases" together */
1888 if(sc_notaliases_merge(a2r_a->router, a2r_b->router) != 0)
1889 goto done;
1890
1891 /* copy across b's aliases into a */
1892 list = a2r_b->router->addrs; a2r_b->router->addrs = NULL;
1893 sc_router_free(a2r_b->router); a2r_b->router = NULL;
1894 for(sn=slist_head_node(list); sn != NULL; sn=slist_node_next(sn))
1895 {
1896 a2r_c = slist_node_item(sn);
1897 a2r_c->router = a2r_a->router;
1898 }
1899 slist_concat(a2r_a->router->addrs, list);
1900 slist_free(list);
1901 assert(a2r_b->router == a2r_a->router);
1902 }
1903 }
1904 else if(dealias->result == SCAMPER_DEALIAS_RESULT_NOTALIASES)
1905 {
1906 /* mark these routers as not being aliases to save further probing */
1907 if(a2r_a->router != a2r_b->router)
1908 {
1909 if(sc_notaliases_add(a2r_a->router, a2r_b->router) != 0)
1910 goto done;
1911 }
1912 }
1913 else if(dealias->result == SCAMPER_DEALIAS_RESULT_NONE && ts->attempt < 2)
1914 {
1915 ts->attempt++;
1916 timeval_add_s(&tv, &now, 1);
1917 if(sc_wait_targetset(&tv, ts) == 0)
1918 rc = 0;
1919 goto done;
1920 }
1921
1922 for(;;)
1923 {
1924 /*
1925 * if we are at the end of the list of targets for this set, free
1926 * the targetset and move on.
1927 */
1928 if((ts->next = slist_node_next(ts->next)) == NULL)
1929 {
1930 while((tg = slist_head_pop(ts->targets)) != NULL)
1931 {
1932 tg->ts = NULL;
1933 sc_target_detachtree(tg);
1934 }
1935 while((tg = slist_head_pop(ts->blocked)) != NULL)
1936 {
1937 if(heap_insert(probeheap, tg) == NULL)
1938 goto done;
1939 blocked--;
1940 }
1941
1942 sc_targetset_free(ts);
1943 rc = 0;
1944 goto done;
1945 }
1946
1947 /* skip over if the transitive closure implies we know the answer */
1948 tg = slist_node_item(ts->next);
1949 a2r_c = sc_addr2router_find(tg->addr); assert(a2r_c != NULL);
1950 if(a2r_a->router == a2r_c->router ||
1951 sc_notaliases_check(a2r_a->router, a2r_c->router) == 1)
1952 continue;
1953
1954 /* probe this address */
1955 break;
1956 }
1957 ts->attempt = 0;
1958 timeval_cpy(&tv, &now);
1959 if(sc_wait_targetset(&tv, ts) == 0)
1960 rc = 0;
1961
1962 done:
1963 if(dealias != NULL) scamper_dealias_free(dealias);
1964 return rc;
1965 }
1966
do_decoderead(void)1967 static int do_decoderead(void)
1968 {
1969 void *data;
1970 uint16_t type;
1971
1972 /* try and read from the warts decoder */
1973 if(scamper_file_read(decode_in, ffilter, &type, &data) != 0)
1974 {
1975 fprintf(stderr, "do_decoderead: scamper_file_read errno %d\n", errno);
1976 return -1;
1977 }
1978 if(data == NULL)
1979 {
1980 if(scamper_file_geteof(decode_in) != 0)
1981 {
1982 scamper_file_close(decode_in);
1983 decode_in = NULL;
1984 decode_in_fd = -1;
1985 }
1986 return 0;
1987 }
1988 probing--;
1989
1990 if(scamper_file_write_obj(outfile, type, data) != 0)
1991 {
1992 fprintf(stderr, "do_decoderead: could not write obj %d\n", type);
1993 /* XXX: free data */
1994 return -1;
1995 }
1996
1997 if(type == SCAMPER_FILE_OBJ_PING)
1998 return do_decoderead_ping(data);
1999 else if(type == SCAMPER_FILE_OBJ_DEALIAS)
2000 return do_decoderead_dealias(data);
2001
2002 return -1;
2003 }
2004
do_scamperread_line(void * param,uint8_t * buf,size_t linelen)2005 static int do_scamperread_line(void *param, uint8_t *buf, size_t linelen)
2006 {
2007 char *head = (char *)buf;
2008 uint8_t uu[64];
2009 size_t uus;
2010 long lo;
2011
2012 /* skip empty lines */
2013 if(head[0] == '\0')
2014 return 0;
2015
2016 /* if currently decoding data, then pass it to uudecode */
2017 if(data_left > 0)
2018 {
2019 uus = sizeof(uu);
2020 if(uudecode_line(head, linelen, uu, &uus) != 0)
2021 {
2022 fprintf(stderr, "could not uudecode_line\n");
2023 return -1;
2024 }
2025 if(uus != 0)
2026 scamper_writebuf_send(decode_wb, uu, uus);
2027 data_left -= (linelen + 1);
2028 return 0;
2029 }
2030
2031 /* feedback letting us know that the command was accepted */
2032 if(linelen >= 2 && strncasecmp(head, "OK", 2) == 0)
2033 return 0;
2034
2035 /* if the scamper process is asking for more tasks, give it more */
2036 if(linelen == 4 && strncasecmp(head, "MORE", linelen) == 0)
2037 {
2038 more++;
2039 if(do_method() != 0)
2040 return -1;
2041 return 0;
2042 }
2043
2044 /* new piece of data */
2045 if(linelen > 5 && strncasecmp(head, "DATA ", 5) == 0)
2046 {
2047 if(string_isnumber(head+5) == 0 || string_tolong(head+5, &lo) != 0)
2048 {
2049 fprintf(stderr, "could not parse %s\n", head);
2050 return -1;
2051 }
2052 data_left = lo;
2053 return 0;
2054 }
2055
2056 /* feedback letting us know that the command was not accepted */
2057 if(linelen >= 3 && strncasecmp(head, "ERR", 3) == 0)
2058 {
2059 more++;
2060 if(do_method() != 0)
2061 return -1;
2062 return 0;
2063 }
2064
2065 fprintf(stderr, "unknown response '%s'\n", head);
2066 return -1;
2067 }
2068
do_scamperread(void)2069 static int do_scamperread(void)
2070 {
2071 ssize_t rc;
2072 uint8_t buf[512];
2073
2074 if((rc = read(scamper_fd, buf, sizeof(buf))) > 0)
2075 {
2076 scamper_linepoll_handle(scamper_lp, buf, rc);
2077 return 0;
2078 }
2079 else if(rc == 0)
2080 {
2081 close(scamper_fd);
2082 scamper_fd = -1;
2083 return 0;
2084 }
2085 else if(errno == EINTR || errno == EAGAIN)
2086 {
2087 return 0;
2088 }
2089
2090 fprintf(stderr, "could not read: errno %d\n", errno);
2091 return -1;
2092 }
2093
addressfile_line(char * addr,void * param)2094 static int addressfile_line(char *addr, void *param)
2095 {
2096 splaytree_t *tree = param;
2097 scamper_addr_t *a = NULL;
2098
2099 if(addr[0] == '#' || addr[0] == '\0')
2100 return 0;
2101
2102 if((a = scamper_addr_resolve(AF_INET6, addr)) == NULL)
2103 {
2104 fprintf(stderr, "could not resolve '%s'\n", addr);
2105 return -1;
2106 }
2107
2108 /*
2109 * make sure the address is in 2000::/3
2110 * and is not already in the probelist
2111 */
2112 if(scamper_addr_isunicast(a) != 1 || splaytree_find(tree, a) != NULL)
2113 {
2114 scamper_addr_free(a);
2115 return 0;
2116 }
2117
2118 /* make a note that the address is in the list to be probed */
2119 if(splaytree_insert(tree, a) == NULL)
2120 {
2121 scamper_addr_free(a);
2122 return -1;
2123 }
2124
2125 return 0;
2126 }
2127
do_addressfile(void)2128 static int do_addressfile(void)
2129 {
2130 scamper_addr_t *addr = NULL;
2131 splaytree_t *tree = NULL;
2132 slist_t *list = NULL;
2133 sc_target_t *target = NULL;
2134 int rc = -1;
2135
2136 if((tree = splaytree_alloc((splaytree_cmp_t)scamper_addr_cmp)) == NULL ||
2137 (list = slist_alloc()) == NULL ||
2138 file_lines(addressfile, addressfile_line, tree) != 0)
2139 goto done;
2140
2141 splaytree_inorder(tree, tree_to_slist, list);
2142 splaytree_free(tree, NULL); tree = NULL;
2143
2144 while((addr = slist_head_pop(list)) != NULL)
2145 {
2146 if((target = sc_target_alloc(addr)) == NULL)
2147 goto done;
2148 scamper_addr_free(addr); addr = NULL;
2149
2150 if(slist_tail_push(probelist, target) == NULL ||
2151 ((options & OPT_INCR) && slist_tail_push(incr, target) == NULL))
2152 {
2153 fprintf(stderr, "could push target\n");
2154 goto done;
2155 }
2156 }
2157
2158 rc = 0;
2159
2160 done:
2161 if(tree != NULL) splaytree_free(tree, (splaytree_free_t)scamper_addr_free);
2162 if(list != NULL) slist_free_cb(list, (slist_free_t)scamper_addr_free);
2163 return rc;
2164 }
2165
2166 /*
2167 * do_scamperconnect
2168 *
2169 * allocate socket and connect to scamper process listening on the port
2170 * specified.
2171 */
do_scamperconnect(void)2172 static int do_scamperconnect(void)
2173 {
2174 struct sockaddr_un sun;
2175 struct sockaddr_storage sas;
2176 struct sockaddr *sa = (struct sockaddr *)&sas;
2177 struct in_addr in;
2178
2179 if(options & OPT_PORT)
2180 {
2181 if(dst_addr != NULL)
2182 {
2183 if(sockaddr_compose_str(sa, dst_addr, dst_port) != 0)
2184 {
2185 fprintf(stderr, "%s: could not compose sockaddr from %s:%d\n",
2186 __func__, dst_addr, dst_port);
2187 return -1;
2188 }
2189 }
2190 else
2191 {
2192 in.s_addr = htonl(INADDR_LOOPBACK);
2193 sockaddr_compose(sa, AF_INET, &in, dst_port);
2194 }
2195
2196 if((scamper_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
2197 {
2198 fprintf(stderr, "could not allocate new socket\n");
2199 return -1;
2200 }
2201 if(connect(scamper_fd, sa, sockaddr_len(sa)) != 0)
2202 {
2203 fprintf(stderr, "could not connect to scamper process\n");
2204 return -1;
2205 }
2206 return 0;
2207 }
2208 else if(options & OPT_UNIX)
2209 {
2210 if(sockaddr_compose_un((struct sockaddr *)&sun, unix_name) != 0)
2211 {
2212 fprintf(stderr, "could not build sockaddr_un\n");
2213 return -1;
2214 }
2215 if((scamper_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
2216 {
2217 fprintf(stderr, "could not allocate unix domain socket\n");
2218 return -1;
2219 }
2220 if(connect(scamper_fd, (const struct sockaddr *)&sun, sizeof(sun)) != 0)
2221 {
2222 fprintf(stderr, "could not connect to scamper process\n");
2223 return -1;
2224 }
2225 return 0;
2226 }
2227
2228 return -1;
2229 }
2230
speedtrap_data_select(void)2231 static int speedtrap_data_select(void)
2232 {
2233 struct timeval tv, *tv_ptr;
2234 fd_set rfds, wfds, *wfdsp;
2235 sc_wait_t *w;
2236 int nfds;
2237
2238 for(;;)
2239 {
2240 /*
2241 * need to set a timeout on select if scamper's processing window is
2242 * not full and there is a task in the waiting queue.
2243 */
2244 tv_ptr = NULL;
2245 if(more > 0)
2246 {
2247 gettimeofday_wrap(&now);
2248
2249 /*
2250 * if there is something ready to probe now, then try and
2251 * do it.
2252 */
2253 w = heap_head_item(waiting);
2254 if(slist_count(probelist) > 0 ||
2255 (probeheap != NULL && heap_count(probeheap) > 0) ||
2256 (w != NULL && timeval_cmp(&w->tv, &now) <= 0))
2257 {
2258 if(do_method() != 0)
2259 return -1;
2260 }
2261
2262 /*
2263 * if we could not send a new command just yet, but scamper
2264 * wants one, then wait for an appropriate length of time.
2265 */
2266 w = heap_head_item(waiting);
2267 if(more > 0 && tv_ptr == NULL && w != NULL)
2268 {
2269 tv_ptr = &tv;
2270 if(timeval_cmp(&w->tv, &now) > 0)
2271 timeval_diff_tv(&tv, &now, &w->tv);
2272 else
2273 memset(&tv, 0, sizeof(tv));
2274 }
2275 }
2276
2277 nfds = 0; FD_ZERO(&rfds); FD_ZERO(&wfds); wfdsp = NULL;
2278 if(scamper_fd < 0 && decode_in_fd < 0)
2279 break;
2280
2281 if(scamper_fd >= 0)
2282 {
2283 FD_SET(scamper_fd, &rfds);
2284 if(nfds < scamper_fd) nfds = scamper_fd;
2285 if(scamper_writebuf_len(scamper_wb) > 0)
2286 {
2287 FD_SET(scamper_fd, &wfds);
2288 wfdsp = &wfds;
2289 }
2290 }
2291
2292 if(decode_in_fd >= 0)
2293 {
2294 FD_SET(decode_in_fd, &rfds);
2295 if(nfds < decode_in_fd) nfds = decode_in_fd;
2296 }
2297
2298 if(decode_out_fd >= 0 && scamper_writebuf_len(decode_wb) > 0)
2299 {
2300 FD_SET(decode_out_fd, &wfds);
2301 wfdsp = &wfds;
2302 if(nfds < decode_out_fd) nfds = decode_out_fd;
2303 }
2304
2305 if(splaytree_count(targets) == 0 && slist_count(probelist) == 0 &&
2306 (probeheap == NULL || heap_count(probeheap) == 0) &&
2307 heap_count(waiting) == 0)
2308 {
2309 logprint(1, "done\n");
2310 break;
2311 }
2312
2313 if(select(nfds+1, &rfds, wfdsp, NULL, tv_ptr) < 0)
2314 {
2315 if(errno == EINTR) continue;
2316 fprintf(stderr, "select error\n");
2317 break;
2318 }
2319
2320 gettimeofday_wrap(&now);
2321
2322 if(more > 0)
2323 {
2324 if(do_method() != 0)
2325 return -1;
2326 }
2327
2328 if(scamper_fd >= 0)
2329 {
2330 if(FD_ISSET(scamper_fd, &rfds) && do_scamperread() != 0)
2331 return -1;
2332 if(wfdsp != NULL && FD_ISSET(scamper_fd, wfdsp) &&
2333 scamper_writebuf_write(scamper_fd, scamper_wb) != 0)
2334 return -1;
2335 }
2336
2337 if(decode_in_fd >= 0)
2338 {
2339 if(FD_ISSET(decode_in_fd, &rfds) && do_decoderead() != 0)
2340 return -1;
2341 }
2342
2343 if(decode_out_fd >= 0)
2344 {
2345 if(wfdsp != NULL && FD_ISSET(decode_out_fd, wfdsp) &&
2346 scamper_writebuf_write(decode_out_fd, decode_wb) != 0)
2347 return -1;
2348
2349 if(scamper_fd < 0 && scamper_writebuf_len(decode_wb) == 0)
2350 {
2351 close(decode_out_fd);
2352 decode_out_fd = -1;
2353 }
2354 }
2355 }
2356
2357 return 0;
2358 }
2359
speedtrap_data(void)2360 static int speedtrap_data(void)
2361 {
2362 int pair[2];
2363
2364 if((targets = splaytree_alloc((splaytree_cmp_t)sc_target_addr_cmp)) == NULL ||
2365 (waiting = heap_alloc((heap_cmp_t)sc_wait_cmp)) == NULL ||
2366 (probelist = slist_alloc()) == NULL ||
2367 (incr = slist_alloc()) == NULL ||
2368 (candidates = slist_alloc()) == NULL ||
2369 (notaliases = splaytree_alloc((splaytree_cmp_t)sc_notaliases_cmp))==NULL||
2370 (overlap_act = dlist_alloc()) == NULL ||
2371 do_addressfile() != 0 || do_scamperconnect() != 0 ||
2372 (scamper_lp = scamper_linepoll_alloc(do_scamperread_line, NULL)) == NULL ||
2373 (scamper_wb = scamper_writebuf_alloc()) == NULL ||
2374 (decode_wb = scamper_writebuf_alloc()) == NULL ||
2375 (outfile = scamper_file_open(outfile_name, 'w', "warts")) == NULL ||
2376 socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0 ||
2377 (decode_in = scamper_file_openfd(pair[0], NULL, 'r', "warts")) == NULL ||
2378 fcntl_set(pair[0], O_NONBLOCK) == -1 ||
2379 fcntl_set(pair[1], O_NONBLOCK) == -1)
2380 return -1;
2381
2382 decode_in_fd = pair[0];
2383 decode_out_fd = pair[1];
2384 scamper_writebuf_send(scamper_wb, "attach\n", 7);
2385
2386 random_seed();
2387 slist_shuffle(probelist);
2388
2389 if(options & OPT_INCR)
2390 {
2391 mode = MODE_DESCEND;
2392 if((descend = slist_alloc()) == NULL)
2393 return -1;
2394 }
2395
2396 return speedtrap_data_select();
2397 }
2398
ping_read(const scamper_ping_t * ping,uint32_t * ipids,int * ipidc,int * replyc)2399 static int ping_read(const scamper_ping_t *ping, uint32_t *ipids,
2400 int *ipidc, int *replyc)
2401 {
2402 scamper_ping_reply_t *reply;
2403 int i, maxipidc = *ipidc;
2404
2405 *ipidc = 0;
2406 *replyc = 0;
2407
2408 for(i=0; i<ping->ping_sent; i++)
2409 {
2410 if((reply = ping->ping_replies[i]) == NULL)
2411 continue;
2412 if(SCAMPER_PING_REPLY_IS_ICMP_ECHO_REPLY(reply) == 0)
2413 continue;
2414 (*replyc)++;
2415 if(reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_IPID)
2416 {
2417 if(*ipidc == maxipidc)
2418 return -1;
2419 ipids[*ipidc] = reply->reply_ipid32;
2420 (*ipidc)++;
2421 }
2422 }
2423
2424 return 0;
2425 }
2426
process_1_ping(const scamper_ping_t * ping)2427 static int process_1_ping(const scamper_ping_t *ping)
2428 {
2429 sc_router_t *r;
2430 sc_addr2router_t *a2r;
2431 uint32_t ipids[10];
2432 int ipidc, replyc;
2433
2434 if(ping->userid != 0)
2435 return 0;
2436
2437 ipidc = sizeof(ipids) / sizeof(uint32_t);
2438 if(ping_read(ping, ipids, &ipidc, &replyc) != 0)
2439 return -1;
2440 if(ipid_incr(ipids, ipidc) == 0)
2441 return 0;
2442
2443 if(sc_addr2router_find(ping->dst) != NULL)
2444 return 0;
2445
2446 if((r = sc_router_alloc()) == NULL ||
2447 (a2r = sc_addr2router_alloc(ping->dst, r)) == NULL ||
2448 slist_tail_push(r->addrs, a2r) == NULL)
2449 return -1;
2450 return 0;
2451 }
2452
process_1_ally(const scamper_dealias_t * dealias)2453 static int process_1_ally(const scamper_dealias_t *dealias)
2454 {
2455 const scamper_dealias_ally_t *ally = dealias->data;
2456 sc_addr2router_t *a2r_a, *a2r_b, *a2r_c;
2457 slist_t *list;
2458 sc_router_t *r;
2459 slist_node_t *sn;
2460 scamper_addr_t *a = ally->probedefs[0].dst;
2461 scamper_addr_t *b = ally->probedefs[1].dst;
2462
2463 if(dealias->result != SCAMPER_DEALIAS_RESULT_ALIASES)
2464 return 0;
2465
2466 a2r_a = sc_addr2router_find(a);
2467 a2r_b = sc_addr2router_find(b);
2468
2469 if(a2r_a != NULL && a2r_b != NULL)
2470 {
2471 if(a2r_a->router != a2r_b->router)
2472 {
2473 list = a2r_b->router->addrs; a2r_b->router->addrs = NULL;
2474 sc_router_free(a2r_b->router); a2r_b->router = NULL;
2475 for(sn=slist_head_node(list); sn != NULL; sn=slist_node_next(sn))
2476 {
2477 a2r_c = slist_node_item(sn);
2478 a2r_c->router = a2r_a->router;
2479 }
2480 slist_concat(a2r_a->router->addrs, list);
2481 slist_free(list);
2482 }
2483 }
2484 else if(a2r_a != NULL)
2485 {
2486 r = a2r_a->router;
2487 if((a2r_b = sc_addr2router_alloc(b, r)) == NULL ||
2488 slist_tail_push(a2r_a->router->addrs, a2r_b) == NULL)
2489 goto err;
2490 }
2491 else if(a2r_b != NULL)
2492 {
2493 r = a2r_b->router;
2494 if((a2r_a = sc_addr2router_alloc(a, r)) == NULL ||
2495 slist_tail_push(a2r_b->router->addrs, a2r_a) == NULL)
2496 goto err;
2497 }
2498 else
2499 {
2500 if((r = sc_router_alloc()) == NULL ||
2501 (a2r_a = sc_addr2router_alloc(a, r)) == NULL ||
2502 slist_tail_push(r->addrs, a2r_a) == NULL ||
2503 (a2r_b = sc_addr2router_alloc(b, r)) == NULL ||
2504 slist_tail_push(r->addrs, a2r_b) == NULL)
2505 goto err;
2506 }
2507
2508 return 0;
2509
2510 err:
2511 return -1;
2512 }
2513
finish_1(void)2514 static void finish_1(void)
2515 {
2516 sc_addr2router_t *a2r;
2517 dlist_node_t *dn;
2518 slist_node_t *sn;
2519 sc_router_t *r;
2520 char buf[128];
2521 int x;
2522
2523 for(dn=dlist_head_node(routers); dn != NULL; dn=dlist_node_next(dn))
2524 {
2525 r = dlist_node_item(dn);
2526 slist_qsort(r->addrs, (slist_cmp_t)sc_addr2router_human_cmp);
2527 }
2528 dlist_qsort(routers, (dlist_cmp_t)sc_router_cmp);
2529 for(dn=dlist_head_node(routers); dn != NULL; dn=dlist_node_next(dn))
2530 {
2531 r = dlist_node_item(dn); x = 0;
2532 for(sn=slist_head_node(r->addrs); sn != NULL; sn=slist_node_next(sn))
2533 {
2534 a2r = slist_node_item(sn);
2535 if(x != 0) printf(" ");
2536 printf("%s", scamper_addr_tostr(a2r->addr, buf, sizeof(buf)));
2537 x++;
2538 }
2539 printf("\n");
2540 }
2541
2542 return;
2543 }
2544
process_2_ping(const scamper_ping_t * ping)2545 static int process_2_ping(const scamper_ping_t *ping)
2546 {
2547 uint32_t ipids[10];
2548 int ipidc, replyc;
2549 char buf[64];
2550
2551 if(ping->userid != 0)
2552 {
2553 dump_stop = 1;
2554 return 0;
2555 }
2556
2557 ipidc = sizeof(ipids) / sizeof(uint32_t);
2558 if(ping_read(ping, ipids, &ipidc, &replyc) != 0)
2559 return -1;
2560
2561 scamper_addr_tostr(ping->dst, buf, sizeof(buf));
2562 if(ipidc == 0)
2563 {
2564 if(replyc == 0)
2565 printf("%s unresponsive\n", buf);
2566 else if(replyc == 1)
2567 printf("%s gone-silent\n", buf);
2568 else
2569 printf("%s no-frags\n", buf);
2570 }
2571 else if(ipidc < 3)
2572 printf("%s insuff-ipids\n", buf);
2573 else if(ipid_incr(ipids, ipidc) == 0)
2574 printf("%s random\n", buf);
2575 else
2576 printf("%s incr\n", buf);
2577
2578 return 0;
2579 }
2580
2581 static int d3_states_probec[6];
2582 static struct timeval d3_states_first[6];
2583 static struct timeval d3_states_last[6];
2584
process_3_ping(const scamper_ping_t * ping)2585 static int process_3_ping(const scamper_ping_t *ping)
2586 {
2587 uint32_t id = ping->userid;
2588 if(timeval_cmp(&d3_states_first[id], &ping->start) > 0 ||
2589 d3_states_first[id].tv_sec == 0)
2590 timeval_cpy(&d3_states_first[id], &ping->start);
2591 if(timeval_cmp(&d3_states_last[id], &ping->start) < 0)
2592 timeval_cpy(&d3_states_last[id], &ping->start);
2593 d3_states_probec[id] += ping->ping_sent;
2594 return 0;
2595 }
2596
process_3_ally(const scamper_dealias_t * dealias)2597 static int process_3_ally(const scamper_dealias_t *dealias)
2598 {
2599 uint32_t id = dealias->userid;
2600 d3_states_probec[id] += dealias->probec;
2601 if(timeval_cmp(&d3_states_first[id], &dealias->start) > 0 ||
2602 d3_states_first[id].tv_sec == 0)
2603 timeval_cpy(&d3_states_first[id], &dealias->start);
2604 if(timeval_cmp(&d3_states_last[id], &dealias->start) < 0)
2605 timeval_cpy(&d3_states_last[id], &dealias->start);
2606 return 0;
2607 }
2608
finish_3(void)2609 static void finish_3(void)
2610 {
2611 int h, m, s, i, sum_time = 0, sum_probes = 0;
2612 struct timeval tv;
2613
2614 for(i=0; i<6; i++)
2615 {
2616 if(d3_states_probec[i] == 0)
2617 continue;
2618 timeval_diff_tv(&tv, &d3_states_first[i], &d3_states_last[i]);
2619 hms(tv.tv_sec, &h, &m, &s);
2620 assert((h * 3600) + (m * 60) + s == tv.tv_sec);
2621 printf("%d: %d %d:%02d:%02d\n", i, d3_states_probec[i], h, m, s);
2622 sum_time += tv.tv_sec;
2623 sum_probes += d3_states_probec[i];
2624 }
2625 hms(sum_time, &h, &m, &s);
2626 printf("total: %d %d:%02d:%02d\n", sum_probes, h, m, s);
2627
2628 return;
2629 }
2630
process_4_ping(const scamper_ping_t * ping)2631 static int process_4_ping(const scamper_ping_t *ping)
2632 {
2633 scamper_ping_reply_t *reply;
2634 sc_target_t *target;
2635 sc_targetipid_t ti;
2636 uint16_t u16;
2637
2638 /* only interested in the first three stages */
2639 if(ping->userid != MODE_DESCEND &&
2640 ping->userid != MODE_OVERLAP &&
2641 ping->userid != MODE_DESCEND2)
2642 return 0;
2643
2644 if(targets == NULL &&
2645 (targets = splaytree_alloc((splaytree_cmp_t)sc_target_addr_cmp)) == NULL)
2646 return -1;
2647
2648 if((target = sc_target_findtree(ping->dst)) == NULL)
2649 {
2650 if((target = sc_target_alloc(ping->dst)) == NULL ||
2651 (target->tree_node = splaytree_insert(targets, target)) == NULL)
2652 return -1;
2653 }
2654
2655 for(u16=0; u16<ping->ping_sent; u16++)
2656 {
2657 if((reply = ping->ping_replies[u16]) == NULL ||
2658 SCAMPER_PING_REPLY_IS_ICMP_ECHO_REPLY(reply) == 0 ||
2659 (reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_IPID) == 0)
2660 continue;
2661
2662 /* record the response */
2663 ti.target = target;
2664 ti.ipid = reply->reply_ipid32;
2665 timeval_cpy(&ti.tx, &reply->tx);
2666 timeval_add_tv3(&ti.rx, &reply->tx, &reply->rtt);
2667 if(sc_target_sample(target, &ti) == NULL)
2668 return -1;
2669 }
2670
2671 return 0;
2672 }
2673
finish_4(void)2674 static void finish_4(void)
2675 {
2676 slist_t *tg_list = NULL, *sets = NULL;
2677 slist_node_t *sa, *sb;
2678 sc_target_t *ta, *tb;
2679 sc_targetset_t *ts;
2680 char ba[128], bb[128];
2681 int i = 0;
2682
2683 if((candidates = slist_alloc()) == NULL)
2684 goto done;
2685 if((tg_list = slist_alloc()) == NULL || (sets = slist_alloc()) == NULL)
2686 goto done;
2687 splaytree_inorder(targets, tree_to_slist, tg_list);
2688 if(pairwise_all(tg_list) != 0)
2689 goto done;
2690 slist_qsort(candidates, (slist_cmp_t)sc_targetset_targetc_asc_cmp);
2691
2692 while((ts = slist_head_pop(candidates)) != NULL)
2693 {
2694 if(i > 0)
2695 printf("\n");
2696
2697 sa = slist_head_node(ts->targets);
2698 ta = slist_node_item(sa);
2699
2700 for(sb=slist_node_next(sa); sb != NULL; sb=slist_node_next(sb))
2701 {
2702 tb = slist_node_item(sb);
2703 if(pairwise(ta, tb) == 1)
2704 printf("%s %s\n",
2705 scamper_addr_tostr(ta->addr, ba, sizeof(ba)),
2706 scamper_addr_tostr(tb->addr, bb, sizeof(bb)));
2707 }
2708
2709 sc_targetset_free(ts);
2710 i++;
2711 }
2712
2713 done:
2714 if(tg_list != NULL) slist_free(tg_list);
2715 if(sets != NULL) slist_free_cb(sets, (slist_free_t)sc_targetset_free);
2716 return;
2717 }
2718
speedtrap_read(void)2719 static int speedtrap_read(void)
2720 {
2721 scamper_file_t *in;
2722 char *filename;
2723 uint16_t type;
2724 void *data;
2725 int i, stdin_used=0;
2726
2727 for(i=0; i<dump_filec; i++)
2728 {
2729 filename = dump_files[i]; dump_stop = 0;
2730
2731 if(string_isdash(filename) != 0)
2732 {
2733 if(stdin_used == 1)
2734 {
2735 fprintf(stderr, "stdin already used\n");
2736 return -1;
2737 }
2738 stdin_used++;
2739 in = scamper_file_openfd(STDIN_FILENO, "-", 'r', "warts");
2740 }
2741 else
2742 {
2743 in = scamper_file_open(filename, 'r', NULL);
2744 }
2745
2746 if(in == NULL)
2747 {
2748 fprintf(stderr,"could not open %s: %s\n", filename, strerror(errno));
2749 return -1;
2750 }
2751
2752 while(scamper_file_read(in, ffilter, &type, &data) == 0)
2753 {
2754 /* EOF */
2755 if(data == NULL)
2756 break;
2757
2758 if(type == SCAMPER_FILE_OBJ_PING)
2759 {
2760 if(dump_funcs[dump_id].proc_ping != NULL)
2761 dump_funcs[dump_id].proc_ping(data);
2762 scamper_ping_free(data);
2763 }
2764 else if(type == SCAMPER_FILE_OBJ_DEALIAS)
2765 {
2766 if(dump_funcs[dump_id].proc_ally != NULL)
2767 dump_funcs[dump_id].proc_ally(data);
2768 scamper_dealias_free(data);
2769 }
2770
2771 if(dump_stop != 0)
2772 break;
2773 }
2774
2775 scamper_file_close(in);
2776 }
2777
2778 if(dump_funcs[dump_id].finish != NULL)
2779 dump_funcs[dump_id].finish();
2780
2781 return 0;
2782 }
2783
speedtrap_init(void)2784 static int speedtrap_init(void)
2785 {
2786 uint16_t types[] = {SCAMPER_FILE_OBJ_PING, SCAMPER_FILE_OBJ_DEALIAS};
2787 int typec = sizeof(types) / sizeof(uint16_t);
2788
2789 #ifdef HAVE_PTHREAD
2790 int i;
2791 #endif
2792
2793 if((ffilter = scamper_file_filter_alloc(types, typec)) == NULL)
2794 return -1;
2795
2796 #ifdef HAVE_PTHREAD
2797 if(threadc == -1)
2798 {
2799 threadc = 1;
2800 #ifdef _SC_NPROCESSORS_ONLN
2801 if((i = sysconf(_SC_NPROCESSORS_ONLN)) > 1)
2802 threadc = i;
2803 #endif
2804 }
2805 #else
2806 threadc = 0;
2807 #endif
2808
2809 if((addr2routers =
2810 splaytree_alloc((splaytree_cmp_t)sc_addr2router_cmp)) == NULL ||
2811 (routers = dlist_alloc()) == NULL)
2812 return -1;
2813
2814 return 0;
2815 }
2816
cleanup(void)2817 static void cleanup(void)
2818 {
2819 if(dst_addr != NULL)
2820 {
2821 free(dst_addr);
2822 dst_addr = NULL;
2823 }
2824
2825 if(addr2routers != NULL)
2826 {
2827 splaytree_free(addr2routers, (splaytree_free_t)sc_addr2router_free);
2828 addr2routers = NULL;
2829 }
2830
2831 if(routers != NULL)
2832 {
2833 dlist_foreach(routers, (dlist_foreach_t)sc_router_node_setnull, NULL);
2834 dlist_free_cb(routers, (dlist_free_t)sc_router_free);
2835 routers = NULL;
2836 }
2837
2838 if(pairwise_uint32 != NULL)
2839 {
2840 free(pairwise_uint32);
2841 pairwise_uint32 = NULL;
2842 }
2843
2844 if(pairwise_tipid != NULL)
2845 {
2846 free(pairwise_tipid);
2847 pairwise_tipid = NULL;
2848 }
2849
2850 if(notaliases != NULL)
2851 {
2852 splaytree_free(notaliases, (splaytree_free_t)sc_notaliases_free);
2853 notaliases = NULL;
2854 }
2855
2856 if(descend != NULL)
2857 {
2858 slist_free(descend);
2859 descend = NULL;
2860 }
2861
2862 if(incr != NULL)
2863 {
2864 slist_free_cb(incr, (slist_free_t)sc_target_free);
2865 incr = NULL;
2866 }
2867
2868 if(targets != NULL)
2869 {
2870 splaytree_free(targets, NULL);
2871 targets = NULL;
2872 }
2873
2874 if(candidates != NULL)
2875 {
2876 slist_free(candidates);
2877 candidates = NULL;
2878 }
2879
2880 if(overlap_act != NULL)
2881 {
2882 dlist_free(overlap_act);
2883 overlap_act = NULL;
2884 }
2885
2886 if(probelist != NULL)
2887 {
2888 slist_free(probelist);
2889 probelist = NULL;
2890 }
2891
2892 if(probeheap != NULL)
2893 {
2894 heap_free(probeheap, NULL);
2895 probeheap = NULL;
2896 }
2897
2898 if(waiting != NULL)
2899 {
2900 heap_free(waiting, NULL);
2901 waiting = NULL;
2902 }
2903
2904 if(outfile != NULL)
2905 {
2906 scamper_file_close(outfile);
2907 outfile = NULL;
2908 }
2909
2910 if(decode_in != NULL)
2911 {
2912 scamper_file_close(decode_in);
2913 decode_in = NULL;
2914 }
2915
2916 if(ffilter != NULL)
2917 {
2918 scamper_file_filter_free(ffilter);
2919 ffilter = NULL;
2920 }
2921
2922 if(logfile != NULL)
2923 {
2924 fclose(logfile);
2925 logfile = NULL;
2926 }
2927
2928 if(scamper_wb != NULL)
2929 {
2930 scamper_writebuf_free(scamper_wb);
2931 scamper_wb = NULL;
2932 }
2933
2934 if(scamper_lp != NULL)
2935 {
2936 scamper_linepoll_free(scamper_lp, 0);
2937 scamper_lp = NULL;
2938 }
2939
2940 if(decode_wb != NULL)
2941 {
2942 scamper_writebuf_free(decode_wb);
2943 decode_wb = NULL;
2944 }
2945
2946 return;
2947 }
2948
main(int argc,char * argv[])2949 int main(int argc, char *argv[])
2950 {
2951 #if defined(DMALLOC)
2952 free(malloc(1));
2953 #endif
2954
2955 atexit(cleanup);
2956
2957 if(check_options(argc, argv) != 0)
2958 return -1;
2959
2960 if(speedtrap_init() != 0)
2961 return -1;
2962
2963 if(options & OPT_DUMP)
2964 return speedtrap_read();
2965
2966 return speedtrap_data();
2967 }
2968