mirror of
https://github.com/netblue30/firejail.git
synced 2026-05-15 14:16:14 -06:00
more on nettrace
This commit is contained in:
parent
c18d68f36d
commit
500a56efd3
10 changed files with 4595 additions and 63 deletions
|
|
@ -138,6 +138,7 @@ endif
|
|||
# profiles and settings
|
||||
install -m 0755 -d $(DESTDIR)$(sysconfdir)/firejail
|
||||
install -m 0644 -t $(DESTDIR)$(sysconfdir)/firejail src/firecfg/firecfg.config
|
||||
install -m 0644 -t $(DESTDIR)$(sysconfdir)/firejail src/fnettrace/hostnames
|
||||
install -m 0644 -t $(DESTDIR)$(sysconfdir)/firejail etc/profile-a-l/*.profile etc/profile-m-z/*.profile etc/inc/*.inc etc/net/*.net etc/firejail.config etc/ids.config
|
||||
sh -c "if [ ! -f $(DESTDIR)/$(sysconfdir)/firejail/login.users ]; then install -c -m 0644 etc/login.users $(DESTDIR)/$(sysconfdir)/firejail/.; fi;"
|
||||
ifeq ($(BUSYBOX_WORKAROUND),yes)
|
||||
|
|
|
|||
18
README.md
18
README.md
|
|
@ -298,19 +298,23 @@ INTRUSION DETECTION SYSTEM (IDS)
|
|||
|
||||
### Network Monitor
|
||||
`````
|
||||
--nettrace=name|pid
|
||||
--nettrace=name|pid
|
||||
Monitor TCP and UDP traffic coming into the sandbox specified by
|
||||
name or pid. Only networked sandboxes created with --net are
|
||||
supported.
|
||||
|
||||
$ firejail --nettrace=browser
|
||||
9.9.9.9:53 => 192.168.1.60 UDP: 122 B/sec
|
||||
72.21.91.29:80 => 192.168.1.60 TCP: 257 B/sec
|
||||
80.92.126.65:123 => 192.168.1.60 UDP: 25 B/sec
|
||||
69.30.241.50:443 => 192.168.1.60 TCP: 88 KB/sec
|
||||
140.82.112.4:443 => 192.168.1.60 TCP: 1861 B/sec
|
||||
86 KB/s ********* 64.222.84.207:443 United States
|
||||
76 KB/s ******** 192.229.210.163:443 MCI
|
||||
111 B/s 9.9.9.9:53 Quad9 DNS
|
||||
32 KB/s *** 142.250.179.182:443 Google
|
||||
|
||||
(14 streams in the last one minute)
|
||||
If /usr/bin/geoiplookup is installed (geoip-bin packet in De‐
|
||||
bian), the country the IP address originates from is added to
|
||||
the trace. We also use the static IP map in /etc/firejail/host‐
|
||||
names to print the domain names for some of the more common web‐
|
||||
sites and cloud platforms. No external services are contacted
|
||||
for reverse IP lookup.
|
||||
|
||||
`````
|
||||
|
||||
|
|
|
|||
|
|
@ -27,12 +27,14 @@
|
|||
#include <netinet/in.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
//#define DEBUG 1
|
||||
|
||||
//#define NETLOCK_INTERVAL 15
|
||||
#define NETLOCK_INTERVAL 60
|
||||
#define DISPLAY_INTERVAL 3
|
||||
#define DISPLAY_INTERVAL 2
|
||||
#define DISPLAY_TTL 4
|
||||
#define DISPLAY_BW_UNITS 20
|
||||
|
||||
void logprintf(char* fmt, ...);
|
||||
|
||||
static inline void ansi_topleft(void) {
|
||||
char str[] = {0x1b, '[', '1', ';', '1', 'H', '\0'};
|
||||
|
|
@ -53,6 +55,12 @@ static inline uint8_t hash(uint32_t ip) {
|
|||
return *ptr ^ *(ptr + 1) ^ *(ptr + 2) ^ *(ptr + 3);
|
||||
}
|
||||
|
||||
// main.c
|
||||
void logprintf(char* fmt, ...);
|
||||
|
||||
// hostnames.c
|
||||
void load_hostnames(const char *fname);
|
||||
char* retrieve_hostname(uint32_t ip);
|
||||
void build_list(const char *fname);
|
||||
|
||||
#endif
|
||||
4029
src/fnettrace/hostnames
Normal file
4029
src/fnettrace/hostnames
Normal file
File diff suppressed because it is too large
Load diff
120
src/fnettrace/hostnames.c
Normal file
120
src/fnettrace/hostnames.c
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2021 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 "radix.h"
|
||||
#define MAXBUF 1024
|
||||
|
||||
|
||||
char *retrieve_hostname(uint32_t ip) {
|
||||
char *rv = NULL;
|
||||
char *cmd;
|
||||
if (asprintf(&cmd, "/usr/bin/geoiplookup %d.%d.%d.%d", PRINT_IP(ip)) == -1)
|
||||
errExit("asprintf");
|
||||
|
||||
FILE *fp = popen(cmd, "r");
|
||||
if (fp) {
|
||||
char *ptr;
|
||||
char buf[MAXBUF];
|
||||
if (fgets(buf, MAXBUF, fp)) {
|
||||
ptr = strchr(buf, '\n');
|
||||
if (ptr)
|
||||
*ptr = '\0';
|
||||
if (strncmp(buf, "GeoIP Country Edition:", 22) == 0) {
|
||||
ptr = buf + 22;
|
||||
if (*ptr == ' ' && *(ptr + 3) == ',' && *(ptr + 4) == ' ') {
|
||||
rv = ptr + 5;
|
||||
radix_add(ip, 0xffffffff, ptr + 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void load_hostnames(const char *fname) {
|
||||
assert(fname);
|
||||
FILE *fp = fopen(fname, "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Warning: cannot find %s file\n", fname);
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[MAXBUF];
|
||||
int line = 0;
|
||||
while (fgets(buf, MAXBUF, fp)) {
|
||||
line++;
|
||||
|
||||
// skip empty spaces
|
||||
char *start = buf;
|
||||
while (*start == ' ' || *start == '\t')
|
||||
start++;
|
||||
// comments
|
||||
if (*start == '#')
|
||||
continue;
|
||||
char *end = strchr(start, '#');
|
||||
if (end)
|
||||
*end = '\0';
|
||||
|
||||
// end
|
||||
end = strchr(start, '\n');
|
||||
if (end)
|
||||
*end = '\0';
|
||||
end = start + strlen(start);
|
||||
if (end == start) // empty line
|
||||
continue;
|
||||
|
||||
// line format: 1.2.3.4/32 name_without_empty_spaces
|
||||
// a single empty space between address and name
|
||||
end = strchr(start, ' ');
|
||||
if (!end)
|
||||
goto errexit;
|
||||
*end = '\0';
|
||||
end++;
|
||||
if (*end == '\0')
|
||||
goto errexit;
|
||||
|
||||
uint32_t ip;
|
||||
uint32_t mask;
|
||||
if (atocidr(start, &ip, &mask)) {
|
||||
fprintf(stderr, "Error: invalid CIDR address\n");
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
radix_add(ip, mask, end);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return;
|
||||
|
||||
|
||||
errexit:
|
||||
fprintf(stderr, "Error: invalid line %d in file %s\n", line, fname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void build_list(const char *fname) {
|
||||
assert(fname);
|
||||
load_hostnames(fname);
|
||||
radix_build_list();
|
||||
}
|
||||
|
||||
|
|
@ -18,37 +18,42 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#include "fnettrace.h"
|
||||
//#define DEBUG 1
|
||||
#include "radix.h"
|
||||
#include <sys/ioctl.h>
|
||||
#define MAX_BUF_SIZE (64 * 1024)
|
||||
|
||||
static int arg_netfilter = 0;
|
||||
static char *arg_log = NULL;
|
||||
|
||||
typedef struct hlist_t {
|
||||
struct hlist_t *hnext; // used for hash table
|
||||
struct hlist_t *dnext; // used to display stremas on the screen
|
||||
typedef struct hnode_t {
|
||||
struct hnode_t *hnext; // used for hash table
|
||||
struct hnode_t *dnext; // used to display stremas on the screen
|
||||
uint32_t ip_src;
|
||||
uint32_t ip_dst;
|
||||
uint64_t bytes; // number of bytes received in the last display interval
|
||||
uint32_t bytes; // number of bytes received in the last display interval
|
||||
uint16_t port_src;
|
||||
uint16_t ip_instance;
|
||||
// the firewall is build based on source address, and in the linked list
|
||||
// we have elements with the same address but different ports
|
||||
uint8_t protocol;
|
||||
} HList;
|
||||
// the firewall is build based on source address, and in the linked list
|
||||
// we have elements with the same address but different ports
|
||||
uint8_t ip_instance;
|
||||
char *hostname;
|
||||
int ttl;
|
||||
} HNode;
|
||||
|
||||
// hash table
|
||||
#define HMAX 256
|
||||
HList *htable[HMAX] = {NULL};
|
||||
HNode *htable[HMAX] = {NULL};
|
||||
// display linked list
|
||||
HList *dlist = NULL;
|
||||
HNode *dlist = NULL;
|
||||
|
||||
static void hlist_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16_t port_src, uint64_t bytes) {
|
||||
static unsigned bwmax = 0; // max bytes received in a display interval
|
||||
|
||||
static void hnode_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16_t port_src, uint32_t bytes) {
|
||||
uint8_t h = hash(ip_src);
|
||||
|
||||
// find
|
||||
int ip_instance = 0;
|
||||
HList *ptr = htable[h];
|
||||
HNode *ptr = htable[h];
|
||||
while (ptr) {
|
||||
if (ptr->ip_src == ip_src) {
|
||||
ip_instance++;
|
||||
|
|
@ -63,9 +68,10 @@ static void hlist_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16
|
|||
#ifdef DEBUG
|
||||
printf("malloc %d.%d.%d.%d\n", PRINT_IP(ip_src));
|
||||
#endif
|
||||
HList *hnew = malloc(sizeof(HList));
|
||||
HNode *hnew = malloc(sizeof(HNode));
|
||||
if (!hnew)
|
||||
errExit("malloc");
|
||||
hnew->hostname = NULL;
|
||||
hnew->ip_src = ip_src;
|
||||
hnew->ip_dst = ip_dst;
|
||||
hnew->port_src = port_src;
|
||||
|
|
@ -73,6 +79,7 @@ static void hlist_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16
|
|||
hnew->hnext = NULL;
|
||||
hnew->bytes = bytes;
|
||||
hnew->ip_instance = ip_instance + 1;
|
||||
hnew->ttl = DISPLAY_TTL;
|
||||
if (htable[h] == NULL)
|
||||
htable[h] = hnew;
|
||||
else {
|
||||
|
|
@ -95,17 +102,17 @@ static void hlist_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16
|
|||
logprintf(" %d.%d.%d.%d ", PRINT_IP(hnew->ip_src));
|
||||
}
|
||||
|
||||
static void hlist_free(HList *elem) {
|
||||
static void hnode_free(HNode *elem) {
|
||||
assert(elem);
|
||||
#ifdef DEBUG
|
||||
printf("free %d.%d.%d.%d\n", PRINT_IP(elem->ip_src));
|
||||
#endif
|
||||
|
||||
uint8_t h = hash(elem->ip_src);
|
||||
HList *ptr = htable[h];
|
||||
HNode *ptr = htable[h];
|
||||
assert(ptr);
|
||||
|
||||
HList *prev = NULL;
|
||||
HNode *prev = NULL;
|
||||
while (ptr != elem) {
|
||||
prev = ptr;
|
||||
ptr = ptr->hnext;
|
||||
|
|
@ -119,25 +126,45 @@ static void hlist_free(HList *elem) {
|
|||
|
||||
#ifdef DEBUG
|
||||
static void debug_dlist(void) {
|
||||
HList *ptr = dlist;
|
||||
HNode *ptr = dlist;
|
||||
while (ptr) {
|
||||
printf("dlist %d.%d.%d.%d:%d\n", PRINT_IP(ptr->ip_src), ptr->port_src);
|
||||
ptr = ptr->dnext;
|
||||
}
|
||||
}
|
||||
static void debug_hlist(void) {
|
||||
static void debug_hnode(void) {
|
||||
int i;
|
||||
for (i = 0; i < HMAX; i++) {
|
||||
HList *ptr = htable[i];
|
||||
HNode *ptr = htable[i];
|
||||
while (ptr) {
|
||||
printf("hlist (%d) %d.%d.%d.%d:%d\n", i, PRINT_IP(ptr->ip_src), ptr->port_src);
|
||||
printf("hnode (%d) %d.%d.%d.%d:%d\n", i, PRINT_IP(ptr->ip_src), ptr->port_src);
|
||||
ptr = ptr->hnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void hlist_print(void) {
|
||||
static char *bw_line[DISPLAY_BW_UNITS + 1] = { NULL };
|
||||
|
||||
static char *print_bw(unsigned units) {
|
||||
if (units > DISPLAY_BW_UNITS)
|
||||
units = DISPLAY_BW_UNITS ;
|
||||
|
||||
if (bw_line[units] == NULL) {
|
||||
char *ptr = malloc(DISPLAY_BW_UNITS + 1);
|
||||
if (!ptr)
|
||||
errExit("malloc");
|
||||
bw_line[units] = ptr;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < DISPLAY_BW_UNITS; i++, ptr++)
|
||||
sprintf(ptr, "%s", (i < units)? "*": " ");
|
||||
}
|
||||
|
||||
return bw_line[units];
|
||||
}
|
||||
|
||||
static void hnode_print(void) {
|
||||
assert(!arg_netfilter);
|
||||
ansi_clrscr();
|
||||
|
||||
|
|
@ -145,30 +172,66 @@ static void hlist_print(void) {
|
|||
printf("*********************\n");
|
||||
debug_dlist();
|
||||
printf("-----------------------------\n");
|
||||
debug_hlist();
|
||||
debug_hnode();
|
||||
printf("*********************\n");
|
||||
#endif
|
||||
|
||||
HList *ptr = dlist;
|
||||
HList *prev = NULL;
|
||||
while (ptr) {
|
||||
HList *next = ptr->dnext;
|
||||
if (ptr->bytes) {
|
||||
char ip_src[30];
|
||||
sprintf(ip_src, "%d.%d.%d.%d:%u", PRINT_IP(ptr->ip_src), ptr->port_src);
|
||||
char ip_dst[30];
|
||||
sprintf(ip_dst, "%d.%d.%d.%d", PRINT_IP(ptr->ip_dst));
|
||||
printf("%-22s => %-15s %s:",
|
||||
ip_src,
|
||||
ip_dst,
|
||||
(ptr->protocol == 6)? "TCP": "UDP");
|
||||
// get terminal size
|
||||
struct winsize sz;
|
||||
int col = 80;
|
||||
if (isatty(STDIN_FILENO)) {
|
||||
if (!ioctl(0, TIOCGWINSZ, &sz))
|
||||
col = sz.ws_col;
|
||||
}
|
||||
#define LINE_MAX 200
|
||||
char line[LINE_MAX + 1];
|
||||
if (col > LINE_MAX)
|
||||
col = LINE_MAX;
|
||||
|
||||
if (ptr->bytes > (DISPLAY_INTERVAL * 1024 * 2)) // > 2 KB/second
|
||||
printf(" %lu KB/sec\n",
|
||||
ptr->bytes / (DISPLAY_INTERVAL * 1024));
|
||||
HNode *ptr = dlist;
|
||||
HNode *prev = NULL;
|
||||
while (ptr) {
|
||||
HNode *next = ptr->dnext;
|
||||
if (--ptr->ttl > 0) {
|
||||
char bytes[11];
|
||||
if (ptr->bytes > (DISPLAY_INTERVAL * 1024 * 1024 * 2)) // > 2 MB/second
|
||||
sprintf(bytes, "%u MB/s",
|
||||
(unsigned) (ptr->bytes / (DISPLAY_INTERVAL * 1024* 1024)));
|
||||
else if (ptr->bytes > (DISPLAY_INTERVAL * 1024 * 2)) // > 2 KB/second
|
||||
sprintf(bytes, "%u KB/s",
|
||||
(unsigned) (ptr->bytes / (DISPLAY_INTERVAL * 1024)));
|
||||
else
|
||||
printf(" %lu B/sec\n",
|
||||
ptr->bytes / DISPLAY_INTERVAL);
|
||||
sprintf(bytes, "%u B/s", (unsigned) (ptr->bytes / DISPLAY_INTERVAL));
|
||||
|
||||
char *hostname = ptr->hostname;
|
||||
if (!hostname)
|
||||
hostname = radix_find_last(ptr->ip_src);
|
||||
|
||||
if (!hostname)
|
||||
hostname = retrieve_hostname(ptr->ip_src);
|
||||
|
||||
if (!hostname)
|
||||
hostname = " ";
|
||||
else {
|
||||
ptr->hostname = strdup(hostname);
|
||||
if (!ptr->hostname)
|
||||
errExit("strdup");
|
||||
}
|
||||
|
||||
unsigned bwunit = bwmax / DISPLAY_BW_UNITS;
|
||||
unsigned units = ptr->bytes / bwunit;
|
||||
char *bwline = print_bw(units);
|
||||
|
||||
sprintf(line, "%10s %s %d.%d.%d.%d:%u %s\n", bytes, bwline, PRINT_IP(ptr->ip_src), ptr->port_src, hostname);
|
||||
int len = strlen(line);
|
||||
if (col > 4 && len > col) {
|
||||
line[col] = '\0';
|
||||
line[col - 1] = '\n';
|
||||
}
|
||||
printf("%s", line);
|
||||
|
||||
if (ptr->bytes)
|
||||
ptr->ttl = DISPLAY_TTL;
|
||||
ptr->bytes = 0;
|
||||
prev = ptr;
|
||||
}
|
||||
|
|
@ -178,7 +241,7 @@ static void hlist_print(void) {
|
|||
dlist = next;
|
||||
else
|
||||
prev->dnext = next;
|
||||
hlist_free(ptr);
|
||||
hnode_free(ptr);
|
||||
}
|
||||
|
||||
ptr = next;
|
||||
|
|
@ -199,14 +262,18 @@ static void run_trace(void) {
|
|||
unsigned last_print_traces = 0;
|
||||
unsigned last_print_remaining = 0;
|
||||
unsigned char buf[MAX_BUF_SIZE];
|
||||
unsigned bwcurrent = 0;
|
||||
while (1) {
|
||||
unsigned end = time(NULL);
|
||||
if (arg_netfilter && end - start >= NETLOCK_INTERVAL)
|
||||
break;
|
||||
if (end % DISPLAY_INTERVAL == 1 && last_print_traces != end) { // first print after 1 second
|
||||
if (bwcurrent > bwmax)
|
||||
bwmax = bwcurrent;
|
||||
if (!arg_netfilter)
|
||||
hlist_print();
|
||||
hnode_print();
|
||||
last_print_traces = end;
|
||||
bwcurrent = 0;
|
||||
}
|
||||
if (arg_netfilter && last_print_remaining != end) {
|
||||
logprintf(".");
|
||||
|
|
@ -233,6 +300,7 @@ static void run_trace(void) {
|
|||
|
||||
unsigned bytes = recvfrom(sock, buf, MAX_BUF_SIZE, 0, NULL, NULL);
|
||||
if (bytes >= 20) { // size of IP header
|
||||
bwcurrent += bytes + 14; // assume a 14 byte Ethernet layer
|
||||
// filter out loopback traffic
|
||||
if (buf[12] != 127) {
|
||||
uint32_t ip_src;
|
||||
|
|
@ -248,7 +316,7 @@ static void run_trace(void) {
|
|||
memcpy(&port_src, buf + hlen, 2);
|
||||
port_src = ntohs(port_src);
|
||||
|
||||
hlist_add(ip_src, ip_dst, buf[9], port_src, (uint64_t) bytes);
|
||||
hnode_add(ip_src, ip_dst, buf[9], port_src, bytes + 14);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -274,7 +342,7 @@ static int print_filter(FILE *fp) {
|
|||
|
||||
int i;
|
||||
for (i = 0; i < HMAX; i++) {
|
||||
HList *ptr = htable[i];
|
||||
HNode *ptr = htable[i];
|
||||
while (ptr) {
|
||||
// filter rules are targeting ip address, the port number is disregarded,
|
||||
// so we look only at the first instance of an address
|
||||
|
|
@ -416,6 +484,7 @@ void logprintf(char* fmt, ...) {
|
|||
static void usage(void) {
|
||||
printf("Usage: fnetlock [OPTIONS]\n");
|
||||
printf("Options:\n");
|
||||
printf(" --build=filename - compact list of addresses\n");
|
||||
printf(" --help, -? - this help screen\n");
|
||||
printf(" --netfilter - build the firewall rules and commit them.\n");
|
||||
printf(" --log=filename - logfile\n");
|
||||
|
|
@ -424,7 +493,26 @@ static void usage(void) {
|
|||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
printf("\n\n");
|
||||
|
||||
#ifdef DEBUG
|
||||
// radix test
|
||||
radix_add(0x09000000, 0xff000000, "IBM");
|
||||
radix_add(0x09090909, 0xffffffff, "Quad9 DNS");
|
||||
radix_add(0x09000000, 0xff000000, "IBM");
|
||||
radix_print();
|
||||
printf("This test should print \"IBM, Quad9 DNS, IBM\"\n");
|
||||
char *name = radix_find_first(0x09090909);
|
||||
printf("%s, ", name);
|
||||
name = radix_find_last(0x09090909);
|
||||
printf("%s, ", name);
|
||||
name = radix_find_last(0x09322209);
|
||||
printf("%s\n", name);
|
||||
#endif
|
||||
|
||||
if (argc == 2 && strncmp(argv[1], "--build=", 8) == 0) {
|
||||
build_list(argv[1] + 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (getuid() != 0) {
|
||||
fprintf(stderr, "Error: you need to be root to run this program\n");
|
||||
|
|
@ -449,6 +537,13 @@ int main(int argc, char **argv) {
|
|||
ansi_clrscr();
|
||||
if (arg_netfilter)
|
||||
logprintf("starting network lockdown\n");
|
||||
else {
|
||||
char *fname;
|
||||
if (asprintf(&fname, "%s/hostnames", SYSCONFDIR) == -1)
|
||||
errExit("asprintf");
|
||||
load_hostnames(fname);
|
||||
free(fname);
|
||||
}
|
||||
|
||||
run_trace();
|
||||
if (arg_netfilter) {
|
||||
|
|
|
|||
218
src/fnettrace/radix.c
Normal file
218
src/fnettrace/radix.c
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2021 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include "radix.h"
|
||||
#include "fnettrace.h"
|
||||
|
||||
RNode *head = 0;
|
||||
|
||||
static inline RNode *addOne(RNode *ptr, uint32_t ip, uint32_t mask, char *name) {
|
||||
assert(ptr);
|
||||
if (ptr->one)
|
||||
return ptr->one;
|
||||
RNode *node = malloc(sizeof(RNode));
|
||||
if (!node)
|
||||
errExit("malloc");
|
||||
memset(node, 0, sizeof(RNode));
|
||||
node->ip = ip;
|
||||
node->mask = mask;
|
||||
if (name) {
|
||||
node->name = strdup(name);
|
||||
if (!node->name)
|
||||
errExit("strdup");
|
||||
}
|
||||
|
||||
ptr->one = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
static inline RNode *addZero(RNode *ptr, uint32_t ip, uint32_t mask, char *name) {
|
||||
assert(ptr);
|
||||
if (ptr->zero)
|
||||
return ptr->zero;
|
||||
RNode *node = malloc(sizeof(RNode));
|
||||
if (!node)
|
||||
errExit("malloc");
|
||||
memset(node, 0, sizeof(RNode));
|
||||
node->ip = ip;
|
||||
node->mask = mask;
|
||||
if (name) {
|
||||
node->name = strdup(name);
|
||||
if (!node->name)
|
||||
errExit("strdup");
|
||||
}
|
||||
|
||||
ptr->zero = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
// add to radix tree
|
||||
void radix_add(uint32_t ip, uint32_t mask, char *name) {
|
||||
assert(name);
|
||||
char *tmp = strdup(name);
|
||||
if (!tmp)
|
||||
errExit("strdup");
|
||||
name = tmp;
|
||||
|
||||
uint32_t m = 0x80000000;
|
||||
uint32_t lastm = 0;
|
||||
if (head == 0) {
|
||||
head = malloc(sizeof(RNode));
|
||||
memset(head, 0, sizeof(RNode));
|
||||
}
|
||||
RNode *ptr = head;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 32; i++, m >>= 1) {
|
||||
if (!(m & mask))
|
||||
break;
|
||||
|
||||
lastm |= m;
|
||||
int valid = (lastm == mask)? 1: 0;
|
||||
if (m & ip)
|
||||
ptr = addOne(ptr, ip & lastm, mask & lastm, (valid)? name: NULL);
|
||||
else
|
||||
ptr = addZero(ptr, ip & lastm, mask & lastm, (valid)? name: NULL);
|
||||
}
|
||||
assert(ptr);
|
||||
if (!ptr->name) {
|
||||
ptr->name = strdup(name);
|
||||
if (!ptr->name)
|
||||
errExit("strdup");
|
||||
}
|
||||
}
|
||||
|
||||
// find first match
|
||||
char *radix_find_first(uint32_t ip) {
|
||||
if (!head)
|
||||
return NULL;
|
||||
|
||||
uint32_t m = 0x80000000;
|
||||
RNode *ptr = head;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 32; i++, m >>= 1) {
|
||||
if (m & ip)
|
||||
ptr = ptr->one;
|
||||
else
|
||||
ptr = ptr->zero;
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
if (ptr->name)
|
||||
return ptr->name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find last match
|
||||
char *radix_find_last(uint32_t ip) {
|
||||
if (!head)
|
||||
return NULL;
|
||||
|
||||
uint32_t m = 0x80000000;
|
||||
RNode *ptr = head;
|
||||
RNode *rv = NULL;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 32; i++, m >>= 1) {
|
||||
if (m & ip)
|
||||
ptr = ptr->one;
|
||||
else
|
||||
ptr = ptr->zero;
|
||||
if (!ptr)
|
||||
break;
|
||||
if (ptr->name)
|
||||
rv = ptr;
|
||||
}
|
||||
|
||||
return (rv)? rv->name: NULL;
|
||||
}
|
||||
|
||||
static void radix_print_node(RNode *ptr, int level) {
|
||||
assert(ptr);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < level; i++)
|
||||
printf(" ");
|
||||
printf("%08x %08x", ptr->ip, ptr->mask);
|
||||
if (ptr->name)
|
||||
printf(" (%s)\n", ptr->name);
|
||||
else
|
||||
printf(" (NULL)\n");
|
||||
|
||||
if (ptr->zero)
|
||||
radix_print_node(ptr->zero, level + 1);
|
||||
if (ptr->one)
|
||||
radix_print_node(ptr->one, level + 1);
|
||||
}
|
||||
|
||||
void radix_print(void) {
|
||||
if (!head) {
|
||||
printf("radix tree is empty\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("radix IPv4 tree\n");
|
||||
radix_print_node(head, 0);
|
||||
}
|
||||
|
||||
|
||||
static inline int mask2cidr(uint32_t mask) {
|
||||
uint32_t m = 0x80000000;
|
||||
int i;
|
||||
int cnt = 0;
|
||||
for (i = 0; i < 32; i++, m = m >> 1) {
|
||||
if (mask & m)
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static void radix_build_list_node(RNode *ptr) {
|
||||
assert(ptr);
|
||||
|
||||
|
||||
if (ptr->name) {
|
||||
printf("%d.%d.%d.%d/%d %s\n", PRINT_IP(ptr->ip), mask2cidr(ptr->mask), ptr->name);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (ptr->zero)
|
||||
radix_build_list_node(ptr->zero);
|
||||
if (ptr->one)
|
||||
radix_build_list_node(ptr->one);
|
||||
}
|
||||
}
|
||||
|
||||
void radix_build_list(void) {
|
||||
if (!head) {
|
||||
printf("radix tree is empty\n");
|
||||
return;
|
||||
}
|
||||
|
||||
radix_build_list_node(head);
|
||||
}
|
||||
|
||||
37
src/fnettrace/radix.h
Normal file
37
src/fnettrace/radix.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2021 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.
|
||||
*/
|
||||
#ifndef RADIX_H
|
||||
#define RADIX_H
|
||||
|
||||
typedef struct rnode_t {
|
||||
struct rnode_t *zero;
|
||||
struct rnode_t *one;
|
||||
uint32_t ip;
|
||||
uint32_t mask;
|
||||
char *name;
|
||||
} RNode;
|
||||
|
||||
char *radix_find_first(uint32_t ip);
|
||||
char *radix_find_last(uint32_t ip);
|
||||
void radix_add(uint32_t ip, uint32_t mask, char *name);
|
||||
void radix_print(void);
|
||||
void radix_build_list(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -73,6 +73,25 @@ static inline int atoip(const char *str, uint32_t *ip) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// read an IPv4 address in CIDR format, for example 192.168.1.0/24
|
||||
static inline int atocidr(const char *str, uint32_t *ip, uint32_t *mask) {
|
||||
unsigned a, b, c, d, e;
|
||||
|
||||
// extract ip
|
||||
int rv = sscanf(str, "%u.%u.%u.%u/%u", &a, &b, &c, &d, &e);
|
||||
if (rv != 5 || a > 255 || b > 255 || c > 255 || d > 255 || e > 32)
|
||||
return 1;
|
||||
*ip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d;
|
||||
|
||||
// extract mask
|
||||
uint32_t tmp;
|
||||
unsigned i;
|
||||
for (i = 0, *mask = 0, tmp = 0x80000000; i < e; i++, tmp >>= 1) {
|
||||
*mask |= tmp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// verify an ip address is in the network range given by ifip and mask
|
||||
static inline char *in_netrange(uint32_t ip, uint32_t ifip, uint32_t ifmask) {
|
||||
if ((ip & ifmask) != (ifip & ifmask))
|
||||
|
|
|
|||
|
|
@ -1488,20 +1488,21 @@ created with \-\-net are supported.
|
|||
.br
|
||||
$ firejail --nettrace=browser
|
||||
.br
|
||||
9.9.9.9:53 => 192.168.1.60 UDP: 122 B/sec
|
||||
86 KB/s ********* 64.222.84.207:443 United States
|
||||
.br
|
||||
72.21.91.29:80 => 192.168.1.60 TCP: 257 B/sec
|
||||
76 KB/s ******** 192.229.210.163:443 MCI
|
||||
.br
|
||||
80.92.126.65:123 => 192.168.1.60 UDP: 25 B/sec
|
||||
111 B/s 9.9.9.9:53 Quad9 DNS
|
||||
.br
|
||||
69.30.241.50:443 => 192.168.1.60 TCP: 88 KB/sec
|
||||
.br
|
||||
140.82.112.4:443 => 192.168.1.60 TCP: 1861 B/sec
|
||||
32 KB/s *** 142.250.179.182:443 Google
|
||||
.br
|
||||
|
||||
.br
|
||||
(14 streams in the last one minute)
|
||||
|
||||
If /usr/bin/geoiplookup is installed (geoip-bin packet in Debian),
|
||||
the country the IP address originates from is added to the trace.
|
||||
We also use the static IP map in /etc/firejail/hostnames
|
||||
to print the domain names for some of the more common websites and cloud platforms.
|
||||
No external services are contacted for reverse IP lookup.
|
||||
#endif
|
||||
.TP
|
||||
\fB\-\-nice=value
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue