aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/firecfg/firecfg.config1
-rw-r--r--src/firejail/netfilter.c4
-rw-r--r--src/fnetlock/Makefile9
-rw-r--r--src/fnetlock/fnetlock.h51
-rw-r--r--src/fnetlock/main.c394
-rw-r--r--src/fnetlock/tail.c (renamed from src/fnettrace/tail.c)2
-rw-r--r--src/fnettrace-dns/main.c16
-rw-r--r--src/fnettrace-sni/main.c2
-rw-r--r--src/fnettrace/fnettrace.h3
-rw-r--r--src/fnettrace/main.c486
-rw-r--r--src/fnettrace/runprog.c31
-rw-r--r--src/fnettrace/static-ip-map.txt94
12 files changed, 805 insertions, 288 deletions
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index 8a8833968..ce69738eb 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -774,6 +774,7 @@ slashem
774smplayer 774smplayer
775smtube 775smtube
776smuxi-frontend-gnome 776smuxi-frontend-gnome
777sniffnet
777snox 778snox
778soffice 779soffice
779sol 780sol
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c
index 458fb0dd1..e07776163 100644
--- a/src/firejail/netfilter.c
+++ b/src/firejail/netfilter.c
@@ -65,7 +65,7 @@ void netfilter_netlock(pid_t pid) {
65 umask(orig_umask); 65 umask(orig_umask);
66 66
67 char *cmd; 67 char *cmd;
68 if (asprintf(&cmd, "%s -e \"%s/firejail/fnettrace --tail --log=%s\"", terminal, LIBDIR, flog) == -1) 68 if (asprintf(&cmd, "%s -e \"%s/firejail/fnetlock --tail --log=%s\"", terminal, LIBDIR, flog) == -1)
69 errExit("asprintf"); 69 errExit("asprintf");
70 int rv = system(cmd); 70 int rv = system(cmd);
71 (void) rv; 71 (void) rv;
@@ -74,7 +74,7 @@ void netfilter_netlock(pid_t pid) {
74 } 74 }
75 75
76 char *cmd; 76 char *cmd;
77 if (asprintf(&cmd, "%s/firejail/fnettrace --netfilter --log=%s", LIBDIR, flog) == -1) 77 if (asprintf(&cmd, "%s/firejail/fnetlock --log=%s", LIBDIR, flog) == -1)
78 errExit("asprintf"); 78 errExit("asprintf");
79 free(flog); 79 free(flog);
80 80
diff --git a/src/fnetlock/Makefile b/src/fnetlock/Makefile
new file mode 100644
index 000000000..789df06ac
--- /dev/null
+++ b/src/fnetlock/Makefile
@@ -0,0 +1,9 @@
1.SUFFIXES:
2ROOT = ../..
3-include $(ROOT)/config.mk
4
5MOD_DIR = src/fnetlock
6PROG = fnetlock
7TARGET = $(PROG)
8
9include $(ROOT)/src/prog.mk
diff --git a/src/fnetlock/fnetlock.h b/src/fnetlock/fnetlock.h
new file mode 100644
index 000000000..018f58223
--- /dev/null
+++ b/src/fnetlock/fnetlock.h
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) 2014-2023 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#ifndef FNETLOCK_H
21#define FNETLOCK_H
22
23#include "../include/common.h"
24#include <unistd.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <netinet/in.h>
29#include <time.h>
30#include <stdarg.h>
31#include <fcntl.h>
32#include <sys/mman.h>
33
34
35//#define DEBUG 1
36
37#define NETLOCK_INTERVAL 60 // seconds
38
39static inline uint8_t hash(uint32_t ip) {
40 uint8_t *ptr = (uint8_t *) &ip;
41 // simple byte xor
42 return *ptr ^ *(ptr + 1) ^ *(ptr + 2) ^ *(ptr + 3);
43}
44
45// main.c
46void logprintf(char* fmt, ...);
47
48// tail.c
49void tail(const char *logfile);
50
51#endif
diff --git a/src/fnetlock/main.c b/src/fnetlock/main.c
new file mode 100644
index 000000000..d4169b7e1
--- /dev/null
+++ b/src/fnetlock/main.c
@@ -0,0 +1,394 @@
1/*
2 * Copyright (C) 2014-2023 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "fnetlock.h"
21#include <limits.h>
22#include <sys/ioctl.h>
23#include <sys/prctl.h>
24#include <signal.h>
25#define MAX_BUF_SIZE (64 * 1024)
26
27static int arg_tail = 0;
28static char *arg_log = NULL;
29
30//*****************************************************************
31// traffic trace storage - hash table for fast access + linked list for display purposes
32//*****************************************************************
33typedef struct hnode_t {
34 struct hnode_t *hnext; // used for hash table and unused linked list
35 struct hnode_t *dnext; // used to display streams on the screen
36 uint32_t ip_src;
37 uint16_t port_src;
38 uint8_t protocol;
39
40 // the firewall is build based on source address, and in the linked list
41 // we could have elements with the same address but different ports
42 uint8_t ip_instance;
43} HNode;
44
45// hash table
46#define HMAX 256
47HNode *htable[HMAX] = {NULL};
48static int have_traffic = 0;
49
50// using protocol 0 and port 0 for ICMP
51static void hnode_add(uint32_t ip_src, uint8_t protocol, uint16_t port_src) {
52 uint8_t h = hash(ip_src);
53 int ip_instance = 0;
54 HNode *ptr = htable[h];
55 while (ptr) {
56 if (ptr->ip_src == ip_src) {
57 ip_instance++;
58 if (ptr->port_src == port_src && ptr->protocol == protocol)
59 return;
60 }
61 ptr = ptr->hnext;
62 }
63
64 logprintf("netlock: adding %d.%d.%d.%d\n", PRINT_IP(ip_src));
65 have_traffic = 1;
66 HNode *hnew = malloc(sizeof(HNode));
67 assert(hnew);
68 hnew->ip_src = ip_src;
69 hnew->port_src = port_src;
70 hnew->protocol = protocol;
71 hnew->hnext = NULL;
72 hnew->ip_instance = ip_instance + 1;
73 if (htable[h] == NULL)
74 htable[h] = hnew;
75 else {
76 hnew->hnext = htable[h];
77 htable[h] = hnew;
78 }
79}
80
81
82
83
84// trace rx traffic coming in
85static void run_trace(void) {
86 logprintf("netlock: accumulating traffic for %d seconds\n", NETLOCK_INTERVAL);
87
88 // trace only rx ipv4 tcp and upd
89 int s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
90 int s2 = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
91 if (s1 < 0 || s2 < 0)
92 errExit("socket");
93
94
95 unsigned start = time(NULL);
96 unsigned char buf[MAX_BUF_SIZE];
97 // FIXME: error: variable 'bw' set but not used [-Werror,-Wunused-but-set-variable]
98 //unsigned bw = 0; // bandwidth calculations
99
100 int printed = 0;
101 while (1) {
102 unsigned runtime = time(NULL) - start;
103 if ( runtime >= NETLOCK_INTERVAL)
104 break;
105 if (runtime % 10 == 0) {
106 if (!printed)
107 logprintf("netlock: %u seconds remaining\n", NETLOCK_INTERVAL - runtime);
108 printed = 1;
109 }
110 else
111 printed = 0;
112
113 fd_set rfds;
114 FD_ZERO(&rfds);
115 FD_SET(s1, &rfds);
116 FD_SET(s2, &rfds);
117 int maxfd = (s1 > s2) ? s1 : s2;
118 maxfd++;
119
120 struct timeval tv;
121 tv.tv_sec = 1;
122 tv.tv_usec = 0;
123
124 int rv = select(maxfd, &rfds, NULL, NULL, &tv);
125 if (rv < 0)
126 errExit("select");
127 else if (rv == 0)
128 continue;
129
130
131 // rx tcp traffic by default
132 int sock = s1;
133
134 if (FD_ISSET(s2, &rfds))
135 sock = s2;
136
137 unsigned bytes = recvfrom(sock, buf, MAX_BUF_SIZE, 0, NULL, NULL);
138 if (bytes >= 20) { // size of IP header
139#ifdef DEBUG
140 {
141 uint32_t ip_src;
142 memcpy(&ip_src, buf + 12, 4);
143 ip_src = ntohl(ip_src);
144
145 uint32_t ip_dst;
146 memcpy(&ip_dst, buf + 16, 4);
147 ip_dst = ntohl(ip_dst);
148 printf("%d.%d.%d.%d -> %d.%d.%d.%d, %u bytes\n", PRINT_IP(ip_src), PRINT_IP(ip_dst), bytes);
149 }
150#endif
151 // filter out loopback traffic
152 if (buf[12] != 127 && buf[16] != 127) {
153 // FIXME: error: variable 'bw' set but not used [-Werror,-Wunused-but-set-variable]
154 //bw += bytes + 14; // assume a 14 byte Ethernet layer
155
156 uint32_t ip_src;
157 memcpy(&ip_src, buf + 12, 4);
158 ip_src = ntohl(ip_src);
159
160 uint8_t hlen = (buf[0] & 0x0f) * 4;
161 uint16_t port_src = 0;
162 memcpy(&port_src, buf + hlen, 2);
163 port_src = ntohs(port_src);
164
165 uint8_t protocol = buf[9];
166 hnode_add(ip_src, protocol, port_src);
167 }
168 }
169 }
170
171 close(s1);
172 close(s2);
173}
174
175static char *filter_start =
176 "*filter\n"
177 ":INPUT DROP [0:0]\n"
178 ":FORWARD DROP [0:0]\n"
179 ":OUTPUT DROP [0:0]\n";
180
181// return 1 if error
182static int print_filter(FILE *fp) {
183 fprintf(fp, "%s\n", filter_start);
184 fprintf(fp, "-A INPUT -s 127.0.0.0/8 -j ACCEPT\n");
185 fprintf(fp, "-A OUTPUT -d 127.0.0.0/8 -j ACCEPT\n");
186 fprintf(fp, "\n");
187
188 int i;
189 for (i = 0; i < HMAX; i++) {
190 HNode *ptr = htable[i];
191 while (ptr) {
192 // filter rules are targeting ip address, the port number is disregarded,
193 // so we look only at the first instance of an address
194 if (ptr->ip_instance == 1) {
195 char *protocol = (ptr->protocol == 6) ? "tcp" : "udp";
196 fprintf(fp, "-A INPUT -s %d.%d.%d.%d -p %s -j ACCEPT\n",
197 PRINT_IP(ptr->ip_src),
198 protocol);
199 fprintf(fp, "-A OUTPUT -d %d.%d.%d.%d -p %s -j ACCEPT\n",
200 PRINT_IP(ptr->ip_src),
201 protocol);
202 fprintf(fp, "\n");
203 }
204 ptr = ptr->hnext;
205 }
206 }
207 fprintf(fp, "COMMIT\n");
208
209 return 0;
210}
211
212static char *flush_rules[] = {
213 "-P INPUT ACCEPT",
214// "-P FORWARD DENY",
215 "-P OUTPUT ACCEPT",
216 "-F",
217 "-X",
218// "-t nat -F",
219// "-t nat -X",
220// "-t mangle -F",
221// "-t mangle -X",
222// "iptables -t raw -F",
223// "-t raw -X",
224 NULL
225};
226
227static void deploy_netfilter(void) {
228 int rv;
229 char *cmd;
230 int i;
231
232 if (have_traffic == 0) {
233 logprintf("Sorry, no network traffic was detected. The firewall was not configured.\n");
234 return;
235 }
236 // find iptables command
237 char *iptables = NULL;
238 char *iptables_restore = NULL;
239 if (access("/sbin/iptables", X_OK) == 0) {
240 iptables = "/sbin/iptables";
241 iptables_restore = "/sbin/iptables-restore";
242 }
243 else if (access("/usr/sbin/iptables", X_OK) == 0) {
244 iptables = "/usr/sbin/iptables";
245 iptables_restore = "/usr/sbin/iptables-restore";
246 }
247 if (iptables == NULL || iptables_restore == NULL) {
248 fprintf(stderr, "Error: iptables command not found, netfilter not configured\n");
249 exit(1);
250 }
251
252 // flush all netfilter rules
253 i = 0;
254 while (flush_rules[i]) {
255 char *cmd;
256 if (asprintf(&cmd, "%s %s", iptables, flush_rules[i]) == -1)
257 errExit("asprintf");
258 int rv = system(cmd);
259 (void) rv;
260 free(cmd);
261 i++;
262 }
263
264 // create temporary file
265 char fname[] = "/tmp/firejail-XXXXXX";
266 int fd = mkstemp(fname);
267 if (fd == -1) {
268 fprintf(stderr, "Error: cannot create temporary configuration file\n");
269 exit(1);
270 }
271
272 FILE *fp = fdopen(fd, "w");
273 if (!fp) {
274 rv = unlink(fname);
275 (void) rv;
276 fprintf(stderr, "Error: cannot create temporary configuration file\n");
277 exit(1);
278 }
279 print_filter(fp);
280 fclose(fp);
281
282 logprintf("\n\n");
283 logprintf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
284 if (asprintf(&cmd, "cat %s >> %s", fname, arg_log) == -1)
285 errExit("asprintf");
286 rv = system(cmd);
287 (void) rv;
288 free(cmd);
289
290 if (asprintf(&cmd, "cat %s", fname) == -1)
291 errExit("asprintf");
292 rv = system(cmd);
293 (void) rv;
294 free(cmd);
295 logprintf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
296
297
298 // configuring
299 if (asprintf(&cmd, "%s %s", iptables_restore, fname) == -1)
300 errExit("asprintf");
301 rv = system(cmd);
302 if (rv)
303 fprintf(stdout, "Warning: possible netfilter problem!");
304 free(cmd);
305
306 rv = unlink(fname);
307 (void) rv;
308 logprintf("\nnetlock: firewall deployed\n");
309}
310
311void logprintf(char *fmt, ...) {
312 if (!arg_log)
313 return;
314
315 FILE *fp = fopen(arg_log, "a");
316 if (fp) { // disregard if error
317 va_list args;
318 va_start(args, fmt);
319 vfprintf(fp, fmt, args);
320 va_end(args);
321 fclose(fp);
322 }
323
324 va_list args;
325 va_start(args, fmt);
326 vfprintf(stdout, fmt, args);
327 va_end(args);
328}
329
330static const char *const usage_str =
331 "Usage: fnettrace [OPTIONS]\n"
332 "Options:\n"
333 " --help, -? - this help screen\n"
334 " --log=filename - netlocker logfile\n"
335 " --tail - \"tail -f\" functionality\n";
336
337static void usage(void) {
338 puts(usage_str);
339}
340
341int main(int argc, char **argv) {
342 int i;
343
344 for (i = 1; i < argc; i++) {
345 if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-?") == 0) {
346 usage();
347 return 0;
348 }
349 else if (strcmp(argv[i], "--tail") == 0)
350 arg_tail = 1;
351 else if (strncmp(argv[i], "--log=", 6) == 0)
352 arg_log = argv[i] + 6;
353 else {
354 fprintf(stderr, "Error: invalid argument\n");
355 return 1;
356 }
357 }
358
359 // tail
360 if (arg_tail) {
361 if (!arg_log) {
362 fprintf(stderr, "Error: no log file\n");
363 usage();
364 exit(1);
365 }
366
367 tail(arg_log);
368 sleep(5);
369 exit(0);
370 }
371
372 if (getuid() != 0) {
373 fprintf(stderr, "Error: you need to be root to run this program\n");
374 return 1;
375 }
376
377 // kill the process if the parent died
378 prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
379
380 logprintf("netlock: starting network lockdown\n");
381 run_trace();
382
383 // TCP path MTU discovery will not work properly since the firewall drops all ICMP packets
384 // Instead, we use iPacketization Layer PMTUD (RFC 4821) support in Linux kernel
385 int rv = system("echo 1 > /proc/sys/net/ipv4/tcp_mtu_probing");
386 (void) rv;
387
388 deploy_netfilter();
389 sleep(3);
390 if (arg_log)
391 unlink(arg_log);
392
393 return 0;
394}
diff --git a/src/fnettrace/tail.c b/src/fnetlock/tail.c
index 3b1b274f8..e5d0367f6 100644
--- a/src/fnettrace/tail.c
+++ b/src/fnetlock/tail.c
@@ -17,7 +17,7 @@
17 * with this program; if not, write to the Free Software Foundation, Inc., 17 * with this program; if not, write to the Free Software Foundation, Inc.,
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 "fnetlock.h"
21 21
22void tail(const char *logfile) { 22void tail(const char *logfile) {
23 assert(logfile); 23 assert(logfile);
diff --git a/src/fnettrace-dns/main.c b/src/fnettrace-dns/main.c
index 1cde1942c..6324a17db 100644
--- a/src/fnettrace-dns/main.c
+++ b/src/fnettrace-dns/main.c
@@ -26,6 +26,7 @@
26#include <signal.h> 26#include <signal.h>
27#define MAX_BUF_SIZE (64 * 1024) 27#define MAX_BUF_SIZE (64 * 1024)
28 28
29static int arg_nolocal = 0;
29static char last[512] = {'\0'}; 30static char last[512] = {'\0'};
30 31
31// pkt - start of DNS layer 32// pkt - start of DNS layer
@@ -116,7 +117,7 @@ static void print_date(void) {
116 struct tm *t = localtime(&now); 117 struct tm *t = localtime(&now);
117 118
118 if (day != t->tm_yday) { 119 if (day != t->tm_yday) {
119 printf("\nDNS trace for %s", ctime(&now)); 120 printf("DNS trace for %s", ctime(&now));
120 day = t->tm_yday; 121 day = t->tm_yday;
121 } 122 }
122 fflush(0); 123 fflush(0);
@@ -159,6 +160,14 @@ static void run_trace(void) {
159 memcpy(&ip_src, buf + 14 + 12, 4); 160 memcpy(&ip_src, buf + 14 + 12, 4);
160 ip_src = ntohl(ip_src); 161 ip_src = ntohl(ip_src);
161 162
163 if (arg_nolocal) {
164 if ((ip_src & 0xff000000) == 0x7f000000 || // 127.0.0.0/8
165 (ip_src & 0xff000000) == 0x0a000000 || // 10.0.0.0/8
166 (ip_src & 0xffff0000) == 0xc0a80000 || // 192.168.0.0/16
167 (ip_src & 0xfff00000) == 0xac100000) // 172.16.0.0/12
168 continue;
169 }
170
162 // if DNS packet, extract the query 171 // if DNS packet, extract the query
163 if (port_src == 53 && protocol == 0x11) // UDP protocol 172 if (port_src == 53 && protocol == 0x11) // UDP protocol
164 print_dns(ip_src, buf + 14 + ip_hlen + 8); // IP and UDP header len 173 print_dns(ip_src, buf + 14 + ip_hlen + 8); // IP and UDP header len
@@ -170,7 +179,8 @@ static void run_trace(void) {
170static const char *const usage_str = 179static const char *const usage_str =
171 "Usage: fnettrace-dns [OPTIONS]\n" 180 "Usage: fnettrace-dns [OPTIONS]\n"
172 "Options:\n" 181 "Options:\n"
173 " --help, -? - this help screen\n"; 182 " --help, -? - this help screen\n"
183 " --nolocal\n";
174 184
175static void usage(void) { 185static void usage(void) {
176 puts(usage_str); 186 puts(usage_str);
@@ -184,6 +194,8 @@ int main(int argc, char **argv) {
184 usage(); 194 usage();
185 return 0; 195 return 0;
186 } 196 }
197 else if (strcmp(argv[i], "--nolocal") == 0)
198 arg_nolocal = 1;
187 else { 199 else {
188 fprintf(stderr, "Error: invalid argument\n"); 200 fprintf(stderr, "Error: invalid argument\n");
189 return 1; 201 return 1;
diff --git a/src/fnettrace-sni/main.c b/src/fnettrace-sni/main.c
index e7782d656..d4fbf703a 100644
--- a/src/fnettrace-sni/main.c
+++ b/src/fnettrace-sni/main.c
@@ -152,7 +152,7 @@ static void print_date(void) {
152 struct tm *t = localtime(&now); 152 struct tm *t = localtime(&now);
153 153
154 if (day != t->tm_yday) { 154 if (day != t->tm_yday) {
155 printf("\nSNI trace for %s", ctime(&now)); 155 printf("SNI trace for %s", ctime(&now));
156 day = t->tm_yday; 156 day = t->tm_yday;
157 } 157 }
158 158
diff --git a/src/fnettrace/fnettrace.h b/src/fnettrace/fnettrace.h
index b1a2f5b6c..b4a8f26c7 100644
--- a/src/fnettrace/fnettrace.h
+++ b/src/fnettrace/fnettrace.h
@@ -75,4 +75,7 @@ void terminal_handler(int s);
75void terminal_set(void); 75void terminal_set(void);
76void terminal_restore(void); 76void terminal_restore(void);
77 77
78// runprog.c
79int runprog(const char *program);
80
78#endif 81#endif
diff --git a/src/fnettrace/main.c b/src/fnettrace/main.c
index 932afff61..3bafd9090 100644
--- a/src/fnettrace/main.c
+++ b/src/fnettrace/main.c
@@ -25,15 +25,63 @@
25#include <signal.h> 25#include <signal.h>
26#define MAX_BUF_SIZE (64 * 1024) 26#define MAX_BUF_SIZE (64 * 1024)
27 27
28static int arg_netfilter = 0;
29static int arg_tail = 0;
30static char *arg_log = NULL; 28static char *arg_log = NULL;
31 29
30//*****************************************************************
31// packet stats
32//*****************************************************************
32uint32_t stats_pkts = 0; 33uint32_t stats_pkts = 0;
33uint32_t stats_icmp = 0; 34uint32_t stats_icmp_echo = 0;
34uint32_t stats_dns = 0; 35uint32_t stats_dns = 0;
36uint32_t stats_dns_dot = 0;
37uint32_t stats_dns_doh = 0;
38uint32_t stats_dns_doq = 0;
39uint32_t stats_tls = 0;
40uint32_t stats_quic = 0;
41uint32_t stats_tor = 0;
42uint32_t stats_http = 0;
43uint32_t stats_ssh = 0;
44
45//*****************************************************************
46// sni/dns log storage
47//*****************************************************************
48typedef struct lognode_t {
49#define LOG_RECORD_LEN 255
50 char record[LOG_RECORD_LEN + 1];
51} LogNode;
52// circular list of SNI log records
53#define SNIMAX 64
54LogNode sni_table[SNIMAX] = {0};
55int sni_index = 0;
56
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}
35 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}
36 81
82//*****************************************************************
83// traffic trace storage - hash table for fast access + linked list for display purposes
84//*****************************************************************
37typedef struct hnode_t { 85typedef struct hnode_t {
38 struct hnode_t *hnext; // used for hash table and unused linked list 86 struct hnode_t *hnext; // used for hash table and unused linked list
39 struct hnode_t *dnext; // used to display streams on the screen 87 struct hnode_t *dnext; // used to display streams on the screen
@@ -42,6 +90,7 @@ typedef struct hnode_t {
42 90
43 // stats 91 // stats
44 uint32_t bytes; // number of bytes received in the last display interval 92 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
45 uint16_t port_src; 94 uint16_t port_src;
46 uint8_t protocol; 95 uint8_t protocol;
47 96
@@ -97,6 +146,7 @@ static void hnode_add(uint32_t ip_src, uint8_t protocol, uint16_t port_src, uint
97 ip_instance++; 146 ip_instance++;
98 if (ptr->port_src == port_src && ptr->protocol == protocol) { 147 if (ptr->port_src == port_src && ptr->protocol == protocol) {
99 ptr->bytes += bytes; 148 ptr->bytes += bytes;
149 ptr->pkts++;
100 assert(ptr->rnode); 150 assert(ptr->rnode);
101 ptr->rnode->pkts++; 151 ptr->rnode->pkts++;
102 return; 152 return;
@@ -115,6 +165,7 @@ static void hnode_add(uint32_t ip_src, uint8_t protocol, uint16_t port_src, uint
115 hnew->protocol = protocol; 165 hnew->protocol = protocol;
116 hnew->hnext = NULL; 166 hnew->hnext = NULL;
117 hnew->bytes = bytes; 167 hnew->bytes = bytes;
168 hnew->pkts = 1;
118 hnew->ip_instance = ip_instance + 1; 169 hnew->ip_instance = ip_instance + 1;
119 hnew->ttl = DISPLAY_TTL; 170 hnew->ttl = DISPLAY_TTL;
120 if (htable[h] == NULL) 171 if (htable[h] == NULL)
@@ -139,9 +190,6 @@ static void hnode_add(uint32_t ip_src, uint8_t protocol, uint16_t port_src, uint
139 if (!hnew->rnode) 190 if (!hnew->rnode)
140 hnew->rnode = radix_add(hnew->ip_src, 0xffffffff, NULL); 191 hnew->rnode = radix_add(hnew->ip_src, 0xffffffff, NULL);
141 hnew->rnode->pkts++; 192 hnew->rnode->pkts++;
142
143 if (arg_netfilter)
144 logprintf(" %d.%d.%d.%d ", PRINT_IP(hnew->ip_src));
145} 193}
146 194
147static void hnode_free(HNode *elem) { 195static void hnode_free(HNode *elem) {
@@ -242,23 +290,23 @@ typedef struct port_type_t {
242 char *service; 290 char *service;
243} PortType; 291} PortType;
244static PortType ports[] = { 292static PortType ports[] = {
245 {20, "(FTP)"}, 293 {20, "FTP"},
246 {21, "(FTP)"}, 294 {21, "FTP"},
247 {22, "(SSH)"}, 295 {22, "SSH"},
248 {23, "(telnet)"}, 296 {23, "telnet"},
249 {25, "(SMTP)"}, 297 {25, "SMTP"},
250 {43, "(WHOIS)"}, 298 {43, "WHOIS"},
251 {67, "(DHCP)"}, 299 {67, "DHCP"},
252 {68, "(DHCP)"}, 300 {68, "DHCP"},
253 {69, "(TFTP)"}, 301 {69, "TFTP"},
254 {80, "(HTTP)"}, 302 {80, "HTTP"},
255 {109, "(POP2)"}, 303 {109, "POP2"},
256 {110, "(POP3)"}, 304 {110, "POP3"},
257 {113, "(IRC)"}, 305 {113, "IRC"},
258 {123, "(NTP)"}, 306 {123, "NTP"},
259 {161, "(SNMP)"}, 307 {161, "SNMP"},
260 {162, "(SNMP)"}, 308 {162, "SNMP"},
261 {194, "(IRC)"}, 309 {194, "IRC"},
262 {0, NULL}, 310 {0, NULL},
263}; 311};
264 312
@@ -266,32 +314,32 @@ static PortType ports[] = {
266static inline const char *common_port(uint16_t port) { 314static inline const char *common_port(uint16_t port) {
267 if (port >= 6660 && port <= 10162) { 315 if (port >= 6660 && port <= 10162) {
268 if (port >= 6660 && port <= 6669) 316 if (port >= 6660 && port <= 6669)
269 return "(IRC)"; 317 return "IRC";
270 else if (port == 6679) 318 else if (port == 6679)
271 return "(IRC)"; 319 return "IRC";
272 else if (port == 6771) 320 else if (port == 6771)
273 return "(BitTorrent)"; 321 return "BitTorrent";
274 else if (port >= 6881 && port <= 6999) 322 else if (port >= 6881 && port <= 6999)
275 return "(BitTorrent)"; 323 return "BitTorrent";
276 else if (port == 9001) 324 else if (port == 9001)
277 return "(Tor)"; 325 return "Tor";
278 else if (port == 9030) 326 else if (port == 9030)
279 return "(Tor)"; 327 return "Tor";
280 else if (port == 9050) 328 else if (port == 9050)
281 return "(Tor)"; 329 return "Tor";
282 else if (port == 9051) 330 else if (port == 9051)
283 return "(Tor)"; 331 return "Tor";
284 else if (port == 9150) 332 else if (port == 9150)
285 return "(Tor)"; 333 return "Tor";
286 else if (port == 10161) 334 else if (port == 10161)
287 return "(secure SNMP)"; 335 return "secure SNMP";
288 else if (port == 10162) 336 else if (port == 10162)
289 return "(secure SNMP)"; 337 return "secure SNMP";
290 return NULL; 338 return NULL;
291 } 339 }
292 340
293 if (port <= 194) { 341 if (port <= 194) {
294 PortType *ptr =&ports[0]; 342 PortType *ptr = &ports[0];
295 while(ptr->service != NULL) { 343 while(ptr->service != NULL) {
296 if (ptr->port == port) 344 if (ptr->port == port)
297 return ptr->service; 345 return ptr->service;
@@ -305,7 +353,6 @@ static inline const char *common_port(uint16_t port) {
305 353
306 354
307static void hnode_print(unsigned bw) { 355static void hnode_print(unsigned bw) {
308 assert(!arg_netfilter);
309 bw = (bw < 1024 * DISPLAY_INTERVAL) ? 1024 * DISPLAY_INTERVAL : bw; 356 bw = (bw < 1024 * DISPLAY_INTERVAL) ? 1024 * DISPLAY_INTERVAL : bw;
310#ifdef DEBUG 357#ifdef DEBUG
311 printf("*********************\n"); 358 printf("*********************\n");
@@ -336,7 +383,7 @@ static void hnode_print(unsigned bw) {
336 else 383 else
337 sprintf(stats, "%u KB/s ", bw / (1024 * DISPLAY_INTERVAL)); 384 sprintf(stats, "%u KB/s ", bw / (1024 * DISPLAY_INTERVAL));
338// int len = snprintf(line, LINE_MAX, "%32s geoip %d, IP database %d\n", stats, geoip_calls, radix_nodes); 385// int len = snprintf(line, LINE_MAX, "%32s geoip %d, IP database %d\n", stats, geoip_calls, radix_nodes);
339 int len = snprintf(line, LINE_MAX, "%32s address:port (protocol) network (packets)\n", stats); 386 int len = snprintf(line, LINE_MAX, "%32s address:port (protocol) network\n", stats);
340 adjust_line(line, len, cols); 387 adjust_line(line, len, cols);
341 printf("%s", line); 388 printf("%s", line);
342 389
@@ -369,47 +416,67 @@ static void hnode_print(unsigned bw) {
369 bwline = print_bw(ptr->bytes / bwunit); 416 bwline = print_bw(ptr->bytes / bwunit);
370 417
371 const char *protocol = NULL; 418 const char *protocol = NULL;
372 if (ptr->port_src == 443 && ptr->protocol == 0x06) // TCP 419 if (ptr->port_src == 443 && ptr->protocol == 0x06) { // TCP
373 protocol = "(TLS)"; 420 protocol = "TLS";
374 else if (ptr->port_src == 443 && ptr->protocol == 0x11) // UDP 421 stats_tls += ptr->pkts;
375 protocol = "(QUIC)"; 422 if (strstr(ptr->rnode->name, "DNS")) {
376 else if (ptr->port_src == 53) 423 protocol = "DoH";
377 protocol = "(DNS)"; 424 stats_dns_doh += ptr->pkts;
425 }
426
427 }
428 else if (ptr->port_src == 443 && ptr->protocol == 0x11) { // UDP
429 protocol = "QUIC";
430 stats_quic += ptr->pkts;
431 if (strstr(ptr->rnode->name, "DNS")) {
432 protocol = "DoQ";
433 stats_dns_doq += ptr->pkts;
434 }
435 }
436 else if (ptr->port_src == 53) {
437 protocol = "DNS";
438 stats_dns += ptr->pkts;
439 }
378 else if (ptr->port_src == 853) { 440 else if (ptr->port_src == 853) {
379 if (ptr->protocol == 0x06) 441 if (ptr->protocol == 0x06) {
380 protocol = "(DoT)"; 442 protocol = "DoT";
381 else if (ptr->protocol == 0x11) 443 stats_dns_dot += ptr->pkts;
382 protocol = "(DoQ)"; 444 }
445 else if (ptr->protocol == 0x11) {
446 protocol = "DoQ";
447 stats_dns_doq += ptr->pkts;
448 }
383 else 449 else
384 protocol = NULL; 450 protocol = NULL;
385 } 451 }
386 else if ((protocol = common_port(ptr->port_src)) != NULL) 452 else if ((protocol = common_port(ptr->port_src)) != NULL) {
387 ; 453 if (strcmp(protocol, "HTTP") == 0)
454 stats_http += ptr->pkts;
455 else if (strcmp(protocol, "Tor") == 0)
456 stats_tor += ptr->pkts;
457 else if (strcmp(protocol, "SSH") == 0)
458 stats_ssh += ptr->pkts;
459 }
388 else if (ptr->protocol == 0x11) 460 else if (ptr->protocol == 0x11)
389 protocol = "(UDP)"; 461 protocol = "UDP";
390 else if (ptr->protocol == 0x06) 462 else if (ptr->protocol == 0x06)
391 protocol = "(TCP)"; 463 protocol = "TCP";
392 464
393 if (protocol == NULL) 465 if (protocol == NULL)
394 protocol = ""; 466 protocol = "";
395 if (ptr->port_src == 0) 467 if (ptr->port_src == 0)
396 len = snprintf(line, LINE_MAX, "%10s %s %d.%d.%d.%d (ICMP) %s\n", 468 len = snprintf(line, LINE_MAX, "%10s %s %d.%d.%d.%d (ICMP) %s\n",
397 bytes, bwline, PRINT_IP(ptr->ip_src), ptr->rnode->name); 469 bytes, bwline, PRINT_IP(ptr->ip_src), ptr->rnode->name);
398 else if (ptr->rnode->pkts > 1000000)
399 len = snprintf(line, LINE_MAX, "%10s %s %d.%d.%d.%d:%u%s %s (%.01fM)\n",
400 bytes, bwline, PRINT_IP(ptr->ip_src), ptr->port_src, protocol, ptr->rnode->name, ((double) ptr->rnode->pkts) / 1000000);
401 else if (ptr->rnode->pkts > 1000)
402 len = snprintf(line, LINE_MAX, "%10s %s %d.%d.%d.%d:%u%s %s (%.01fK)\n",
403 bytes, bwline, PRINT_IP(ptr->ip_src), ptr->port_src, protocol, ptr->rnode->name, ((double) ptr->rnode->pkts) / 1000);
404 else 470 else
405 len = snprintf(line, LINE_MAX, "%10s %s %d.%d.%d.%d:%u%s %s (%u)\n", 471 len = snprintf(line, LINE_MAX, "%10s %s %d.%d.%d.%d:%u (%s) %s\n",
406 bytes, bwline, PRINT_IP(ptr->ip_src), ptr->port_src, protocol, ptr->rnode->name, ptr->rnode->pkts); 472 bytes, bwline, PRINT_IP(ptr->ip_src), ptr->port_src, protocol, ptr->rnode->name);
407 adjust_line(line, len, cols); 473 adjust_line(line, len, cols);
408 printf("%s", line); 474 printf("%s", line);
409 475
410 if (ptr->bytes) 476 if (ptr->bytes)
411 ptr->ttl = DISPLAY_TTL; 477 ptr->ttl = DISPLAY_TTL;
412 ptr->bytes = 0; 478 ptr->bytes = 0;
479 ptr->pkts = 0;
413 prev = ptr; 480 prev = ptr;
414 } 481 }
415 else { 482 else {
@@ -440,17 +507,10 @@ static void hnode_print(unsigned bw) {
440 507
441 508
442void print_stats(void) { 509void print_stats(void) {
443 printf("\nIP table: %d entries, %d unknown\n", radix_nodes, geoip_calls);
444 printf(" address network (packets)\n");
445 radix_print(1);
446 printf("Packets: %u total, ICMP %u, DNS %u\n", stats_pkts, stats_icmp, stats_dns);
447} 510}
448 511
449// trace rx traffic coming in 512// trace rx traffic coming in
450static void run_trace(void) { 513static void run_trace(void) {
451 if (arg_netfilter)
452 logprintf("accumulating traffic for %d seconds\n", NETLOCK_INTERVAL);
453
454 // trace only rx ipv4 tcp and upd 514 // trace only rx ipv4 tcp and upd
455 int s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); 515 int s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
456 int s2 = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); 516 int s2 = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
@@ -458,37 +518,45 @@ static void run_trace(void) {
458 if (s1 < 0 || s2 < 0 || s3 < 0) 518 if (s1 < 0 || s2 < 0 || s3 < 0)
459 errExit("socket"); 519 errExit("socket");
460 520
461 unsigned start = time(NULL); 521
522 int p1 = runprog(LIBDIR "/firejail/fnettrace-sni");
523 if (p1 != -1)
524 printf("loading snitrace...");
525
526 int p2 = runprog(LIBDIR "/firejail/fnettrace-dns --nolocal");
527 if (p2 != -1)
528 printf("loading dnstrace...");
462 unsigned last_print_traces = 0; 529 unsigned last_print_traces = 0;
463 unsigned last_print_remaining = 0;
464 unsigned char buf[MAX_BUF_SIZE]; 530 unsigned char buf[MAX_BUF_SIZE];
465 unsigned bw = 0; // bandwidth calculations 531 unsigned bw = 0; // bandwidth calculations
466 532
467 while (1) { 533 while (1) {
468 unsigned end = time(NULL); 534 unsigned end = time(NULL);
469 if (arg_netfilter && end - start >= NETLOCK_INTERVAL)
470 break;
471 if (end % DISPLAY_INTERVAL == 1 && last_print_traces != end) { // first print after 1 second 535 if (end % DISPLAY_INTERVAL == 1 && last_print_traces != end) { // first print after 1 second
472 if (!arg_netfilter) 536 hnode_print(bw);
473 hnode_print(bw);
474 last_print_traces = end; 537 last_print_traces = end;
475 bw = 0; 538 bw = 0;
476 } 539 }
477 if (arg_netfilter && last_print_remaining != end) {
478 logprintf(".");
479 fflush(0);
480 last_print_remaining = end;
481 }
482 540
483 fd_set rfds; 541 fd_set rfds;
484 FD_ZERO(&rfds); 542 FD_ZERO(&rfds);
543 FD_SET(0, &rfds);
544
485 FD_SET(s1, &rfds); 545 FD_SET(s1, &rfds);
486 FD_SET(s2, &rfds); 546 FD_SET(s2, &rfds);
487 FD_SET(s3, &rfds); 547 FD_SET(s3, &rfds);
488 if (!arg_netfilter)
489 FD_SET(0, &rfds);
490 int maxfd = (s1 > s2) ? s1 : s2; 548 int maxfd = (s1 > s2) ? s1 : s2;
491 maxfd = (s3 > maxfd) ? s3 : maxfd; 549 maxfd = (s3 > maxfd) ? s3 : maxfd;
550
551 if (p1 != -1) {
552 FD_SET(p1, &rfds);
553 maxfd = (p1 > maxfd) ? p1 : maxfd;
554 }
555
556 if (p2 != -1) {
557 FD_SET(p2, &rfds);
558 maxfd = (p2 > maxfd) ? p2 : maxfd;
559 }
492 maxfd++; 560 maxfd++;
493 561
494 struct timeval tv; 562 struct timeval tv;
@@ -508,10 +576,78 @@ static void run_trace(void) {
508 576
509 if (FD_ISSET(0, &rfds)) { 577 if (FD_ISSET(0, &rfds)) {
510 getchar(); 578 getchar();
511 print_stats(); 579 printf("\n\nStats: %u packets\n", stats_pkts);
580 printf(" encrypted: TLS %u, QUIC %u, SSH %u, Tor %u\n",
581 stats_tls, stats_quic, stats_ssh, stats_tor);
582 printf(" unencrypted: HTTP %u\n", stats_http);
583 printf(" C&C backchannel: PING %u, DNS %u, DoH %u, DoT %u, DoQ %u\n",
584 stats_icmp_echo, stats_dns, stats_dns_doh, stats_dns_dot, stats_dns_doq);
585 printf("press any key to continue...");
586 fflush(0);
587
588 getchar();
589 printf("\n\nSNI log - time server-address SNI\n");
590 print_sni();
512 printf("press any key to continue..."); 591 printf("press any key to continue...");
513 fflush(0); 592 fflush(0);
593
594 getchar();
595 printf("\n\nDNS log - time server-address domain\n");
596 print_dns();
597 printf("press any key to continue...");
598 fflush(0);
599
514 getchar(); 600 getchar();
601 printf("\n\nIP table: %d addresses - server-address network (packets)\n", radix_nodes);
602 radix_print(1);
603 printf("press any key to continue...");
604 fflush(0);
605
606 getchar();
607 continue;
608 }
609 else if (FD_ISSET(p1, &rfds)) {
610 char buf[1024];
611 ssize_t sz = read(p1, buf, 1024 - 1);
612 if (sz == -1)
613 errExit("error reading snitrace");
614 if (sz == 0) {
615 fprintf(stderr, "Error: snitrace EOF!!!\n");
616 p1 = -1;
617 }
618 if (strncmp(buf, "SNI trace", 9) == 0)
619 continue;
620
621 if (sz > LOG_RECORD_LEN)
622 sz = LOG_RECORD_LEN;
623 buf[sz] = '\0';
624 strcpy(sni_table[sni_index].record, buf);
625 if (++sni_index >= SNIMAX) {
626 sni_index = 0;
627 *sni_table[sni_index].record = '\0';
628 }
629 continue;
630 }
631 else if (FD_ISSET(p2, &rfds)) {
632 char buf[1024];
633 ssize_t sz = read(p2, buf, 1024 - 1);
634 if (sz == -1)
635 errExit("error reading dnstrace");
636 if (sz == 0) {
637 fprintf(stderr, "Error: dnstrace EOF!!!\n");
638 p2 = -1;
639 }
640 if (strncmp(buf, "DNS trace", 9) == 0)
641 continue;
642
643 if (sz > LOG_RECORD_LEN)
644 sz = LOG_RECORD_LEN;
645 buf[sz] = '\0';
646 strcpy(dns_table[dns_index].record, buf);
647 if (++dns_index >= DNSMAX) {
648 dns_index = 0;
649 *dns_table[dns_index].record = '\0';
650 }
515 continue; 651 continue;
516 } 652 }
517 else if (FD_ISSET(s2, &rfds)) 653 else if (FD_ISSET(s2, &rfds))
@@ -557,10 +693,10 @@ static void run_trace(void) {
557 693
558 // stats 694 // stats
559 stats_pkts++; 695 stats_pkts++;
560 if (icmp) 696 if (icmp) {
561 stats_icmp++; 697 if (*(buf + hlen) == 0 || *(buf + hlen) == 8)
562 if (port_src == 53) 698 stats_icmp_echo++;
563 stats_dns++; 699 }
564 700
565 } 701 }
566 } 702 }
@@ -572,142 +708,6 @@ static void run_trace(void) {
572 print_stats(); 708 print_stats();
573} 709}
574 710
575static char *filter_start =
576 "*filter\n"
577 ":INPUT DROP [0:0]\n"
578 ":FORWARD DROP [0:0]\n"
579 ":OUTPUT DROP [0:0]\n";
580
581// return 1 if error
582static int print_filter(FILE *fp) {
583 if (dlist == NULL)
584 return 1;
585 fprintf(fp, "%s\n", filter_start);
586 fprintf(fp, "-A INPUT -s 127.0.0.0/8 -j ACCEPT\n");
587 fprintf(fp, "-A OUTPUT -d 127.0.0.0/8 -j ACCEPT\n");
588 fprintf(fp, "\n");
589
590 int i;
591 for (i = 0; i < HMAX; i++) {
592 HNode *ptr = htable[i];
593 while (ptr) {
594 // filter rules are targeting ip address, the port number is disregarded,
595 // so we look only at the first instance of an address
596 if (ptr->ip_instance == 1) {
597 char *protocol = (ptr->protocol == 6) ? "tcp" : "udp";
598 fprintf(fp, "-A INPUT -s %d.%d.%d.%d -p %s -j ACCEPT\n",
599 PRINT_IP(ptr->ip_src),
600 protocol);
601 fprintf(fp, "-A OUTPUT -d %d.%d.%d.%d -p %s -j ACCEPT\n",
602 PRINT_IP(ptr->ip_src),
603 protocol);
604 fprintf(fp, "\n");
605 }
606 ptr = ptr->hnext;
607 }
608 }
609 fprintf(fp, "COMMIT\n");
610
611 return 0;
612}
613
614static char *flush_rules[] = {
615 "-P INPUT ACCEPT",
616// "-P FORWARD DENY",
617 "-P OUTPUT ACCEPT",
618 "-F",
619 "-X",
620// "-t nat -F",
621// "-t nat -X",
622// "-t mangle -F",
623// "-t mangle -X",
624// "iptables -t raw -F",
625// "-t raw -X",
626 NULL
627};
628
629static void deploy_netfilter(void) {
630 int rv;
631 char *cmd;
632 int i;
633
634 if (dlist == NULL) {
635 logprintf("Sorry, no network traffic was detected. The firewall was not configured.\n");
636 return;
637 }
638 // find iptables command
639 char *iptables = NULL;
640 char *iptables_restore = NULL;
641 if (access("/sbin/iptables", X_OK) == 0) {
642 iptables = "/sbin/iptables";
643 iptables_restore = "/sbin/iptables-restore";
644 }
645 else if (access("/usr/sbin/iptables", X_OK) == 0) {
646 iptables = "/usr/sbin/iptables";
647 iptables_restore = "/usr/sbin/iptables-restore";
648 }
649 if (iptables == NULL || iptables_restore == NULL) {
650 fprintf(stderr, "Error: iptables command not found, netfilter not configured\n");
651 exit(1);
652 }
653
654 // flush all netfilter rules
655 i = 0;
656 while (flush_rules[i]) {
657 char *cmd;
658 if (asprintf(&cmd, "%s %s", iptables, flush_rules[i]) == -1)
659 errExit("asprintf");
660 int rv = system(cmd);
661 (void) rv;
662 free(cmd);
663 i++;
664 }
665
666 // create temporary file
667 char fname[] = "/tmp/firejail-XXXXXX";
668 int fd = mkstemp(fname);
669 if (fd == -1) {
670 fprintf(stderr, "Error: cannot create temporary configuration file\n");
671 exit(1);
672 }
673
674 FILE *fp = fdopen(fd, "w");
675 if (!fp) {
676 rv = unlink(fname);
677 (void) rv;
678 fprintf(stderr, "Error: cannot create temporary configuration file\n");
679 exit(1);
680 }
681 print_filter(fp);
682 fclose(fp);
683
684 logprintf("\n\n");
685 logprintf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
686 if (asprintf(&cmd, "cat %s >> %s", fname, arg_log) == -1)
687 errExit("asprintf");
688 rv = system(cmd);
689 (void) rv;
690 free(cmd);
691
692 if (asprintf(&cmd, "cat %s", fname) == -1)
693 errExit("asprintf");
694 rv = system(cmd);
695 (void) rv;
696 free(cmd);
697 logprintf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
698
699 // configuring
700 if (asprintf(&cmd, "%s %s", iptables_restore, fname) == -1)
701 errExit("asprintf");
702 rv = system(cmd);
703 if (rv)
704 fprintf(stdout, "Warning: possible netfilter problem!");
705 free(cmd);
706
707 rv = unlink(fname);
708 (void) rv;
709 logprintf("\nfirewall deployed\n");
710}
711 711
712void logprintf(char *fmt, ...) { 712void logprintf(char *fmt, ...) {
713 if (!arg_log) 713 if (!arg_log)
@@ -733,14 +733,8 @@ static const char *const usage_str =
733 "Options:\n" 733 "Options:\n"
734 " --help, -? - this help screen\n" 734 " --help, -? - this help screen\n"
735 " --log=filename - netlocker logfile\n" 735 " --log=filename - netlocker logfile\n"
736 " --netfilter - build the firewall rules and commit them\n"
737 " --print-map - print IP map\n" 736 " --print-map - print IP map\n"
738 " --squash-map - compress IP map\n" 737 " --squash-map - compress IP map\n";
739 " --tail - \"tail -f\" functionality\n"
740 "Examples:\n"
741 " # fnettrace - traffic trace\n"
742 " # fnettrace --netfilter --log=logfile - netlocker, dump output in logfile\n"
743 " # fnettrace --tail --log=logifile - similar to \"tail -f logfile\"\n";
744 738
745static void usage(void) { 739static void usage(void) {
746 puts(usage_str); 740 puts(usage_str);
@@ -775,7 +769,7 @@ int main(int argc, char **argv) {
775 return 0; 769 return 0;
776 } 770 }
777 else if (strncmp(argv[i], "--squash-map=", 13) == 0) { 771 else if (strncmp(argv[i], "--squash-map=", 13) == 0) {
778 if (i !=(argc - 1)) { 772 if (i != (argc - 1)) {
779 fprintf(stderr, "Error: please provide a map file\n"); 773 fprintf(stderr, "Error: please provide a map file\n");
780 return 1; 774 return 1;
781 } 775 }
@@ -798,10 +792,6 @@ int main(int argc, char **argv) {
798 fprintf(stderr, "static ip map: input %d, output %d\n", in, radix_nodes); 792 fprintf(stderr, "static ip map: input %d, output %d\n", in, radix_nodes);
799 return 0; 793 return 0;
800 } 794 }
801 else if (strcmp(argv[i], "--netfilter") == 0)
802 arg_netfilter = 1;
803 else if (strcmp(argv[i], "--tail") == 0)
804 arg_tail = 1;
805 else if (strncmp(argv[i], "--log=", 6) == 0) 795 else if (strncmp(argv[i], "--log=", 6) == 0)
806 arg_log = argv[i] + 6; 796 arg_log = argv[i] + 6;
807 else { 797 else {
@@ -810,19 +800,6 @@ int main(int argc, char **argv) {
810 } 800 }
811 } 801 }
812 802
813 // tail
814 if (arg_tail) {
815 if (!arg_log) {
816 fprintf(stderr, "Error: no log file\n");
817 usage();
818 exit(1);
819 }
820
821 tail(arg_log);
822 sleep(5);
823 exit(0);
824 }
825
826 if (getuid() != 0) { 803 if (getuid() != 0) {
827 fprintf(stderr, "Error: you need to be root to run this program\n"); 804 fprintf(stderr, "Error: you need to be root to run this program\n");
828 return 1; 805 return 1;
@@ -838,25 +815,10 @@ int main(int argc, char **argv) {
838 prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); 815 prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
839 816
840 ansi_clrscr(); 817 ansi_clrscr();
841 if (arg_netfilter) 818 char *fname = LIBDIR "/firejail/static-ip-map";
842 logprintf("starting network lockdown\n"); 819 load_hostnames(fname);
843 else {
844 char *fname = LIBDIR "/firejail/static-ip-map";
845 load_hostnames(fname);
846 }
847 820
848 run_trace(); 821 run_trace();
849 if (arg_netfilter) {
850 // TCP path MTU discovery will not work properly since the firewall drops all ICMP packets
851 // Instead, we use iPacketization Layer PMTUD (RFC 4821) support in Linux kernel
852 int rv = system("echo 1 > /proc/sys/net/ipv4/tcp_mtu_probing");
853 (void) rv;
854
855 deploy_netfilter();
856 sleep(3);
857 if (arg_log)
858 unlink(arg_log);
859 }
860 822
861 return 0; 823 return 0;
862} 824}
diff --git a/src/fnettrace/runprog.c b/src/fnettrace/runprog.c
new file mode 100644
index 000000000..e30d8a16c
--- /dev/null
+++ b/src/fnettrace/runprog.c
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2014-2023 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "fnettrace.h"
21
22int runprog(const char *program) {
23 assert(program);
24 FILE *fp = popen(program, "r");
25 if (!fp) {
26 fprintf(stderr, "Error: cannot run %s\n", program);
27 return -1;
28 }
29
30 return fileno(fp);
31}
diff --git a/src/fnettrace/static-ip-map.txt b/src/fnettrace/static-ip-map.txt
index 756658562..59ec79f8f 100644
--- a/src/fnettrace/static-ip-map.txt
+++ b/src/fnettrace/static-ip-map.txt
@@ -38,14 +38,19 @@
38# 38#
39 39
40 40
41# local network addresses 41# local network addresses (based on https://en.wikipedia.org/wiki/Reserved_IP_addresses)
42192.168.0.0/16 local network 4210.0.0.0/8 Local network
4310.0.0.0/8 local network 43100.64.0.0/10 Carrier-grade NAT
44172.16.0.0/16 local network 44127.0.0.0/8 Local host
45169.254.0.0/16 local link 45169.254.0.0/16 Local link
46172.16.0.0/12 Local network
47192.0.2.0/24 Documentation
48192.168.0.0/16 Local network
49198.51.100.0/24 Documentation
50203.0.113.0/24 Documentation
46 51
47# multicast 52# multicast
48224.0.0.0/4 multicast 53224.0.0.0/4 Multicast
49224.0.0.9/32 RIPv2 54224.0.0.9/32 RIPv2
50224.0.0.5/32 OSPF 55224.0.0.5/32 OSPF
51224.0.0.6/32 OSPF 56224.0.0.6/32 OSPF
@@ -86,15 +91,40 @@
864.2.2.4/32 Level3 DNS 914.2.2.4/32 Level3 DNS
878.8.4.0/24 Google DNS 928.8.4.0/24 Google DNS
888.8.8.0/24 Google DNS 938.8.8.0/24 Google DNS
948.20.247.20/32 Comodo DNS
958.26.56.26/32 Comodo DNS
899.9.9.0/24 Quad9 DNS 969.9.9.0/24 Quad9 DNS
9045.90.28.0/22 NextDNS 9745.90.28.0/22 NextDNS
9845.11.45.0/24 DNS-SB
9964.6.64.6/32 Neustar DNS
10064.6.65.6/32 Neustar DNS
10174.82.42.42/32 Hurricane Electric DNS
10276.76.2.0/24 ControlD DNS
10376.76.10.0/24 ControlD DNS
10476.76.19.0/24 Alternate DNS
10576.223.122.150/32 Alternate DNS
10677.88.8.8/32 Yandex DNS
10777.88.8.1/32 Yandex DNS
10880.80.80.0/24 Freenom DNS Cloud
10980.80.81.0/24 Freenom DNS Cloud
11084.200.69.80/32 DSN Watch
11184.200.70.40/32 DNS Watch
9194.140.14.0/23 Adguard DNS 11294.140.14.0/23 Adguard DNS
92149.112.112.0/24 Quad9 DNS 113149.112.112.0/24 Quad9 DNS
93149.112.120.0/21 CIRA DNS Canada 114149.112.120.0/21 CIRA DNS Canada
94146.255.56.96/29 Applied Privacy 115146.255.56.96/29 Applied Privacy DNS
95176.103.128.0/19 Adguard DNS 116176.103.128.0/19 Adguard DNS
117185.222.222.0/24 DNS-SB
96185.228.168.0/24 Cleanbrowsing DNS 118185.228.168.0/24 Cleanbrowsing DNS
119185.236.104.0/24 FlashStart DNS
120185.236.105.0/24 FlashStart DNS
121185.253.5.0/24 NextDNS
122193.110.81.0/24 NextDNS
123205.171.3.66/32 CentyrLink DNS
124205.171.202.166/32 CentyrLink DNS
97208.67.216.0/21 OpenDNS 125208.67.216.0/21 OpenDNS
126216.146.35.35/32 Dyn DNS
127216.146.36.36/32 Dyn DNS
98 128
99# whois 129# whois
100192.0.32.0/20 ICANN 130192.0.32.0/20 ICANN
@@ -106,13 +136,15 @@
106199.212.0.0/24 whois.arin.net US 136199.212.0.0/24 whois.arin.net US
107200.3.12.0/22 whois.lacnic.net Uruguay 137200.3.12.0/22 whois.lacnic.net Uruguay
108201.159.220.0/22 whois.lacnic.net Ecuador 138201.159.220.0/22 whois.lacnic.net Ecuador
139203.119.100.0/22 apnic.net Australia
109 140
110# some popular websites 141# some popular websites
1115.255.255.0/24 Yandex 1425.255.255.0/24 Yandex
11223.160.0.0/24 Twitch 14323.160.0.0/24 Twitch
14423.229.128.0/17 GoDaddy
11323.246.0.0/18 Netflix 14523.246.0.0/18 Netflix
11431.13.24.0/21 Facebook 14631.13.24.0/21 Facebook
11531.13.64.0/18 Facebook 14731.13.64.0/17 Facebook
11637.77.184.0/21 Netflix 14837.77.184.0/21 Netflix
11745.57.0.0/17 Netflix 14945.57.0.0/17 Netflix
11845.58.64.0/20 Dropbox 15045.58.64.0/20 Dropbox
@@ -132,9 +164,14 @@
13266.211.168.0/22 PayPal 16466.211.168.0/22 PayPal
13366.211.172.0/22 eBay 16566.211.172.0/22 eBay
13466.211.176.0/20 eBay 16666.211.176.0/20 eBay
16766.218.64.0/19 Yahoo
13566.220.144.0/20 Facebook 16866.220.144.0/20 Facebook
16969.30.200.200/29 BitChute
13669.53.224.0/19 Netflix 17069.53.224.0/19 Netflix
13769.171.224.0/19 Facebook 17169.171.224.0/19 Facebook
17269.197.182.184/29 BitChute
17374.6.0.0/16 Yahoo
17474.91.29.208/29 BitChute
13887.250.254.0/24 Yandex 17587.250.254.0/24 Yandex
13991.105.192.0/23 Telegram 17691.105.192.0/23 Telegram
14091.108.4.0/22 Telegram 17791.108.4.0/22 Telegram
@@ -147,14 +184,21 @@
14791.189.94.0/24 Ubuntu One 18491.189.94.0/24 Ubuntu One
14895.161.64.0/20 Telegram 18595.161.64.0/20 Telegram
14999.181.64.0/18 Twitch 18699.181.64.0/18 Twitch
150103.53.48.0/23 Twitch 18769.197.138.24/29 BitChute
151104.244.40.0/21 Twitter
152103.10.124.0/23 Steam 188103.10.124.0/23 Steam
153103.28.54.0/24 Steam 189103.28.54.0/24 Steam
190103.53.48.0/23 Twitch
191104.244.40.0/21 Twitter
192107.150.32.0/19 BitChute
193107.150.35.192/29 BitChute
194107.150.45.120/29 BitChute
154108.160.160.0/20 Dropbox 195108.160.160.0/20 Dropbox
155108.175.32.0/20 Netflix 196108.175.32.0/20 Netflix
156129.134.0.0/16 Facebook 197129.134.0.0/16 Facebook
157140.82.112.0/20 GitHub 198140.82.112.0/20 GitHub
199142.54.180.104/29 BitChute
200142.54.181.184/29 BitChute
201142.54.189.192/29 BitChute
158143.55.64.0/20 Github 202143.55.64.0/20 Github
159146.66.152.0/24 Steam 203146.66.152.0/24 Steam
160146.66.155.0/24 Steam 204146.66.155.0/24 Steam
@@ -174,6 +218,10 @@
174162.213.32.0/22 Ubuntu One 218162.213.32.0/22 Ubuntu One
175162.254.192.0/21 Steam 219162.254.192.0/21 Steam
176172.98.56.0/22 Rumble 220172.98.56.0/22 Rumble
221173.208.154.8/29 BitChute
222173.208.154.160/29 BitChute
223173.208.185.200/29 BitChute
224173.208.219.112/29 BitChute
177178.154.131.0/24 Yandex 225178.154.131.0/24 Yandex
178185.2.220.0/22 Netflix 226185.2.220.0/22 Netflix
179185.9.188.0/22 Netflix 227185.9.188.0/22 Netflix
@@ -194,23 +242,33 @@
194192.30.252.0/22 GitHub 242192.30.252.0/22 GitHub
195192.69.96.0/22 Steam 243192.69.96.0/22 Steam
196192.108.239.0/24 Twitch 244192.108.239.0/24 Twitch
245192.151.158.136/29 BitChute
197192.173.64.0/18 Netflix 246192.173.64.0/18 Netflix
247192.187.97.88/29 BitChute
248192.187.114.96/29 BitChute
249192.187.123.112/29 BitChute
198192.189.200.0/23 Dropbox 250192.189.200.0/23 Dropbox
199194.169.254.0/24 Ubuntu One 251194.169.254.0/24 Ubuntu One
200198.38.96.0/19 Netflix 252198.38.96.0/19 Netflix
201198.45.48.0/20 Netflix 253198.45.48.0/20 Netflix
254198.204.226.120/29 BitChute
255198.204.245.88/29 BitChute
256198.252.206.0/24 Stack Exchange
202199.9.248.0/21 Twitch 257199.9.248.0/21 Twitch
203199.16.156.0/22 Twitter 258199.16.156.0/22 Twitter
204199.59.148.0/22 Twitter 259199.59.148.0/22 Twitter
205199.168.96.24/29 BitChute 260199.168.96.24/29 BitChute
261204.12.194.176/29 BitChute
206205.185.194.0/24 Steam 262205.185.194.0/24 Steam
207205.196.6.0/24 Steam 263205.196.6.0/24 Steam
208207.45.72.0/22 Netflix 264207.45.72.0/22 Netflix
209207.241.224.0/20 Internet Archive 265207.241.224.0/20 Internet Archive
266208.82.236.0/22 Creiglist
210208.64.200.0/22 Steam 267208.64.200.0/22 Steam
211208.75.76.0/22 Netflix 268208.75.76.0/22 Netflix
212208.78.164.0/22 Steam 269208.78.164.0/22 Steam
213208.80.152.0/22 Wikipedia 270208.80.152.0/22 Wikipedia
271208.110.68.56/29 BitChute
214209.140.128.0/18 eBay 272209.140.128.0/18 eBay
215 273
216# Imperva 274# Imperva
@@ -261,15 +319,6 @@
261205.224.0.0/14 Level 3 319205.224.0.0/14 Level 3
262209.244.0.0/14 Level 3 320209.244.0.0/14 Level 3
263 321
264# WholeSale Internet
26569.30.192.0/18 WholeSale Internet
26669.197.128.0/18 WholeSale Internet
267173.208.128.0/17 WholeSale Internet
268204.12.192.0/18 WholeSale Internet
269208.67.0.0/21 WholeSale Internet
270208.110.64.0/19 WholeSale Internet
271208.110.91.0/24 WholeSale Internet
272
273# StackPath 322# StackPath
27469.16.173.0/24 StackPath 32369.16.173.0/24 StackPath
27569.16.174.0/23 StackPath 32469.16.174.0/23 StackPath
@@ -279,6 +328,7 @@
279205.185.196.0/23 StackPath 328205.185.196.0/23 StackPath
280205.185.198.0/24 StackPath 329205.185.198.0/24 StackPath
281205.185.200.0/21 StackPath 330205.185.200.0/21 StackPath
331205.185.208.0/24 StackPath
282205.185.212.0/23 StackPath 332205.185.212.0/23 StackPath
283205.185.215.0/24 StackPath 333205.185.215.0/24 StackPath
284205.185.216.0/23 StackPath 334205.185.216.0/23 StackPath
@@ -299,6 +349,8 @@
299205.185.220.0/24 StackPath 349205.185.220.0/24 StackPath
300 350
301# Linode 351# Linode
35245.79.0.0/16 Linode
35350.116.0.0/18 Linode
30266.175.208.0/20 Linode 35466.175.208.0/20 Linode
303103.29.68.0/22 Linode 355103.29.68.0/22 Linode
304104.200.16.0/21 Linode 356104.200.16.0/21 Linode
@@ -397,6 +449,7 @@
397172.105.0.0/19 Linode 449172.105.0.0/19 Linode
398172.105.112.0/20 Linode 450172.105.112.0/20 Linode
399172.105.128.0/23 Linode 451172.105.128.0/23 Linode
452173.255.192.0/18 Linode
400 453
401# Akamai 454# Akamai
4022.16.0.0/13 Akamai 4552.16.0.0/13 Akamai
@@ -576,7 +629,7 @@
576103.21.244.0/22 Cloudflare 629103.21.244.0/22 Cloudflare
577103.22.200.0/22 Cloudflare 630103.22.200.0/22 Cloudflare
578103.31.4.0/22 Cloudflare 631103.31.4.0/22 Cloudflare
579104.16.0.0/13 Cloudflare 632104.16.0.0/12 Cloudflare
580104.24.0.0/14 Cloudflare 633104.24.0.0/14 Cloudflare
581108.162.192.0/18 Cloudflare 634108.162.192.0/18 Cloudflare
582131.0.72.0/22 Cloudflare 635131.0.72.0/22 Cloudflare
@@ -684,6 +737,7 @@
6843.136.0.0/13 Amazon 7373.136.0.0/13 Amazon
6853.144.0.0/13 Amazon 7383.144.0.0/13 Amazon
6863.152.0.0/13 Amazon 7393.152.0.0/13 Amazon
7403.160.0.0/14 Amazon
6873.208.0.0/12 Amazon 7413.208.0.0/12 Amazon
6883.224.0.0/12 Amazon 7423.224.0.0/12 Amazon
6893.240.0.0/13 Amazon 7433.240.0.0/13 Amazon