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