feature: stats support for --nettrace

This commit is contained in:
netblue30 2023-07-16 11:32:00 -04:00
parent cb39a0eafd
commit f3e428e6fa
8 changed files with 142 additions and 17 deletions

View file

@ -7,6 +7,7 @@ firejail (0.9.73) baseline; urgency=low
* feature: add IPv6 support for --net.print option
* feature: QUIC (HTTP/3) support in --nettrace
* feature: use seccomp filters build at install time for --restrict-namespaces
* feature: stats support for --nettrace
* modif: Stop forwarding own double-dash to the shell (#5599 #5600)
* modif: Prevent sandbox name (--name=) and host name (--hostname=)
from containing only digits (#5578 #5741)

View file

@ -108,7 +108,7 @@ void netfilter_trace(pid_t pid, const char *cmd) {
arg[3] = NULL;
clearenv();
sbox_exec_v(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, arg);
sbox_exec_v(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP | SBOX_ALLOW_STDIN, arg);
// it will never get here!!
}

View file

@ -70,4 +70,9 @@ char* retrieve_hostname(uint32_t ip);
// tail.c
void tail(const char *logfile);
// terminal.c
void terminal_handler(int s);
void terminal_set(void);
void terminal_restore(void);
#endif

View file

@ -29,6 +29,11 @@ static int arg_netfilter = 0;
static int arg_tail = 0;
static char *arg_log = NULL;
uint32_t stats_pkts = 0;
uint32_t stats_icmp = 0;
uint32_t stats_dns = 0;
typedef struct hnode_t {
struct hnode_t *hnext; // used for hash table and unused linked list
struct hnode_t *dnext; // used to display streams on the screen
@ -331,7 +336,7 @@ static void hnode_print(unsigned bw) {
else
sprintf(stats, "%u KB/s ", bw / (1024 * DISPLAY_INTERVAL));
// int len = snprintf(line, LINE_MAX, "%32s geoip %d, IP database %d\n", stats, geoip_calls, radix_nodes);
int len = snprintf(line, LINE_MAX, "%32s address:port (protocol) host (packets)\n", stats);
int len = snprintf(line, LINE_MAX, "%32s address:port (protocol) network (packets)\n", stats);
adjust_line(line, len, cols);
printf("%s", line);
@ -418,6 +423,7 @@ static void hnode_print(unsigned bw) {
ptr = next;
}
printf("press any key to access stats\n");
#ifdef DEBUG
{
@ -432,6 +438,14 @@ static void hnode_print(unsigned bw) {
#endif
}
void print_stats(void) {
printf("\nIP table: %d entries, %d unknown\n", radix_nodes, geoip_calls);
printf(" address network (packets)\n");
radix_print(1);
printf("Packets: %u total, ICMP %u, DNS %u\n", stats_pkts, stats_icmp, stats_dns);
}
// trace rx traffic coming in
static void run_trace(void) {
if (arg_netfilter)
@ -449,6 +463,7 @@ static void run_trace(void) {
unsigned last_print_remaining = 0;
unsigned char buf[MAX_BUF_SIZE];
unsigned bw = 0; // bandwidth calculations
while (1) {
unsigned end = time(NULL);
if (arg_netfilter && end - start >= NETLOCK_INTERVAL)
@ -470,6 +485,8 @@ static void run_trace(void) {
FD_SET(s1, &rfds);
FD_SET(s2, &rfds);
FD_SET(s3, &rfds);
if (!arg_netfilter)
FD_SET(0, &rfds);
int maxfd = (s1 > s2) ? s1 : s2;
maxfd = (s3 > maxfd) ? s3 : maxfd;
maxfd++;
@ -484,9 +501,20 @@ static void run_trace(void) {
else if (rv == 0)
continue;
int icmp = 0;
// rx tcp traffic by default
int sock = s1;
if (FD_ISSET(s2, &rfds))
int icmp = 0;
if (FD_ISSET(0, &rfds)) {
getchar();
print_stats();
printf("press any key to continue...");
fflush(0);
getchar();
continue;
}
else if (FD_ISSET(s2, &rfds))
sock = s2;
else if (FD_ISSET(s3, &rfds)) {
sock = s3;
@ -516,22 +544,32 @@ static void run_trace(void) {
ip_src = ntohl(ip_src);
uint8_t hlen = (buf[0] & 0x0f) * 4;
uint16_t port_src = 0;
if (icmp)
hnode_add(ip_src, 0, 0, bytes + 14);
else {
uint16_t port_src;
memcpy(&port_src, buf + hlen, 2);
port_src = ntohs(port_src);
uint8_t protocol = buf[9];
hnode_add(ip_src, protocol, port_src, bytes + 14);
}
// stats
stats_pkts++;
if (icmp)
stats_icmp++;
if (port_src == 53)
stats_dns++;
}
}
}
close(s1);
close(s2);
close(s3);
print_stats();
}
static char *filter_start =
@ -733,7 +771,7 @@ int main(int argc, char **argv) {
else if (strcmp(argv[i], "--print-map") == 0) {
char *fname = "static-ip-map.txt";
load_hostnames(fname);
radix_print();
radix_print(0);
return 0;
}
else if (strncmp(argv[i], "--squash-map=", 13) == 0) {
@ -755,7 +793,7 @@ int main(int argc, char **argv) {
printf("# License GPLv2\n");
printf("#\n");
radix_print();
radix_print(0);
printf("\n#\n#\n# input %d, output %d\n#\n#\n", in, radix_nodes);
fprintf(stderr, "static ip map: input %d, output %d\n", in, radix_nodes);
return 0;
@ -790,6 +828,12 @@ int main(int argc, char **argv) {
return 1;
}
terminal_set();
// handle CTRL-C
signal (SIGINT, terminal_handler);
signal (SIGTERM, terminal_handler);
atexit(terminal_restore);
// kill the process if the parent died
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);

View file

@ -151,12 +151,22 @@ RNode *radix_longest_prefix_match(uint32_t ip) {
}
static uint32_t sum;
static void print(RNode *ptr, int level) {
static void print(RNode *ptr, int level, int pkts) {
if (!ptr)
return;
if (ptr->name) {
printf("%d.%d.%d.%d/%d ", PRINT_IP(sum << (32 - level)), level);
printf("%s\n", ptr->name);
if (pkts) {
if (ptr->pkts) {
printf(" %d.%d.%d.%d/%d ", PRINT_IP(sum << (32 - level)), level);
printf("%s", ptr->name);
printf(" (%u)\n", ptr->pkts);
}
}
else {
printf("%d.%d.%d.%d/%d ", PRINT_IP(sum << (32 - level)), level);
printf("%s", ptr->name);
printf("\n");
}
}
if (ptr->zero == NULL && ptr->one == NULL)
@ -164,22 +174,21 @@ static void print(RNode *ptr, int level) {
level++;
sum <<= 1;
print(ptr->zero, level);
print(ptr->zero, level, pkts);
sum++;
print(ptr->one, level);
print(ptr->one, level, pkts);
sum--;
sum >>= 1;
}
void radix_print(void) {
void radix_print(int pkts) {
if (!head)
return;
printf("\n");
sum = 0;
print(head->zero, 1);
print(head->zero, 1, pkts);
assert(sum == 0);
sum = 1;
print(head->one, 1);
print(head->one, 1, pkts);
assert(sum == 1);
}

View file

@ -30,7 +30,7 @@ typedef struct rnode_t {
extern int radix_nodes;
RNode *radix_longest_prefix_match(uint32_t ip);
RNode*radix_add(uint32_t ip, uint32_t mask, char *name);
void radix_print(void);
void radix_print(int pkts);
void radix_squash(void);
#endif

View file

@ -202,6 +202,7 @@
199.9.248.0/21 Twitch
199.16.156.0/22 Twitter
199.59.148.0/22 Twitter
199.168.96.24/29 BitChute
205.185.194.0/24 Steam
205.196.6.0/24 Steam
207.45.72.0/22 Netflix
@ -212,6 +213,19 @@
208.80.152.0/22 Wikipedia
209.140.128.0/18 eBay
# Imperva
199.83.128.0/21 Imperva
198.143.32.0/19 Imperva
149.126.72.0/21 Imperva
103.28.248.0/22 Imperva
45.64.64.0/22 Imperva
185.11.124.0/22 Imperva
192.230.64.0/18 Imperva
107.154.0.0/16 Imperva
45.60.0.0/16 Imperva
45.223.0.0/16 Imperva
131.125.128.0/17 Imperva
# Level 3
66.114.192.0/18 Level 3
66.147.128.0/18 Level 3

52
src/fnettrace/terminal.c Normal file
View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2014-2023 Firejail Authors
*
* This file is part of firejail project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "fnettrace.h"
#include <termios.h>
static struct termios tlocal; // startup terminal setting
static struct termios twait; // no wait on key press
static int tset = 0;
void terminal_restore(void) {
if (tset)
tcsetattr(0, TCSANOW, &tlocal);
}
void terminal_handler(int s) {
// Remove unused parameter warning
(void)s;
terminal_restore();
_exit(0);
}
void terminal_set(void) {
if (tset == 0) {
tcgetattr(0, &twait); // get current terminal attributes; 0 is the file descriptor for stdin
memcpy(&tlocal, &twait, sizeof(tlocal));
twait.c_lflag &= ~ICANON; // disable canonical mode
twait.c_lflag &= ~ECHO; // no echo
twait.c_cc[VMIN] = 1; // wait until at least one keystroke available
twait.c_cc[VTIME] = 0; // no timeout
tset = 1;
}
tcsetattr(0, TCSANOW, &twait);
}