1 /*
2 * sc_filterpolicy : check filter congruity of different addresses for the
3 * : same device
4 *
5 * Authors : Matthew Luckie, Jakub Czyz
6 *
7 * Copyright (C) 2014-2015 The Regents of the University of California
8 * Copyright (C) 2015 Matthew Luckie
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, version 2.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 #include "internal.h"
29
30 #include "scamper_addr.h"
31 #include "scamper_list.h"
32 #include "ping/scamper_ping.h"
33 #include "trace/scamper_trace.h"
34 #include "scamper_file.h"
35 #include "scamper_writebuf.h"
36 #include "scamper_linepoll.h"
37 #include "mjl_list.h"
38 #include "mjl_splaytree.h"
39 #include "mjl_heap.h"
40 #include "utils.h"
41
42 #define OPT_HELP 0x0001
43 #define OPT_INFILE 0x0002
44 #define OPT_OUTFILE 0x0004
45 #define OPT_PORT 0x0008
46 #define OPT_UNIX 0x0010
47 #define OPT_LOG 0x0020
48 #define OPT_DAEMON 0x0040
49 #define OPT_OPTIONS 0x0080
50 #define OPT_TYPE 0x0100
51 #define OPT_READ 0x0200
52 #define OPT_TEST 0x0400
53 #define OPT_ALL 0xffff
54
55 #define FLAG_IMPATIENT 0x0001
56 #define FLAG_TRACEROUTE 0x0002
57 #define FLAG_TUPLES 0x0004
58 #define FLAG_INCONGRUENT 0x0008
59
60 typedef struct sc_iditem
61 {
62 scamper_addr_t *addr;
63 uint32_t tests;
64 uint32_t results;
65 } sc_iditem_t;
66
67 typedef struct sc_idset
68 {
69 uint32_t userid;
70 uint32_t tests;
71 sc_iditem_t **items;
72 int itemc;
73 } sc_idset_t;
74
75 typedef struct sc_name2ips
76 {
77 uint32_t id;
78 char *name;
79 slist_t *addrs;
80 slist_t *methods;
81 splaytree_node_t *tree_node;
82 sc_idset_t *set;
83 } sc_name2ips_t;
84
85 typedef struct sc_ip2n2i
86 {
87 scamper_addr_t *ip;
88 sc_name2ips_t *n2i;
89 splaytree_node_t *tree_node;
90 } sc_ip2n2i_t;
91
92 typedef struct sc_wait
93 {
94 struct timeval tv;
95 sc_name2ips_t *n2i;
96 } sc_wait_t;
97
98 typedef struct sc_policytest
99 {
100 const char *name;
101 size_t namelen;
102 const uint32_t id;
103 const char *payload;
104 const uint16_t port;
105 uint8_t flags;
106 } sc_policytest_t;
107
108 #define PT_FLAG_TCP 0x01
109 #define PT_FLAG_ICMP 0x02
110 #define PT_FLAG_UDP 0x04
111 #define PT_FLAG_ROUTER 0x08
112 #define PT_FLAG_SERVER 0x10
113 #define PT_FLAG_USE 0x20
114
115 static splaytree_t *n2i_tree = NULL;
116 static slist_t *n2i_list = NULL;
117 static uint32_t n2i_id = 1;
118 static sc_name2ips_t *n2i_last = NULL;
119 static uint32_t options = 0;
120 static unsigned int port = 0;
121 static char *unix_name = NULL;
122 static scamper_writebuf_t *scamper_wb = NULL;
123 static int scamper_fd = -1;
124 static scamper_linepoll_t *scamper_lp = NULL;
125 static scamper_writebuf_t *decode_wb = NULL;
126 static scamper_file_t *decode_in = NULL;
127 static int decode_in_fd = -1;
128 static int decode_out_fd = -1;
129 static char *infile = NULL;
130 static char *datafile = NULL;
131 static char *outfile_name = NULL;
132 static scamper_file_t *outfile = NULL;
133 static scamper_file_filter_t *ffilter = NULL;
134 static int data_left = 0;
135 static int more = 0;
136 static int probing = 0;
137 static int flags = 0;
138 static struct timeval now;
139 static FILE *logfile = NULL;
140 static heap_t *waiting = NULL;
141
142 #define PT_METHOD_ICMP 1
143 #define PT_METHOD_NETBIOS 2
144 #define PT_METHOD_MSSQL 3
145 #define PT_METHOD_FTP 4
146 #define PT_METHOD_SSH 5
147 #define PT_METHOD_TELNET 6
148 #define PT_METHOD_MYSQL 7
149 #define PT_METHOD_RDP 8
150 #define PT_METHOD_HTTPS 9
151 #define PT_METHOD_SMB 10
152 #define PT_METHOD_VNC 11
153 #define PT_METHOD_HTTP 12
154 #define PT_METHOD_BGP 13
155 #define PT_METHOD_NTP 14
156 #define PT_METHOD_DNS 15
157 #define PT_METHOD_SNMP 16
158
159 #define PT_METHOD_MAX 16
160
161 static sc_policytest_t methods[] = {
162 {"ICMP", 4, PT_METHOD_ICMP,
163 NULL, 0, PT_FLAG_ICMP | PT_FLAG_SERVER | PT_FLAG_ROUTER},
164 {"NetBIOS", 7, PT_METHOD_NETBIOS,
165 NULL, 139, PT_FLAG_TCP},
166 {"MSSQL", 5, PT_METHOD_MSSQL,
167 NULL, 1433, PT_FLAG_TCP},
168 {"FTP", 3, PT_METHOD_FTP,
169 NULL, 21, PT_FLAG_TCP | PT_FLAG_SERVER},
170 {"SSH", 3, PT_METHOD_SSH,
171 NULL, 22, PT_FLAG_TCP | PT_FLAG_SERVER | PT_FLAG_ROUTER},
172 {"Telnet", 6, PT_METHOD_TELNET,
173 NULL, 23, PT_FLAG_TCP | PT_FLAG_SERVER | PT_FLAG_ROUTER},
174 {"MySQL", 5, PT_METHOD_MYSQL,
175 NULL, 3306, PT_FLAG_TCP | PT_FLAG_SERVER},
176 {"RDP", 3, PT_METHOD_RDP,
177 NULL, 3389, PT_FLAG_TCP | PT_FLAG_SERVER},
178 {"HTTPS", 5, PT_METHOD_HTTPS,
179 NULL, 443, PT_FLAG_TCP | PT_FLAG_SERVER | PT_FLAG_ROUTER},
180 {"SMB", 3, PT_METHOD_SMB,
181 NULL, 445, PT_FLAG_TCP | PT_FLAG_SERVER},
182 {"VNC", 3, PT_METHOD_VNC,
183 NULL, 5900, PT_FLAG_TCP},
184 {"HTTP", 4, PT_METHOD_HTTP,
185 NULL, 80, PT_FLAG_TCP | PT_FLAG_SERVER | PT_FLAG_ROUTER},
186 {"BGP", 3, PT_METHOD_BGP,
187 NULL, 179, PT_FLAG_TCP | PT_FLAG_ROUTER},
188 {"NTP", 3, PT_METHOD_NTP,
189 "160200010000000000000000",
190 123, PT_FLAG_UDP | PT_FLAG_SERVER | PT_FLAG_ROUTER},
191 {"DNS", 3, PT_METHOD_DNS,
192 "a980010000010000000000000377777706676f6f676c6503636f6d0000010001",
193 53, PT_FLAG_UDP | PT_FLAG_SERVER | PT_FLAG_ROUTER},
194 {"SNMP", 4, PT_METHOD_SNMP,
195 "302902010104067075626c6963a01c02046aebe0a002"
196 "0100020100300e300c06082b060102010105000500",
197 161, PT_FLAG_UDP | PT_FLAG_SERVER | PT_FLAG_ROUTER},
198 };
199 static const int methodc = sizeof(methods) / sizeof(sc_policytest_t);
200
usage(uint32_t opt_mask)201 static void usage(uint32_t opt_mask)
202 {
203 int i;
204
205 fprintf(stderr,
206 "usage: sc_filterpolicy [-D] [-a infile] [-o outfile] [-p port] [-U unix]\n"
207 " [-l log] [-O options] [-t type] [-T test]\n"
208 "\n"
209 " sc_filterpolicy [-r datafile]\n"
210 "\n");
211
212 if(opt_mask == 0)
213 {
214 fprintf(stderr, " sc_filterpolicy -?\n\n");
215 return;
216 }
217
218 if(opt_mask & OPT_HELP)
219 fprintf(stderr, " -? give an overview of the usage of sc_filterpolicy\n");
220
221 if(opt_mask & OPT_INFILE)
222 fprintf(stderr, " -a input file\n");
223
224 if(opt_mask & OPT_DAEMON)
225 fprintf(stderr, " -D run as a daemon\n");
226
227 if(opt_mask & OPT_OUTFILE)
228 fprintf(stderr, " -o output warts data file\n");
229
230 if(opt_mask & OPT_OPTIONS)
231 fprintf(stderr, " -O options [impatient | incongruent | trace | tuples]\n");
232
233 if(opt_mask & OPT_PORT)
234 fprintf(stderr, " -p port to find scamper on\n");
235
236 if(opt_mask & OPT_LOG)
237 fprintf(stderr, " -l output logfile\n");
238
239 if(opt_mask & OPT_READ)
240 fprintf(stderr, " -r input warts data file\n");
241
242 if(opt_mask & OPT_TYPE)
243 fprintf(stderr, " -t type of probes: router, server, or all\n");
244
245 if(opt_mask & OPT_TEST)
246 {
247 fprintf(stderr, " -T adjust test schedule; e.g. -http or +vnc\n");
248 for(i=0; i<methodc; i++)
249 {
250 if((i % 4) == 0)
251 {
252 if(i != 0) printf(",\n");
253 printf(" ");
254 }
255 else printf(",");
256 printf(" %s", methods[i].name);
257 if(methods[i].flags & PT_FLAG_TCP)
258 printf(" (tcp/%u)", methods[i].port);
259 else if(methods[i].flags & PT_FLAG_UDP)
260 printf(" (udp/%u)", methods[i].port);
261 }
262 printf("\n");
263 }
264
265 if(opt_mask & OPT_UNIX)
266 fprintf(stderr, " -U unix domain to find scamper on\n");
267
268 return;
269 }
270
check_options(int argc,char * argv[])271 static int check_options(int argc, char *argv[])
272 {
273 char *opts = "?a:Dl:o:O:p:r:t:T:U:";
274 char *opt_port = NULL, *opt_unix = NULL, *opt_log = NULL, *opt_type = NULL;
275 slist_t *test_list = NULL;
276 uint32_t u32;
277 char *test;
278 int i, ch;
279 long lo;
280
281 while((ch = getopt(argc, argv, opts)) != -1)
282 {
283 switch(ch)
284 {
285 case 'a':
286 options |= OPT_INFILE;
287 infile = optarg;
288 break;
289
290 case 'D':
291 options |= OPT_DAEMON;
292 break;
293
294 case 'l':
295 options |= OPT_LOG;
296 opt_log = optarg;
297 break;
298
299 case 'o':
300 options |= OPT_OUTFILE;
301 outfile_name = optarg;
302 break;
303
304 case 'O':
305 if(strcasecmp(optarg, "impatient") == 0)
306 flags |= FLAG_IMPATIENT;
307 else if(strcasecmp(optarg, "incongruent") == 0)
308 flags |= FLAG_INCONGRUENT;
309 else if(strcasecmp(optarg, "trace") == 0)
310 flags |= FLAG_TRACEROUTE;
311 else if(strcasecmp(optarg, "tuples") == 0)
312 flags |= FLAG_TUPLES;
313 else
314 {
315 usage(OPT_OPTIONS);
316 goto err;
317 }
318 break;
319
320 case 'p':
321 options |= OPT_PORT;
322 opt_port = optarg;
323 break;
324
325 case 'r':
326 options |= OPT_READ;
327 datafile = optarg;
328 break;
329
330 case 't':
331 options |= OPT_TYPE;
332 opt_type = optarg;
333 break;
334
335 case 'T':
336 options |= OPT_TEST;
337 if(test_list == NULL && (test_list = slist_alloc()) == NULL)
338 {
339 fprintf(stderr, "could not alloc test_list\n");
340 goto err;
341 }
342 if(slist_tail_push(test_list, optarg) == NULL)
343 {
344 fprintf(stderr, "could not push %s to test_list\n", optarg);
345 goto err;
346 }
347 break;
348
349 case 'U':
350 options |= OPT_UNIX;
351 opt_unix = optarg;
352 break;
353
354 case '?':
355 default:
356 usage(OPT_ALL);
357 goto err;
358 }
359 }
360
361 u32 = options & (OPT_INFILE|OPT_OUTFILE|OPT_READ);
362 if(u32 != OPT_READ &&
363 u32 != (OPT_INFILE|OPT_OUTFILE))
364 {
365 usage(0);
366 goto err;
367 }
368
369 if(options & (OPT_INFILE|OPT_OUTFILE))
370 {
371 if((options & (OPT_PORT|OPT_UNIX)) == 0 ||
372 (options & (OPT_PORT|OPT_UNIX)) == (OPT_PORT|OPT_UNIX) ||
373 argc - optind > 0)
374 {
375 usage(OPT_INFILE|OPT_OUTFILE|OPT_PORT|OPT_UNIX);
376 goto err;
377 }
378
379 if(options & OPT_PORT)
380 {
381 if(string_tolong(opt_port, &lo) != 0 || lo < 1 || lo > 65535)
382 {
383 usage(OPT_PORT);
384 goto err;
385 }
386 port = lo;
387 }
388 else if(options & OPT_UNIX)
389 {
390 unix_name = opt_unix;
391 }
392
393 /* validate the -t parameter */
394 if(opt_type != NULL)
395 {
396 if(strcasecmp(opt_type, "router") == 0)
397 {
398 for(i=0; i<methodc; i++)
399 if(methods[i].flags & PT_FLAG_ROUTER)
400 methods[i].flags |= PT_FLAG_USE;
401 }
402 else if(strcasecmp(opt_type, "server") == 0)
403 {
404 for(i=0; i<methodc; i++)
405 if(methods[i].flags & PT_FLAG_SERVER)
406 methods[i].flags |= PT_FLAG_USE;
407 }
408 else if(strcasecmp(opt_type, "all") == 0)
409 {
410 for(i=0; i<methodc; i++)
411 methods[i].flags |= PT_FLAG_USE;
412 }
413 }
414
415 /*
416 * if the user adjusted the test schedule, incorporate
417 * their changes now
418 */
419 if(test_list != NULL)
420 {
421 while((test = slist_head_pop(test_list)) != NULL)
422 {
423 if(test[0] != '+' && test[0] != '-')
424 {
425 usage(OPT_TEST);
426 goto err;
427 }
428 for(i=0; i<methodc; i++)
429 if(strcasecmp(methods[i].name, test+1) == 0)
430 break;
431 if(i == methodc)
432 {
433 usage(OPT_TEST);
434 fprintf(stderr, "unknown test %s\n", test+1);
435 goto err;
436 }
437
438 if(test[0] == '+')
439 methods[i].flags |= PT_FLAG_USE;
440 else
441 methods[i].flags &= (~PT_FLAG_USE);
442 }
443 }
444
445 /* check that at least one protocol will be tested */
446 for(i=0; i<methodc; i++)
447 if(methods[i].flags & PT_FLAG_USE)
448 break;
449 if(i == methodc)
450 {
451 usage(OPT_TYPE|OPT_TEST);
452 goto err;
453 }
454
455 if(opt_log != NULL)
456 {
457 if((logfile = fopen(opt_log, "w")) == NULL)
458 {
459 usage(OPT_LOG);
460 fprintf(stderr, "could not open %s\n", opt_log);
461 goto err;
462 }
463 }
464 }
465 else
466 {
467 if((options & (OPT_PORT|OPT_UNIX|OPT_LOG|OPT_TYPE|OPT_TEST|OPT_DAEMON)) != 0 ||
468 (flags & (FLAG_TRACEROUTE|FLAG_IMPATIENT|FLAG_TUPLES)) != 0)
469 {
470 usage(OPT_READ);
471 goto err;
472 }
473 }
474
475 if(test_list != NULL) slist_free(test_list);
476 return 0;
477
478 err:
479 if(test_list != NULL) slist_free(test_list);
480 return -1;
481 }
482
logprint(char * format,...)483 static void logprint(char *format, ...)
484 {
485 va_list ap;
486 char msg[131072];
487
488 if(logfile == NULL)
489 return;
490
491 va_start(ap, format);
492 vsnprintf(msg, sizeof(msg), format, ap);
493 va_end(ap);
494
495 fprintf(logfile, "%ld: %s", (long int)now.tv_sec, msg);
496 fflush(logfile);
497
498 return;
499 }
500
ping_to_method(const scamper_ping_t * ping)501 static sc_policytest_t *ping_to_method(const scamper_ping_t *ping)
502 {
503 uint32_t id = 0;
504
505 if(ping->probe_method == SCAMPER_PING_METHOD_ICMP_ECHO)
506 {
507 id = PT_METHOD_ICMP;
508 }
509 else if(ping->probe_method == SCAMPER_PING_METHOD_TCP_SYN)
510 {
511 switch(ping->probe_dport)
512 {
513 case 21: id = PT_METHOD_FTP; break;
514 case 22: id = PT_METHOD_SSH; break;
515 case 23: id = PT_METHOD_TELNET; break;
516 case 80: id = PT_METHOD_HTTP; break;
517 case 139: id = PT_METHOD_NETBIOS; break;
518 case 179: id = PT_METHOD_BGP; break;
519 case 443: id = PT_METHOD_HTTPS; break;
520 case 445: id = PT_METHOD_SMB; break;
521 case 1433: id = PT_METHOD_MSSQL; break;
522 case 3306: id = PT_METHOD_MYSQL; break;
523 case 3389: id = PT_METHOD_RDP; break;
524 case 5900: id = PT_METHOD_VNC; break;
525 }
526 }
527 else if(ping->probe_method == SCAMPER_PING_METHOD_UDP)
528 {
529 switch(ping->probe_dport)
530 {
531 case 53: id = PT_METHOD_DNS; break;
532 case 123: id = PT_METHOD_NTP; break;
533 case 161: id = PT_METHOD_SNMP; break;
534 }
535 }
536
537 if(id == 0)
538 return NULL;
539
540 return &methods[id-1];
541 }
542
ping_r(const sc_policytest_t * method,const scamper_ping_t * ping)543 static int ping_r(const sc_policytest_t *method, const scamper_ping_t *ping)
544 {
545 scamper_ping_reply_t *r;
546 uint16_t i;
547
548 for(i=0; i<ping->ping_sent; i++)
549 {
550 for(r = ping->ping_replies[i]; r != NULL; r = r->next)
551 {
552 if(method->flags & PT_FLAG_TCP)
553 {
554 if(SCAMPER_PING_REPLY_IS_TCP(r) &&
555 (r->tcp_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK))
556 return 1;
557 }
558 else if(method->flags & PT_FLAG_UDP)
559 {
560 if(SCAMPER_PING_REPLY_IS_UDP(r))
561 return 1;
562 }
563 else if(method->flags & PT_FLAG_ICMP)
564 {
565 if(SCAMPER_PING_REPLY_IS_ICMP_ECHO_REPLY(r))
566 return 1;
567 }
568 else return -1;
569 }
570 }
571
572 return 0;
573 }
574
sc_wait_cmp(const void * a,const void * b)575 static int sc_wait_cmp(const void *a, const void *b)
576 {
577 return timeval_cmp(&((sc_wait_t *)b)->tv, &((sc_wait_t *)a)->tv);
578 }
579
sc_wait(struct timeval * tv,sc_name2ips_t * n2i)580 static int sc_wait(struct timeval *tv, sc_name2ips_t *n2i)
581 {
582 sc_wait_t *w;
583 if((w = malloc_zero(sizeof(sc_wait_t))) == NULL)
584 return -1;
585 timeval_cpy(&w->tv, tv);
586 w->n2i = n2i;
587 if(heap_insert(waiting, w) == NULL)
588 return -1;
589 return 0;
590 }
591
sc_iditem_cmp(const sc_iditem_t * a,const sc_iditem_t * b)592 static int sc_iditem_cmp(const sc_iditem_t *a, const sc_iditem_t *b)
593 {
594 return scamper_addr_cmp(a->addr, b->addr);
595 }
596
sc_iditem_free(sc_iditem_t * item)597 static void sc_iditem_free(sc_iditem_t *item)
598 {
599 if(item == NULL)
600 return;
601 if(item->addr != NULL) scamper_addr_free(item->addr);
602 free(item);
603 return;
604 }
605
sc_iditem_get(sc_idset_t * set,scamper_addr_t * addr)606 static sc_iditem_t *sc_iditem_get(sc_idset_t *set, scamper_addr_t *addr)
607 {
608 sc_iditem_t fm, *item;
609
610 fm.addr = addr;
611 if((item = array_find((void **)set->items, set->itemc, &fm,
612 (array_cmp_t)sc_iditem_cmp)) != NULL)
613 return item;
614
615 if((item = malloc_zero(sizeof(sc_iditem_t))) == NULL)
616 return NULL;
617 item->addr = scamper_addr_use(addr);
618 if(array_insert((void ***)&set->items, &set->itemc, item,
619 (array_cmp_t)sc_iditem_cmp) != 0)
620 {
621 sc_iditem_free(item);
622 return NULL;
623 }
624
625 return item;
626 }
627
sc_idset_cmp(const sc_idset_t * a,const sc_idset_t * b)628 static int sc_idset_cmp(const sc_idset_t *a, const sc_idset_t *b)
629 {
630 if(a->userid < b->userid) return -1;
631 if(a->userid > b->userid) return 1;
632 return 0;
633 }
634
sc_idset_free(sc_idset_t * set)635 static void sc_idset_free(sc_idset_t *set)
636 {
637 int i;
638
639 if(set == NULL)
640 return;
641
642 if(set->items != NULL)
643 {
644 for(i=0; i<set->itemc; i++)
645 sc_iditem_free(set->items[i]);
646 free(set->items);
647 }
648 free(set);
649 return;
650 }
651
sc_idset_get(splaytree_t * tree,uint32_t id)652 static sc_idset_t *sc_idset_get(splaytree_t *tree, uint32_t id)
653 {
654 sc_idset_t fm, *set; fm.userid = id;
655
656 /* see if we already have a collection for this id */
657 if((set = splaytree_find(tree, &fm)) != NULL)
658 return set;
659
660 /* no collection, alloc a new one */
661 if((set = malloc_zero(sizeof(sc_idset_t))) == NULL)
662 return NULL;
663 set->userid = id;
664
665 /* add it to the tree. if it fails, free the memory */
666 if(splaytree_insert(tree, set) == NULL)
667 {
668 free(set);
669 return NULL;
670 }
671
672 return set;
673 }
674
sc_idset_incongruent(const sc_idset_t * set)675 static int sc_idset_incongruent(const sc_idset_t *set)
676 {
677 sc_iditem_t *first, *item;
678 int i;
679
680 first = set->items[0];
681 for(i=1; i<set->itemc; i++)
682 {
683 item = set->items[i];
684 if(first->results != item->results)
685 return 1;
686 }
687
688 return 0;
689 }
690
sc_idset_print(const sc_idset_t * set)691 static void sc_idset_print(const sc_idset_t *set)
692 {
693 char fsaddr[30], buf[128];
694 size_t maxaddr, max, len;
695 sc_policytest_t *pt;
696 sc_iditem_t *item;
697 uint32_t o;
698 int i, j;
699
700 /* should we print this at all? */
701 if((flags & FLAG_INCONGRUENT) != 0 && sc_idset_incongruent(set) == 0)
702 return;
703
704 /*
705 * first, figure out the maximum width IP address in the set, and
706 * which protocols are open at all
707 */
708 maxaddr = 0; o = 0;
709 for(i=0; i<set->itemc; i++)
710 {
711 item = set->items[i];
712 scamper_addr_tostr(item->addr, buf, sizeof(buf));
713 if((len = strlen(buf)) > maxaddr)
714 maxaddr = len;
715 o |= item->results;
716 }
717 snprintf(fsaddr, sizeof(fsaddr), "%%%ds :", (int)maxaddr);
718
719 /* next, figure out the maximum width protocol name tested */
720 max = 0;
721 for(j=0; j<PT_METHOD_MAX; j++)
722 {
723 if((set->tests & (1 << j)) == 0)
724 continue;
725 pt = &methods[j];
726 if(pt->namelen > max)
727 max = pt->namelen;
728 }
729
730 /* print the header that goes at the top of the router's results */
731 for(len=0; len<max; len++)
732 {
733 printf(fsaddr, "");
734 for(j=0; j<PT_METHOD_MAX; j++)
735 {
736 if((set->tests & (1 << j)) == 0)
737 continue;
738 pt = &methods[j];
739 if(len < max - pt->namelen)
740 {
741 printf(" ");
742 continue;
743 }
744 printf(" %c", pt->name[len-(max-pt->namelen)]);
745 }
746 printf("\n");
747 }
748
749 /* print a line under the header */
750 for(len=0; len<maxaddr; len++)
751 printf("=");
752 printf("==");
753 for(j=0; j<PT_METHOD_MAX; j++)
754 {
755 if((set->tests & (1 << j)) == 0)
756 continue;
757 printf("===");
758 }
759 printf("\n");
760
761 /* report the open ports */
762 for(i=0; i<set->itemc; i++)
763 {
764 item = set->items[i];
765 printf(fsaddr, scamper_addr_tostr(item->addr, buf, sizeof(buf)));
766 for(j=0; j<PT_METHOD_MAX; j++)
767 {
768 if((set->tests & (1 << j)) == 0)
769 continue;
770 if(item->results & (1 << j))
771 printf(" O");
772 else if((item->tests & (1 << j)) == 0)
773 printf(" ?");
774 else if(o & (1 << j))
775 printf(" X");
776 else
777 printf(" ");
778 }
779 printf("\n");
780 }
781 printf("\n");
782
783 return;
784 }
785
sc_ip2n2i_cmp(const sc_ip2n2i_t * a,const sc_ip2n2i_t * b)786 static int sc_ip2n2i_cmp(const sc_ip2n2i_t *a, const sc_ip2n2i_t *b)
787 {
788 return scamper_addr_cmp(a->ip, b->ip);
789 }
790
sc_ip2n2i_free(sc_ip2n2i_t * ip2n2i)791 static void sc_ip2n2i_free(sc_ip2n2i_t *ip2n2i)
792 {
793 if(ip2n2i == NULL)
794 return;
795 if(ip2n2i->tree_node != NULL)
796 splaytree_remove_node(n2i_tree, ip2n2i->tree_node);
797 if(ip2n2i->ip != NULL)
798 scamper_addr_free(ip2n2i->ip);
799 free(ip2n2i);
800 return;
801 }
802
sc_ip2n2i_find(scamper_addr_t * ip)803 static sc_ip2n2i_t *sc_ip2n2i_find(scamper_addr_t *ip)
804 {
805 sc_ip2n2i_t fm; fm.ip = ip;
806 return splaytree_find(n2i_tree, &fm);
807 }
808
sc_ip2n2i_get(scamper_addr_t * ip,sc_name2ips_t * n2i)809 static sc_ip2n2i_t *sc_ip2n2i_get(scamper_addr_t *ip, sc_name2ips_t *n2i)
810 {
811 sc_ip2n2i_t *ip2n2i;
812
813 if((ip2n2i = sc_ip2n2i_find(ip)) != NULL)
814 {
815 assert(ip2n2i->n2i == n2i);
816 return ip2n2i;
817 }
818
819 if((ip2n2i = malloc_zero(sizeof(sc_ip2n2i_t))) == NULL)
820 return NULL;
821 ip2n2i->ip = scamper_addr_use(ip);
822 ip2n2i->n2i = n2i;
823 if((ip2n2i->tree_node = splaytree_insert(n2i_tree, ip2n2i)) == NULL)
824 {
825 sc_ip2n2i_free(ip2n2i);
826 return NULL;
827 }
828
829 return ip2n2i;
830 }
831
sc_name2ips_methods(sc_name2ips_t * n2i)832 static void sc_name2ips_methods(sc_name2ips_t *n2i)
833 {
834 int i;
835 slist_empty(n2i->methods);
836 for(i=0; i<methodc; i++)
837 if(methods[i].flags & PT_FLAG_USE)
838 slist_tail_push(n2i->methods, &methods[i]);
839 slist_shuffle(n2i->methods);
840 return;
841 }
842
sc_name2ips_name_cmp(const sc_name2ips_t * a,const sc_name2ips_t * b)843 static int sc_name2ips_name_cmp(const sc_name2ips_t *a, const sc_name2ips_t *b)
844 {
845 return strcmp(a->name, b->name);
846 }
847
sc_name2ips_addr_cmp(const sc_name2ips_t * a,const sc_name2ips_t * b)848 static int sc_name2ips_addr_cmp(const sc_name2ips_t *a, const sc_name2ips_t *b)
849 {
850 int ac = slist_count(a->addrs);
851 int bc = slist_count(b->addrs);
852 if(ac > bc) return -1;
853 if(ac < bc) return 1;
854 return 0;
855 }
856
sc_name2ips_free(sc_name2ips_t * n2i)857 static void sc_name2ips_free(sc_name2ips_t *n2i)
858 {
859 scamper_addr_t *addr;
860 if(n2i == NULL) return;
861 if(n2i->tree_node != NULL)
862 splaytree_remove_node(n2i_tree, n2i->tree_node);
863 if(n2i->addrs != NULL)
864 {
865 while((addr = slist_head_pop(n2i->addrs)) != NULL)
866 scamper_addr_free(addr);
867 slist_free(n2i->addrs);
868 }
869 if(n2i->methods != NULL)
870 slist_free(n2i->methods);
871 if(n2i->name != NULL)
872 free(n2i->name);
873 if(n2i->set != NULL)
874 sc_idset_free(n2i->set);
875 free(n2i);
876 return;
877 }
878
sc_name2ips_get(char * name)879 static sc_name2ips_t *sc_name2ips_get(char *name)
880 {
881 sc_name2ips_t fm, *n2i = NULL;
882
883 fm.name = name;
884 if((n2i = splaytree_find(n2i_tree, &fm)) != NULL)
885 return n2i;
886
887 if((n2i = malloc_zero(sizeof(sc_name2ips_t))) == NULL ||
888 (name != NULL && (n2i->name = strdup(name)) == NULL) ||
889 (n2i->addrs = slist_alloc()) == NULL ||
890 (n2i->methods = slist_alloc()) == NULL ||
891 (n2i->tree_node = splaytree_insert(n2i_tree, n2i)) == NULL ||
892 slist_tail_push(n2i_list, n2i) == NULL)
893 {
894 fprintf(stderr, "sc_name2ips_get: could not alloc node\n");
895 goto err;
896 }
897 n2i->id = n2i_id++;
898
899 return n2i;
900
901 err:
902 if(n2i != NULL) sc_name2ips_free(n2i);
903 return NULL;
904 }
905
do_method(void)906 static int do_method(void)
907 {
908 scamper_addr_t *addr;
909 sc_name2ips_t *n2i;
910 sc_policytest_t *pt;
911 sc_wait_t *w;
912 char buf[128], cmd[512];
913 size_t off = 0;
914
915 if(more < 1)
916 return 0;
917
918 if((w = heap_head_item(waiting)) != NULL && timeval_cmp(&now, &w->tv) >= 0)
919 {
920 heap_remove(waiting);
921 n2i = w->n2i;
922 free(w);
923 }
924 else if((n2i = slist_head_pop(n2i_list)) != NULL)
925 {
926 sc_name2ips_methods(n2i);
927 }
928 else return 0;
929
930 addr = slist_head_item(n2i->addrs);
931 scamper_addr_tostr(addr, buf, sizeof(buf));
932
933 if(sc_ip2n2i_get(addr, n2i) == NULL)
934 {
935 logprint("%s: could not sc_ip2n2i_get %s\n", __func__, buf);
936 return -1;
937 }
938
939 pt = slist_head_pop(n2i->methods);
940 if(flags & FLAG_TRACEROUTE)
941 {
942 string_concat(cmd, sizeof(cmd), &off, "trace -q 1 -U %u", n2i->id);
943 if(pt->flags & PT_FLAG_ICMP)
944 string_concat(cmd, sizeof(cmd), &off, " -P icmp-paris");
945 else if(pt->flags & PT_FLAG_TCP)
946 string_concat(cmd, sizeof(cmd), &off, " -P tcp -d %u", pt->port);
947 else if(pt->flags & PT_FLAG_UDP)
948 string_concat(cmd, sizeof(cmd), &off,
949 " -P udp-paris -O dl -O const-payload -d %u -p %s",
950 pt->port, pt->payload);
951 else
952 return -1;
953 string_concat(cmd, sizeof(cmd), &off, " %s\n", buf);
954 }
955 else
956 {
957 string_concat(cmd, sizeof(cmd), &off, "ping -i 5 -U %u -c 1", n2i->id);
958 if(pt->flags & PT_FLAG_ICMP)
959 string_concat(cmd, sizeof(cmd), &off, " -P icmp-echo");
960 else if(pt->flags & PT_FLAG_TCP)
961 string_concat(cmd, sizeof(cmd), &off, " -P tcp-syn -d %u", pt->port);
962 else if(pt->flags & PT_FLAG_UDP)
963 string_concat(cmd, sizeof(cmd), &off,
964 " -P udp -O dl -d %u -B %s",
965 pt->port, pt->payload);
966 string_concat(cmd, sizeof(cmd), &off, " %s\n", buf);
967 }
968 if(scamper_writebuf_send(scamper_wb, cmd, off) != 0)
969 {
970 fprintf(stderr, "could not send %s\n", cmd);
971 return -1;
972 }
973 n2i_last = n2i;
974
975 probing++;
976 more--;
977
978 logprint("p %d, w %d, l %d : %s", probing, heap_count(waiting),
979 slist_count(n2i_list), cmd);
980 return 0;
981 }
982
983 /*
984 * infile_tuples_line
985 *
986 * read the input file, which contains <name, ip> tuples.
987 */
infile_tuples_line(char * line,void * param)988 static int infile_tuples_line(char *line, void *param)
989 {
990 splaytree_t *addrtree = param;
991 scamper_addr_t *addr = NULL;
992 sc_name2ips_t *n2i = NULL;
993 char *name, *ip;
994
995 if(line[0] == '#' || line[0] == '\0')
996 return 0;
997
998 name = line;
999 if((ip = string_nextword(line)) == NULL ||
1000 (addr = scamper_addr_resolve(AF_UNSPEC, ip)) == NULL)
1001 {
1002 fprintf(stderr, "malformed line in input file\n");
1003 goto err;
1004 }
1005
1006 if(splaytree_find(addrtree, addr) != NULL)
1007 {
1008 fprintf(stderr, "%s in list multiple times, aborting\n", ip);
1009 goto err;
1010 }
1011
1012 if(splaytree_insert(addrtree, scamper_addr_use(addr)) == NULL ||
1013 (n2i = sc_name2ips_get(name)) == NULL ||
1014 slist_tail_push(n2i->addrs, addr) == NULL)
1015 {
1016 fprintf(stderr, "could not stuff %s:%s\n", name, ip);
1017 goto err;
1018 }
1019
1020 return 0;
1021
1022 err:
1023 if(addr != NULL) scamper_addr_free(addr);
1024 return -1;
1025 }
1026
infile_rows_line(char * line,void * param)1027 static int infile_rows_line(char *line, void *param)
1028 {
1029 splaytree_t *addrtree = param;
1030 scamper_addr_t *addr = NULL;
1031 sc_name2ips_t *n2i = NULL;
1032 char *name, *ip, *ptr;
1033
1034 if(line[0] == '#' || line[0] == '\0')
1035 return 0;
1036
1037 name = line;
1038 if((ip = string_nextword(line)) == NULL)
1039 {
1040 fprintf(stderr, "malformed line in input file\n");
1041 goto err;
1042 }
1043
1044 if((addr = scamper_addr_resolve(AF_UNSPEC, name)) != NULL)
1045 n2i = sc_name2ips_get(name);
1046 else
1047 n2i = sc_name2ips_get(NULL);
1048 if(n2i == NULL)
1049 goto err;
1050
1051 if(addr != NULL)
1052 {
1053 if(splaytree_find(addrtree, addr) != NULL)
1054 {
1055 fprintf(stderr, "%s in list multiple times, aborting\n", ip);
1056 goto err;
1057 }
1058 if(splaytree_insert(addrtree, scamper_addr_use(addr)) == NULL ||
1059 slist_tail_push(n2i->addrs, addr) == NULL)
1060 {
1061 fprintf(stderr, "could not stuff %s:%s\n", name, ip);
1062 goto err;
1063 }
1064 }
1065 ptr = string_nextword(ip);
1066
1067 for(;;)
1068 {
1069 if((addr = scamper_addr_resolve(AF_UNSPEC, ip)) == NULL)
1070 {
1071 fprintf(stderr, "%s is not an IP address\n", ip);
1072 goto err;
1073 }
1074 if(splaytree_find(addrtree, addr) != NULL)
1075 {
1076 fprintf(stderr, "%s in list multiple times, aborting\n", ip);
1077 goto err;
1078 }
1079 if(splaytree_insert(addrtree, scamper_addr_use(addr)) == NULL ||
1080 slist_tail_push(n2i->addrs, addr) == NULL)
1081 {
1082 fprintf(stderr, "could not stuff %s:%s\n", name, ip);
1083 goto err;
1084 }
1085 if((ip = ptr) == NULL)
1086 break;
1087 ptr = string_nextword(ip);
1088 }
1089
1090 return 0;
1091
1092 err:
1093 if(addr != NULL) scamper_addr_free(addr);
1094 return -1;
1095 }
1096
do_infile(void)1097 static int do_infile(void)
1098 {
1099 splaytree_t *addrtree;
1100 slist_node_t *node;
1101 sc_name2ips_t *n2i;
1102
1103 if((addrtree = splaytree_alloc((splaytree_cmp_t)scamper_addr_cmp)) == NULL)
1104 {
1105 fprintf(stderr, "could not alloc addrtree\n");
1106 return -1;
1107 }
1108
1109 if(flags & FLAG_TUPLES)
1110 {
1111 if(file_lines(infile, infile_tuples_line, addrtree) != 0)
1112 goto err;
1113 }
1114 else
1115 {
1116 if(file_lines(infile, infile_rows_line, addrtree) != 0)
1117 goto err;
1118 }
1119 splaytree_free(addrtree, (splaytree_free_t)scamper_addr_free);
1120 addrtree = NULL;
1121
1122 for(node=slist_head_node(n2i_list); node != NULL; node=slist_node_next(node))
1123 {
1124 n2i = slist_node_item(node);
1125 slist_shuffle(n2i->addrs);
1126 n2i->tree_node = NULL;
1127 }
1128 splaytree_free(n2i_tree, NULL);
1129
1130 if(flags & FLAG_IMPATIENT)
1131 slist_qsort(n2i_list, (slist_cmp_t)sc_name2ips_addr_cmp);
1132 else
1133 slist_shuffle(n2i_list);
1134
1135 if((n2i_tree = splaytree_alloc((splaytree_cmp_t)sc_ip2n2i_cmp)) == NULL)
1136 {
1137 fprintf(stderr, "could not alloc n2i_tree\n");
1138 return -1;
1139 }
1140
1141 return 0;
1142
1143 err:
1144 if(addrtree != NULL)
1145 splaytree_free(addrtree, (splaytree_free_t)scamper_addr_free);
1146 return -1;
1147 }
1148
sc_name2ips_find(scamper_addr_t * dst)1149 static sc_name2ips_t *sc_name2ips_find(scamper_addr_t *dst)
1150 {
1151 sc_ip2n2i_t *ip2n2i;
1152 if((ip2n2i = sc_ip2n2i_find(dst)) == NULL)
1153 return NULL;
1154 return ip2n2i->n2i;
1155 }
1156
do_decoderead_addr(scamper_addr_t * dst)1157 static int do_decoderead_addr(scamper_addr_t *dst)
1158 {
1159 scamper_addr_t *addr;
1160 struct timeval tv;
1161 sc_ip2n2i_t *ip2n2i;
1162 sc_name2ips_t *n2i;
1163 char buf[128];
1164
1165 if((ip2n2i = sc_ip2n2i_find(dst)) == NULL)
1166 {
1167 logprint("%s: could not find %s\n", __func__,
1168 scamper_addr_tostr(dst, buf, sizeof(buf)));
1169 return -1;
1170 }
1171 n2i = ip2n2i->n2i;
1172
1173 if(slist_count(n2i->methods) == 0)
1174 {
1175 sc_ip2n2i_free(ip2n2i);
1176 addr = slist_head_pop(n2i->addrs);
1177 scamper_addr_free(addr);
1178 if(slist_count(n2i->addrs) == 0)
1179 {
1180 if(n2i->set != NULL)
1181 sc_idset_print(n2i->set);
1182 sc_name2ips_free(n2i);
1183 n2i = NULL;
1184 }
1185 else
1186 {
1187 sc_name2ips_methods(n2i);
1188 }
1189 }
1190
1191 if(n2i != NULL)
1192 {
1193 timeval_add_s(&tv, &now, 1);
1194 if(sc_wait(&tv, n2i) != 0)
1195 {
1196 logprint("%s: could not wait\n", __func__);
1197 return -1;
1198 }
1199 }
1200
1201 return 0;
1202 }
1203
do_decoderead_ping(scamper_ping_t * ping)1204 static int do_decoderead_ping(scamper_ping_t *ping)
1205 {
1206 sc_policytest_t *method;
1207 sc_name2ips_t *n2i;
1208 char buf[128];
1209 sc_iditem_t *item;
1210 int rc, code;
1211
1212 if((options & OPT_DAEMON) == 0)
1213 {
1214 if((n2i = sc_name2ips_find(ping->dst)) == NULL)
1215 {
1216 logprint("%s: could not find %s\n", __func__,
1217 scamper_addr_tostr(ping->dst, buf, sizeof(buf)));
1218 goto err;
1219 }
1220
1221 if(n2i->set == NULL &&
1222 (n2i->set = malloc_zero(sizeof(sc_idset_t))) == NULL)
1223 {
1224 logprint("%s: could not malloc idset: %s\n",
1225 __func__, strerror(errno));
1226 goto err;
1227 }
1228
1229 if((method = ping_to_method(ping)) == NULL)
1230 {
1231 logprint("%s: unhandled method\n", __func__);
1232 goto err;
1233 }
1234 code = ping_r(method, ping);
1235 n2i->set->tests |= (1 << (method->id-1));
1236 if((item = sc_iditem_get(n2i->set, ping->dst)) == NULL)
1237 {
1238 logprint("%s: could not get item for %s: %s\n", __func__,
1239 scamper_addr_tostr(ping->dst, buf, sizeof(buf)),
1240 strerror(errno));
1241 goto err;
1242 }
1243 item->tests |= (1 << (method->id-1));
1244 if(code == 1)
1245 item->results |= (1 << (method->id-1));
1246 }
1247
1248 rc = do_decoderead_addr(ping->dst);
1249 scamper_ping_free(ping);
1250 return rc;
1251
1252 err:
1253 scamper_ping_free(ping);
1254 return -1;
1255 }
1256
do_decoderead_trace(scamper_trace_t * trace)1257 static int do_decoderead_trace(scamper_trace_t *trace)
1258 {
1259 int rc = do_decoderead_addr(trace->dst);
1260 scamper_trace_free(trace);
1261 return rc;
1262 }
1263
do_n2i_next(void)1264 static int do_n2i_next(void)
1265 {
1266 scamper_addr_t *addr;
1267 struct timeval tv;
1268 sc_ip2n2i_t *ip2n2i;
1269 char buf[128];
1270
1271 assert(n2i_last != NULL);
1272
1273 addr = slist_head_item(n2i_last->addrs);
1274 scamper_addr_tostr(addr, buf, sizeof(buf));
1275
1276 if((ip2n2i = sc_ip2n2i_find(addr)) == NULL)
1277 {
1278 logprint("%s: could not find %s\n", __func__, buf);
1279 return -1;
1280 }
1281 if(ip2n2i->n2i != n2i_last)
1282 {
1283 logprint("%s: different n2i %u than expected %u\n", __func__,
1284 ip2n2i->n2i->id, n2i_last->id);
1285 return -1;
1286 }
1287
1288 logprint("%s: skipping %s\n", __func__, buf);
1289
1290 sc_ip2n2i_free(ip2n2i);
1291 addr = slist_head_pop(n2i_last->addrs);
1292 scamper_addr_free(addr);
1293 if(slist_count(n2i_last->addrs) == 0)
1294 {
1295 sc_name2ips_free(n2i_last);
1296 n2i_last = NULL;
1297 }
1298 else
1299 {
1300 sc_name2ips_methods(n2i_last);
1301 }
1302
1303 if(n2i_last != NULL)
1304 {
1305 timeval_add_s(&tv, &now, 1);
1306 if(sc_wait(&tv, n2i_last) != 0)
1307 {
1308 logprint("%s: could not wait %s\n", __func__, buf);
1309 return -1;
1310 }
1311 }
1312 return 0;
1313 }
1314
do_decoderead(void)1315 static int do_decoderead(void)
1316 {
1317 void *data;
1318 uint16_t type;
1319
1320 /* try and read a traceroute from the warts decoder */
1321 if(scamper_file_read(decode_in, ffilter, &type, &data) != 0)
1322 {
1323 fprintf(stderr, "do_decoderead: scamper_file_read errno %d\n", errno);
1324 return -1;
1325 }
1326 if(data == NULL)
1327 {
1328 if(scamper_file_geteof(decode_in) != 0)
1329 {
1330 scamper_file_close(decode_in);
1331 decode_in = NULL;
1332 decode_in_fd = -1;
1333 }
1334 return 0;
1335 }
1336 probing--;
1337
1338 if(scamper_file_write_obj(outfile, type, data) != 0)
1339 {
1340 fprintf(stderr, "do_decoderead: could not write obj %d\n", type);
1341 /* XXX: free data */
1342 return -1;
1343 }
1344
1345 if(type == SCAMPER_FILE_OBJ_PING)
1346 return do_decoderead_ping(data);
1347 else if(type == SCAMPER_FILE_OBJ_TRACE)
1348 return do_decoderead_trace(data);
1349
1350 logprint("%s: unknown type %d\n", __func__, type);
1351 return -1;
1352 }
1353
do_scamperread_line(void * param,uint8_t * buf,size_t linelen)1354 static int do_scamperread_line(void *param, uint8_t *buf, size_t linelen)
1355 {
1356 char *head = (char *)buf;
1357 uint8_t uu[64];
1358 size_t uus;
1359 long lo;
1360
1361 /* skip empty lines */
1362 if(head[0] == '\0')
1363 return 0;
1364
1365 /* if currently decoding data, then pass it to uudecode */
1366 if(data_left > 0)
1367 {
1368 uus = sizeof(uu);
1369 if(uudecode_line(head, linelen, uu, &uus) != 0)
1370 {
1371 fprintf(stderr, "could not uudecode_line\n");
1372 return -1;
1373 }
1374 if(uus != 0)
1375 scamper_writebuf_send(decode_wb, uu, uus);
1376 data_left -= (linelen + 1);
1377 return 0;
1378 }
1379
1380 /* feedback letting us know that the command was accepted */
1381 if(linelen >= 2 && strncasecmp(head, "OK", 2) == 0)
1382 return 0;
1383
1384 /* if the scamper process is asking for more tasks, give it more */
1385 if(linelen == 4 && strncasecmp(head, "MORE", linelen) == 0)
1386 {
1387 more++;
1388 if(do_method() != 0)
1389 return -1;
1390 return 0;
1391 }
1392
1393 /* new piece of data */
1394 if(linelen > 5 && strncasecmp(head, "DATA ", 5) == 0)
1395 {
1396 if(string_isnumber(head+5) == 0 || string_tolong(head+5, &lo) != 0)
1397 {
1398 fprintf(stderr, "could not parse %s\n", head);
1399 return -1;
1400 }
1401 data_left = lo;
1402 return 0;
1403 }
1404
1405 /* feedback letting us know that the command was not accepted */
1406 if(linelen >= 3 && strncasecmp(head, "ERR", 3) == 0)
1407 {
1408 more++;
1409 if(do_n2i_next() != 0 || do_method() != 0)
1410 return -1;
1411 return 0;
1412 }
1413
1414 fprintf(stderr, "unknown response '%s'\n", head);
1415 return -1;
1416 }
1417
do_scamperread(void)1418 static int do_scamperread(void)
1419 {
1420 ssize_t rc;
1421 uint8_t buf[512];
1422
1423 if((rc = read(scamper_fd, buf, sizeof(buf))) > 0)
1424 {
1425 scamper_linepoll_handle(scamper_lp, buf, rc);
1426 return 0;
1427 }
1428 else if(rc == 0)
1429 {
1430 close(scamper_fd);
1431 scamper_fd = -1;
1432 return 0;
1433 }
1434 else if(errno == EINTR || errno == EAGAIN)
1435 {
1436 return 0;
1437 }
1438
1439 fprintf(stderr, "could not read: errno %d\n", errno);
1440 return -1;
1441 }
1442
1443 /*
1444 * do_scamperconnect
1445 *
1446 * allocate socket and connect to scamper process listening on the port
1447 * specified.
1448 */
do_scamperconnect(void)1449 static int do_scamperconnect(void)
1450 {
1451 struct sockaddr *sa;
1452 struct sockaddr_un sun;
1453 struct sockaddr_in sin;
1454 struct in_addr in;
1455 socklen_t sl;
1456
1457 if(options & OPT_PORT)
1458 {
1459 inet_aton("127.0.0.1", &in);
1460 sockaddr_compose((struct sockaddr *)&sin, AF_INET, &in, port);
1461 sa = (struct sockaddr *)&sin; sl = sizeof(sin);
1462 if((scamper_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
1463 {
1464 fprintf(stderr, "could not allocate new socket\n");
1465 return -1;
1466 }
1467 }
1468 else if(options & OPT_UNIX)
1469 {
1470 if(sockaddr_compose_un((struct sockaddr *)&sun, unix_name) != 0)
1471 {
1472 fprintf(stderr, "could not build sockaddr_un\n");
1473 return -1;
1474 }
1475 sa = (struct sockaddr *)&sun; sl = sizeof(sun);
1476 if((scamper_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
1477 {
1478 fprintf(stderr, "could not allocate unix domain socket\n");
1479 return -1;
1480 }
1481 }
1482 else return -1;
1483
1484 if(connect(scamper_fd, sa, sl) != 0)
1485 {
1486 fprintf(stderr, "could not connect to scamper process\n");
1487 return -1;
1488 }
1489
1490 if(fcntl_set(scamper_fd, O_NONBLOCK) == -1)
1491 {
1492 fprintf(stderr, "could not set nonblock on scamper_fd\n");
1493 return -1;
1494 }
1495
1496 return 0;
1497 }
1498
fp_data(void)1499 static int fp_data(void)
1500 {
1501 struct timeval tv, *tv_ptr;
1502 fd_set rfds, wfds, *wfdsp;
1503 sc_wait_t *w;
1504 int pair[2];
1505 int nfds;
1506
1507 random_seed();
1508
1509 if((n2i_tree = splaytree_alloc((splaytree_cmp_t)sc_name2ips_name_cmp)) == NULL ||
1510 (n2i_list = slist_alloc()) == NULL ||
1511 (waiting = heap_alloc(sc_wait_cmp)) == NULL ||
1512 (scamper_wb = scamper_writebuf_alloc()) == NULL ||
1513 (scamper_lp = scamper_linepoll_alloc(do_scamperread_line,NULL)) == NULL ||
1514 (decode_wb = scamper_writebuf_alloc()) == NULL ||
1515 do_infile() != 0 || do_scamperconnect() != 0 ||
1516 (outfile = scamper_file_open(outfile_name, 'w', "warts")) == NULL ||
1517 socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0 ||
1518 (decode_in = scamper_file_openfd(pair[0], NULL, 'r', "warts")) == NULL ||
1519 fcntl_set(pair[0], O_NONBLOCK) == -1 ||
1520 fcntl_set(pair[1], O_NONBLOCK) == -1)
1521 return -1;
1522
1523 decode_in_fd = pair[0];
1524 decode_out_fd = pair[1];
1525 scamper_writebuf_send(scamper_wb, "attach\n", 7);
1526
1527 for(;;)
1528 {
1529 nfds = 0; FD_ZERO(&rfds); FD_ZERO(&wfds); wfdsp = NULL;
1530 if(scamper_fd < 0 && decode_in_fd < 0)
1531 break;
1532
1533 if(scamper_fd >= 0)
1534 {
1535 FD_SET(scamper_fd, &rfds);
1536 if(nfds < scamper_fd) nfds = scamper_fd;
1537 if(scamper_writebuf_len(scamper_wb) > 0)
1538 {
1539 FD_SET(scamper_fd, &wfds);
1540 wfdsp = &wfds;
1541 }
1542 }
1543
1544 if(decode_in_fd >= 0)
1545 {
1546 FD_SET(decode_in_fd, &rfds);
1547 if(nfds < decode_in_fd) nfds = decode_in_fd;
1548 }
1549
1550 if(decode_out_fd >= 0 && scamper_writebuf_len(decode_wb) > 0)
1551 {
1552 FD_SET(decode_out_fd, &wfds);
1553 wfdsp = &wfds;
1554 if(nfds < decode_out_fd) nfds = decode_out_fd;
1555 }
1556
1557 /*
1558 * need to set a timeout on select if scamper's processing window is
1559 * not full and there is a trace in the waiting queue.
1560 */
1561 tv_ptr = NULL;
1562 if(more > 0)
1563 {
1564 gettimeofday_wrap(&now);
1565
1566 /*
1567 * if there is something ready to probe now, then try and
1568 * do it.
1569 */
1570 w = heap_head_item(waiting);
1571 if(slist_count(n2i_list) > 0 ||
1572 (w != NULL && timeval_cmp(&w->tv, &now) <= 0))
1573 {
1574 if(do_method() != 0)
1575 return -1;
1576 }
1577
1578 /*
1579 * if we could not send a new command just yet, but scamper
1580 * wants one, then wait for an appropriate length of time.
1581 */
1582 w = heap_head_item(waiting);
1583 if(more > 0 && tv_ptr == NULL && w != NULL)
1584 {
1585 tv_ptr = &tv;
1586 if(timeval_cmp(&w->tv, &now) > 0)
1587 timeval_diff_tv(&tv, &now, &w->tv);
1588 else
1589 memset(&tv, 0, sizeof(tv));
1590 }
1591 }
1592
1593 if(splaytree_count(n2i_tree) == 0 && slist_count(n2i_list) == 0 &&
1594 heap_count(waiting) == 0)
1595 {
1596 logprint("done\n");
1597 break;
1598 }
1599
1600 if(select(nfds+1, &rfds, wfdsp, NULL, tv_ptr) < 0)
1601 {
1602 if(errno == EINTR) continue;
1603 fprintf(stderr, "select error\n");
1604 break;
1605 }
1606
1607 gettimeofday_wrap(&now);
1608
1609 if(more > 0)
1610 {
1611 if(do_method() != 0)
1612 return -1;
1613 }
1614
1615 if(scamper_fd >= 0)
1616 {
1617 if(FD_ISSET(scamper_fd, &rfds) && do_scamperread() != 0)
1618 return -1;
1619 if(wfdsp != NULL && FD_ISSET(scamper_fd, wfdsp) &&
1620 scamper_writebuf_write(scamper_fd, scamper_wb) != 0)
1621 {
1622 logprint("could not write to scamper_fd: %d %s\n",
1623 errno, strerror(errno));
1624 return -1;
1625 }
1626 }
1627
1628 if(decode_in_fd >= 0)
1629 {
1630 if(FD_ISSET(decode_in_fd, &rfds) && do_decoderead() != 0)
1631 return -1;
1632 }
1633
1634 if(decode_out_fd >= 0)
1635 {
1636 if(wfdsp != NULL && FD_ISSET(decode_out_fd, wfdsp) &&
1637 scamper_writebuf_write(decode_out_fd, decode_wb) != 0)
1638 {
1639 logprint("could not write to decode_out_fd: %d %s\n",
1640 errno, strerror(errno));
1641 return -1;
1642 }
1643
1644 if(scamper_fd < 0 && scamper_writebuf_len(decode_wb) == 0)
1645 {
1646 close(decode_out_fd);
1647 decode_out_fd = -1;
1648 }
1649 }
1650 }
1651
1652 return 0;
1653 }
1654
sc_idset_print_cb(void * ptr,void * item)1655 static int sc_idset_print_cb(void *ptr, void *item)
1656 {
1657 sc_idset_print(item);
1658 return 0;
1659 }
1660
fp_read(void)1661 static int fp_read(void)
1662 {
1663 splaytree_t *tree = NULL;
1664 scamper_file_t *in = NULL;
1665 sc_policytest_t *method;
1666 scamper_ping_t *ping;
1667 sc_idset_t *set;
1668 sc_iditem_t *item;
1669 uint16_t type;
1670 void *data;
1671 int code;
1672
1673 if(string_isdash(datafile) != 0)
1674 in = scamper_file_openfd(STDIN_FILENO, "-", 'r', "warts");
1675 else
1676 in = scamper_file_open(datafile, 'r', NULL);
1677 if(in == NULL)
1678 {
1679 fprintf(stderr, "could not open %s: %s\n", datafile, strerror(errno));
1680 goto err;
1681 }
1682
1683 if((tree = splaytree_alloc((splaytree_cmp_t)sc_idset_cmp)) == NULL)
1684 goto err;
1685
1686 while(scamper_file_read(in, ffilter, &type, &data) == 0)
1687 {
1688 if(data == NULL)
1689 break;
1690
1691 ping = data;
1692 if((method = ping_to_method(ping)) == NULL)
1693 goto err;
1694 code = ping_r(method, ping);
1695
1696 if((set = sc_idset_get(tree, ping->userid)) == NULL)
1697 goto err;
1698 set->tests |= (1 << (method->id-1));
1699
1700 if((item = sc_iditem_get(set, ping->dst)) == NULL)
1701 goto err;
1702 item->tests |= (1 << (method->id-1));
1703 if(code == 1)
1704 item->results |= (1 << (method->id-1));
1705
1706 scamper_ping_free(ping);
1707 }
1708 scamper_file_close(in);
1709
1710 splaytree_inorder(tree, sc_idset_print_cb, NULL);
1711 splaytree_free(tree, (splaytree_free_t)sc_idset_free);
1712
1713 return 0;
1714
1715 err:
1716 return -1;
1717 }
1718
fp_init(void)1719 static int fp_init(void)
1720 {
1721 uint16_t type;
1722
1723 if(flags & FLAG_TRACEROUTE)
1724 type = SCAMPER_FILE_OBJ_TRACE;
1725 else
1726 type = SCAMPER_FILE_OBJ_PING;
1727
1728 if((ffilter = scamper_file_filter_alloc(&type, 1)) == NULL)
1729 return -1;
1730
1731 return 0;
1732 }
1733
cleanup(void)1734 static void cleanup(void)
1735 {
1736 if(n2i_tree != NULL) splaytree_free(n2i_tree, NULL);
1737 if(n2i_list != NULL) slist_free(n2i_list);
1738 if(waiting != NULL) heap_free(waiting, free);
1739 if(scamper_wb != NULL) scamper_writebuf_free(scamper_wb);
1740 if(scamper_lp != NULL) scamper_linepoll_free(scamper_lp, 0);
1741 if(decode_wb != NULL) scamper_writebuf_free(decode_wb);
1742 if(outfile != NULL) scamper_file_close(outfile);
1743 if(decode_in != NULL) scamper_file_close(decode_in);
1744 if(ffilter != NULL) scamper_file_filter_free(ffilter);
1745 if(logfile != NULL) fclose(logfile);
1746 if(decode_in_fd != -1) close(decode_in_fd);
1747 if(decode_out_fd != -1) close(decode_out_fd);
1748 if(scamper_fd != -1) close(scamper_fd);
1749 return;
1750 }
1751
main(int argc,char * argv[])1752 int main(int argc, char *argv[])
1753 {
1754 #if defined(DMALLOC)
1755 free(malloc(1));
1756 #endif
1757
1758 atexit(cleanup);
1759
1760 if(check_options(argc, argv) != 0)
1761 return -1;
1762
1763 /* start a daemon if asked to */
1764 if((options & OPT_DAEMON) != 0 && daemon(1, 0) != 0)
1765 return -1;
1766
1767 if(fp_init() != 0)
1768 return -1;
1769
1770 if(options & OPT_READ)
1771 return fp_read();
1772
1773 return fp_data();
1774 }
1775