diff options
author | 2022-10-24 08:35:01 -0400 | |
---|---|---|
committer | 2022-10-24 08:35:01 -0400 | |
commit | 729b1251cd1783a0bc72a96ebc5aba455ccb375f (patch) | |
tree | 4abb82b3883dc4d1ce5261815f7e53fd8bc4cc3c /src/fnettrace-icmp | |
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/fnettrace-icmp')
-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 |
3 files changed, 266 insertions, 0 deletions
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 | } | ||