aboutsummaryrefslogtreecommitdiffstats
path: root/src/fnettrace/main.c
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@protonmail.com>2022-01-04 10:42:51 -0500
committerLibravatar netblue30 <netblue30@protonmail.com>2022-01-04 10:42:51 -0500
commit1000c238d5299a7fe3fc54a0d7001f8ce8979df8 (patch)
treee95d9d61070965bd5fe61523177268206939c04f /src/fnettrace/main.c
parentMerge pull request #4807 from WhyNotHugo/skype-config (diff)
downloadfirejail-1000c238d5299a7fe3fc54a0d7001f8ce8979df8.tar.gz
firejail-1000c238d5299a7fe3fc54a0d7001f8ce8979df8.tar.zst
firejail-1000c238d5299a7fe3fc54a0d7001f8ce8979df8.zip
nettrace/netlock
Diffstat (limited to 'src/fnettrace/main.c')
-rw-r--r--src/fnettrace/main.c331
1 files changed, 173 insertions, 158 deletions
diff --git a/src/fnettrace/main.c b/src/fnettrace/main.c
index 04aabf514..658b90eb3 100644
--- a/src/fnettrace/main.c
+++ b/src/fnettrace/main.c
@@ -18,144 +18,176 @@
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#define MAX_BUF_SIZE (64 * 1024) 22#define MAX_BUF_SIZE (64 * 1024)
22 23
23static int arg_netfilter = 0; 24static int arg_netfilter = 0;
24static char *arg_log = NULL; 25static char *arg_log = NULL;
25 26
26typedef struct hlist_t { 27typedef struct hlist_t {
27 struct hlist_t *next; 28 struct hlist_t *hnext; // used for hash table
29 struct hlist_t *dnext; // used to display stremas on the screen
28 uint32_t ip_src; 30 uint32_t ip_src;
29 uint32_t ip_dst; 31 uint32_t ip_dst;
32 uint64_t bytes; // number of bytes received in the last display interval
30 uint16_t port_src; 33 uint16_t port_src;
31 uint64_t bytes; 34 uint16_t ip_instance;
32 int instance; 35 // the firewall is build based on source address, and in the linked list
33#define MAX_TTL 20 // 20 * DISPLAY_INTERVAL = 1 minute 36 // we have elements with the same address but different ports
34 short ttl;
35 uint8_t protocol; 37 uint8_t protocol;
36} HList; 38} HList;
37 39
40// hash table
38#define HMAX 256 41#define HMAX 256
39HList *htable[HMAX] = {NULL}; 42HList *htable[HMAX] = {NULL};
40static int htable_empty = 1; 43// display linked list
44HList *dlist = NULL;
41 45
42static void hlist_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16_t port_src, uint64_t bytes) { 46static void hlist_add(uint32_t ip_src, uint32_t ip_dst, uint8_t protocol, uint16_t port_src, uint64_t bytes) {
43 uint8_t h = hash(ip_src); 47 uint8_t h = hash(ip_src);
44 htable_empty = 0;
45 48
46 // find 49 // find
47 int instance = 0; 50 int ip_instance = 0;
48 HList *ptr = htable[h]; 51 HList *ptr = htable[h];
49 while (ptr) { 52 while (ptr) {
50 if (ptr->ip_src == ip_src) { 53 if (ptr->ip_src == ip_src) {
51 instance++; 54 ip_instance++;
52 if (ptr->ip_dst == ip_dst && ptr->port_src == port_src && ptr->protocol == protocol) { 55 if (ptr->ip_dst == ip_dst && ptr->port_src == port_src && ptr->protocol == protocol) {
53 ptr->bytes += bytes; 56 ptr->bytes += bytes;
54 ptr->ttl = MAX_TTL;
55 return; 57 return;
56 } 58 }
57 } 59 }
58 ptr = ptr->next; 60 ptr = ptr->hnext;
59 } 61 }
60 62
63#ifdef DEBUG
64 printf("malloc %d.%d.%d.%d\n", PRINT_IP(ip_src));
65#endif
61 HList *hnew = malloc(sizeof(HList)); 66 HList *hnew = malloc(sizeof(HList));
67 if (!hnew)
68 errExit("malloc");
62 hnew->ip_src = ip_src; 69 hnew->ip_src = ip_src;
63 hnew->ip_dst = ip_dst; 70 hnew->ip_dst = ip_dst;
64 hnew->port_src = port_src; 71 hnew->port_src = port_src;
65 hnew->protocol = protocol; 72 hnew->protocol = protocol;
66 hnew->next = NULL; 73 hnew->hnext = NULL;
67 hnew->bytes = bytes; 74 hnew->bytes = bytes;
68 hnew->ttl = MAX_TTL; 75 hnew->ip_instance = ip_instance + 1;
69 hnew->instance = instance + 1;
70 if (htable[h] == NULL) 76 if (htable[h] == NULL)
71 htable[h] = hnew; 77 htable[h] = hnew;
72 else { 78 else {
73 hnew->next = htable[h]; 79 hnew->hnext = htable[h];
74 htable[h] = hnew; 80 htable[h] = hnew;
75 } 81 }
76 82
77 ansi_clrline(1); 83 // add to the end of list
78 logprintf(" %d%d.%d.%d\n", PRINT_IP(hnew->ip_src)); 84 hnew->dnext = NULL;
85 if (dlist == NULL)
86 dlist = hnew;
87 else {
88 ptr = dlist;
89 while (ptr->dnext != NULL)
90 ptr = ptr->dnext;
91 ptr->dnext = hnew;
92 }
93
94 if (arg_netfilter)
95 logprintf(" %d.%d.%d.%d ", PRINT_IP(hnew->ip_src));
79} 96}
80 97
81// remove entries with a ttl <= 0 98static void hlist_free(HList *elem) {
82static void hlist_clean_ttl() { 99 assert(elem);
83 if (htable_empty) 100#ifdef DEBUG
84 return; 101 printf("free %d.%d.%d.%d\n", PRINT_IP(elem->ip_src));
102#endif
85 103
86 int i; 104 uint8_t h = hash(elem->ip_src);
87 for (i = 0; i < HMAX; i++) { 105 HList *ptr = htable[h];
88 HList *ptr = htable[i]; 106 assert(ptr);
89 HList *parent = NULL; 107
90 while (ptr) { 108 HList *prev = NULL;
91 if (--ptr->ttl <= 0) { 109 while (ptr != elem) {
92 HList *tmp = ptr; 110 prev = ptr;
93 ptr = ptr->next; 111 ptr = ptr->hnext;
94 if (parent)
95 parent->next = ptr;
96 else
97 htable[i] = ptr;
98 free(tmp);
99 }
100 else {
101 parent = ptr;
102 ptr = ptr->next;
103 }
104 }
105 } 112 }
113 if (prev == NULL)
114 htable[h] = elem->hnext;
115 else
116 prev->hnext = elem->hnext;
117 free(elem);
106} 118}
107 119
108static void hlist_print() { 120#ifdef DEBUG
109 ansi_clrscr(0); 121static void debug_dlist(void) {
110 if (htable_empty) 122 HList *ptr = dlist;
111 return; 123 while (ptr) {
112 if (arg_netfilter) 124 printf("dlist %d.%d.%d.%d:%d\n", PRINT_IP(ptr->ip_src), ptr->port_src);
113 printf("\n\n"); 125 ptr = ptr->dnext;
114 126 }
127}
128static void debug_hlist(void) {
115 int i; 129 int i;
116 int cnt = 0;
117 int cnt_printed = 0;
118 for (i = 0; i < HMAX; i++) { 130 for (i = 0; i < HMAX; i++) {
119 HList *ptr = htable[i]; 131 HList *ptr = htable[i];
120 while (ptr) { 132 while (ptr) {
121 if (ptr->bytes) { 133 printf("hlist (%d) %d.%d.%d.%d:%d\n", i, PRINT_IP(ptr->ip_src), ptr->port_src);
122 cnt_printed++; 134 ptr = ptr->hnext;
123 char ip_src[30];
124 sprintf(ip_src, "%d.%d.%d.%d:%u", PRINT_IP(ptr->ip_src), ptr->port_src);
125 char ip_dst[30];
126 sprintf(ip_dst, "%d.%d.%d.%d", PRINT_IP(ptr->ip_dst));
127 printf("%-25s => %-25s\t%s:",
128 ip_src,
129 ip_dst,
130 (ptr->protocol == 6)? "TCP": "UDP");
131
132 if (ptr->bytes > (DISPLAY_INTERVAL * 1024 * 2)) // > 2 KB/second
133 printf(" %lu KB/sec\n",
134 ptr->bytes / (DISPLAY_INTERVAL * 1024));
135 else
136 printf(" %lu B/sec\n",
137 ptr->bytes / DISPLAY_INTERVAL);
138 ptr->bytes = 0;
139 }
140
141 ptr = ptr->next;
142 cnt++;
143 } 135 }
144 } 136 }
137}
138#endif
139
140static void hlist_print(void) {
141 assert(!arg_netfilter);
142 ansi_clrscr();
143
144#ifdef DEBUG
145 printf("*********************\n");
146 debug_dlist();
147 printf("-----------------------------\n");
148 debug_hlist();
149 printf("*********************\n");
150#endif
151
152 HList *ptr = dlist;
153 HList *prev = NULL;
154 while (ptr) {
155 HList *next = ptr->dnext;
156 if (ptr->bytes) {
157 char ip_src[30];
158 sprintf(ip_src, "%d.%d.%d.%d:%u", PRINT_IP(ptr->ip_src), ptr->port_src);
159 char ip_dst[30];
160 sprintf(ip_dst, "%d.%d.%d.%d", PRINT_IP(ptr->ip_dst));
161 printf("%-22s => %-15s %s:",
162 ip_src,
163 ip_dst,
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
170 printf(" %lu B/sec\n",
171 ptr->bytes / DISPLAY_INTERVAL);
172 ptr->bytes = 0;
173 prev = ptr;
174 }
175 else {
176 // free the element
177 if (prev == NULL)
178 dlist = next;
179 else
180 prev->dnext = next;
181 hlist_free(ptr);
182 }
145 183
146 if (cnt_printed < 7) { 184 ptr = next;
147 for (i = 0; i < 7 - cnt_printed; i++)
148 printf("\n");
149 }
150
151 if (!arg_netfilter) {
152 printf("(%d %s in the last one minute)\n", cnt, (cnt == 1)? "stream": "streams");
153 hlist_clean_ttl();
154 } 185 }
155} 186}
156 187
157static void run_trace(void) { 188static void run_trace(void) {
158 logprintf("accumulating traffic for %d seconds...\n", NETLOCK_INTERVAL); 189 if (arg_netfilter)
190 logprintf("accumulating traffic for %d seconds\n", NETLOCK_INTERVAL);
159 191
160 // trace only rx ipv4 tcp and upd 192 // trace only rx ipv4 tcp and upd
161 int s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); 193 int s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
@@ -169,18 +201,16 @@ static void run_trace(void) {
169 unsigned char buf[MAX_BUF_SIZE]; 201 unsigned char buf[MAX_BUF_SIZE];
170 while (1) { 202 while (1) {
171 unsigned end = time(NULL); 203 unsigned end = time(NULL);
172 if (arg_netfilter && end - start >= NETLOCK_INTERVAL) { 204 if (arg_netfilter && end - start >= NETLOCK_INTERVAL)
173 ansi_clrline(1);
174 break; 205 break;
175 }
176 if (end % DISPLAY_INTERVAL == 1 && last_print_traces != end) { // first print after 1 second 206 if (end % DISPLAY_INTERVAL == 1 && last_print_traces != end) { // first print after 1 second
177 hlist_print(); 207 if (!arg_netfilter)
208 hlist_print();
178 last_print_traces = end; 209 last_print_traces = end;
179 } 210 }
180 if (arg_netfilter && last_print_remaining != end) { 211 if (arg_netfilter && last_print_remaining != end) {
181 ansi_clrline(1); 212 logprintf(".");
182 int secs = NETLOCK_INTERVAL - (end - start); 213 fflush(0);
183 logprintf("%d %s remaining ", secs, (secs == 1)? "second": "seconds");
184 last_print_remaining = end; 214 last_print_remaining = end;
185 } 215 }
186 216
@@ -228,14 +258,14 @@ static void run_trace(void) {
228} 258}
229 259
230static char *filter_start = 260static char *filter_start =
231"*filter\n" 261 "*filter\n"
232":INPUT DROP [0:0]\n" 262 ":INPUT DROP [0:0]\n"
233":FORWARD DROP [0:0]\n" 263 ":FORWARD DROP [0:0]\n"
234":OUTPUT DROP [0:0]\n"; 264 ":OUTPUT DROP [0:0]\n";
235 265
236// return 1 if error 266// return 1 if error
237static int print_filter(FILE *fp) { 267static int print_filter(FILE *fp) {
238 if (htable_empty) 268 if (dlist == NULL)
239 return 1; 269 return 1;
240 fprintf(fp, "%s\n", filter_start); 270 fprintf(fp, "%s\n", filter_start);
241 fprintf(fp, "-A INPUT -s 127.0.0.0/8 -j ACCEPT\n"); 271 fprintf(fp, "-A INPUT -s 127.0.0.0/8 -j ACCEPT\n");
@@ -246,19 +276,19 @@ static int print_filter(FILE *fp) {
246 for (i = 0; i < HMAX; i++) { 276 for (i = 0; i < HMAX; i++) {
247 HList *ptr = htable[i]; 277 HList *ptr = htable[i];
248 while (ptr) { 278 while (ptr) {
249 if (ptr->instance == 1) { 279 // filter rules are targeting ip address, the port number is disregarded,
280 // so we look only at the first instance of an address
281 if (ptr->ip_instance == 1) {
250 char *protocol = (ptr->protocol == 6)? "tcp": "udp"; 282 char *protocol = (ptr->protocol == 6)? "tcp": "udp";
251 fprintf(fp, "-A INPUT -s %d.%d.%d.%d -sport %u -p %s -j ACCEPT\n", 283 fprintf(fp, "-A INPUT -s %d.%d.%d.%d -p %s -j ACCEPT\n",
252 PRINT_IP(ptr->ip_src), 284 PRINT_IP(ptr->ip_src),
253 ptr->port_src,
254 protocol); 285 protocol);
255 fprintf(fp, "-A OUTPUT -d %d.%d.%d.%d -dport %u -p %s -j ACCEPT\n", 286 fprintf(fp, "-A OUTPUT -d %d.%d.%d.%d -p %s -j ACCEPT\n",
256 PRINT_IP(ptr->ip_src), 287 PRINT_IP(ptr->ip_src),
257 ptr->port_src,
258 protocol); 288 protocol);
259 fprintf(fp, "\n"); 289 fprintf(fp, "\n");
260 } 290 }
261 ptr = ptr->next; 291 ptr = ptr->hnext;
262 } 292 }
263 } 293 }
264 fprintf(fp, "COMMIT\n"); 294 fprintf(fp, "COMMIT\n");
@@ -268,33 +298,46 @@ static int print_filter(FILE *fp) {
268 298
269static char *flush_rules[] = { 299static char *flush_rules[] = {
270 "-P INPUT ACCEPT", 300 "-P INPUT ACCEPT",
271 "-P FORWARD ACCEPT", 301// "-P FORWARD DENY",
272 "-P OUTPUT ACCEPT", 302 "-P OUTPUT ACCEPT",
273 "-F", 303 "-F",
274 "-X", 304 "-X",
275 "-t nat -F", 305// "-t nat -F",
276 "-t nat -X", 306// "-t nat -X",
277 "-t mangle -F", 307// "-t mangle -F",
278 "-t mangle -X", 308// "-t mangle -X",
279 "iptables -t raw -F", 309// "iptables -t raw -F",
280 "-t raw -X", 310// "-t raw -X",
281 NULL 311 NULL
282}; 312};
283 313
284static void flush_netfilter(void) { 314static void deploy_netfilter(void) {
315 int rv;
316 char *cmd;
317 int i;
318
319 if (dlist == NULL) {
320 logprintf("Sorry, no network traffic was detected. The firewall was not configured.\n");
321 return;
322 }
285 // find iptables command 323 // find iptables command
286 struct stat s;
287 char *iptables = NULL; 324 char *iptables = NULL;
288 if (stat("/sbin/iptables", &s) == 0) 325 char *iptables_restore = NULL;
326 if (access("/sbin/iptables", X_OK) == 0) {
289 iptables = "/sbin/iptables"; 327 iptables = "/sbin/iptables";
290 else if (stat("/usr/sbin/iptables", &s) == 0) 328 iptables_restore = "/sbin/iptables-restore";
329 }
330 else if (access("/usr/sbin/iptables", X_OK) == 0) {
291 iptables = "/usr/sbin/iptables"; 331 iptables = "/usr/sbin/iptables";
292 if (iptables == NULL) { 332 iptables_restore = "/usr/sbin/iptables-restore";
333 }
334 if (iptables == NULL || iptables_restore == NULL) {
293 fprintf(stderr, "Error: iptables command not found, netfilter not configured\n"); 335 fprintf(stderr, "Error: iptables command not found, netfilter not configured\n");
294 exit(1); 336 exit(1);
295 } 337 }
296 338
297 int i = 0; 339 // flush all netfilter rules
340 i = 0;
298 while (flush_rules[i]) { 341 while (flush_rules[i]) {
299 char *cmd; 342 char *cmd;
300 if (asprintf(&cmd, "%s %s", iptables, flush_rules[i]) == -1) 343 if (asprintf(&cmd, "%s %s", iptables, flush_rules[i]) == -1)
@@ -304,11 +347,6 @@ static void flush_netfilter(void) {
304 free(cmd); 347 free(cmd);
305 i++; 348 i++;
306 } 349 }
307}
308
309static void deploy_netfilter(void) {
310 int rv;
311 char *cmd;
312 350
313 // create temporary file 351 // create temporary file
314 char fname[] = "/tmp/firejail-XXXXXX"; 352 char fname[] = "/tmp/firejail-XXXXXX";
@@ -328,54 +366,28 @@ static void deploy_netfilter(void) {
328 print_filter(fp); 366 print_filter(fp);
329 fclose(fp); 367 fclose(fp);
330 368
331 if (arg_log) { 369 logprintf("\n\n");
332 logprintf("\n"); 370 logprintf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
333 logprintf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); 371 if (asprintf(&cmd, "cat %s >> %s", fname, arg_log) == -1)
334 if (asprintf(&cmd, "cat %s >> %s", fname, arg_log) == -1)
335 errExit("asprintf");
336 rv = system(cmd);
337 (void) rv;
338 free(cmd);
339 logprintf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
340 }
341
342 // find iptables command
343 struct stat s;
344 char *iptables = NULL;
345 char *iptables_restore = NULL;
346 if (stat("/sbin/iptables", &s) == 0) {
347 iptables = "/sbin/iptables";
348 iptables_restore = "/sbin/iptables-restore";
349 }
350 else if (stat("/usr/sbin/iptables", &s) == 0) {
351 iptables = "/usr/sbin/iptables";
352 iptables_restore = "/usr/sbin/iptables-restore";
353 }
354 if (iptables == NULL || iptables_restore == NULL) {
355 fprintf(stderr, "Error: iptables command not found, netfilter not configured\n");
356 rv = unlink(fname);
357 (void) rv;
358 exit(1);
359 }
360
361 // configuring
362 if (asprintf(&cmd, "%s %s", iptables_restore, fname) == -1)
363 errExit("asprintf"); 372 errExit("asprintf");
364 rv = system(cmd); 373 rv = system(cmd);
365 if (rv) 374 (void) rv;
366 fprintf(stdout, "Warning: possible netfilter problem!");
367 free(cmd); 375 free(cmd);
368 376
369 sleep(1); 377 if (asprintf(&cmd, "cat %s", fname) == -1)
370 if (asprintf(&cmd, "%s %s", iptables_restore, fname) == -1)
371 errExit("asprintf"); 378 errExit("asprintf");
372 rv = system(cmd); 379 rv = system(cmd);
380 (void) rv;
373 free(cmd); 381 free(cmd);
382 logprintf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
374 383
375 printf("Current firewall configuration:\n\n"); 384 // configuring
376 if (asprintf(&cmd, "%s -vL -n", iptables) == -1) 385 if (asprintf(&cmd, "%s %s", iptables_restore, fname) == -1)
377 errExit("asprintf"); 386 errExit("asprintf");
378 rv = system(cmd); 387 rv = system(cmd);
388 if (rv)
389 fprintf(stdout, "Warning: possible netfilter problem!");
390 free(cmd);
379 391
380 rv = unlink(fname); 392 rv = unlink(fname);
381 (void) rv; 393 (void) rv;
@@ -394,6 +406,11 @@ void logprintf(char* fmt, ...) {
394 va_end(args); 406 va_end(args);
395 fclose(fp); 407 fclose(fp);
396 } 408 }
409
410 va_list args;
411 va_start(args,fmt);
412 vfprintf(stdout, fmt, args);
413 va_end(args);
397} 414}
398 415
399static void usage(void) { 416static void usage(void) {
@@ -429,12 +446,10 @@ int main(int argc, char **argv) {
429 } 446 }
430 } 447 }
431 448
432 if (arg_netfilter) { 449 ansi_clrscr();
450 if (arg_netfilter)
433 logprintf("starting network lockdown\n"); 451 logprintf("starting network lockdown\n");
434 flush_netfilter();
435 }
436 452
437 ansi_clrscr(0);
438 run_trace(); 453 run_trace();
439 if (arg_netfilter) { 454 if (arg_netfilter) {
440 deploy_netfilter(); 455 deploy_netfilter();