diff options
author | netblue30 <netblue30@protonmail.com> | 2022-10-24 08:35:01 -0400 |
---|---|---|
committer | netblue30 <netblue30@protonmail.com> | 2022-10-24 08:35:01 -0400 |
commit | 729b1251cd1783a0bc72a96ebc5aba455ccb375f (patch) | |
tree | 4abb82b3883dc4d1ce5261815f7e53fd8bc4cc3c /src | |
parent | Merge pull request #5431 from netblue30/musl_warnings (diff) | |
download | firejail-729b1251cd1783a0bc72a96ebc5aba455ccb375f.tar.gz firejail-729b1251cd1783a0bc72a96ebc5aba455ccb375f.tar.zst firejail-729b1251cd1783a0bc72a96ebc5aba455ccb375f.zip |
--icmptrace
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/main.c | 38 | ||||
-rw-r--r-- | src/fnettrace-icmp/Makefile | 17 | ||||
-rw-r--r-- | src/fnettrace-icmp/fnettrace_icmp.h | 34 | ||||
-rw-r--r-- | src/fnettrace-icmp/main.c | 215 | ||||
-rw-r--r-- | src/man/firejail.txt | 40 |
5 files changed, 337 insertions, 7 deletions
diff --git a/src/firejail/main.c b/src/firejail/main.c index fe80c5e2e..ed5b4901b 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -450,13 +450,13 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
450 | exit_err_feature("networking"); | 450 | exit_err_feature("networking"); |
451 | exit(0); | 451 | exit(0); |
452 | } | 452 | } |
453 | else if (strncmp(argv[i], "--dnstrace=", 15) == 0) { | 453 | else if (strncmp(argv[i], "--dnstrace=", 11) == 0) { |
454 | if (checkcfg(CFG_NETWORK)) { | 454 | if (checkcfg(CFG_NETWORK)) { |
455 | if (getuid() != 0) { | 455 | if (getuid() != 0) { |
456 | fprintf(stderr, "Error: --dnstrace is only available to root user\n"); | 456 | fprintf(stderr, "Error: --dnstrace is only available to root user\n"); |
457 | exit(1); | 457 | exit(1); |
458 | } | 458 | } |
459 | pid_t pid = require_pid(argv[i] + 15); | 459 | pid_t pid = require_pid(argv[i] + 11); |
460 | netfilter_trace(pid, LIBDIR "/firejail/fnettrace-dns"); | 460 | netfilter_trace(pid, LIBDIR "/firejail/fnettrace-dns"); |
461 | } | 461 | } |
462 | else | 462 | else |
@@ -475,19 +475,49 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
475 | exit_err_feature("networking"); | 475 | exit_err_feature("networking"); |
476 | exit(0); | 476 | exit(0); |
477 | } | 477 | } |
478 | else if (strncmp(argv[i], "--snitrace=", 15) == 0) { | 478 | else if (strncmp(argv[i], "--snitrace=", 11) == 0) { |
479 | if (checkcfg(CFG_NETWORK)) { | 479 | if (checkcfg(CFG_NETWORK)) { |
480 | if (getuid() != 0) { | 480 | if (getuid() != 0) { |
481 | fprintf(stderr, "Error: --snitrace is only available to root user\n"); | 481 | fprintf(stderr, "Error: --snitrace is only available to root user\n"); |
482 | exit(1); | 482 | exit(1); |
483 | } | 483 | } |
484 | pid_t pid = require_pid(argv[i] + 15); | 484 | pid_t pid = require_pid(argv[i] + 11); |
485 | netfilter_trace(pid, LIBDIR "/firejail/fnettrace-sni"); | 485 | netfilter_trace(pid, LIBDIR "/firejail/fnettrace-sni"); |
486 | } | 486 | } |
487 | else | 487 | else |
488 | exit_err_feature("networking"); | 488 | exit_err_feature("networking"); |
489 | exit(0); | 489 | exit(0); |
490 | } | 490 | } |
491 | |||
492 | |||
493 | else if (strcmp(argv[i], "--icmptrace") == 0) { | ||
494 | if (checkcfg(CFG_NETWORK)) { | ||
495 | if (getuid() != 0) { | ||
496 | fprintf(stderr, "Error: --icmptrace is only available to root user\n"); | ||
497 | exit(1); | ||
498 | } | ||
499 | netfilter_trace(0, LIBDIR "/firejail/fnettrace-icmp"); | ||
500 | } | ||
501 | else | ||
502 | exit_err_feature("networking"); | ||
503 | exit(0); | ||
504 | } | ||
505 | else if (strncmp(argv[i], "--icmptrace=", 12) == 0) { | ||
506 | if (checkcfg(CFG_NETWORK)) { | ||
507 | if (getuid() != 0) { | ||
508 | fprintf(stderr, "Error: -icmptrace is only available to root user\n"); | ||
509 | exit(1); | ||
510 | } | ||
511 | pid_t pid = require_pid(argv[i] + 12); | ||
512 | netfilter_trace(pid, LIBDIR "/firejail/fnettrace-icmp"); | ||
513 | } | ||
514 | else | ||
515 | exit_err_feature("networking"); | ||
516 | exit(0); | ||
517 | } | ||
518 | |||
519 | |||
520 | |||
491 | else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { | 521 | else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { |
492 | if (checkcfg(CFG_NETWORK)) { | 522 | if (checkcfg(CFG_NETWORK)) { |
493 | logargs(argc, argv); | 523 | logargs(argc, argv); |
diff --git a/src/fnettrace-icmp/Makefile b/src/fnettrace-icmp/Makefile new file mode 100644 index 000000000..4dfdc891a --- /dev/null +++ b/src/fnettrace-icmp/Makefile | |||
@@ -0,0 +1,17 @@ | |||
1 | .PHONY: all | ||
2 | all: fnettrace-icmp | ||
3 | |||
4 | ROOT = ../.. | ||
5 | include $(ROOT)/src/common.mk | ||
6 | |||
7 | %.o : %.c $(H_FILE_LIST) $(ROOT)/config.mk | ||
8 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | ||
9 | |||
10 | fnettrace-icmp: $(OBJS) $(ROOT)/config.mk | ||
11 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) | ||
12 | |||
13 | .PHONY: clean | ||
14 | clean:; rm -fr *.o fnettrace-icmp *.gcov *.gcda *.gcno *.plist | ||
15 | |||
16 | .PHONY: distclean | ||
17 | distclean: clean | ||
diff --git a/src/fnettrace-icmp/fnettrace_icmp.h b/src/fnettrace-icmp/fnettrace_icmp.h new file mode 100644 index 000000000..790a3ce7f --- /dev/null +++ b/src/fnettrace-icmp/fnettrace_icmp.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 FNETTRACE_SNI_H | ||
21 | #define FNETTRACE_SNI_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 | #endif \ No newline at end of file | ||
diff --git a/src/fnettrace-icmp/main.c b/src/fnettrace-icmp/main.c new file mode 100644 index 000000000..47d61a326 --- /dev/null +++ b/src/fnettrace-icmp/main.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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_icmp.h" | ||
21 | #include <sys/ioctl.h> | ||
22 | #include <time.h> | ||
23 | #include <linux/filter.h> | ||
24 | #include <linux/if_ether.h> | ||
25 | #define MAX_BUF_SIZE (64 * 1024) | ||
26 | |||
27 | char *type_description[19] = { | ||
28 | "Echo reply", | ||
29 | "unassigned", | ||
30 | "unassigned", | ||
31 | "Destination unreachable", | ||
32 | "Source quench", | ||
33 | "Redirect message", | ||
34 | "unassigned", | ||
35 | "unassigned", | ||
36 | "Echo request", | ||
37 | "Router advertisement", | ||
38 | "Router solicitation" | ||
39 | "Time exceeded", | ||
40 | "Bad IP header", | ||
41 | "Timestamp", | ||
42 | "Timestamp replay", | ||
43 | "Information request", | ||
44 | "Information reply", | ||
45 | "Address mask request", | ||
46 | "Address mask reply" | ||
47 | }; | ||
48 | |||
49 | char *code_dest_unreachable[16] = { | ||
50 | "Network unreachable", | ||
51 | "Host unreachable", | ||
52 | "Protocol unreachable", | ||
53 | "Port unreachable", | ||
54 | "Fragmentation required, and DF flag set", | ||
55 | "Source route failed", | ||
56 | "Network unknown", | ||
57 | "Host unknown", | ||
58 | "Source host isolated", | ||
59 | "Network administratively prohibited", | ||
60 | "Host administratively prohibited", | ||
61 | "Network unreachable for ToS", | ||
62 | "Host unreachable for ToS", | ||
63 | "Communication administratively prohibited", | ||
64 | "Host Precedence Violation", | ||
65 | "Precedence cutoff in effect " | ||
66 | }; | ||
67 | |||
68 | char *code_redirect_message[4] = { | ||
69 | "Datagram for the Network", | ||
70 | "Datagram for the Host", | ||
71 | "Datagram for the ToS & network", | ||
72 | "Datagram for the ToS & host " | ||
73 | }; | ||
74 | |||
75 | char *code_time_exceeded[2] = { | ||
76 | "TTL expired in transit", | ||
77 | "Fragment reassembly time exceeded " | ||
78 | }; | ||
79 | |||
80 | char *code_bad_ip_header[3] = { | ||
81 | "Pointer indicates the error", | ||
82 | "Missing a required option", | ||
83 | "Bad length" | ||
84 | }; | ||
85 | |||
86 | static void print_icmp(uint32_t ip_dest, uint32_t ip_src, uint8_t type, uint8_t code, unsigned icmp_bytes) { | ||
87 | char type_number[10]; | ||
88 | char *type_ptr = type_number; | ||
89 | if (type < 19) | ||
90 | type_ptr = type_description[type]; | ||
91 | else | ||
92 | sprintf(type_number, "%u", type); | ||
93 | |||
94 | char code_number[10]; | ||
95 | char *code_ptr = code_number; | ||
96 | if (type ==3 && code < 16) | ||
97 | code_ptr = code_dest_unreachable[code]; | ||
98 | else if (type == 5 && code < 4) | ||
99 | code_ptr = code_redirect_message[code]; | ||
100 | else if (type == 11 && code < 2) | ||
101 | code_ptr = code_time_exceeded[code]; | ||
102 | else if (type == 12 && code < 3) | ||
103 | code_ptr = code_bad_ip_header[code]; | ||
104 | else | ||
105 | sprintf(code_number, "%u", code); | ||
106 | |||
107 | time_t seconds = time(NULL); | ||
108 | struct tm *t = localtime(&seconds); | ||
109 | printf("%02d:%02d:%02d %d.%d.%d.%d -> %d.%d.%d.%d - %u bytes - %s/%s\n", | ||
110 | t->tm_hour, t->tm_min, t->tm_sec, | ||
111 | PRINT_IP(ip_src), | ||
112 | PRINT_IP(ip_dest), | ||
113 | icmp_bytes, | ||
114 | type_ptr, | ||
115 | code_ptr); | ||
116 | } | ||
117 | |||
118 | // https://www.kernel.org/doc/html/latest/networking/filter.html | ||
119 | static void custom_bpf(int sock) { | ||
120 | struct sock_filter code[] = { | ||
121 | // sudo tcpdump "icmp" -dd | ||
122 | { 0x28, 0, 0, 0x0000000c }, | ||
123 | { 0x15, 0, 3, 0x00000800 }, | ||
124 | { 0x30, 0, 0, 0x00000017 }, | ||
125 | { 0x15, 0, 1, 0x00000001 }, | ||
126 | { 0x6, 0, 0, 0x00040000 }, | ||
127 | { 0x6, 0, 0, 0x00000000 }, | ||
128 | }; | ||
129 | |||
130 | struct sock_fprog bpf = { | ||
131 | .len = (unsigned short) sizeof(code) / sizeof(code[0]), | ||
132 | .filter = code, | ||
133 | }; | ||
134 | |||
135 | int rv = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); | ||
136 | if (rv < 0) { | ||
137 | fprintf(stderr, "Error: cannot attach BPF filter\n"); | ||
138 | exit(1); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static void run_trace(void) { | ||
143 | // grab all Ethernet packets and use a custom BPF filter to get TLS/SNI packets | ||
144 | int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); | ||
145 | if (s < 0) | ||
146 | errExit("socket"); | ||
147 | custom_bpf(s); | ||
148 | |||
149 | unsigned char buf[MAX_BUF_SIZE]; | ||
150 | while (1) { | ||
151 | fd_set rfds; | ||
152 | FD_ZERO(&rfds); | ||
153 | FD_SET(s, &rfds); | ||
154 | struct timeval tv; | ||
155 | tv.tv_sec = 1; | ||
156 | tv.tv_usec = 0; | ||
157 | int rv = select(s + 1, &rfds, NULL, NULL, &tv); | ||
158 | if (rv < 0) | ||
159 | errExit("select"); | ||
160 | else if (rv == 0) | ||
161 | continue; | ||
162 | unsigned bytes = recvfrom(s, buf, MAX_BUF_SIZE, 0, NULL, NULL); | ||
163 | |||
164 | if (bytes >= (14 + 20 + 2)) { // size of MAC + IP + ICMP code and type fields | ||
165 | uint8_t ip_hlen = (buf[14] & 0x0f) * 4; | ||
166 | uint8_t type = *(buf + 14 +ip_hlen); | ||
167 | uint8_t code = *(buf + 14 + ip_hlen + 1); | ||
168 | |||
169 | uint32_t ip_dest; | ||
170 | memcpy(&ip_dest, buf + 14 + 16, 4); | ||
171 | ip_dest = ntohl(ip_dest); | ||
172 | uint32_t ip_src; | ||
173 | memcpy(&ip_src, buf + 14 + 12, 4); | ||
174 | ip_src = ntohl(ip_src); | ||
175 | |||
176 | print_icmp(ip_dest, ip_src, type, code, bytes); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | close(s); | ||
181 | } | ||
182 | |||
183 | |||
184 | static void usage(void) { | ||
185 | printf("Usage: fnettrace-icmp [OPTIONS]\n"); | ||
186 | printf("Options:\n"); | ||
187 | printf(" --help, -? - this help screen\n"); | ||
188 | printf("\n"); | ||
189 | } | ||
190 | |||
191 | int main(int argc, char **argv) { | ||
192 | int i; | ||
193 | |||
194 | for (i = 1; i < argc; i++) { | ||
195 | if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-?") == 0) { | ||
196 | usage(); | ||
197 | return 0; | ||
198 | } | ||
199 | else { | ||
200 | fprintf(stderr, "Error: invalid argument\n"); | ||
201 | return 1; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | if (getuid() != 0) { | ||
206 | fprintf(stderr, "Error: you need to be root to run this program\n"); | ||
207 | return 1; | ||
208 | } | ||
209 | |||
210 | time_t now = time(NULL); | ||
211 | printf("ICMP trace for %s\n", ctime(&now)); | ||
212 | run_trace(); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index a7e418981..b4be1cd62 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -791,7 +791,9 @@ Without a name/pid, Firejail will monitor the main system network namespace. | |||
791 | .br | 791 | .br |
792 | 792 | ||
793 | .br | 793 | .br |
794 | $ sudo firejail --dnstrace=browser | 794 | Example: |
795 | .br | ||
796 | $ sudo firejail --dnstrace | ||
795 | .br | 797 | .br |
796 | 11:31:43 9.9.9.9 linux.com (type 1) | 798 | 11:31:43 9.9.9.9 linux.com (type 1) |
797 | .br | 799 | .br |
@@ -917,6 +919,34 @@ $ firejail --ignore=seccomp --ignore=caps firefox | |||
917 | $ firejail \-\-ignore="net eth0" firefox | 919 | $ firejail \-\-ignore="net eth0" firefox |
918 | #endif | 920 | #endif |
919 | 921 | ||
922 | #ifdef HAVE_NETWORK | ||
923 | .TP | ||
924 | \fB\-\-icmptrace[=name|pid] | ||
925 | Monitor ICMP traffic. The sandbox can be specified by name or pid. Only networked sandboxes | ||
926 | created with \-\-net are supported. This option is only available when running the sandbox as root. | ||
927 | .br | ||
928 | |||
929 | .br | ||
930 | Without a name/pid, Firejail will monitor the main system network namespace. | ||
931 | .br | ||
932 | |||
933 | .br | ||
934 | Example | ||
935 | .br | ||
936 | $ sudo firejail --icmptrace | ||
937 | .br | ||
938 | 20:53:54 192.168.1.60 -> 142.250.65.174 - 98 bytes - Echo request/0 | ||
939 | .br | ||
940 | 20:53:54 142.250.65.174 -> 192.168.1.60 - 98 bytes - Echo reply/0 | ||
941 | .br | ||
942 | 20:53:55 192.168.1.60 -> 142.250.65.174 - 98 bytes - Echo request/0 | ||
943 | .br | ||
944 | 20:53:55 142.250.65.174 -> 192.168.1.60 - 98 bytes - Echo reply/0 | ||
945 | .br | ||
946 | 20:53:55 192.168.1.60 -> 1.1.1.1 - 154 bytes - Destination unreachable/Port unreachable | ||
947 | .br | ||
948 | #endif | ||
949 | |||
920 | .TP | 950 | .TP |
921 | \fB\-\-\include=file.profile | 951 | \fB\-\-\include=file.profile |
922 | Include a profile file before the regular profiles are used. | 952 | Include a profile file before the regular profiles are used. |
@@ -1597,7 +1627,9 @@ Without a name/pid, Firejail will monitor the main system network namespace. | |||
1597 | .br | 1627 | .br |
1598 | 1628 | ||
1599 | .br | 1629 | .br |
1600 | $ sudo firejail --nettrace=browser | 1630 | Example: |
1631 | .br | ||
1632 | $ sudo firejail --nettrace | ||
1601 | .br | 1633 | .br |
1602 | 95 KB/s geoip 457, IP database 4436 | 1634 | 95 KB/s geoip 457, IP database 4436 |
1603 | .br | 1635 | .br |
@@ -2791,7 +2823,9 @@ Without a name/pid, Firejail will monitor the main system network namespace. | |||
2791 | .br | 2823 | .br |
2792 | 2824 | ||
2793 | .br | 2825 | .br |
2794 | $ sudo firejail --snitrace=browser | 2826 | Example: |
2827 | .br | ||
2828 | $ sudo firejail --snitrace | ||
2795 | .br | 2829 | .br |
2796 | 07:49:51 23.185.0.3 linux.com | 2830 | 07:49:51 23.185.0.3 linux.com |
2797 | .br | 2831 | .br |