1 /*
2 * sc_wartsfilter
3 *
4 * $Id: sc_wartsfilter.c,v 1.6 2021/08/22 08:11:53 mjl Exp $
5 *
6 * Matthew Luckie
7 * mjl@luckie.org.nz
8 *
9 * Copyright (C) 2019-2020 The University of Waikato
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, version 2.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 #include "internal.h"
30
31 #include "scamper_file.h"
32 #include "scamper_addr.h"
33 #include "scamper_list.h"
34 #include "dealias/scamper_dealias.h"
35 #include "ping/scamper_ping.h"
36 #include "tbit/scamper_tbit.h"
37 #include "trace/scamper_trace.h"
38 #include "tracelb/scamper_tracelb.h"
39 #include "mjl_list.h"
40 #include "mjl_prefixtree.h"
41 #include "utils.h"
42
43 #define OPT_OUTFILE 0x0001
44 #define OPT_INFILE 0x0002
45 #define OPT_ADDR 0x0004
46 #define OPT_TYPE 0x0008
47
48 static scamper_file_t *infile = NULL;
49 static scamper_file_t *outfile = NULL;
50 static prefixtree_t *addr_pt4 = NULL;
51 static prefixtree_t *addr_pt6 = NULL;
52 static int addrc = 0;
53 static scamper_file_filter_t *filter = NULL;
54 static int check_hops = 0;
55
usage(uint32_t opts)56 static void usage(uint32_t opts)
57 {
58 fprintf(stderr,
59 "usage: sc_wartsfilter [-a address] [-i infile] [-o outfile]\n"
60 " [-O options] [-t type]\n");
61 return;
62 }
63
check_options(int argc,char * argv[])64 static int check_options(int argc, char *argv[])
65 {
66 char *opt_infile = NULL, *opt_outfile = NULL;
67 uint32_t type_mask = 0;
68 slist_t *addrs = NULL;
69 slist_node_t *sn;
70 char *opts = "a:i:o:O:t:?";
71 char *addr, *ptr, *dup = NULL;
72 prefix4_t *pfx4 = NULL;
73 prefix6_t *pfx6 = NULL;
74 struct in_addr in4;
75 struct in6_addr in6;
76 uint16_t types_def[] = {
77 SCAMPER_FILE_OBJ_DEALIAS,
78 SCAMPER_FILE_OBJ_PING,
79 SCAMPER_FILE_OBJ_TBIT,
80 SCAMPER_FILE_OBJ_TRACE,
81 SCAMPER_FILE_OBJ_TRACELB,
82 };
83 uint16_t *types = NULL;
84 int i, typec;
85 long lo;
86 int ch;
87
88 if((addrs = slist_alloc()) == NULL)
89 {
90 fprintf(stderr, "%s: could not alloc addrs\n", __func__);
91 goto err;
92 }
93
94 while((ch = getopt(argc, argv, opts)) != -1)
95 {
96 switch(ch)
97 {
98 case 'a':
99 if((dup = strdup(optarg)) == NULL ||
100 slist_tail_push(addrs, dup) == NULL)
101 {
102 fprintf(stderr, "%s: error handling -a\n", __func__);
103 goto err;
104 }
105 dup = NULL;
106 break;
107
108 case 'i':
109 opt_infile = optarg;
110 break;
111
112 case 'o':
113 opt_outfile = optarg;
114 break;
115
116 case 'O':
117 if(strcasecmp(optarg, "check-hops") == 0)
118 check_hops = 1;
119 else
120 {
121 fprintf(stderr, "%s: unknown -O %s\n", __func__, optarg);
122 goto err;
123 }
124 break;
125
126 case 't':
127 if(strcasecmp(optarg, "dealias") == 0)
128 type_mask |= (1 << SCAMPER_FILE_OBJ_DEALIAS);
129 else if(strcasecmp(optarg, "ping") == 0)
130 type_mask |= (1 << SCAMPER_FILE_OBJ_PING);
131 else if(strcasecmp(optarg, "tbit") == 0)
132 type_mask |= (1 << SCAMPER_FILE_OBJ_TBIT);
133 else if(strcasecmp(optarg, "trace") == 0)
134 type_mask |= (1 << SCAMPER_FILE_OBJ_TRACE);
135 else if(strcasecmp(optarg, "tracelb") == 0)
136 type_mask |= (1 << SCAMPER_FILE_OBJ_TRACELB);
137 else
138 {
139 usage(0);
140 goto err;
141 }
142 break;
143
144 case '?':
145 usage(0xffffffff);
146 goto err;
147
148 default:
149 usage(0);
150 goto err;
151 }
152 }
153
154 /* make sure there is some filter */
155 if((addrc = slist_count(addrs)) == 0 && type_mask == 0)
156 {
157 usage(OPT_ADDR | OPT_TYPE);
158 goto err;
159 }
160
161 /* go through the filter types */
162 if(type_mask == 0)
163 {
164 typec = sizeof(types_def) / sizeof(uint16_t);
165 if((filter = scamper_file_filter_alloc(types_def, typec)) == NULL)
166 {
167 fprintf(stderr, "%s: could not alloc default filter\n", __func__);
168 goto err;
169 }
170 }
171 else
172 {
173 typec = countbits32(type_mask);
174 if((types = malloc(sizeof(uint16_t) * typec)) == NULL)
175 {
176 fprintf(stderr, "%s: could not malloc %d types\n", __func__, typec);
177 goto err;
178 }
179 i = 0;
180 if(type_mask & (1 << SCAMPER_FILE_OBJ_DEALIAS))
181 types[i++] = SCAMPER_FILE_OBJ_DEALIAS;
182 if(type_mask & (1 << SCAMPER_FILE_OBJ_PING))
183 types[i++] = SCAMPER_FILE_OBJ_PING;
184 if(type_mask & (1 << SCAMPER_FILE_OBJ_TBIT))
185 types[i++] = SCAMPER_FILE_OBJ_TBIT;
186 if(type_mask & (1 << SCAMPER_FILE_OBJ_TRACE))
187 types[i++] = SCAMPER_FILE_OBJ_TRACE;
188 if(type_mask & (1 << SCAMPER_FILE_OBJ_TRACELB))
189 types[i++] = SCAMPER_FILE_OBJ_TRACELB;
190 assert(i == typec);
191 if((filter = scamper_file_filter_alloc(types, typec)) == NULL)
192 {
193 fprintf(stderr, "%s: could not alloc filter\n", __func__);
194 goto err;
195 }
196 free(types); types = NULL;
197 }
198
199 /* go through the list of addresses */
200 for(sn=slist_head_node(addrs); sn != NULL; sn=slist_node_next(sn))
201 {
202 addr = slist_node_item(sn);
203
204 /* if address is not a prefix, install a specific /32 or /128 */
205 if((ptr = string_firstof_char(addr, '/')) == NULL)
206 {
207 if(inet_pton(AF_INET, addr, &in4) == 1)
208 {
209 if((pfx4 = prefix4_alloc(&in4, 32, NULL)) == NULL ||
210 prefixtree_insert4(addr_pt4, pfx4) == NULL)
211 {
212 fprintf(stderr, "%s: could not alloc prefix for %s\n",
213 __func__, addr);
214 goto err;
215 }
216 }
217 else if(inet_pton(AF_INET6, addr, &in6) == 1)
218 {
219 if((pfx6 = prefix6_alloc(&in6, 128, NULL)) == NULL ||
220 prefixtree_insert6(addr_pt6, pfx6) == NULL)
221 {
222 fprintf(stderr, "%s: could not alloc prefix for %s\n",
223 __func__, addr);
224 goto err;
225 }
226 }
227 else
228 {
229 fprintf(stderr, "%s: could not parse addr %s\n", __func__, addr);
230 goto err;
231 }
232 continue;
233 }
234
235 *ptr = '\0'; ptr++;
236 if(string_tolong(ptr, &lo) != 0 || lo < 1)
237 {
238 fprintf(stderr, "%s: invalid prefix length %s\n", __func__, ptr);
239 goto err;
240 }
241 if(inet_pton(AF_INET, addr, &in4) == 1)
242 {
243 if(lo > 32)
244 {
245 fprintf(stderr, "%s: invalid IPv4 prefix length %ld\n",
246 __func__, lo);
247 goto err;
248 }
249 if((pfx4 = prefix4_alloc(&in4, lo, NULL)) == NULL)
250 {
251 fprintf(stderr, "%s: could not alloc IPv4 prefix\n", __func__);
252 goto err;
253 }
254 pfx4->ptr = pfx4;
255 if(prefixtree_insert4(addr_pt4, pfx4) == NULL)
256 {
257 fprintf(stderr, "%s: could not insert IPv4 prefix\n", __func__);
258 goto err;
259 }
260 }
261 else if(inet_pton(AF_INET6, addr, &in6) == 1)
262 {
263 if(lo > 128)
264 {
265 fprintf(stderr, "%s: invalid IPv6 prefix length %ld\n",
266 __func__, lo);
267 goto err;
268 }
269 if((pfx6 = prefix6_alloc(&in6, lo, NULL)) == NULL)
270 {
271 fprintf(stderr, "%s: could not alloc IPv6 prefix\n", __func__);
272 goto err;
273 }
274 pfx6->ptr = pfx6;
275 if(prefixtree_insert6(addr_pt6, pfx6) == NULL)
276 {
277 fprintf(stderr, "%s: could not insert IPv6 prefix\n", __func__);
278 goto err;
279 }
280 }
281 else
282 {
283 fprintf(stderr, "%s: could not parse prefix %s/%s\n",
284 __func__, addr, ptr);
285 goto err;
286 }
287 }
288 slist_free_cb(addrs, free); addrs = NULL;
289
290 /* determine where to read the warts file */
291 if(opt_infile == NULL)
292 {
293 if((infile = scamper_file_openfd(STDIN_FILENO,"-",'r',"warts")) == NULL)
294 {
295 fprintf(stderr, "could not open stdin\n");
296 goto err;
297 }
298 }
299 else
300 {
301 if((infile = scamper_file_open(opt_infile, 'r', "warts")) == NULL)
302 {
303 fprintf(stderr, "could not open %s\n", opt_infile);
304 goto err;
305 }
306 }
307
308 /* determine where to write the filtered records */
309 if(opt_outfile == NULL || string_isdash(opt_outfile) != 0)
310 {
311 /* writing to stdout; don't dump a binary structure to a tty. */
312 if(isatty(STDOUT_FILENO) != 0)
313 {
314 fprintf(stderr, "not going to dump warts to a tty\n");
315 goto err;
316 }
317 if((outfile = scamper_file_openfd(STDOUT_FILENO,"-",'w',"warts")) == NULL)
318 {
319 fprintf(stderr, "could not open stdout\n");
320 goto err;
321 }
322 }
323 else
324 {
325 if((outfile = scamper_file_open(opt_outfile, 'w', "warts")) == NULL)
326 {
327 usage(OPT_OUTFILE);
328 goto err;
329 }
330 }
331
332 return 0;
333
334 err:
335 if(dup != NULL) free(dup);
336 if(types != NULL) free(types);
337 if(addrs != NULL) slist_free_cb(addrs, free);
338 return -1;
339 }
340
addr_matched(scamper_addr_t * addr)341 static int addr_matched(scamper_addr_t *addr)
342 {
343 if(SCAMPER_ADDR_TYPE_IS_IPV4(addr))
344 {
345 if(prefixtree_find_ip4(addr_pt4, addr->addr) == NULL)
346 return 0;
347 }
348 else if(SCAMPER_ADDR_TYPE_IS_IPV6(addr))
349 {
350 if(prefixtree_find_ip6(addr_pt6, addr->addr) == NULL)
351 return 0;
352 }
353 else return 0;
354 return 1;
355 }
356
process_dealias(scamper_dealias_t * dealias)357 static void process_dealias(scamper_dealias_t *dealias)
358 {
359 scamper_dealias_mercator_t *mc;
360 scamper_dealias_ally_t *ally;
361 scamper_dealias_radargun_t *rg;
362 scamper_dealias_prefixscan_t *pfs;
363 uint32_t i;
364
365 if(addrc > 0)
366 {
367 if(SCAMPER_DEALIAS_METHOD_IS_MERCATOR(dealias))
368 {
369 mc = dealias->data;
370 if(addr_matched(mc->probedef.dst) == 0)
371 goto done;
372 }
373 else if(SCAMPER_DEALIAS_METHOD_IS_ALLY(dealias))
374 {
375 ally = dealias->data;
376 if(addr_matched(ally->probedefs[0].dst) == 0 &&
377 addr_matched(ally->probedefs[1].dst) == 0)
378 goto done;
379 }
380 else if(SCAMPER_DEALIAS_METHOD_IS_RADARGUN(dealias))
381 {
382 rg = dealias->data;
383 for(i=0; i<rg->probedefc; i++)
384 if(addr_matched(rg->probedefs[i].dst) != 0)
385 break;
386 if(i == rg->probedefc)
387 goto done;
388 }
389 else if(SCAMPER_DEALIAS_METHOD_IS_PREFIXSCAN(dealias))
390 {
391 pfs = dealias->data;
392 for(i=0; i<pfs->probedefc; i++)
393 if(addr_matched(pfs->probedefs[i].dst) != 0)
394 break;
395 if(i == pfs->probedefc)
396 goto done;
397 }
398 else goto done;
399 }
400 scamper_file_write_dealias(outfile, dealias);
401
402 done:
403 scamper_dealias_free(dealias);
404 return;
405 }
406
process_ping(scamper_ping_t * ping)407 static void process_ping(scamper_ping_t *ping)
408 {
409 if(addrc > 0 && addr_matched(ping->dst) == 0)
410 goto done;
411 scamper_file_write_ping(outfile, ping);
412
413 done:
414 scamper_ping_free(ping);
415 return;
416 }
417
process_tbit(scamper_tbit_t * tbit)418 static void process_tbit(scamper_tbit_t *tbit)
419 {
420 if(addrc > 0 && addr_matched(tbit->dst) == 0)
421 goto done;
422 scamper_file_write_tbit(outfile, tbit);
423
424 done:
425 scamper_tbit_free(tbit);
426 return;
427 }
428
process_trace(scamper_trace_t * trace)429 static void process_trace(scamper_trace_t *trace)
430 {
431 scamper_trace_hop_t *hop;
432 uint16_t i;
433
434 if(addrc == 0)
435 {
436 scamper_file_write_trace(outfile, trace);
437 goto done;
438 }
439 else if(addr_matched(trace->dst) != 0)
440 {
441 scamper_file_write_trace(outfile, trace);
442 goto done;
443 }
444 else if(check_hops != 0)
445 {
446 for(i=0; i<trace->hop_count; i++)
447 {
448 for(hop=trace->hops[i]; hop != NULL; hop=hop->hop_next)
449 {
450 if(addr_matched(hop->hop_addr) != 0)
451 {
452 scamper_file_write_trace(outfile, trace);
453 goto done;
454 }
455 }
456 }
457 }
458
459 done:
460 scamper_trace_free(trace);
461 return;
462 }
463
process_tracelb(scamper_tracelb_t * tracelb)464 static int process_tracelb(scamper_tracelb_t *tracelb)
465 {
466 scamper_tracelb_node_t *node;
467 scamper_tracelb_link_t *link;
468 scamper_tracelb_probeset_t *set;
469 scamper_tracelb_probe_t *probe;
470 scamper_tracelb_reply_t *reply;
471 uint32_t i, j, k, l, m;
472
473 if(addrc == 0)
474 {
475 scamper_file_write_tracelb(outfile, tracelb);
476 goto done;
477 }
478 else if(addr_matched(tracelb->dst) != 0)
479 {
480 scamper_file_write_tracelb(outfile, tracelb);
481 goto done;
482 }
483 else if(check_hops != 0)
484 {
485 for(i=0; i<tracelb->nodec; i++)
486 {
487 node = tracelb->nodes[i];
488 if(node->addr != NULL && addr_matched(node->addr) != 0)
489 {
490 scamper_file_write_tracelb(outfile, tracelb);
491 goto done;
492 }
493 for(j=0; j<node->linkc; j++)
494 {
495 link = node->links[j];
496 if(link->to != NULL && addr_matched(link->to->addr) != 0)
497 {
498 scamper_file_write_tracelb(outfile, tracelb);
499 goto done;
500 }
501 for(k=0; k<link->hopc-1; k++)
502 {
503 set = link->sets[k];
504 for(l=0; l<set->probec; l++)
505 {
506 probe = set->probes[l];
507 for(m=0; m<probe->rxc; m++)
508 {
509 reply = probe->rxs[m];
510 if(addr_matched(reply->reply_from) != 0)
511 {
512 scamper_file_write_tracelb(outfile, tracelb);
513 goto done;
514 }
515 }
516 }
517 }
518 }
519 }
520 }
521
522 done:
523 scamper_tracelb_free(tracelb);
524 return 0;
525 }
526
cleanup(void)527 static void cleanup(void)
528 {
529 if(infile != NULL)
530 {
531 scamper_file_close(infile);
532 infile = NULL;
533 }
534
535 if(filter != NULL)
536 {
537 scamper_file_filter_free(filter);
538 filter = NULL;
539 }
540
541 if(outfile != NULL)
542 {
543 scamper_file_close(outfile);
544 outfile = NULL;
545 }
546
547 if(addr_pt4 != NULL)
548 {
549 prefixtree_free_cb(addr_pt4, (prefix_free_t)prefix4_free);
550 addr_pt4 = NULL;
551 }
552
553 if(addr_pt6 != NULL)
554 {
555 prefixtree_free_cb(addr_pt6, (prefix_free_t)prefix6_free);
556 addr_pt6 = NULL;
557 }
558
559 return;
560 }
561
main(int argc,char * argv[])562 int main(int argc, char *argv[])
563 {
564 uint16_t type;
565 void *data;
566
567 #ifdef DMALLOC
568 free(malloc(1));
569 #endif
570
571 atexit(cleanup);
572
573 if((addr_pt4 = prefixtree_alloc(AF_INET)) == NULL ||
574 (addr_pt6 = prefixtree_alloc(AF_INET6)) == NULL)
575 {
576 fprintf(stderr, "%s: could not alloc prefixtrees\n", __func__);
577 goto err;
578 }
579
580 if(check_options(argc, argv) != 0)
581 goto err;
582
583 while(scamper_file_read(infile, filter, &type, (void *)&data) == 0)
584 {
585 if(data == NULL)
586 break; /* EOF */
587
588 if(type == SCAMPER_FILE_OBJ_DEALIAS)
589 process_dealias(data);
590 else if(type == SCAMPER_FILE_OBJ_PING)
591 process_ping(data);
592 else if(type == SCAMPER_FILE_OBJ_TRACE)
593 process_trace(data);
594 else if(type == SCAMPER_FILE_OBJ_TBIT)
595 process_tbit(data);
596 else if(type == SCAMPER_FILE_OBJ_TRACELB)
597 process_tracelb(data);
598 }
599
600 return 0;
601
602 err:
603 return -1;
604 }
605