1 /*
2  * scamper
3  *
4  * $Id: scamper.c,v 1.280 2020/04/30 06:22:05 mjl Exp $
5  *
6  *        Matthew Luckie
7  *        mjl@luckie.org.nz
8  *
9  * Copyright (C) 2003-2006 Matthew Luckie
10  * Copyright (C) 2006-2011 The University of Waikato
11  * Copyright (C) 2012      Matthew Luckie
12  * Copyright (C) 2014      The Regents of the University of California
13  * Copyright (C) 2014-2020 Matthew Luckie
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation, version 2.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  *
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 #include "internal.h"
34 
35 #include "scamper.h"
36 #include "scamper_debug.h"
37 #include "scamper_addr.h"
38 #include "scamper_list.h"
39 #include "scamper_file.h"
40 #include "scamper_outfiles.h"
41 #include "scamper_fds.h"
42 #include "scamper_task.h"
43 #include "scamper_sources.h"
44 #include "scamper_source_cmdline.h"
45 #include "scamper_source_file.h"
46 #include "scamper_source_tsps.h"
47 #include "scamper_queue.h"
48 #include "scamper_getsrc.h"
49 #include "scamper_addr2mac.h"
50 #include "scamper_icmp4.h"
51 #include "scamper_icmp6.h"
52 #include "scamper_udp4.h"
53 #include "scamper_udp6.h"
54 #include "scamper_tcp4.h"
55 #include "scamper_rtsock.h"
56 #include "scamper_dl.h"
57 #include "scamper_firewall.h"
58 #include "scamper_probe.h"
59 #include "scamper_privsep.h"
60 #include "scamper_control.h"
61 #include "scamper_osinfo.h"
62 #include "trace/scamper_trace_do.h"
63 #include "ping/scamper_ping_do.h"
64 #include "tracelb/scamper_tracelb_do.h"
65 #include "dealias/scamper_dealias_do.h"
66 #include "sting/scamper_sting_do.h"
67 #include "neighbourdisc/scamper_neighbourdisc_do.h"
68 #include "tbit/scamper_tbit_do.h"
69 #include "sniff/scamper_sniff_do.h"
70 #include "host/scamper_host_do.h"
71 
72 #include "utils.h"
73 
74 #define OPT_PPS             0x00000001 /* p: */
75 #define OPT_OUTFILE         0x00000002 /* o: */
76 #define OPT_OPTION          0x00000004 /* O: */
77 #define OPT_PIDFILE         0x00000010 /* e: */
78 #define OPT_VERSION         0x00000020 /* v: */
79 #define OPT_DAEMON          0x00000200 /* D: */
80 #define OPT_IP              0x00000400 /* i: */
81 #define OPT_MONITORNAME     0x00002000 /* M: */
82 #define OPT_COMMAND         0x00004000 /* c: */
83 #define OPT_HELP            0x00008000 /* ?: */
84 #define OPT_WINDOW          0x00010000 /* w: */
85 #define OPT_DEBUGFILE       0x00020000 /* d: */
86 #define OPT_LISTNAME        0x00040000 /* l: */
87 #define OPT_LISTID          0x00080000 /* L: */
88 #define OPT_CYCLEID         0x00100000 /* C: */
89 #define OPT_FIREWALL        0x00200000 /* F: */
90 #define OPT_CMDLIST         0x00400000 /* I: */
91 #define OPT_INFILE          0x00800000 /* f: */
92 #define OPT_CTRL_INET       0x01000000 /* P: */
93 #define OPT_CTRL_UNIX       0x02000000 /* U: */
94 #define OPT_CTRL_REMOTE     0x04000000 /* R: */
95 #define OPT_NAMESERVER      0x08000000 /* n: */
96 
97 #define FLAG_NOINITNDC       0x00000001
98 #define FLAG_OUTCOPY         0x00000002
99 #define FLAG_SELECT          0x00000004
100 #define FLAG_KQUEUE          0x00000008
101 #define FLAG_PLANETLAB       0x00000010
102 #define FLAG_EPOLL           0x00000020
103 #define FLAG_RAWTCP          0x00000040
104 #define FLAG_DEBUGFILEAPPEND 0x00000080
105 #define FLAG_NOTLS_REMOTE    0x00000100
106 #define FLAG_NOTLS           0x00000200
107 #if defined(IP_RECVERR) || defined(IPV6_RECVERR)
108 #define FLAG_ICMP_RECVERR    0x00000400
109 #endif
110 
111 /*
112  * parameters configurable by the command line:
113  *
114  * options:     bitmask corresponding to command line arguments
115  * command:     default command to use with scamper
116  * pps:         how many probe packets to send per second
117  * window:      maximum number of concurrent tasks to actively probe
118  * outfile:     where to send results by default
119  * outtype:     format to use when writing results to outfile
120  * intype:      format of input file
121  * ctrl_inet_addr: address to use for control socket
122  * ctrl_inet_port: port to use for control socket
123  * ctrl_unix:   file to use for unix domain control
124  * ctrl_rem_port: port on remote host to connect to for direction
125  * ctrl_rem_name: name or IP address of remote host to connect to
126  * monitorname: canonical name of monitor assigned by human
127  * nameserver:  IP address of a nameserver to use
128  * listname:    name of list assigned by human
129  * listid:      id of list assigned by human
130  * cycleid:     id of cycle assigned by human
131  * arglist:     whatever is left over after getopt processing
132  * arglist_len: number of arguments left over after getopt processing
133  * debugfile:   place to write debugging output
134  * firewall:    scamper should use the system firewall when needed
135  * pidfile:     place to write process id
136  */
137 static uint32_t options    = 0;
138 static uint32_t flags      = 0;
139 static char  *command      = NULL;
140 static int    pps          = SCAMPER_OPTION_PPS_DEF;
141 static int    window       = SCAMPER_OPTION_WINDOW_DEF;
142 static char  *outfile      = "-";
143 static char  *outtype      = "text";
144 static char  *intype       = NULL;
145 static char  *ctrl_inet_addr = NULL;
146 static int    ctrl_inet_port = 0;
147 static char  *ctrl_unix    = NULL;
148 static int    ctrl_rem_port = 0;
149 static char  *ctrl_rem_name = NULL;
150 static char  *monitorname  = NULL;
151 static char  *nameserver   = NULL;
152 static char  *listname     = NULL;
153 static int    listid       = -1;
154 static int    cycleid      = -1;
155 static char **arglist      = NULL;
156 static int    arglist_len  = 0;
157 static char  *firewall     = NULL;
158 static char  *pidfile      = NULL;
159 
160 #ifndef WITHOUT_DEBUGFILE
161 static char  *debugfile    = NULL;
162 #endif
163 
164 /*
165  * parameters calculated by scamper at run time:
166  *
167  * wait_between:   calculated wait between probes to reach pps, in microseconds
168  * probe_window:   maximum extension of probing window before truncation
169  * exit_when_done: exit scamper when current window of tasks is completed
170  */
171 static int    wait_between   = 1000000 / SCAMPER_OPTION_PPS_DEF;
172 static int    probe_window   = 250000;
173 static int    exit_when_done = 1;
174 
175 /* central cache of addresses that scamper is dealing with */
176 scamper_addrcache_t *addrcache = NULL;
177 
178 /* central TLS context with CA certificates loaded */
179 #ifdef HAVE_OPENSSL
180 SSL_CTX *tls_ctx = NULL;
181 #endif
182 
183 /* Source port to use in our probes */
184 static uint16_t default_sport = 0;
185 
186 typedef struct scamper_multicall
187 {
188   char         *argv0;
189   char         *cmd;
190   int         (*validate)(int, char **, int *);
191   const char *(*usage)(void);
192 } scamper_multicall_t;
193 
version(void)194 static void version(void)
195 {
196   fprintf(stderr, "scamper version %s\n", SCAMPER_VERSION);
197   return;
198 }
199 
usage_str(char c,const char * str)200 static void usage_str(char c, const char *str)
201 {
202   fprintf(stderr, "            -%c %s\n", c, str);
203   return;
204 }
205 
usage_line(const char * str)206 static void usage_line(const char *str)
207 {
208   fprintf(stderr, "               %s\n", str);
209   return;
210 }
211 
usage(uint32_t opt_mask)212 static void usage(uint32_t opt_mask)
213 {
214   char buf[256];
215 
216   fprintf(stderr,
217     "usage: scamper [-?Dv] [-c command] [-p pps] [-w window]\n"
218     "               [-M monitorname] [-l listname] [-L listid] [-C cycleid]\n"
219     "               [-o outfile] [-O options] [-F firewall] [-e pidfile]\n"
220     "               [-n nameserver]\n"
221 #ifndef WITHOUT_DEBUGFILE
222     "               [-d debugfile]\n"
223 #endif
224     "               [-i IPs | -I cmds | -f file | -P [ip:]port | -R name:port"
225 #if defined(AF_UNIX) && !defined(_WIN32)
226     " |\n                -U unix]\n");
227 #else
228     "]\n");
229 #endif
230 
231   if(opt_mask == 0) return;
232 
233   fprintf(stderr, "\n");
234 
235   if((opt_mask & OPT_HELP) != 0)
236     usage_str('?', "give an overview of the usage of scamper");
237 
238   if((opt_mask & OPT_COMMAND) != 0)
239     {
240       (void)snprintf(buf, sizeof(buf), "command string (default: %s)",
241 		     SCAMPER_OPTION_COMMAND_DEF);
242       usage_str('c', buf);
243     }
244 
245   if((opt_mask & OPT_CYCLEID) != 0)
246     usage_str('C', "cycle id");
247 
248 #ifndef WITHOUT_DEBUGFILE
249   if((opt_mask & OPT_DEBUGFILE) != 0)
250     usage_str('d', "write debugging information to the specified file");
251 #endif
252 
253 #ifdef HAVE_DAEMON
254   if((opt_mask & OPT_DAEMON) != 0)
255     usage_str('D', "start as a daemon listening for commands on a port");
256 #endif
257 
258   if((opt_mask & OPT_PIDFILE) != 0)
259     usage_str('e', "write process ID to specified file");
260 
261   if((opt_mask & OPT_INFILE) != 0)
262     usage_str('f', "list of files provided on the command line");
263 
264   if((opt_mask & OPT_FIREWALL) != 0)
265     usage_str('F', "use the system firewall to install rules as necessary");
266 
267   if((opt_mask & OPT_IP) != 0)
268     usage_str('i', "list of IP addresses provided on the command line");
269 
270   if((opt_mask & OPT_CMDLIST) != 0)
271     usage_str('I', "list of scamper commands provided on the command line");
272 
273   if((opt_mask & OPT_LISTID) != 0)
274     usage_str('l', "name to assign to default list");
275 
276   if((opt_mask & OPT_LISTNAME) != 0)
277     usage_str('L', "list id for default list");
278 
279   if((opt_mask & OPT_MONITORNAME) != 0)
280     usage_str('M', "specify the canonical name of the monitor");
281 
282   if((opt_mask & OPT_OUTFILE) != 0)
283     usage_str('o', "specify the file to write output to");
284 
285   if((opt_mask & OPT_OPTION) != 0)
286     {
287       usage_str('O', "specify options to use:");
288       usage_line("text: output results in plain text for interactive use");
289       usage_line("warts: output results in warts format for science");
290       usage_line("tsps: input file for ping -T tsprespec=%s");
291       usage_line("cmdfile: input file specifies whole commands");
292       usage_line("json: output results in json format, better to use warts");
293       usage_line("planetlab: necessary to use safe raw sockets on planetlab");
294       usage_line("noinitndc: do not initialise neighbour discovery cache");
295       usage_line("outcopy: output copy of all results collected to file");
296       usage_line("rawtcp: use raw socket to send IPv4 TCP probes");
297 #if defined(IP_RECVERR) || defined(IPV6_RECVERR)
298       usage_line("icmp-rxerr: use recverr cmsg to receive ICMP responses");
299 #endif
300       usage_line("notls: do not use TLS anywhere in scamper");
301       usage_line("notls-remote: do not use TLS on remote control sockets");
302 #ifndef _WIN32
303       usage_line("select: use select(2) rather than poll(2)");
304 #endif
305 #ifdef HAVE_KQUEUE
306       usage_line("kqueue: use kqueue(2) rather than poll(2)");
307 #endif
308 #ifdef HAVE_EPOLL
309       usage_line("epoll: use epoll(7) rather than poll(2)");
310 #endif
311 #ifndef WITHOUT_DEBUGFILE
312       usage_line("debugfileappend: append to debugfile, rather than truncate");
313 #endif
314     }
315 
316   if((opt_mask & OPT_PPS) != 0)
317     {
318       snprintf(buf, sizeof(buf),
319 	       "number of packets per second to send (%d <= pps <= %d)",
320 	       SCAMPER_OPTION_PPS_MIN, SCAMPER_OPTION_PPS_MAX);
321       usage_str('p', buf);
322     }
323 
324   if((opt_mask & OPT_CTRL_INET) != 0)
325     usage_str('P', "[ip:]port for control socket, default to loopback");
326 
327   if((opt_mask & OPT_CTRL_REMOTE) != 0)
328     usage_str('R', "name and port of remote host to receive commands from");
329 
330   if((opt_mask & OPT_CTRL_UNIX) != 0)
331     usage_str('U', "name of control socket in the file system");
332 
333   if((opt_mask & OPT_VERSION) != 0)
334     usage_str('v', "output the version of scamper this binary is");
335 
336   if((opt_mask & OPT_WINDOW) != 0)
337     usage_str('w', "limit the window of actively probing tasks");
338 
339   return;
340 }
341 
set_opt(uint32_t opt,char * str,int (* setfunc)(int))342 static int set_opt(uint32_t opt, char *str, int (*setfunc)(int))
343 {
344   long l = 0;
345 
346   if(string_isnumber(str) == 0 || string_tolong(str, &l) == -1)
347     {
348       usage(opt);
349       return -1;
350     }
351 
352   return setfunc(l);
353 }
354 
multicall_do(const scamper_multicall_t * mc,int argc,char * argv[])355 static int multicall_do(const scamper_multicall_t *mc, int argc, char *argv[])
356 {
357   char *str;
358   size_t off, len, tmp;
359   int i, stop;
360 
361   if(argc == 1 || mc->validate(argc, argv, &stop) != 0 || stop == argc)
362     {
363       if(mc->usage != NULL)
364 	{
365 	  printf("usage: scamper-%s <ip list>\n", mc->usage());
366 	}
367       return -1;
368     }
369 
370   /* assemble the command string */
371   len = strlen(mc->cmd) + 1;
372   for(i=1; i<stop; i++)
373     {
374       len += strlen(argv[i]) + 1;
375     }
376   if((str = malloc_zero(len)) == NULL)
377     {
378       printerror(__func__, "could not assemble %s command", mc->cmd);
379       return -1;
380     }
381   off = strlen(mc->cmd);
382   memcpy(str, mc->cmd, off);
383   str[off++] = ' ';
384   for(i=1; i<stop; i++)
385     {
386       tmp = strlen(argv[i]);
387       memcpy(str+off, argv[i], tmp);
388       off += tmp;
389       str[off++] = ' ';
390     }
391   str[off] = '\0';
392 
393   /* set the command */
394   scamper_option_command_set(str);
395   free(str);
396 
397   options |= OPT_IP;
398 
399   arglist     = argv + stop;
400   arglist_len = argc - stop;
401 
402   return 0;
403 }
404 
cycleid_set(const int cid)405 static int cycleid_set(const int cid)
406 {
407   if(cid > 0 && cid <= 0x7fffffff)
408     {
409       cycleid = cid;
410       return 0;
411     }
412   return -1;
413 }
414 
listid_set(const int lid)415 static int listid_set(const int lid)
416 {
417   if(lid > 0 && lid <= 0x7fffffff)
418     {
419       listid = lid;
420       return 0;
421     }
422   return -1;
423 }
424 
ppswindow_set(int p,int w)425 static int ppswindow_set(int p, int w)
426 {
427   if(p == 0 && w == 0)
428     return -1;
429 
430   if(p != pps)
431     {
432       if(p != 0 && (p < SCAMPER_OPTION_PPS_MIN || p > SCAMPER_OPTION_PPS_MAX))
433 	return -1;
434 
435       /*
436        * reset the pps scamper is operating at.  re-calculate the
437        * inter-probe delay, and the maximum size of the probe window.
438        */
439       pps = p;
440       if(p != 0)
441 	wait_between = 1000000 / pps;
442       else
443 	wait_between = 0;
444       probe_window = 250000;
445       if(wait_between > 250000)
446 	probe_window += wait_between;
447     }
448 
449   if(w != window)
450     {
451       if(w != 0 &&
452 	 (w < SCAMPER_OPTION_WINDOW_MIN || w > SCAMPER_OPTION_WINDOW_MAX))
453 	return -1;
454       window = w;
455     }
456 
457   return 0;
458 }
459 
check_options(int argc,char * argv[])460 static int check_options(int argc, char *argv[])
461 {
462   static const scamper_multicall_t multicall[] = {
463     {"scamper-trace",   "trace",
464      scamper_do_trace_arg_validate, scamper_do_trace_usage},
465     {"scamper-ping",    "ping",
466      scamper_do_ping_arg_validate, scamper_do_ping_usage},
467     {"scamper-tracelb", "tracelb",
468      scamper_do_tracelb_arg_validate, scamper_do_tracelb_usage},
469     {"scamper-dealias", "dealias",
470      scamper_do_dealias_arg_validate, scamper_do_dealias_usage},
471     {"scamper-sting",   "sting",
472      scamper_do_sting_arg_validate, scamper_do_sting_usage},
473     {"scamper-neighbourdisc", "neighbourdisc",
474      scamper_do_neighbourdisc_arg_validate, scamper_do_neighbourdisc_usage},
475     {"scamper-tbit", "tbit",
476      scamper_do_tbit_arg_validate, scamper_do_tbit_usage},
477     {"scamper-sniff", "sniff",
478      scamper_do_sniff_arg_validate, scamper_do_sniff_usage},
479     {"scamper-host", "host",
480      scamper_do_host_arg_validate, scamper_do_host_usage},
481   };
482   int   i;
483   long  lo_w = window, lo_p = pps;
484   char  opts[64];
485   char *opt_cycleid = NULL, *opt_listid = NULL, *opt_listname = NULL;
486   char *opt_ctrl_inet = NULL, *opt_ctrl_unix = NULL, *opt_monitorname = NULL;
487   char *opt_pps = NULL, *opt_command = NULL, *opt_window = NULL;
488   char *opt_firewall = NULL, *opt_pidfile = NULL, *opt_ctrl_remote = NULL;
489   char *opt_nameserver = NULL;
490 
491 #ifndef WITHOUT_DEBUGFILE
492   char *opt_debugfile = NULL;
493 #endif
494 
495   size_t argv0 = strlen(argv[0]);
496   size_t m, len;
497   size_t off;
498   uint32_t o;
499 
500   for(m=0; m<sizeof(multicall)/sizeof(scamper_multicall_t); m++)
501     {
502       len = strlen(multicall[m].argv0);
503       if(argv0 >= len && strcmp(argv[0]+argv0-len, multicall[m].argv0) == 0)
504 	{
505 	  return multicall_do(&multicall[m], argc, argv);
506 	}
507     }
508 
509   off = 0;
510   string_concat(opts, sizeof(opts), &off, "c:C:e:fF:iIl:L:M:n:o:O:p:P:R:vw:?");
511 #ifndef WITHOUT_DEBUGFILE
512   string_concat(opts, sizeof(opts), &off, "d:");
513 #endif
514 #if HAVE_DAEMON
515   string_concat(opts, sizeof(opts), &off, "D");
516 #endif
517 #if defined(AF_UNIX)
518   string_concat(opts, sizeof(opts), &off, "U:");
519 #endif
520 
521   while((i = getopt(argc, argv, opts)) != -1)
522     {
523       switch(i)
524 	{
525 	case 'c':
526 	  options |= OPT_COMMAND;
527 	  opt_command = optarg;
528 	  break;
529 
530 	case 'C':
531 	  options |= OPT_CYCLEID;
532 	  opt_cycleid = optarg;
533 	  break;
534 
535 #ifndef WITHOUT_DEBUGFILE
536 	case 'd':
537 	  options |= OPT_DEBUGFILE;
538 	  opt_debugfile = optarg;
539 	  break;
540 #endif
541 
542 #ifdef HAVE_DAEMON
543 	case 'D':
544 	  options |= OPT_DAEMON;
545 	  break;
546 #endif
547 
548 	case 'e':
549 	  options |= OPT_PIDFILE;
550 	  opt_pidfile = optarg;
551 	  break;
552 
553 	case 'f':
554 	  options |= OPT_INFILE;
555 	  break;
556 
557 	case 'F':
558 	  options |= OPT_FIREWALL;
559 	  opt_firewall = optarg;
560 	  break;
561 
562 	case 'i':
563 	  options |= OPT_IP;
564 	  break;
565 
566 	case 'I':
567 	  options |= OPT_CMDLIST;
568 	  break;
569 
570 	case 'l':
571 	  options |= OPT_LISTNAME;
572 	  opt_listname = optarg;
573 	  break;
574 
575 	case 'L':
576 	  options |= OPT_LISTID;
577 	  opt_listid = optarg;
578 	  break;
579 
580 	case 'M':
581 	  options |= OPT_MONITORNAME;
582 	  opt_monitorname = optarg;
583 	  break;
584 
585 	case 'n':
586 	  options |= OPT_NAMESERVER;
587 	  opt_nameserver = optarg;
588 	  break;
589 
590         case 'o':
591           options |= OPT_OUTFILE;
592           outfile = optarg;
593           break;
594 
595 	case 'O':
596 	  if(strcasecmp(optarg, "text") == 0)
597 	    outtype = optarg;
598 	  else if(strcasecmp(optarg, "warts") == 0)
599 	    outtype = optarg;
600 	  else if(strcasecmp(optarg, "json") == 0)
601 	    outtype = optarg;
602 	  else if(strcasecmp(optarg, "tsps") == 0)
603 	    intype = optarg;
604 	  else if(strcasecmp(optarg, "cmdfile") == 0)
605 	    intype = optarg;
606 	  else if(strcasecmp(optarg, "planetlab") == 0)
607 	    flags |= FLAG_PLANETLAB;
608 	  else if(strcasecmp(optarg, "noinitndc") == 0)
609 	    flags |= FLAG_NOINITNDC;
610 	  else if(strcasecmp(optarg, "outcopy") == 0)
611 	    flags |= FLAG_OUTCOPY;
612 	  else if(strcasecmp(optarg, "rawtcp") == 0)
613 	    flags |= FLAG_RAWTCP;
614 #if defined(IP_RECVERR) || defined(IPV6_RECVERR)
615 	  else if(strcasecmp(optarg, "icmp-rxerr") == 0 ||
616 		  strcasecmp(optarg, "rxerr-icmp") == 0)
617 	    flags |= FLAG_ICMP_RECVERR;
618 #endif
619 	  else if(strcasecmp(optarg, "notls-remote") == 0)
620 	    flags |= FLAG_NOTLS_REMOTE;
621 	  else if(strcasecmp(optarg, "notls") == 0)
622 	    flags |= FLAG_NOTLS;
623 #ifndef _WIN32
624 	  else if(strcasecmp(optarg, "select") == 0)
625 	    flags |= FLAG_SELECT;
626 #endif
627 #ifdef HAVE_KQUEUE
628 	  else if(strcasecmp(optarg, "kqueue") == 0)
629 	    flags |= FLAG_KQUEUE;
630 #endif
631 #ifdef HAVE_EPOLL
632 	  else if(strcasecmp(optarg, "epoll") == 0)
633 	    flags |= FLAG_EPOLL;
634 #endif
635 #ifndef WITHOUT_DEBUGFILE
636 	  else if(strcasecmp(optarg, "debugfileappend") == 0)
637 	    flags |= FLAG_DEBUGFILEAPPEND;
638 #endif
639 	  else
640 	    {
641 	      usage(OPT_OPTION);
642 	      return -1;
643 	    }
644 	  break;
645 
646 	case 'p':
647 	  options |= OPT_PPS;
648 	  opt_pps = optarg;
649 	  break;
650 
651 	case 'P':
652 	  options |= OPT_CTRL_INET;
653 	  opt_ctrl_inet = optarg;
654 	  break;
655 
656 	case 'R':
657 	  options |= OPT_CTRL_REMOTE;
658 	  opt_ctrl_remote = optarg;
659 	  break;
660 
661 	case 'U':
662 	  options |= OPT_CTRL_UNIX;
663 	  opt_ctrl_unix = optarg;
664 	  break;
665 
666 	case 'v':
667 	  options |= OPT_VERSION;
668 	  break;
669 
670 	case 'w':
671 	  options |= OPT_WINDOW;
672 	  opt_window = optarg;
673 	  break;
674 
675 	case '?':
676 	  options |= OPT_HELP;
677 	  usage(0xffffffff);
678 	  return -1;
679 
680 	default:
681 	  printerror(__func__, "could not parse command line options");
682 	  return -1;
683 	}
684     }
685 
686   if(options & OPT_VERSION)
687     {
688       version();
689       return -1;
690     }
691 
692 
693   /*
694    * if one of -IPRUi is not provided, pretend that -f was for backward
695    * compatibility
696    */
697   if((options & (OPT_CMDLIST | OPT_CTRL_INET | OPT_CTRL_REMOTE |
698 		 OPT_CTRL_UNIX | OPT_IP)) == 0)
699     {
700       options |= OPT_INFILE;
701     }
702 
703   if(options & (OPT_PPS|OPT_WINDOW))
704     {
705       if(opt_window != NULL && string_tolong(opt_window, &lo_w) != 0)
706 	{
707 	  usage(OPT_WINDOW);
708 	  return -1;
709 	}
710       if(opt_pps != NULL && string_tolong(opt_pps, &lo_p) != 0)
711 	{
712 	  usage(OPT_PPS);
713 	  return -1;
714 	}
715       if(ppswindow_set(lo_p, lo_w) != 0)
716 	{
717 	  usage(OPT_PPS|OPT_WINDOW);
718 	  return -1;
719 	}
720     }
721 
722   if(options & OPT_FIREWALL && (firewall = strdup(opt_firewall)) == NULL)
723     {
724       printerror(__func__, "could not strdup firewall");
725       return -1;
726     }
727 
728   if(options & OPT_MONITORNAME &&
729      (monitorname = strdup(opt_monitorname)) == NULL)
730     {
731       printerror(__func__, "could not strdup monitorname");
732       return -1;
733     }
734 
735   if(options & OPT_NAMESERVER &&
736      (nameserver = strdup(opt_nameserver)) == NULL)
737     {
738       printerror(__func__, "could not strdup nameserver");
739       return -1;
740     }
741 
742   if(options & OPT_LISTNAME && (listname = strdup(opt_listname)) == NULL)
743     {
744       printerror(__func__, "could not strdup listname");
745       return -1;
746     }
747 
748   if(options & OPT_LISTID && set_opt(OPT_LISTID, opt_listid, listid_set) != 0)
749     {
750       usage(OPT_LISTID);
751       return -1;
752     }
753 
754   if(options & OPT_CYCLEID &&
755      set_opt(OPT_CYCLEID, opt_cycleid, cycleid_set) != 0)
756     {
757       usage(OPT_CYCLEID);
758       return -1;
759     }
760 
761 #ifndef WITHOUT_DEBUGFILE
762   if(options & OPT_DEBUGFILE && (debugfile = strdup(opt_debugfile)) == NULL)
763     {
764       printerror(__func__, "could not strdup debugfile");
765       return -1;
766     }
767 #endif
768 
769   if(options & OPT_PIDFILE && (pidfile = strdup(opt_pidfile)) == NULL)
770     {
771       printerror(__func__, "could not strdup pidfile");
772       return -1;
773     }
774 
775   /* these are the left-over arguments */
776   arglist     = argv + optind;
777   arglist_len = argc - optind;
778 
779   /* if one of -PUi is used, then a default command must be set */
780   if((options & (OPT_CTRL_INET | OPT_CTRL_UNIX | OPT_IP | OPT_INFILE)) != 0 &&
781      scamper_option_command_set((options & OPT_COMMAND) ?
782 				opt_command : SCAMPER_OPTION_COMMAND_DEF) != 0)
783     {
784       return -1;
785     }
786 
787 #ifdef HAVE_DAEMON
788   if((options & OPT_DAEMON) &&
789      (options & (OPT_CTRL_INET|OPT_CTRL_UNIX|OPT_CTRL_REMOTE)) == 0)
790     {
791       usage(OPT_DAEMON | OPT_CTRL_INET | OPT_CTRL_UNIX | OPT_CTRL_REMOTE);
792       return -1;
793     }
794 #endif
795 
796   o = options & (OPT_CTRL_INET | OPT_CTRL_UNIX | OPT_CTRL_REMOTE |
797 		 OPT_IP | OPT_CMDLIST | OPT_INFILE);
798 
799   if(options & (OPT_CTRL_INET|OPT_CTRL_REMOTE|OPT_CTRL_UNIX))
800     {
801       if(options & (OPT_IP | OPT_CMDLIST | OPT_INFILE))
802 	{
803 	  usage(o);
804 	  return -1;
805 	}
806 
807       if(options & OPT_CTRL_INET)
808 	{
809 	  /* if listening on control socket there should be no leftover args */
810 	  if(arglist_len != 0 ||
811 	     string_addrport(opt_ctrl_inet, &ctrl_inet_addr, &ctrl_inet_port) != 0)
812 	    {
813 	      usage(OPT_CTRL_INET);
814 	      return -1;
815 	    }
816 	}
817       if(options & OPT_CTRL_REMOTE)
818 	{
819 	  /*
820 	   * if using a remote control socket, there should be no
821 	   * leftover args
822 	   */
823 	  if(arglist_len != 0 ||
824 	     string_addrport(opt_ctrl_remote, &ctrl_rem_name, &ctrl_rem_port) != 0)
825 	    {
826 	      usage(OPT_CTRL_REMOTE);
827 	      return -1;
828 	    }
829 	}
830       if(options & OPT_CTRL_UNIX)
831 	{
832 	  /* if listening on control socket there should be no leftover args */
833 	  if(arglist_len != 0)
834 	    {
835 	      usage(OPT_CTRL_UNIX);
836 	      return -1;
837 	    }
838 	  ctrl_unix = opt_ctrl_unix;
839 	}
840     }
841   else if(options & (OPT_IP | OPT_CMDLIST))
842     {
843       /* only one of the following should be specified */
844       if((options & (OPT_CTRL_INET|OPT_CTRL_REMOTE|OPT_CTRL_UNIX|OPT_INFILE)) ||
845 	 ((options & OPT_IP) && (options & OPT_CMDLIST)))
846 	{
847 	  usage(o);
848 	  return -1;
849 	}
850 
851       /*
852        * if a list of IP addresses or commands is to be supplied, there has to
853        * be at least one left over argument.
854        */
855       if(arglist_len < 1)
856 	{
857 	  if(options & OPT_IP)
858 	    usage(OPT_IP);
859 	  else if(options & OPT_CMDLIST)
860 	    usage(OPT_CMDLIST);
861 	  return -1;
862 	}
863     }
864   else
865     {
866       /*
867        * if a listfile is specified, then there may only be one left over
868        * argument, which specifies the listfile.
869        */
870       assert(o == OPT_INFILE);
871       if(arglist_len != 1)
872 	{
873 	  usage(0);
874 	  return -1;
875 	}
876     }
877 
878   return 0;
879 }
880 
scamper_option_command_get(void)881 const char *scamper_option_command_get(void)
882 {
883   assert(command != NULL);
884   return command;
885 }
886 
scamper_option_command_set(const char * command_in)887 int scamper_option_command_set(const char *command_in)
888 {
889   char *d;
890 
891   if(command_in == NULL)
892     {
893       return -1;
894     }
895 
896   if((d = strdup(command_in)) == NULL)
897     {
898       printerror(__func__, "could not strdup command");
899       return -1;
900     }
901 
902   if(command != NULL)
903     free(command);
904 
905   command = d;
906   return 0;
907 }
908 
scamper_exitwhendone(int on)909 void scamper_exitwhendone(int on)
910 {
911   if(on == 1 || on == 0)
912     {
913       exit_when_done = on;
914     }
915   return;
916 }
917 
scamper_option_pps_get()918 int scamper_option_pps_get()
919 {
920   return pps;
921 }
922 
scamper_option_pps_set(const int p)923 int scamper_option_pps_set(const int p)
924 {
925   return ppswindow_set(p, window);
926 }
927 
scamper_option_window_get()928 int scamper_option_window_get()
929 {
930   return window;
931 }
932 
scamper_option_window_set(const int w)933 int scamper_option_window_set(const int w)
934 {
935   return ppswindow_set(pps, w);
936 }
937 
scamper_option_monitorname_get()938 const char *scamper_option_monitorname_get()
939 {
940   return monitorname;
941 }
942 
scamper_option_monitorname_set(const char * mn)943 int scamper_option_monitorname_set(const char *mn)
944 {
945   char *tmp;
946 
947   /*
948    * before removing the old monitor name, get a copy of the monitor name
949    * since that's what we'll be using to store afterward
950    */
951   if(mn != NULL)
952     {
953       if((tmp = strdup(mn)) == NULL)
954 	{
955 	  return -1;
956 	}
957     }
958   else
959     {
960       tmp = NULL;
961     }
962 
963   if(monitorname != NULL)
964     {
965       free(monitorname);
966     }
967 
968   monitorname = tmp;
969   return 0;
970 }
971 
scamper_option_nameserver_get(void)972 const char *scamper_option_nameserver_get(void)
973 {
974   return nameserver;
975 }
976 
scamper_option_planetlab(void)977 int scamper_option_planetlab(void)
978 {
979   if(flags & FLAG_PLANETLAB) return 1;
980   return 0;
981 }
982 
scamper_option_select(void)983 int scamper_option_select(void)
984 {
985   if(flags & FLAG_SELECT) return 1;
986   return 0;
987 }
988 
scamper_option_kqueue(void)989 int scamper_option_kqueue(void)
990 {
991   if(flags & FLAG_KQUEUE) return 1;
992   return 0;
993 }
994 
scamper_option_epoll(void)995 int scamper_option_epoll(void)
996 {
997   if(flags & FLAG_EPOLL) return 1;
998   return 0;
999 }
1000 
scamper_option_noinitndc(void)1001 int scamper_option_noinitndc(void)
1002 {
1003   if(flags & FLAG_NOINITNDC) return 1;
1004   return 0;
1005 }
1006 
scamper_option_rawtcp(void)1007 int scamper_option_rawtcp(void)
1008 {
1009   if(flags & FLAG_RAWTCP) return 1;
1010   return 0;
1011 }
1012 
scamper_option_icmp_rxerr(void)1013 int scamper_option_icmp_rxerr(void)
1014 {
1015 #ifdef __ANDROID__
1016   return 1;
1017 #else
1018 #if defined(IP_RECVERR) || defined(IPV6_RECVERR)
1019   if(flags & FLAG_ICMP_RECVERR) return 1;
1020 #endif
1021   return 0;
1022 #endif
1023 }
1024 
scamper_option_debugfileappend(void)1025 int scamper_option_debugfileappend(void)
1026 {
1027   if(flags & FLAG_DEBUGFILEAPPEND) return 1;
1028   return 0;
1029 }
1030 
scamper_option_notls(void)1031 int scamper_option_notls(void)
1032 {
1033 #ifdef HAVE_OPENSSL
1034   if(flags & FLAG_NOTLS) return 1;
1035   return 0;
1036 #else
1037   return 1;
1038 #endif
1039 }
1040 
scamper_option_daemon(void)1041 int scamper_option_daemon(void)
1042 {
1043   if(options & OPT_DAEMON) return 1;
1044   return 0;
1045 }
1046 
scamper_pidfile(void)1047 static int scamper_pidfile(void)
1048 {
1049   char buf[32];
1050   mode_t mode;
1051   size_t len;
1052   int fd, fd_flags = O_WRONLY | O_TRUNC | O_CREAT;
1053 
1054 #ifndef _WIN32
1055   pid_t pid = getpid();
1056   mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1057 #else
1058   DWORD pid = GetCurrentProcessId();
1059   mode = _S_IREAD | _S_IWRITE;
1060 #endif
1061 
1062 #if defined(WITHOUT_PRIVSEP)
1063   fd = open(pidfile, fd_flags, mode);
1064 #else
1065   fd = scamper_privsep_open_file(pidfile, fd_flags, mode);
1066 #endif
1067 
1068   if(fd == -1)
1069     {
1070       printerror(__func__, "could not open %s", pidfile);
1071       goto err;
1072     }
1073 
1074   snprintf(buf, sizeof(buf), "%ld\n", (long)pid);
1075   len = strlen(buf);
1076   if(write_wrap(fd, buf, NULL, len) != 0)
1077     {
1078       printerror(__func__, "could not write pid");
1079       goto err;
1080     }
1081   close(fd);
1082 
1083   return 0;
1084 
1085  err:
1086   if(fd != -1) close(fd);
1087   return -1;
1088 }
1089 
1090 #ifndef _WIN32
scamper_chld(int sig)1091 static void scamper_chld(int sig)
1092 {
1093   int status;
1094 
1095   if(sig != SIGCHLD)
1096     return;
1097 
1098   for(;;)
1099     {
1100       if(waitpid(-1, &status, WNOHANG) == -1)
1101 	{
1102 	  break;
1103 	}
1104     }
1105 
1106   return;
1107 }
1108 #endif
1109 
scamper_sport_init(void)1110 static void scamper_sport_init(void)
1111 {
1112 #ifndef _WIN32
1113   pid_t pid = getpid();
1114 #else
1115   DWORD pid = GetCurrentProcessId();
1116 #endif
1117   default_sport = (pid & 0x7fff) + 0x8000;
1118   return;
1119 }
1120 
scamper_sport_default(void)1121 uint16_t scamper_sport_default(void)
1122 {
1123   return default_sport;
1124 }
1125 
1126 /*
1127  * scamper_timeout
1128  *
1129  * figure out how long the timeout on the poll (or equivalent) should be.
1130  *
1131  * returns:
1132  *  zero if there is a timeout value computed
1133  *  one  if there is no timeout value computed
1134  *  two  if scamper should exit because it is done.
1135  */
scamper_timeout(struct timeval * timeout,struct timeval * nextprobe,struct timeval * lastprobe)1136 static int scamper_timeout(struct timeval *timeout, struct timeval *nextprobe,
1137 			   struct timeval *lastprobe)
1138 {
1139   struct timeval tv;
1140   int probe = 0;
1141 
1142   if(scamper_queue_readycount() > 0 ||
1143      ((window == 0 || scamper_queue_windowcount() < window) &&
1144       scamper_sources_isready() != 0))
1145     {
1146       /*
1147        * if there is something ready to be probed right now, then set the
1148        * timeout to go off when it is time to send the next probe
1149        */
1150       timeval_add_us(nextprobe, lastprobe, wait_between);
1151       probe = 1;
1152     }
1153   else if(scamper_queue_count() > 0)
1154     {
1155       /*
1156        * if there isn't anything ready to go right now, but we are
1157        * waiting on a response from an earlier probe, then set the timer
1158        * to go off when that probe expires.
1159        */
1160       scamper_queue_waittime(nextprobe);
1161       probe = 1;
1162     }
1163   else
1164     {
1165       if(exit_when_done != 0 && scamper_sources_isempty() == 1)
1166 	return 2;
1167     }
1168 
1169   /*
1170    * if there are no events to consider, then we only need to consider
1171    * if there are events in the future
1172    */
1173   if(scamper_queue_event_waittime(&tv) == 0)
1174     {
1175       if(probe == 0)
1176 	return 1;
1177       timeval_cpy(timeout, nextprobe);
1178       return 0;
1179     }
1180 
1181   /*
1182    * there is an event and (maybe) a probe timeout to consider.
1183    * figure out which comes first: the event or the probe
1184    */
1185   if(probe != 0 && timeval_cmp(nextprobe, &tv) <= 0)
1186     timeval_cpy(timeout, nextprobe);
1187   else
1188     timeval_cpy(timeout, &tv);
1189   return 0;
1190 }
1191 
1192 /*
1193  * scamper:
1194  *
1195  * this bit of code contains most of the logic for driving the parallel
1196  * measurement processes.
1197  */
scamper(int argc,char * argv[])1198 static int scamper(int argc, char *argv[])
1199 {
1200   struct timeval           tv;
1201   struct timeval           lastprobe;
1202   struct timeval           nextprobe;
1203   struct timeval           timeout, *timeout_ptr;
1204   const char              *sofname;
1205   scamper_source_params_t  ssp;
1206   scamper_source_t        *source = NULL;
1207   scamper_task_t          *task;
1208   scamper_outfile_t       *sof, *sof2;
1209   scamper_file_t          *file;
1210   int                      x;
1211 
1212   if(check_options(argc, argv) == -1)
1213     {
1214       return -1;
1215     }
1216 
1217 #ifdef HAVE_DAEMON
1218   if((options & OPT_DAEMON) != 0)
1219     {
1220       if(daemon(1, 0) != 0)
1221 	{
1222 	  printerror(__func__, "could not daemon");
1223 	  return -1;
1224 	}
1225       scamper_debug_daemon();
1226     }
1227 #endif
1228 
1229 #ifndef WITHOUT_DEBUGFILE
1230   /*
1231    * open the debug file immediately so initialisation debugging information
1232    * makes it to the file
1233    */
1234   if(debugfile != NULL && scamper_debug_open(debugfile) != 0)
1235     {
1236       return -1;
1237     }
1238 #endif
1239 
1240   if(scamper_osinfo_init() != 0)
1241     return -1;
1242 
1243   /*
1244    * this has to be done before priviledge separation, as if scamper is
1245    * running on a BPF system it has to open a BPF fd to establish
1246    * version compatibility
1247    */
1248   if(scamper_dl_init() == -1)
1249     {
1250       return -1;
1251     }
1252 
1253 #ifdef HAVE_OPENSSL
1254   if((flags & FLAG_NOTLS) == 0)
1255     {
1256       SSL_library_init();
1257       if((tls_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
1258 	{
1259 	  printerror_msg(__func__, "could not create ssl_ctx");
1260 	  return -1;
1261 	}
1262       SSL_CTX_set_options(tls_ctx,
1263 			  SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
1264       SSL_CTX_set_verify(tls_ctx, SSL_VERIFY_PEER, NULL);
1265 
1266       /* load the default set of certs into the SSL context */
1267       if(SSL_CTX_set_default_verify_paths(tls_ctx) != 1)
1268 	{
1269 	  printerror_msg(__func__, "could not load default CA certs");
1270 	  return -1;
1271 	}
1272     }
1273 #endif
1274 
1275 #ifndef WITHOUT_PRIVSEP
1276   /* revoke the root priviledges we started with */
1277   if(scamper_privsep_init() == -1)
1278     {
1279       return -1;
1280     }
1281 #endif
1282 
1283   /* now that we've forked for privsep, write the pidfile */
1284   if((options & OPT_PIDFILE) != 0 && scamper_pidfile() != 0)
1285     return -1;
1286 
1287   random_seed();
1288 
1289   if(firewall != NULL)
1290     {
1291       if(scamper_firewall_init(firewall) != 0)
1292 	return -1;
1293       free(firewall);
1294       firewall = NULL;
1295     }
1296 
1297   /* determine a suitable default value for the source port in packets */
1298   scamper_sport_init();
1299 
1300   /* allocate the cache of addresses for scamper to keep track of */
1301   if((addrcache = scamper_addrcache_alloc()) == NULL)
1302     {
1303       return -1;
1304     }
1305 
1306   /* init the probing code */
1307   if(scamper_probe_init() != 0)
1308     return -1;
1309 
1310   /* initialise the queues that hold the current tasks */
1311   if(scamper_queue_init() == -1)
1312     return -1;
1313 
1314   /* setup the file descriptor monitoring code */
1315   if(scamper_fds_init() == -1)
1316     {
1317       return -1;
1318     }
1319 
1320   /* initialise the subsystem responsible for obtaining source addresses */
1321   if(scamper_getsrc_init() == -1)
1322     {
1323       return -1;
1324     }
1325 
1326   /* initialise the subsystem responsible for recording mac addresses */
1327   if(scamper_addr2mac_init() == -1)
1328     {
1329       return -1;
1330     }
1331 
1332   if(scamper_rtsock_init() == -1)
1333     {
1334       return -1;
1335     }
1336 
1337   /* initialise the structures necessary to keep track of addresses to probe */
1338   if(scamper_sources_init() == -1)
1339     {
1340       return -1;
1341     }
1342 
1343   /*
1344    * initialise the data structures necessary to keep track of the signatures
1345    * of tasks currently being probed
1346    */
1347   if(scamper_task_init() == -1)
1348     {
1349       return -1;
1350     }
1351 
1352   /*
1353    * initialise the data structures necessary to keep track of output files
1354    * currently being written to
1355    */
1356   if(scamper_outfiles_init(outfile, outtype) == -1)
1357     {
1358       return -1;
1359     }
1360 
1361   /* initialise scamper so it is ready to traceroute and ping */
1362   if(scamper_do_trace_init() != 0 ||
1363      scamper_do_ping_init() != 0 ||
1364      scamper_do_tracelb_init() != 0 ||
1365      scamper_do_dealias_init() != 0 ||
1366      scamper_do_sting_init() != 0 ||
1367      scamper_do_neighbourdisc_init() != 0 ||
1368      scamper_do_tbit_init() != 0 ||
1369      scamper_do_sniff_init() != 0 ||
1370      scamper_do_host_init() != 0)
1371     {
1372       return -1;
1373     }
1374 
1375   if(options & (OPT_CTRL_INET|OPT_CTRL_UNIX|OPT_CTRL_REMOTE))
1376     {
1377       if(scamper_control_init() != 0)
1378 	return -1;
1379       if(options & OPT_CTRL_INET &&
1380 	 scamper_control_add_inet(ctrl_inet_addr, ctrl_inet_port) != 0)
1381 	return -1;
1382       if(options & OPT_CTRL_UNIX &&
1383 	 scamper_control_add_unix(ctrl_unix) != 0)
1384 	return -1;
1385       if(options & OPT_CTRL_REMOTE)
1386 	{
1387 #ifdef HAVE_OPENSSL
1388 	  if(flags & FLAG_NOTLS || flags & FLAG_NOTLS_REMOTE)
1389 	    x = 0;
1390 	  else
1391 	    x = 1;
1392 #else
1393 	  x = 0;
1394 #endif
1395 	  if(scamper_control_add_remote(ctrl_rem_name, ctrl_rem_port, x) != 0)
1396 	    return -1;
1397 	}
1398 
1399       /* wait for more tasks when finished with the active window */
1400       exit_when_done = 0;
1401     }
1402 
1403   /* parameters for the default list */
1404   memset(&ssp, 0, sizeof(ssp));
1405   ssp.name     = "default";
1406   ssp.descr    = "default";
1407   ssp.priority = 1;
1408   ssp.sof      = scamper_outfiles_get(NULL);
1409   if(options & OPT_LISTNAME)
1410     ssp.name = listname;
1411   if(options & OPT_LISTID)
1412     ssp.list_id = listid;
1413   if(options & OPT_CYCLEID)
1414     ssp.cycle_id = cycleid;
1415 
1416   /*
1417    * if we have an address list of some description on the command line,
1418    * read the addresses now
1419    */
1420   if(options & (OPT_IP|OPT_CMDLIST))
1421     {
1422       if((source = scamper_source_cmdline_alloc(&ssp, command,
1423 						arglist, arglist_len)) == NULL)
1424 	{
1425 	  return -1;
1426 	}
1427     }
1428   else if((options & (OPT_CTRL_INET|OPT_CTRL_UNIX|OPT_CTRL_REMOTE)) == 0)
1429     {
1430       if(intype == NULL)
1431 	source = scamper_source_file_alloc(&ssp, arglist[0], command, 1, 0);
1432       else if(strcasecmp(intype, "tsps") == 0)
1433 	source = scamper_source_tsps_alloc(&ssp, arglist[0]);
1434       else if(strcasecmp(intype, "cmdfile") == 0)
1435 	source = scamper_source_file_alloc(&ssp, arglist[0], NULL, 1, 0);
1436       if(source == NULL)
1437 	return -1;
1438     }
1439 
1440   if(source != NULL)
1441     {
1442       scamper_sources_add(source);
1443       scamper_source_free(source);
1444     }
1445 
1446   gettimeofday_wrap(&lastprobe);
1447 
1448   for(;;)
1449     {
1450       if((x = scamper_timeout(&timeout, &nextprobe, &lastprobe)) == 0)
1451 	{
1452 	  /*
1453 	   * we've been told to calculate a timeout value.  figure out what
1454 	   * it should be.
1455 	   */
1456 	  gettimeofday_wrap(&tv);
1457 	  if(timeval_cmp(&timeout, &tv) <= 0)
1458 	    memset(&tv, 0, sizeof(tv));
1459 	  else
1460 	    timeval_diff_tv(&tv, &tv, &timeout);
1461 	  timeout_ptr = &tv;
1462 	}
1463       else if(x == 1)
1464 	{
1465 	  timeout_ptr = NULL;
1466 	}
1467       else
1468 	{
1469 	  /* exit when done */
1470 	  break;
1471 	}
1472 
1473       /* listen until it is time to send the next probe */
1474       if(scamper_fds_poll(timeout_ptr) == -1)
1475 	return -1;
1476 
1477       /* get the current time */
1478       gettimeofday_wrap(&tv);
1479 
1480       if(scamper_queue_event_proc(&tv) != 0)
1481 	return -1;
1482 
1483       /* take any 'done' tasks and output them now */
1484       while((task = scamper_queue_getdone(&tv)) != NULL)
1485 	{
1486 	  /* write the data out */
1487 	  if((source = scamper_task_getsource(task)) != NULL &&
1488 	     (sofname = scamper_source_getoutfile(source)) != NULL &&
1489 	     (sof = scamper_outfiles_get(sofname)) != NULL)
1490 	    {
1491 	      file = scamper_outfile_getfile(sof);
1492 	      scamper_task_write(task, file);
1493 
1494 	      /*
1495 	       * write a copy of the data out if asked to, and it has not
1496 	       * already been written to this output file.
1497 	       */
1498 	      if((flags & FLAG_OUTCOPY) != 0 &&
1499 		 (sof2 = scamper_outfiles_get(NULL)) != NULL && sof != sof2)
1500 		{
1501 		  file = scamper_outfile_getfile(sof2);
1502 		  scamper_task_write(task, file);
1503 		}
1504 	    }
1505 
1506 	  /* cleanup the task */
1507 	  scamper_task_free(task);
1508 	}
1509 
1510       /*
1511        * if there is something waiting to be probed, then find out if it is
1512        * time to probe yet
1513        */
1514       if(scamper_queue_readycount() > 0 || scamper_sources_isready() == 1)
1515 	{
1516 	  /*
1517 	   * check for large differences between the time the last probe
1518 	   * was sent and the current time.  don't allow the difference to
1519 	   * be larger than a particular amount, since that could result in
1520 	   * either a large flutter of probes to be sent, or a large time
1521 	   * before the next probe is sent
1522 	   */
1523 	  if(timeval_inrange_us(&tv, &lastprobe, probe_window) == 0)
1524 	    timeval_sub_us(&lastprobe, &tv, wait_between);
1525 
1526 	  /*
1527 	   * when probing at > HZ, scamper might find that select blocks it
1528 	   * from achieving the specified packets per second rate if it sends
1529 	   * one probe per select.  Based on the time spent in the last call
1530 	   * to select, send the necessary number of packets to fill that
1531 	   * window where we sent no packets.
1532 	   */
1533 	  for(;;)
1534 	    {
1535 	      timeval_add_us(&nextprobe, &lastprobe, wait_between);
1536 
1537 	      /* if the next probe is not due to be sent, don't send one */
1538 	      if(timeval_cmp(&nextprobe, &tv) > 0)
1539 		break;
1540 
1541 	      /*
1542 	       * look for an address that we can send a probe to.  if
1543 	       * scamper doesn't have a task on the probe queue waiting
1544 	       * to be probed, then get a fresh task. if there's absolutely
1545 	       * nothing that scamper can probe, then break.
1546 	       */
1547 	      if((task = scamper_queue_select()) == NULL)
1548 		{
1549 		  /*
1550 		   * if we are already probing to the window limit, don't
1551 		   * add any new tasks
1552 		   */
1553 		  if(window != 0 && scamper_queue_windowcount() >= window)
1554 		    break;
1555 
1556 		  /*
1557 		   * if there are no more tasks ready to be added yet, there's
1558 		   * nothing more to be done in the loop
1559 		   */
1560 		  if(scamper_sources_gettask(&task) != 0 || task == NULL)
1561 		    break;
1562 		}
1563 
1564 	      scamper_task_probe(task);
1565 	      timeval_cpy(&lastprobe, &nextprobe);
1566 	    }
1567 	}
1568     }
1569 
1570   return 0;
1571 }
1572 
1573 /*
1574  * cleanup:
1575  *
1576  * be nice to the system and clean up all our mallocs
1577  */
cleanup(void)1578 static void cleanup(void)
1579 {
1580   scamper_firewall_cleanup();
1581   scamper_getsrc_cleanup();
1582   scamper_rtsock_cleanup();
1583 
1584   scamper_icmp4_cleanup();
1585   scamper_icmp6_cleanup();
1586   scamper_udp4_cleanup();
1587   scamper_tcp4_cleanup();
1588 
1589   scamper_addr2mac_cleanup();
1590 
1591   scamper_do_trace_cleanup();
1592   scamper_do_ping_cleanup();
1593   scamper_do_tracelb_cleanup();
1594   scamper_do_dealias_cleanup();
1595   scamper_do_sting_cleanup();
1596   scamper_do_neighbourdisc_cleanup();
1597   scamper_do_tbit_cleanup();
1598   scamper_do_sniff_cleanup();
1599   scamper_do_host_cleanup();
1600 
1601   scamper_dl_cleanup();
1602 
1603   if(options & (OPT_CTRL_INET|OPT_CTRL_UNIX|OPT_CTRL_REMOTE))
1604     scamper_control_cleanup();
1605 
1606   scamper_sources_cleanup();
1607   scamper_outfiles_cleanup();
1608   scamper_fds_cleanup();
1609 
1610 #ifndef WITHOUT_PRIVSEP
1611   scamper_privsep_cleanup();
1612 #endif
1613 
1614   /* free the address cache, if one was used */
1615   if(addrcache != NULL)
1616     {
1617       scamper_addrcache_free(addrcache);
1618       addrcache = NULL;
1619     }
1620 
1621   if(ctrl_inet_addr != NULL)
1622     {
1623       free(ctrl_inet_addr);
1624       ctrl_inet_addr = NULL;
1625     }
1626 
1627   if(ctrl_rem_name != NULL)
1628     {
1629       free(ctrl_rem_name);
1630       ctrl_rem_name = NULL;
1631     }
1632 
1633   if(monitorname != NULL)
1634     {
1635       free(monitorname);
1636       monitorname = NULL;
1637     }
1638 
1639   if(nameserver != NULL)
1640     {
1641       free(nameserver);
1642       nameserver = NULL;
1643     }
1644 
1645   if(firewall != NULL)
1646     {
1647       free(firewall);
1648       firewall = NULL;
1649     }
1650 
1651   if(command != NULL)
1652     {
1653       free(command);
1654       command = NULL;
1655     }
1656   scamper_queue_cleanup();
1657   scamper_task_cleanup();
1658   scamper_probe_cleanup();
1659 
1660 #ifndef WITHOUT_DEBUGFILE
1661   if(options & OPT_DEBUGFILE)
1662     scamper_debug_close();
1663 #endif
1664 
1665   scamper_osinfo_cleanup();
1666 
1667 #ifndef WITHOUT_DEBUGFILE
1668   if(debugfile != NULL)
1669     {
1670       free(debugfile);
1671       debugfile = NULL;
1672     }
1673 #endif
1674 
1675   if(pidfile != NULL)
1676     {
1677       free(pidfile);
1678       pidfile = NULL;
1679     }
1680 
1681 #ifdef HAVE_OPENSSL
1682   if(tls_ctx != NULL)
1683     {
1684       SSL_CTX_free(tls_ctx);
1685       tls_ctx = NULL;
1686     }
1687 #endif
1688 
1689   return;
1690 }
1691 
main(int argc,char * argv[])1692 int main(int argc, char *argv[])
1693 {
1694   int i;
1695 
1696 #ifndef _WIN32
1697   struct sigaction si_sa;
1698 #endif
1699 
1700 #ifdef _WIN32
1701   WSADATA wsaData;
1702 #endif
1703 
1704   /*
1705    * if we are using dmalloc, then we want to get it to register its
1706    * logdump function to occur after we have used cleanup to free up
1707    * scamper's core data structures.  this is a dirty hack.
1708    *
1709    * if we are running a debug build on freebsd, make poor malloc use more
1710    * prone to causing scamper to crash.
1711    */
1712 #if defined(DMALLOC)
1713   free(malloc(1));
1714 #elif !defined (NDEBUG) && defined(__FreeBSD__) && __FreeBSD_version >= 500014 && __FreeBSD_version < 1000011
1715   _malloc_options = "AJ";
1716 #endif
1717 
1718 #ifdef _WIN32
1719   WSAStartup(MAKEWORD(2,2), &wsaData);
1720   timeBeginPeriod(1);
1721 #endif
1722 
1723 #ifndef _WIN32
1724   if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
1725     {
1726       printerror(__func__, "could not ignore SIGPIPE");
1727       return -1;
1728     }
1729 
1730   sigemptyset(&si_sa.sa_mask);
1731   si_sa.sa_flags   = 0;
1732   si_sa.sa_handler = scamper_chld;
1733   if(sigaction(SIGCHLD, &si_sa, 0) == -1)
1734     {
1735       printerror(__func__, "could not set sigaction for SIGCHLD");
1736       return -1;
1737     }
1738 #endif
1739 
1740   i = scamper(argc, argv);
1741 
1742   cleanup();
1743 
1744 #ifdef _WIN32
1745   timeEndPeriod(1);
1746   WSACleanup();
1747 #endif
1748 
1749   return i;
1750 }
1751