aboutsummaryrefslogtreecommitdiffstats
path: root/src/fnettrace/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fnettrace/main.c')
-rw-r--r--src/fnettrace/main.c244
1 files changed, 147 insertions, 97 deletions
diff --git a/src/fnettrace/main.c b/src/fnettrace/main.c
index 3bafd9090..a1e46f307 100644
--- a/src/fnettrace/main.c
+++ b/src/fnettrace/main.c
@@ -27,6 +27,12 @@
27 27
28static char *arg_log = NULL; 28static char *arg_log = NULL;
29 29
30// only 0 or negative values; postive values as defiend in RFCsq
31#define PROTOCOL_ICMP 0
32#define PROTOCOL_SSH -1
33
34
35
30//***************************************************************** 36//*****************************************************************
31// packet stats 37// packet stats
32//***************************************************************** 38//*****************************************************************
@@ -42,41 +48,18 @@ uint32_t stats_tor = 0;
42uint32_t stats_http = 0; 48uint32_t stats_http = 0;
43uint32_t stats_ssh = 0; 49uint32_t stats_ssh = 0;
44 50
45//***************************************************************** 51static void clear_stats(void) {
46// sni/dns log storage 52 stats_pkts = 0;
47//***************************************************************** 53 stats_icmp_echo = 0;
48typedef struct lognode_t { 54 stats_dns = 0;
49#define LOG_RECORD_LEN 255 55 stats_dns_dot = 0;
50 char record[LOG_RECORD_LEN + 1]; 56 stats_dns_doh = 0;
51} LogNode; 57 stats_dns_doq = 0;
52// circular list of SNI log records 58 stats_tls = 0;
53#define SNIMAX 64 59 stats_quic = 0;
54LogNode sni_table[SNIMAX] = {0}; 60 stats_tor = 0;
55int sni_index = 0; 61 stats_http = 0;
56 62 stats_ssh = 0;
57// circular list of SNI log records
58#define DNSMAX 64
59LogNode dns_table[SNIMAX] = {0};
60int dns_index = 0;
61
62static void print_sni(void) {
63 int i;
64 for (i = sni_index; i < SNIMAX; i++)
65 if (*sni_table[i].record)
66 printf(" %s", sni_table[i].record);
67 for (i = 0; i < sni_index; i++)
68 if (*sni_table[i].record)
69 printf(" %s", sni_table[i].record);
70}
71
72static void print_dns(void) {
73 int i;
74 for (i = dns_index; i < DNSMAX; i++)
75 if (*dns_table[i].record)
76 printf(" %s", dns_table[i].record);
77 for (i = 0; i < dns_index; i++)
78 if (*dns_table[i].record)
79 printf(" %s", dns_table[i].record);
80} 63}
81 64
82//***************************************************************** 65//*****************************************************************
@@ -92,7 +75,7 @@ typedef struct hnode_t {
92 uint32_t bytes; // number of bytes received in the last display interval 75 uint32_t bytes; // number of bytes received in the last display interval
93 uint32_t pkts; // number of packets received in the last display interval 76 uint32_t pkts; // number of packets received in the last display interval
94 uint16_t port_src; 77 uint16_t port_src;
95 uint8_t protocol; 78 int protocol;
96 79
97 // the firewall is build based on source address, and in the linked list 80 // the firewall is build based on source address, and in the linked list
98 // we could have elements with the same address but different ports 81 // we could have elements with the same address but different ports
@@ -135,7 +118,7 @@ void hfree(HNode *ptr) {
135} 118}
136 119
137// using protocol 0 and port 0 for ICMP 120// using protocol 0 and port 0 for ICMP
138static void hnode_add(uint32_t ip_src, uint8_t protocol, uint16_t port_src, uint32_t bytes) { 121static void hnode_add(uint32_t ip_src, int protocol, uint16_t port_src, uint32_t bytes) {
139 uint8_t h = hash(ip_src); 122 uint8_t h = hash(ip_src);
140 123
141 // find 124 // find
@@ -383,7 +366,9 @@ static void hnode_print(unsigned bw) {
383 else 366 else
384 sprintf(stats, "%u KB/s ", bw / (1024 * DISPLAY_INTERVAL)); 367 sprintf(stats, "%u KB/s ", bw / (1024 * DISPLAY_INTERVAL));
385// int len = snprintf(line, LINE_MAX, "%32s geoip %d, IP database %d\n", stats, geoip_calls, radix_nodes); 368// int len = snprintf(line, LINE_MAX, "%32s geoip %d, IP database %d\n", stats, geoip_calls, radix_nodes);
386 int len = snprintf(line, LINE_MAX, "%32s address:port (protocol) network\n", stats); 369 char faint1[] = {0x1b, '[', '2', 'm', '\0'};
370 char faint2[] = {0x1b, '[', '0', 'm', '\0'};
371 int len = snprintf(line, LINE_MAX, "%32s %saddress:port (protocol) network%s\n", stats, faint1, faint2);
387 adjust_line(line, len, cols); 372 adjust_line(line, len, cols);
388 printf("%s", line); 373 printf("%s", line);
389 374
@@ -461,10 +446,14 @@ static void hnode_print(unsigned bw) {
461 protocol = "UDP"; 446 protocol = "UDP";
462 else if (ptr->protocol == 0x06) 447 else if (ptr->protocol == 0x06)
463 protocol = "TCP"; 448 protocol = "TCP";
449 else if (ptr->protocol == PROTOCOL_SSH) {
450 protocol = "SSH";
451 stats_ssh += ptr->pkts;
452 }
464 453
465 if (protocol == NULL) 454 if (protocol == NULL)
466 protocol = ""; 455 protocol = "";
467 if (ptr->port_src == 0) 456 if (ptr->port_src == PROTOCOL_ICMP)
468 len = snprintf(line, LINE_MAX, "%10s %s %d.%d.%d.%d (ICMP) %s\n", 457 len = snprintf(line, LINE_MAX, "%10s %s %d.%d.%d.%d (ICMP) %s\n",
469 bytes, bwline, PRINT_IP(ptr->ip_src), ptr->rnode->name); 458 bytes, bwline, PRINT_IP(ptr->ip_src), ptr->rnode->name);
470 else 459 else
@@ -490,7 +479,7 @@ static void hnode_print(unsigned bw) {
490 479
491 ptr = next; 480 ptr = next;
492 } 481 }
493 printf("press any key to access stats\n"); 482 ansi_faint("(D)isplay, (S)ave, (C)lear, e(X)it\n");
494 483
495#ifdef DEBUG 484#ifdef DEBUG
496 { 485 {
@@ -505,10 +494,34 @@ static void hnode_print(unsigned bw) {
505#endif 494#endif
506} 495}
507 496
497static void print_stats(FILE *fp) {
498 assert(fp);
499
500 fprintf(fp, "Stats: %u packets\n", stats_pkts);
501 fprintf(fp, " encrypted: TLS %u, QUIC %u, Tor %u\n",
502 stats_tls, stats_quic, stats_tor);
503 fprintf(fp, " unencrypted: HTTP %u\n", stats_http);
504 fprintf(fp, " C&C backchannel: SSH %u, PING %u, DNS %u, DoH %u, DoT %u, DoQ %u\n",
505 stats_ssh, stats_icmp_echo, stats_dns, stats_dns_doh, stats_dns_dot, stats_dns_doq);
506
507 fprintf(fp, "\n\nIP map");
508 if (fp == stdout)
509 ansi_faint(" - server-address network (packets)\n");
510 else
511 fprintf(fp, " - server-address network (packets)\n");
512 radix_print(fp, 1);
513
514 fprintf(fp, "\n\nEvents %d", ev_cnt);
515 if (fp == stdout)
516 ansi_faint(" - time address:port data\n");
517 else
518 fprintf(fp, " - time address:port data\n");
519 ev_print(fp);
508 520
509void print_stats(void) {
510} 521}
511 522
523
524
512// trace rx traffic coming in 525// trace rx traffic coming in
513static void run_trace(void) { 526static void run_trace(void) {
514 // trace only rx ipv4 tcp and upd 527 // trace only rx ipv4 tcp and upd
@@ -523,7 +536,7 @@ static void run_trace(void) {
523 if (p1 != -1) 536 if (p1 != -1)
524 printf("loading snitrace..."); 537 printf("loading snitrace...");
525 538
526 int p2 = runprog(LIBDIR "/firejail/fnettrace-dns --nolocal"); 539 int p2 = runprog(LIBDIR "/firejail/fnettrace-dns");
527 if (p2 != -1) 540 if (p2 != -1)
528 printf("loading dnstrace..."); 541 printf("loading dnstrace...");
529 unsigned last_print_traces = 0; 542 unsigned last_print_traces = 0;
@@ -575,40 +588,67 @@ static void run_trace(void) {
575 int icmp = 0; 588 int icmp = 0;
576 589
577 if (FD_ISSET(0, &rfds)) { 590 if (FD_ISSET(0, &rfds)) {
578 getchar(); 591 int c = getchar();
579 printf("\n\nStats: %u packets\n", stats_pkts); 592 if (c == 'c' || c == 'C') {
580 printf(" encrypted: TLS %u, QUIC %u, SSH %u, Tor %u\n", 593 clear_stats();
581 stats_tls, stats_quic, stats_ssh, stats_tor); 594 ev_clear();
582 printf(" unencrypted: HTTP %u\n", stats_http); 595 radix_clear_data();
583 printf(" C&C backchannel: PING %u, DNS %u, DoH %u, DoT %u, DoQ %u\n", 596 continue;
584 stats_icmp_echo, stats_dns, stats_dns_doh, stats_dns_dot, stats_dns_doq); 597 }
585 printf("press any key to continue..."); 598 else if (c == 'd' || c == 'D') {
586 fflush(0); 599 printf("\n\n");
587 600 ansi_bold("__________________________________________________________________________\n");
588 getchar(); 601 print_stats(stdout);
589 printf("\n\nSNI log - time server-address SNI\n"); 602 ansi_bold("__________________________________________________________________________\n");
590 print_sni(); 603 ansi_faint("press any key to continue...");
591 printf("press any key to continue..."); 604 fflush(0);
592 fflush(0); 605
593 606 getchar();
594 getchar(); 607 continue;
595 printf("\n\nDNS log - time server-address domain\n"); 608 }
596 print_dns(); 609 if (c == 's' || c == 'S') {
597 printf("press any key to continue..."); 610 printf("The file is saved in /tmp directory. Please enter the file name: ");
598 fflush(0); 611 fflush(0);
599 612
600 getchar(); 613 char buf[LINE_MAX + 5]; // eave some room to add /tmp/
601 printf("\n\nIP table: %d addresses - server-address network (packets)\n", radix_nodes); 614 strcpy(buf, "/tmp/");
602 radix_print(1); 615 terminal_restore();
603 printf("press any key to continue..."); 616 if (fgets(buf + 5, LINE_MAX, stdin) == NULL)
604 fflush(0); 617 errExit("fgets");
605 618 terminal_set();
606 getchar(); 619
620 // remove '\n' and open the file
621 char *ptr = strchr(buf, '\n');
622 if (!ptr) { // we should have a '\n'
623 printf("Error: invalid file name\n");
624 sleep(5);
625 continue;
626 }
627 *ptr = '\0';
628
629 FILE *fp = fopen(buf, "w");
630 if (!fp) {
631 printf("Error: cannot open file %s\n", buf);
632 perror("fopen");
633 sleep(5);
634 continue;
635 }
636
637 printf("Saving stats in %s file...\n", buf);
638 print_stats(fp);
639 fclose(fp);
640 int rv = chmod(buf, 0600);
641 (void) rv;
642 sleep(1);
643 continue;
644 }
645 else if (c == 'x' || c == 'X')
646 break;
607 continue; 647 continue;
608 } 648 }
609 else if (FD_ISSET(p1, &rfds)) { 649 else if (FD_ISSET(p1, &rfds)) {
610 char buf[1024]; 650 char buf[LINE_MAX];
611 ssize_t sz = read(p1, buf, 1024 - 1); 651 ssize_t sz = read(p1, buf, LINE_MAX - 1);
612 if (sz == -1) 652 if (sz == -1)
613 errExit("error reading snitrace"); 653 errExit("error reading snitrace");
614 if (sz == 0) { 654 if (sz == 0) {
@@ -618,19 +658,13 @@ static void run_trace(void) {
618 if (strncmp(buf, "SNI trace", 9) == 0) 658 if (strncmp(buf, "SNI trace", 9) == 0)
619 continue; 659 continue;
620 660
621 if (sz > LOG_RECORD_LEN)
622 sz = LOG_RECORD_LEN;
623 buf[sz] = '\0'; 661 buf[sz] = '\0';
624 strcpy(sni_table[sni_index].record, buf); 662 ev_add(buf);
625 if (++sni_index >= SNIMAX) {
626 sni_index = 0;
627 *sni_table[sni_index].record = '\0';
628 }
629 continue; 663 continue;
630 } 664 }
631 else if (FD_ISSET(p2, &rfds)) { 665 else if (FD_ISSET(p2, &rfds)) {
632 char buf[1024]; 666 char buf[LINE_MAX];
633 ssize_t sz = read(p2, buf, 1024 - 1); 667 ssize_t sz = read(p2, buf, LINE_MAX - 1);
634 if (sz == -1) 668 if (sz == -1)
635 errExit("error reading dnstrace"); 669 errExit("error reading dnstrace");
636 if (sz == 0) { 670 if (sz == 0) {
@@ -640,16 +674,11 @@ static void run_trace(void) {
640 if (strncmp(buf, "DNS trace", 9) == 0) 674 if (strncmp(buf, "DNS trace", 9) == 0)
641 continue; 675 continue;
642 676
643 if (sz > LOG_RECORD_LEN)
644 sz = LOG_RECORD_LEN;
645 buf[sz] = '\0'; 677 buf[sz] = '\0';
646 strcpy(dns_table[dns_index].record, buf); 678 ev_add(buf);
647 if (++dns_index >= DNSMAX) {
648 dns_index = 0;
649 *dns_table[dns_index].record = '\0';
650 }
651 continue; 679 continue;
652 } 680 }
681 // by default we assume TCP
653 else if (FD_ISSET(s2, &rfds)) 682 else if (FD_ISSET(s2, &rfds))
654 sock = s2; 683 sock = s2;
655 else if (FD_ISSET(s3, &rfds)) { 684 else if (FD_ISSET(s3, &rfds)) {
@@ -658,7 +687,7 @@ static void run_trace(void) {
658 } 687 }
659 688
660 unsigned bytes = recvfrom(sock, buf, MAX_BUF_SIZE, 0, NULL, NULL); 689 unsigned bytes = recvfrom(sock, buf, MAX_BUF_SIZE, 0, NULL, NULL);
661 if (bytes >= 20) { // size of IP header 690 if (bytes >= 20) { // minimum size of IP packet
662#ifdef DEBUG 691#ifdef DEBUG
663 { 692 {
664 uint32_t ip_src; 693 uint32_t ip_src;
@@ -682,12 +711,30 @@ static void run_trace(void) {
682 uint8_t hlen = (buf[0] & 0x0f) * 4; 711 uint8_t hlen = (buf[0] & 0x0f) * 4;
683 uint16_t port_src = 0; 712 uint16_t port_src = 0;
684 if (icmp) 713 if (icmp)
685 hnode_add(ip_src, 0, 0, bytes + 14); 714 hnode_add(ip_src, PROTOCOL_ICMP, 0, bytes + 14);
686 else { 715 else { // itcp or udp
687 memcpy(&port_src, buf + hlen, 2); 716 memcpy(&port_src, buf + hlen, 2);
688 port_src = ntohs(port_src); 717 port_src = ntohs(port_src);
689 718 int protocol = (int) buf[9];
690 uint8_t protocol = buf[9]; 719
720 // detect ssh on a standard or not so standard port (22)
721 if (protocol == 6) { // tcp
722 uint8_t dataoffset = *(buf + hlen + 12);
723 uint8_t tcphlen = (dataoffset >> 2);
724 if (memcmp(buf + hlen + tcphlen, "SSH-", 4) == 0) {
725 time_t seconds = time(NULL);
726 struct tm *t = localtime(&seconds);
727 char ip[30];
728 sprintf(ip, "%d.%d.%d.%d", PRINT_IP(ip_src));
729 char *msg;
730 if (asprintf(&msg, "%02d:%02d:%02d %-15s SSH connection",
731 t->tm_hour, t->tm_min, t->tm_sec, ip) == -1)
732 errExit("asprintf");
733 ev_add(msg);
734 free(msg);
735 protocol = PROTOCOL_SSH;
736 }
737 }
691 hnode_add(ip_src, protocol, port_src, bytes + 14); 738 hnode_add(ip_src, protocol, port_src, bytes + 14);
692 } 739 }
693 740
@@ -705,7 +752,10 @@ static void run_trace(void) {
705 close(s1); 752 close(s1);
706 close(s2); 753 close(s2);
707 close(s3); 754 close(s3);
708 print_stats(); 755 if (p1 != -1)
756 close(p1);
757 if (p2 != -1)
758 close(p2);
709} 759}
710 760
711 761
@@ -765,7 +815,7 @@ int main(int argc, char **argv) {
765 else if (strcmp(argv[i], "--print-map") == 0) { 815 else if (strcmp(argv[i], "--print-map") == 0) {
766 char *fname = "static-ip-map.txt"; 816 char *fname = "static-ip-map.txt";
767 load_hostnames(fname); 817 load_hostnames(fname);
768 radix_print(0); 818 radix_print(stdout, 0);
769 return 0; 819 return 0;
770 } 820 }
771 else if (strncmp(argv[i], "--squash-map=", 13) == 0) { 821 else if (strncmp(argv[i], "--squash-map=", 13) == 0) {
@@ -787,7 +837,7 @@ int main(int argc, char **argv) {
787 printf("# License GPLv2\n"); 837 printf("# License GPLv2\n");
788 printf("#\n"); 838 printf("#\n");
789 839
790 radix_print(0); 840 radix_print(stdout, 0);
791 printf("\n#\n#\n# input %d, output %d\n#\n#\n", in, radix_nodes); 841 printf("\n#\n#\n# input %d, output %d\n#\n#\n", in, radix_nodes);
792 fprintf(stderr, "static ip map: input %d, output %d\n", in, radix_nodes); 842 fprintf(stderr, "static ip map: input %d, output %d\n", in, radix_nodes);
793 return 0; 843 return 0;