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