diff options
Diffstat (limited to 'src/fnettrace/main.c')
-rw-r--r-- | src/fnettrace/main.c | 193 |
1 files changed, 176 insertions, 17 deletions
diff --git a/src/fnettrace/main.c b/src/fnettrace/main.c index c996adb19..54ef54314 100644 --- a/src/fnettrace/main.c +++ b/src/fnettrace/main.c | |||
@@ -29,11 +29,60 @@ static int arg_netfilter = 0; | |||
29 | static int arg_tail = 0; | 29 | static int arg_tail = 0; |
30 | static char *arg_log = NULL; | 30 | static char *arg_log = NULL; |
31 | 31 | ||
32 | //***************************************************************** | ||
33 | // packet stats | ||
34 | //***************************************************************** | ||
32 | uint32_t stats_pkts = 0; | 35 | uint32_t stats_pkts = 0; |
33 | uint32_t stats_icmp_echo = 0; | 36 | uint32_t stats_icmp_echo = 0; |
34 | uint32_t stats_dns = 0; | 37 | uint32_t stats_dns = 0; |
38 | uint32_t stats_dns_dot = 0; | ||
39 | uint32_t stats_dns_doh = 0; | ||
40 | uint32_t stats_dns_doq = 0; | ||
41 | uint32_t stats_tls = 0; | ||
42 | uint32_t stats_quic = 0; | ||
43 | uint32_t stats_tor = 0; | ||
44 | uint32_t stats_http = 0; | ||
45 | |||
46 | //***************************************************************** | ||
47 | // sni/dns log storage | ||
48 | //***************************************************************** | ||
49 | typedef struct lognode_t { | ||
50 | #define LOG_RECORD_LEN 255 | ||
51 | char record[LOG_RECORD_LEN + 1]; | ||
52 | } LogNode; | ||
53 | // circular list of SNI log records | ||
54 | #define SNIMAX 64 | ||
55 | LogNode sni_table[SNIMAX] = {0}; | ||
56 | int sni_index = 0; | ||
57 | |||
58 | // circular list of SNI log records | ||
59 | #define DNSMAX 64 | ||
60 | LogNode dns_table[SNIMAX] = {0}; | ||
61 | int dns_index = 0; | ||
62 | |||
63 | static void print_sni(void) { | ||
64 | int i; | ||
65 | for (i = sni_index; i < SNIMAX; i++) | ||
66 | if (*sni_table[i].record) | ||
67 | printf(" %s", sni_table[i].record); | ||
68 | for (i = 0; i < sni_index; i++) | ||
69 | if (*sni_table[i].record) | ||
70 | printf(" %s", sni_table[i].record); | ||
71 | } | ||
35 | 72 | ||
73 | static void print_dns(void) { | ||
74 | int i; | ||
75 | for (i = dns_index; i < DNSMAX; i++) | ||
76 | if (*dns_table[i].record) | ||
77 | printf(" %s", dns_table[i].record); | ||
78 | for (i = 0; i < dns_index; i++) | ||
79 | if (*dns_table[i].record) | ||
80 | printf(" %s", dns_table[i].record); | ||
81 | } | ||
36 | 82 | ||
83 | //***************************************************************** | ||
84 | // traffic trace storage - hash table for fast access + linked list for display purposes | ||
85 | //***************************************************************** | ||
37 | typedef struct hnode_t { | 86 | typedef struct hnode_t { |
38 | struct hnode_t *hnext; // used for hash table and unused linked list | 87 | struct hnode_t *hnext; // used for hash table and unused linked list |
39 | struct hnode_t *dnext; // used to display streams on the screen | 88 | struct hnode_t *dnext; // used to display streams on the screen |
@@ -42,6 +91,7 @@ typedef struct hnode_t { | |||
42 | 91 | ||
43 | // stats | 92 | // stats |
44 | uint32_t bytes; // number of bytes received in the last display interval | 93 | uint32_t bytes; // number of bytes received in the last display interval |
94 | uint32_t pkts; // number of packets received in the last display interval | ||
45 | uint16_t port_src; | 95 | uint16_t port_src; |
46 | uint8_t protocol; | 96 | uint8_t protocol; |
47 | 97 | ||
@@ -97,6 +147,7 @@ static void hnode_add(uint32_t ip_src, uint8_t protocol, uint16_t port_src, uint | |||
97 | ip_instance++; | 147 | ip_instance++; |
98 | if (ptr->port_src == port_src && ptr->protocol == protocol) { | 148 | if (ptr->port_src == port_src && ptr->protocol == protocol) { |
99 | ptr->bytes += bytes; | 149 | ptr->bytes += bytes; |
150 | ptr->pkts++; | ||
100 | assert(ptr->rnode); | 151 | assert(ptr->rnode); |
101 | ptr->rnode->pkts++; | 152 | ptr->rnode->pkts++; |
102 | return; | 153 | return; |
@@ -115,6 +166,7 @@ static void hnode_add(uint32_t ip_src, uint8_t protocol, uint16_t port_src, uint | |||
115 | hnew->protocol = protocol; | 166 | hnew->protocol = protocol; |
116 | hnew->hnext = NULL; | 167 | hnew->hnext = NULL; |
117 | hnew->bytes = bytes; | 168 | hnew->bytes = bytes; |
169 | hnew->pkts = 1; | ||
118 | hnew->ip_instance = ip_instance + 1; | 170 | hnew->ip_instance = ip_instance + 1; |
119 | hnew->ttl = DISPLAY_TTL; | 171 | hnew->ttl = DISPLAY_TTL; |
120 | if (htable[h] == NULL) | 172 | if (htable[h] == NULL) |
@@ -369,22 +421,41 @@ static void hnode_print(unsigned bw) { | |||
369 | bwline = print_bw(ptr->bytes / bwunit); | 421 | bwline = print_bw(ptr->bytes / bwunit); |
370 | 422 | ||
371 | const char *protocol = NULL; | 423 | const char *protocol = NULL; |
372 | if (ptr->port_src == 443 && ptr->protocol == 0x06) // TCP | 424 | if (ptr->port_src == 443 && ptr->protocol == 0x06) { // TCP |
373 | protocol = "(TLS)"; | 425 | protocol = "(TLS)"; |
374 | else if (ptr->port_src == 443 && ptr->protocol == 0x11) // UDP | 426 | stats_tls += ptr->pkts; |
427 | } | ||
428 | else if (ptr->port_src == 443 && ptr->protocol == 0x11) { // UDP | ||
375 | protocol = "(QUIC)"; | 429 | protocol = "(QUIC)"; |
376 | else if (ptr->port_src == 53) | 430 | stats_quic += ptr->pkts; |
377 | protocol = "(DNS)"; | 431 | } |
378 | else if (ptr->port_src == 853) { | 432 | else if (ptr->port_src == 53) { |
433 | stats_dns += ptr->pkts; | ||
379 | if (ptr->protocol == 0x06) | 434 | if (ptr->protocol == 0x06) |
380 | protocol = "(DoT)"; | 435 | protocol = "(TCP/DNS)"; |
381 | else if (ptr->protocol == 0x11) | 436 | else if (ptr->protocol == 0x11) |
437 | protocol = "(UDP/DNS)"; | ||
438 | else | ||
439 | protocol = NULL; | ||
440 | } | ||
441 | else if (ptr->port_src == 853) { | ||
442 | if (ptr->protocol == 0x06) { | ||
443 | protocol = "(DoT)"; | ||
444 | stats_dns_dot += ptr->pkts; | ||
445 | } | ||
446 | else if (ptr->protocol == 0x11) { | ||
382 | protocol = "(DoQ)"; | 447 | protocol = "(DoQ)"; |
448 | stats_dns_doq += ptr->pkts; | ||
449 | } | ||
383 | else | 450 | else |
384 | protocol = NULL; | 451 | protocol = NULL; |
385 | } | 452 | } |
386 | else if ((protocol = common_port(ptr->port_src)) != NULL) | 453 | else if ((protocol = common_port(ptr->port_src)) != NULL) { |
387 | ; | 454 | if (strcmp(protocol, "(HTTP)") == 0) |
455 | stats_http += ptr->pkts; | ||
456 | else if (strcmp(protocol, "(Tor)") == 0) | ||
457 | stats_tor += ptr->pkts; | ||
458 | } | ||
388 | else if (ptr->protocol == 0x11) | 459 | else if (ptr->protocol == 0x11) |
389 | protocol = "(UDP)"; | 460 | protocol = "(UDP)"; |
390 | else if (ptr->protocol == 0x06) | 461 | else if (ptr->protocol == 0x06) |
@@ -410,6 +481,7 @@ static void hnode_print(unsigned bw) { | |||
410 | if (ptr->bytes) | 481 | if (ptr->bytes) |
411 | ptr->ttl = DISPLAY_TTL; | 482 | ptr->ttl = DISPLAY_TTL; |
412 | ptr->bytes = 0; | 483 | ptr->bytes = 0; |
484 | ptr->pkts = 0; | ||
413 | prev = ptr; | 485 | prev = ptr; |
414 | } | 486 | } |
415 | else { | 487 | else { |
@@ -440,9 +512,6 @@ static void hnode_print(unsigned bw) { | |||
440 | 512 | ||
441 | 513 | ||
442 | void print_stats(void) { | 514 | void print_stats(void) { |
443 | printf("\nIP table: %d entries - address network (packets)\n", radix_nodes); | ||
444 | radix_print(1); | ||
445 | printf("Packets: %u total, PING %u, DNS %u\n", stats_pkts, stats_icmp_echo, stats_dns); | ||
446 | } | 515 | } |
447 | 516 | ||
448 | // trace rx traffic coming in | 517 | // trace rx traffic coming in |
@@ -457,6 +526,18 @@ static void run_trace(void) { | |||
457 | if (s1 < 0 || s2 < 0 || s3 < 0) | 526 | if (s1 < 0 || s2 < 0 || s3 < 0) |
458 | errExit("socket"); | 527 | errExit("socket"); |
459 | 528 | ||
529 | |||
530 | int p1 = -1; | ||
531 | if (!arg_netfilter) | ||
532 | p1 = runprog(LIBDIR "/firejail/fnettrace-sni"); | ||
533 | if (p1 != -1) | ||
534 | printf("loading snitrace..."); | ||
535 | |||
536 | int p2 = -1; | ||
537 | if (!arg_netfilter) | ||
538 | p2 = runprog(LIBDIR "/firejail/fnettrace-dns --nolocal"); | ||
539 | if (p2 != -1) | ||
540 | printf("loading dnstrace..."); | ||
460 | unsigned start = time(NULL); | 541 | unsigned start = time(NULL); |
461 | unsigned last_print_traces = 0; | 542 | unsigned last_print_traces = 0; |
462 | unsigned last_print_remaining = 0; | 543 | unsigned last_print_remaining = 0; |
@@ -480,14 +561,26 @@ static void run_trace(void) { | |||
480 | } | 561 | } |
481 | 562 | ||
482 | fd_set rfds; | 563 | fd_set rfds; |
564 | |||
483 | FD_ZERO(&rfds); | 565 | FD_ZERO(&rfds); |
566 | if (!arg_netfilter) | ||
567 | FD_SET(0, &rfds); | ||
568 | |||
484 | FD_SET(s1, &rfds); | 569 | FD_SET(s1, &rfds); |
485 | FD_SET(s2, &rfds); | 570 | FD_SET(s2, &rfds); |
486 | FD_SET(s3, &rfds); | 571 | FD_SET(s3, &rfds); |
487 | if (!arg_netfilter) | ||
488 | FD_SET(0, &rfds); | ||
489 | int maxfd = (s1 > s2) ? s1 : s2; | 572 | int maxfd = (s1 > s2) ? s1 : s2; |
490 | maxfd = (s3 > maxfd) ? s3 : maxfd; | 573 | maxfd = (s3 > maxfd) ? s3 : maxfd; |
574 | |||
575 | if (p1 != -1) { | ||
576 | FD_SET(p1, &rfds); | ||
577 | maxfd = (p1 > maxfd) ? p1 : maxfd; | ||
578 | } | ||
579 | |||
580 | if (p2 != -1) { | ||
581 | FD_SET(p2, &rfds); | ||
582 | maxfd = (p2 > maxfd) ? p2 : maxfd; | ||
583 | } | ||
491 | maxfd++; | 584 | maxfd++; |
492 | 585 | ||
493 | struct timeval tv; | 586 | struct timeval tv; |
@@ -505,14 +598,82 @@ static void run_trace(void) { | |||
505 | int sock = s1; | 598 | int sock = s1; |
506 | int icmp = 0; | 599 | int icmp = 0; |
507 | 600 | ||
508 | if (FD_ISSET(0, &rfds)) { | 601 | if (!arg_netfilter && FD_ISSET(0, &rfds)) { |
602 | getchar(); | ||
603 | printf("\n\nStats: %u packets\n", stats_pkts); | ||
604 | printf(" encrypted: TLS %u, QUIC %u, Tor %u\n", | ||
605 | stats_tls, stats_quic, stats_tor); | ||
606 | printf(" unencrypted: HTTP %u\n", stats_http); | ||
607 | printf(" C&C backchannel: PING %u, DNS %u, DoH %u, DoT %u, DoQ %u\n", | ||
608 | stats_icmp_echo, stats_dns, stats_dns_doh, stats_dns_dot, stats_dns_doq); | ||
609 | printf("press any key to continue..."); | ||
610 | fflush(0); | ||
611 | |||
612 | getchar(); | ||
613 | printf("\n\nSNI log - time server-address SNI\n"); | ||
614 | print_sni(); | ||
615 | printf("press any key to continue..."); | ||
616 | fflush(0); | ||
617 | |||
618 | getchar(); | ||
619 | printf("\n\nDNS log - time server-address domain\n"); | ||
620 | print_dns(); | ||
621 | printf("press any key to continue..."); | ||
622 | fflush(0); | ||
623 | |||
509 | getchar(); | 624 | getchar(); |
510 | print_stats(); | 625 | printf("\n\nIP table: %d addresses - server-address network (packets)\n", radix_nodes); |
626 | radix_print(1); | ||
511 | printf("press any key to continue..."); | 627 | printf("press any key to continue..."); |
512 | fflush(0); | 628 | fflush(0); |
629 | |||
513 | getchar(); | 630 | getchar(); |
514 | continue; | 631 | continue; |
515 | } | 632 | } |
633 | else if (!arg_netfilter && FD_ISSET(p1, &rfds)) { | ||
634 | char buf[1024]; | ||
635 | ssize_t sz = read(p1, buf, 1024 - 1); | ||
636 | if (sz == -1) | ||
637 | errExit("error reading snitrace"); | ||
638 | if (sz == 0) { | ||
639 | fprintf(stderr, "Error: snitrace EOF!!!\n"); | ||
640 | p1 = -1; | ||
641 | } | ||
642 | if (strncmp(buf, "SNI trace", 9) == 0) | ||
643 | continue; | ||
644 | |||
645 | if (sz > LOG_RECORD_LEN) | ||
646 | sz = LOG_RECORD_LEN; | ||
647 | buf[sz] = '\0'; | ||
648 | strcpy(sni_table[sni_index].record, buf); | ||
649 | if (++sni_index >= SNIMAX) { | ||
650 | sni_index = 0; | ||
651 | *sni_table[sni_index].record = '\0'; | ||
652 | } | ||
653 | continue; | ||
654 | } | ||
655 | else if (!arg_netfilter && FD_ISSET(p2, &rfds)) { | ||
656 | char buf[1024]; | ||
657 | ssize_t sz = read(p2, buf, 1024 - 1); | ||
658 | if (sz == -1) | ||
659 | errExit("error reading dnstrace"); | ||
660 | if (sz == 0) { | ||
661 | fprintf(stderr, "Error: dnstrace EOF!!!\n"); | ||
662 | p2 = -1; | ||
663 | } | ||
664 | if (strncmp(buf, "DNS trace", 9) == 0) | ||
665 | continue; | ||
666 | |||
667 | if (sz > LOG_RECORD_LEN) | ||
668 | sz = LOG_RECORD_LEN; | ||
669 | buf[sz] = '\0'; | ||
670 | strcpy(dns_table[dns_index].record, buf); | ||
671 | if (++dns_index >= DNSMAX) { | ||
672 | dns_index = 0; | ||
673 | *dns_table[dns_index].record = '\0'; | ||
674 | } | ||
675 | continue; | ||
676 | } | ||
516 | else if (FD_ISSET(s2, &rfds)) | 677 | else if (FD_ISSET(s2, &rfds)) |
517 | sock = s2; | 678 | sock = s2; |
518 | else if (FD_ISSET(s3, &rfds)) { | 679 | else if (FD_ISSET(s3, &rfds)) { |
@@ -560,8 +721,6 @@ static void run_trace(void) { | |||
560 | if (*(buf + hlen) == 0 || *(buf + hlen) == 8) | 721 | if (*(buf + hlen) == 0 || *(buf + hlen) == 8) |
561 | stats_icmp_echo++; | 722 | stats_icmp_echo++; |
562 | } | 723 | } |
563 | else if (port_src == 53) | ||
564 | stats_dns++; | ||
565 | 724 | ||
566 | } | 725 | } |
567 | } | 726 | } |