aboutsummaryrefslogtreecommitdiffstats
path: root/src/fnettrace/main.c
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@protonmail.com>2022-01-07 09:52:00 -0500
committerLibravatar netblue30 <netblue30@protonmail.com>2022-01-07 09:52:00 -0500
commit500a56efd310396f142440019aee671b5f747efb (patch)
tree8effc272b3814207c8b5583e99bcd9b925558dab /src/fnettrace/main.c
parentfix wrap/nowrap help string in firemon (diff)
downloadfirejail-500a56efd310396f142440019aee671b5f747efb.tar.gz
firejail-500a56efd310396f142440019aee671b5f747efb.tar.zst
firejail-500a56efd310396f142440019aee671b5f747efb.zip
more on nettrace
Diffstat (limited to 'src/fnettrace/main.c')
-rw-r--r--src/fnettrace/main.c187
1 files changed, 141 insertions, 46 deletions
diff --git a/src/fnettrace/main.c b/src/fnettrace/main.c
index 658b90eb3..eeac2fd85 100644
--- a/src/fnettrace/main.c
+++ b/src/fnettrace/main.c
@@ -18,37 +18,42 @@
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/ 19*/
20#include "fnettrace.h" 20#include "fnettrace.h"
21//#define DEBUG 1 21#include "radix.h"
22#include <sys/ioctl.h>
22#define MAX_BUF_SIZE (64 * 1024) 23#define MAX_BUF_SIZE (64 * 1024)
23 24
24static int arg_netfilter = 0; 25static int arg_netfilter = 0;
25static char *arg_log = NULL; 26static char *arg_log = NULL;
26 27
27typedef struct hlist_t { 28typedef struct hnode_t {
28 struct hlist_t *hnext; // used for hash table 29 struct hnode_t *hnext; // used for hash table
29 struct hlist_t *dnext; // used to display stremas on the screen 30 struct hnode_t *dnext; // used to display stremas on the screen
30 uint32_t ip_src; 31 uint32_t ip_src;
31 uint32_t ip_dst; 32 uint32_t ip_dst;
32 uint64_t bytes; // number of bytes received in the last display interval 33 uint32_t bytes; // number of bytes received in the last display interval
33 uint16_t port_src; 34 uint16_t port_src;
34 uint16_t ip_instance;
35 // the firewall is build based on source address, and in the linked list
36 // we have elements with the same address but different ports
37 uint8_t protocol; 35 uint8_t protocol;
38} HList; 36 // the firewall is build based on source address, and in the linked list
37 // we have elements with the same address but different ports
38 uint8_t ip_instance;
39 char *hostname;
40 int ttl;
41} HNode;
39 42
40// hash table 43// hash table
41#define HMAX 256 44#define HMAX 256
42HList *htable[HMAX] = {NULL}; 45HNode *htable[HMAX] = {NULL};
43// display linked list 46// display linked list
44HList *dlist = NULL; 47HNode *dlist = NULL;
45 48
46static void hlist_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16_t port_src, uint64_t bytes) { 49static unsigned bwmax = 0; // max bytes received in a display interval
50
51static void hnode_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16_t port_src, uint32_t bytes) {
47 uint8_t h = hash(ip_src); 52 uint8_t h = hash(ip_src);
48 53
49 // find 54 // find
50 int ip_instance = 0; 55 int ip_instance = 0;
51 HList *ptr = htable[h]; 56 HNode *ptr = htable[h];
52 while (ptr) { 57 while (ptr) {
53 if (ptr->ip_src == ip_src) { 58 if (ptr->ip_src == ip_src) {
54 ip_instance++; 59 ip_instance++;
@@ -63,9 +68,10 @@ static void hlist_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16
63#ifdef DEBUG 68#ifdef DEBUG
64 printf("malloc %d.%d.%d.%d\n", PRINT_IP(ip_src)); 69 printf("malloc %d.%d.%d.%d\n", PRINT_IP(ip_src));
65#endif 70#endif
66 HList *hnew = malloc(sizeof(HList)); 71 HNode *hnew = malloc(sizeof(HNode));
67 if (!hnew) 72 if (!hnew)
68 errExit("malloc"); 73 errExit("malloc");
74 hnew->hostname = NULL;
69 hnew->ip_src = ip_src; 75 hnew->ip_src = ip_src;
70 hnew->ip_dst = ip_dst; 76 hnew->ip_dst = ip_dst;
71 hnew->port_src = port_src; 77 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
73 hnew->hnext = NULL; 79 hnew->hnext = NULL;
74 hnew->bytes = bytes; 80 hnew->bytes = bytes;
75 hnew->ip_instance = ip_instance + 1; 81 hnew->ip_instance = ip_instance + 1;
82 hnew->ttl = DISPLAY_TTL;
76 if (htable[h] == NULL) 83 if (htable[h] == NULL)
77 htable[h] = hnew; 84 htable[h] = hnew;
78 else { 85 else {
@@ -95,17 +102,17 @@ static void hlist_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16
95 logprintf(" %d.%d.%d.%d ", PRINT_IP(hnew->ip_src)); 102 logprintf(" %d.%d.%d.%d ", PRINT_IP(hnew->ip_src));
96} 103}
97 104
98static void hlist_free(HList *elem) { 105static void hnode_free(HNode *elem) {
99 assert(elem); 106 assert(elem);
100#ifdef DEBUG 107#ifdef DEBUG
101 printf("free %d.%d.%d.%d\n", PRINT_IP(elem->ip_src)); 108 printf("free %d.%d.%d.%d\n", PRINT_IP(elem->ip_src));
102#endif 109#endif
103 110
104 uint8_t h = hash(elem->ip_src); 111 uint8_t h = hash(elem->ip_src);
105 HList *ptr = htable[h]; 112 HNode *ptr = htable[h];
106 assert(ptr); 113 assert(ptr);
107 114
108 HList *prev = NULL; 115 HNode *prev = NULL;
109 while (ptr != elem) { 116 while (ptr != elem) {
110 prev = ptr; 117 prev = ptr;
111 ptr = ptr->hnext; 118 ptr = ptr->hnext;
@@ -119,25 +126,45 @@ static void hlist_free(HList *elem) {
119 126
120#ifdef DEBUG 127#ifdef DEBUG
121static void debug_dlist(void) { 128static void debug_dlist(void) {
122 HList *ptr = dlist; 129 HNode *ptr = dlist;
123 while (ptr) { 130 while (ptr) {
124 printf("dlist %d.%d.%d.%d:%d\n", PRINT_IP(ptr->ip_src), ptr->port_src); 131 printf("dlist %d.%d.%d.%d:%d\n", PRINT_IP(ptr->ip_src), ptr->port_src);
125 ptr = ptr->dnext; 132 ptr = ptr->dnext;
126 } 133 }
127} 134}
128static void debug_hlist(void) { 135static void debug_hnode(void) {
129 int i; 136 int i;
130 for (i = 0; i < HMAX; i++) { 137 for (i = 0; i < HMAX; i++) {
131 HList *ptr = htable[i]; 138 HNode *ptr = htable[i];
132 while (ptr) { 139 while (ptr) {
133 printf("hlist (%d) %d.%d.%d.%d:%d\n", i, PRINT_IP(ptr->ip_src), ptr->port_src); 140 printf("hnode (%d) %d.%d.%d.%d:%d\n", i, PRINT_IP(ptr->ip_src), ptr->port_src);
134 ptr = ptr->hnext; 141 ptr = ptr->hnext;
135 } 142 }
136 } 143 }
137} 144}
138#endif 145#endif
139 146
140static void hlist_print(void) { 147static char *bw_line[DISPLAY_BW_UNITS + 1] = { NULL };
148
149static char *print_bw(unsigned units) {
150 if (units > DISPLAY_BW_UNITS)
151 units = DISPLAY_BW_UNITS ;
152
153 if (bw_line[units] == NULL) {
154 char *ptr = malloc(DISPLAY_BW_UNITS + 1);
155 if (!ptr)
156 errExit("malloc");
157 bw_line[units] = ptr;
158
159 unsigned i;
160 for (i = 0; i < DISPLAY_BW_UNITS; i++, ptr++)
161 sprintf(ptr, "%s", (i < units)? "*": " ");
162 }
163
164 return bw_line[units];
165}
166
167static void hnode_print(void) {
141 assert(!arg_netfilter); 168 assert(!arg_netfilter);
142 ansi_clrscr(); 169 ansi_clrscr();
143 170
@@ -145,30 +172,66 @@ static void hlist_print(void) {
145 printf("*********************\n"); 172 printf("*********************\n");
146 debug_dlist(); 173 debug_dlist();
147 printf("-----------------------------\n"); 174 printf("-----------------------------\n");
148 debug_hlist(); 175 debug_hnode();
149 printf("*********************\n"); 176 printf("*********************\n");
150#endif 177#endif
151 178
152 HList *ptr = dlist; 179 // get terminal size
153 HList *prev = NULL; 180 struct winsize sz;
181 int col = 80;
182 if (isatty(STDIN_FILENO)) {
183 if (!ioctl(0, TIOCGWINSZ, &sz))
184 col = sz.ws_col;
185 }
186#define LINE_MAX 200
187 char line[LINE_MAX + 1];
188 if (col > LINE_MAX)
189 col = LINE_MAX;
190
191 HNode *ptr = dlist;
192 HNode *prev = NULL;
154 while (ptr) { 193 while (ptr) {
155 HList *next = ptr->dnext; 194 HNode *next = ptr->dnext;
156 if (ptr->bytes) { 195 if (--ptr->ttl > 0) {
157 char ip_src[30]; 196 char bytes[11];
158 sprintf(ip_src, "%d.%d.%d.%d:%u", PRINT_IP(ptr->ip_src), ptr->port_src); 197 if (ptr->bytes > (DISPLAY_INTERVAL * 1024 * 1024 * 2)) // > 2 MB/second
159 char ip_dst[30]; 198 sprintf(bytes, "%u MB/s",
160 sprintf(ip_dst, "%d.%d.%d.%d", PRINT_IP(ptr->ip_dst)); 199 (unsigned) (ptr->bytes / (DISPLAY_INTERVAL * 1024* 1024)));
161 printf("%-22s => %-15s %s:", 200 else if (ptr->bytes > (DISPLAY_INTERVAL * 1024 * 2)) // > 2 KB/second
162 ip_src, 201 sprintf(bytes, "%u KB/s",
163 ip_dst, 202 (unsigned) (ptr->bytes / (DISPLAY_INTERVAL * 1024)));
164 (ptr->protocol == 6)? "TCP": "UDP");
165
166 if (ptr->bytes > (DISPLAY_INTERVAL * 1024 * 2)) // > 2 KB/second
167 printf(" %lu KB/sec\n",
168 ptr->bytes / (DISPLAY_INTERVAL * 1024));
169 else 203 else
170 printf(" %lu B/sec\n", 204 sprintf(bytes, "%u B/s", (unsigned) (ptr->bytes / DISPLAY_INTERVAL));
171 ptr->bytes / DISPLAY_INTERVAL); 205
206 char *hostname = ptr->hostname;
207 if (!hostname)
208 hostname = radix_find_last(ptr->ip_src);
209
210 if (!hostname)
211 hostname = retrieve_hostname(ptr->ip_src);
212
213 if (!hostname)
214 hostname = " ";
215 else {
216 ptr->hostname = strdup(hostname);
217 if (!ptr->hostname)
218 errExit("strdup");
219 }
220
221 unsigned bwunit = bwmax / DISPLAY_BW_UNITS;
222 unsigned units = ptr->bytes / bwunit;
223 char *bwline = print_bw(units);
224
225 sprintf(line, "%10s %s %d.%d.%d.%d:%u %s\n", bytes, bwline, PRINT_IP(ptr->ip_src), ptr->port_src, hostname);
226 int len = strlen(line);
227 if (col > 4 && len > col) {
228 line[col] = '\0';
229 line[col - 1] = '\n';
230 }
231 printf("%s", line);
232
233 if (ptr->bytes)
234 ptr->ttl = DISPLAY_TTL;
172 ptr->bytes = 0; 235 ptr->bytes = 0;
173 prev = ptr; 236 prev = ptr;
174 } 237 }
@@ -178,7 +241,7 @@ static void hlist_print(void) {
178 dlist = next; 241 dlist = next;
179 else 242 else
180 prev->dnext = next; 243 prev->dnext = next;
181 hlist_free(ptr); 244 hnode_free(ptr);
182 } 245 }
183 246
184 ptr = next; 247 ptr = next;
@@ -199,14 +262,18 @@ static void run_trace(void) {
199 unsigned last_print_traces = 0; 262 unsigned last_print_traces = 0;
200 unsigned last_print_remaining = 0; 263 unsigned last_print_remaining = 0;
201 unsigned char buf[MAX_BUF_SIZE]; 264 unsigned char buf[MAX_BUF_SIZE];
265 unsigned bwcurrent = 0;
202 while (1) { 266 while (1) {
203 unsigned end = time(NULL); 267 unsigned end = time(NULL);
204 if (arg_netfilter && end - start >= NETLOCK_INTERVAL) 268 if (arg_netfilter && end - start >= NETLOCK_INTERVAL)
205 break; 269 break;
206 if (end % DISPLAY_INTERVAL == 1 && last_print_traces != end) { // first print after 1 second 270 if (end % DISPLAY_INTERVAL == 1 && last_print_traces != end) { // first print after 1 second
271 if (bwcurrent > bwmax)
272 bwmax = bwcurrent;
207 if (!arg_netfilter) 273 if (!arg_netfilter)
208 hlist_print(); 274 hnode_print();
209 last_print_traces = end; 275 last_print_traces = end;
276 bwcurrent = 0;
210 } 277 }
211 if (arg_netfilter && last_print_remaining != end) { 278 if (arg_netfilter && last_print_remaining != end) {
212 logprintf("."); 279 logprintf(".");
@@ -233,6 +300,7 @@ static void run_trace(void) {
233 300
234 unsigned bytes = recvfrom(sock, buf, MAX_BUF_SIZE, 0, NULL, NULL); 301 unsigned bytes = recvfrom(sock, buf, MAX_BUF_SIZE, 0, NULL, NULL);
235 if (bytes >= 20) { // size of IP header 302 if (bytes >= 20) { // size of IP header
303 bwcurrent += bytes + 14; // assume a 14 byte Ethernet layer
236 // filter out loopback traffic 304 // filter out loopback traffic
237 if (buf[12] != 127) { 305 if (buf[12] != 127) {
238 uint32_t ip_src; 306 uint32_t ip_src;
@@ -248,7 +316,7 @@ static void run_trace(void) {
248 memcpy(&port_src, buf + hlen, 2); 316 memcpy(&port_src, buf + hlen, 2);
249 port_src = ntohs(port_src); 317 port_src = ntohs(port_src);
250 318
251 hlist_add(ip_src, ip_dst, buf[9], port_src, (uint64_t) bytes); 319 hnode_add(ip_src, ip_dst, buf[9], port_src, bytes + 14);
252 } 320 }
253 } 321 }
254 } 322 }
@@ -274,7 +342,7 @@ static int print_filter(FILE *fp) {
274 342
275 int i; 343 int i;
276 for (i = 0; i < HMAX; i++) { 344 for (i = 0; i < HMAX; i++) {
277 HList *ptr = htable[i]; 345 HNode *ptr = htable[i];
278 while (ptr) { 346 while (ptr) {
279 // filter rules are targeting ip address, the port number is disregarded, 347 // filter rules are targeting ip address, the port number is disregarded,
280 // so we look only at the first instance of an address 348 // so we look only at the first instance of an address
@@ -416,6 +484,7 @@ void logprintf(char* fmt, ...) {
416static void usage(void) { 484static void usage(void) {
417 printf("Usage: fnetlock [OPTIONS]\n"); 485 printf("Usage: fnetlock [OPTIONS]\n");
418 printf("Options:\n"); 486 printf("Options:\n");
487 printf(" --build=filename - compact list of addresses\n");
419 printf(" --help, -? - this help screen\n"); 488 printf(" --help, -? - this help screen\n");
420 printf(" --netfilter - build the firewall rules and commit them.\n"); 489 printf(" --netfilter - build the firewall rules and commit them.\n");
421 printf(" --log=filename - logfile\n"); 490 printf(" --log=filename - logfile\n");
@@ -424,7 +493,26 @@ static void usage(void) {
424 493
425int main(int argc, char **argv) { 494int main(int argc, char **argv) {
426 int i; 495 int i;
427 printf("\n\n"); 496
497#ifdef DEBUG
498 // radix test
499 radix_add(0x09000000, 0xff000000, "IBM");
500 radix_add(0x09090909, 0xffffffff, "Quad9 DNS");
501 radix_add(0x09000000, 0xff000000, "IBM");
502 radix_print();
503 printf("This test should print \"IBM, Quad9 DNS, IBM\"\n");
504 char *name = radix_find_first(0x09090909);
505 printf("%s, ", name);
506 name = radix_find_last(0x09090909);
507 printf("%s, ", name);
508 name = radix_find_last(0x09322209);
509 printf("%s\n", name);
510#endif
511
512 if (argc == 2 && strncmp(argv[1], "--build=", 8) == 0) {
513 build_list(argv[1] + 8);
514 return 0;
515 }
428 516
429 if (getuid() != 0) { 517 if (getuid() != 0) {
430 fprintf(stderr, "Error: you need to be root to run this program\n"); 518 fprintf(stderr, "Error: you need to be root to run this program\n");
@@ -449,6 +537,13 @@ int main(int argc, char **argv) {
449 ansi_clrscr(); 537 ansi_clrscr();
450 if (arg_netfilter) 538 if (arg_netfilter)
451 logprintf("starting network lockdown\n"); 539 logprintf("starting network lockdown\n");
540 else {
541 char *fname;
542 if (asprintf(&fname, "%s/hostnames", SYSCONFDIR) == -1)
543 errExit("asprintf");
544 load_hostnames(fname);
545 free(fname);
546 }
452 547
453 run_trace(); 548 run_trace();
454 if (arg_netfilter) { 549 if (arg_netfilter) {