aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/arp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/arp.c')
-rw-r--r--src/firejail/arp.c474
1 files changed, 474 insertions, 0 deletions
diff --git a/src/firejail/arp.c b/src/firejail/arp.c
new file mode 100644
index 000000000..37f8716e7
--- /dev/null
+++ b/src/firejail/arp.c
@@ -0,0 +1,474 @@
1/*
2 * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com)
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 "firejail.h"
21#include <sys/socket.h>
22#include <sys/ioctl.h>
23#include <linux/if_ether.h> //TCP/IP Protocol Suite for Linux
24#include <net/if.h>
25#include <netinet/in.h>
26#include <linux/ip.h>
27#include <linux/udp.h>
28#include <linux/tcp.h>
29#include <linux/if_packet.h>
30
31typedef struct arp_hdr_t {
32 uint16_t htype;
33 uint16_t ptype;
34 uint8_t hlen;
35 uint8_t plen;
36 uint16_t opcode;
37 uint8_t sender_mac[6];
38 uint8_t sender_ip[4];
39 uint8_t target_mac[6];
40 uint8_t target_ip[4];
41} ArpHdr;
42
43// returns 0 if the address is not in use, -1 otherwise
44int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) {
45 if (strlen(dev) > IFNAMSIZ) {
46 fprintf(stderr, "Error: invalid network device name %s\n", dev);
47 exit(1);
48 }
49
50 if (arg_debug)
51 printf("Trying %d.%d.%d.%d ...\n", PRINT_IP(destaddr));
52
53 // find interface address
54 int sock;
55 if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
56 errExit("socket");
57
58 srcaddr = htonl(srcaddr);
59 destaddr = htonl(destaddr);
60
61 // Find interface MAC address
62 struct ifreq ifr;
63 memset(&ifr, 0, sizeof (ifr));
64 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
65 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
66 errExit("ioctl");
67 close(sock);
68
69 // configure layer2 socket address information
70 struct sockaddr_ll addr;
71 memset(&addr, 0, sizeof(addr));
72 if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
73 errExit("if_nametoindex");
74 addr.sll_family = AF_PACKET;
75 memcpy (addr.sll_addr, ifr.ifr_hwaddr.sa_data, 6);
76 addr.sll_halen = htons(6);
77
78 // build the arp packet header
79 ArpHdr hdr;
80 memset(&hdr, 0, sizeof(hdr));
81 hdr.htype = htons(1);
82 hdr.ptype = htons(ETH_P_IP);
83 hdr.hlen = 6;
84 hdr.plen = 4;
85 hdr.opcode = htons(1); //ARPOP_REQUEST
86 memcpy(hdr.sender_mac, ifr.ifr_hwaddr.sa_data, 6);
87 memcpy(hdr.sender_ip, (uint8_t *)&srcaddr, 4);
88 memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4);
89
90 // buiild ethernet frame
91 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
92 memset(frame, 0, sizeof(frame));
93 frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
94 memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6);
95 frame[12] = ETH_P_ARP / 256;
96 frame[13] = ETH_P_ARP % 256;
97 memcpy (frame + 14, &hdr, sizeof(hdr));
98
99 // open layer2 socket
100 if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
101 errExit("socket");
102
103 int len;
104 if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
105 errExit("send");
106 fflush(0);
107
108 // wait not more than one second for an answer
109 fd_set fds;
110 FD_ZERO(&fds);
111 FD_SET(sock, &fds);
112 int maxfd = sock;
113 struct timeval ts;
114 ts.tv_sec = 1; // 1 second wait time
115 ts.tv_usec = 0;
116 while (1) {
117 int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts);
118 if (nready < 0)
119 errExit("select");
120 else if (nready == 0) { // timeout
121 close(sock);
122 return 0;
123 }
124 else {
125 // read the incoming packet
126 int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL);
127 if (len < 0) {
128 perror("recvfrom");
129 close(sock);
130 return -1;
131 }
132
133 // parse the incomming packet
134 if (len < 14 + sizeof(ArpHdr))
135 continue;
136 if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256))
137 continue;
138 memcpy(&hdr, frame + 14, sizeof(ArpHdr));
139 if (hdr.opcode == htons(1))
140 continue;
141 if (hdr.opcode == htons(2)) {
142 // check my mac and my address
143 if (memcmp(ifr.ifr_hwaddr.sa_data, hdr.target_mac, 6) != 0)
144 continue;
145 uint32_t ip;
146 memcpy(&ip, hdr.target_ip, 4);
147 if (ip != srcaddr) {
148 continue;
149 }
150 close(sock);
151 return -1;
152 }
153 }
154 }
155
156 // it will never get here!
157 close(sock);
158 return -1;
159}
160
161// assign a random IP address and check it
162// the address needs to be in the range if it --iprange was specified
163static uint32_t arp_random(const char *dev, Bridge *br) {
164 assert(dev);
165 assert(br);
166 uint32_t ifip = br->ip;
167 uint32_t ifmask = br->mask;
168 assert(ifip);
169 assert(ifmask);
170
171 if (arg_debug)
172 printf("ARP-scan %s, %d.%d.%d.%d/%d\n",
173 dev, PRINT_IP(ifip), mask2bits(ifmask));
174
175 // determine the range based on network address
176 uint32_t range = ~ifmask + 1; // the number of potential addresses
177 // this software is not supported for /31 networks
178 if (range < 4)
179 return 0; // the user will have to set the IP address manually
180 range -= 2; // subtract the network address and the broadcast address
181 uint32_t start = (ifip & ifmask) + 1;
182
183 // adjust range based on --iprange params
184 if (br->iprange_start && br->iprange_end) {
185 start = br->iprange_start;
186 range = br->iprange_end - br->iprange_start;
187 }
188
189 if (arg_debug)
190 printf("IP address range from %d.%d.%d.%d to %d.%d.%d.%d\n",
191 PRINT_IP(start), PRINT_IP(start + range));
192
193 // generate a random address - 10 tries
194 uint32_t dest = 0;
195 int i = 0;
196 for (i = 0; i < 10; i++) {
197 dest = start + ((uint32_t) rand()) % range;
198 if (dest == ifip) // do not allow the interface address
199 continue; // try again
200
201 // if we've made it up to here, we have a valid address
202 break;
203 }
204 if (i == 10) // we failed 10 times
205 return 0;
206
207 // check address
208 uint32_t rv = arp_check(dev, dest, ifip);
209 if (!rv)
210 return dest;
211 return 0;
212}
213
214// go sequentially trough all IP addresses and assign the first one not in use
215static uint32_t arp_sequential(const char *dev, Bridge *br) {
216 assert(dev);
217 assert(br);
218 uint32_t ifip = br->ip;
219 uint32_t ifmask = br->mask;
220 assert(ifip);
221 assert(ifmask);
222
223 // range based on network address
224 uint32_t range = ~ifmask + 1; // the number of potential addresses
225 // this software is not supported for /31 networks
226 if (range < 4)
227 return 0; // the user will have to set the IP address manually
228 range -= 2; // subtract the network address and the broadcast address
229
230 // try all possible ip addresses in ascending order
231 // start address
232 uint32_t dest = (ifip & ifmask) + 1;
233 if (br->iprange_start)
234 dest = br->iprange_start;
235 // end address
236 uint32_t last = dest + range - 1;
237 if (br->iprange_end)
238 last = br->iprange_end;
239
240 if (arg_debug)
241 printf("Trying IP address range from %d.%d.%d.%d to %d.%d.%d.%d\n",
242 PRINT_IP(dest), PRINT_IP(last));
243
244 // loop through addresses and stop as soon as you find an unused one
245 while (dest <= last) {
246 if (dest == ifip) {
247 dest++;
248 continue;
249 }
250 uint32_t rv = arp_check(dev, dest, ifip);
251 if (!rv)
252 return dest;
253 dest++;
254 }
255
256 return 0;
257}
258
259// assign an IP address first trying some random addresses, and if this fails
260// by doing an arp scan.
261//
262// dev is the name of the device to use in scanning,
263// br is bridge structure holding the ip address and mask to use in
264// arp packets. It also holds values for for the range of addresses
265// if --iprange was set by the user
266uint32_t arp_assign(const char *dev, Bridge *br) {
267 assert(br);
268 uint32_t ip = 0;
269
270 // try two random IP addresses
271 ip = arp_random(dev, br);
272 if (!ip)
273 ip = arp_random(dev, br);
274
275 // try all possible IP addresses one by one
276 if (!ip)
277 ip = arp_sequential(dev, br);
278
279 // print result
280 if (!ip) {
281 fprintf(stderr, "Error: cannot assign an IP address; it looks like all of them are in use.\n");
282 logerr("Cannot assign an IP address; it looks like all of them are in use.");
283 exit(1);
284 }
285
286 return ip;
287}
288
289// scan interface (--scan option)
290void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) {
291 assert(dev);
292 assert(ifip);
293
294// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n",
295// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask));
296
297 if (strlen(dev) > IFNAMSIZ) {
298 fprintf(stderr, "Error: invalid network device name %s\n", dev);
299 exit(1);
300 }
301
302 // find interface mac address
303 int sock;
304 if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
305 errExit("socket");
306 struct ifreq ifr;
307 memset(&ifr, 0, sizeof (ifr));
308 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
309 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
310 errExit("ioctl");
311 close(sock);
312 uint8_t mac[6];
313 memcpy (mac, ifr.ifr_hwaddr.sa_data, 6);
314
315 // open layer2 socket
316 if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
317 errExit("socket");
318
319 // try all possible ip addresses in ascending order
320 uint32_t range = ~ifmask + 1; // the number of potential addresses
321 // this software is not supported for /31 networks
322 if (range < 4) {
323 fprintf(stderr, "Warning: this option is not supported for /31 networks\n");
324 close(sock);
325 return;
326 }
327
328 uint32_t dest = (ifip & ifmask) + 1;
329 uint32_t last = dest + range - 1;
330 uint32_t src = htonl(ifip);
331
332 // wait not more than one second for an answer
333 int header_printed = 0;
334 int last_ip = 0;
335 struct timeval ts;
336 ts.tv_sec = 2; // 2 seconds receive timeout
337 ts.tv_usec = 0;
338
339 while (1) {
340 fd_set rfds;
341 FD_ZERO(&rfds);
342 FD_SET(sock, &rfds);
343 fd_set wfds;
344 FD_ZERO(&wfds);
345 FD_SET(sock, &wfds);
346 int maxfd = sock;
347
348 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
349 memset(frame, 0, ETH_FRAME_LEN);
350
351 int nready;
352 if (dest < last)
353 nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL);
354 else
355 nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts);
356
357 if (nready < 0)
358 errExit("select");
359
360 if (nready == 0) { // timeout
361 break;
362 }
363
364 if (FD_ISSET(sock, &wfds) && dest < last) {
365 // configure layer2 socket address information
366 struct sockaddr_ll addr;
367 memset(&addr, 0, sizeof(addr));
368 if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
369 errExit("if_nametoindex");
370 addr.sll_family = AF_PACKET;
371 memcpy (addr.sll_addr, mac, 6);
372 addr.sll_halen = htons(6);
373
374 // build the arp packet header
375 ArpHdr hdr;
376 memset(&hdr, 0, sizeof(hdr));
377 hdr.htype = htons(1);
378 hdr.ptype = htons(ETH_P_IP);
379 hdr.hlen = 6;
380 hdr.plen = 4;
381 hdr.opcode = htons(1); //ARPOP_REQUEST
382 memcpy(hdr.sender_mac, mac, 6);
383 memcpy(hdr.sender_ip, (uint8_t *)&src, 4);
384 uint32_t dst = htonl(dest);
385 memcpy(hdr.target_ip, (uint8_t *)&dst, 4);
386
387 // buiild ethernet frame
388 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
389 memset(frame, 0, sizeof(frame));
390 frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
391 memcpy(frame + 6, mac, 6);
392 frame[12] = ETH_P_ARP / 256;
393 frame[13] = ETH_P_ARP % 256;
394 memcpy (frame + 14, &hdr, sizeof(hdr));
395
396 // send packet
397 int len;
398 if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
399 errExit("send");
400//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest));
401 fflush(0);
402 dest++;
403 }
404
405 if (FD_ISSET(sock, &rfds)) {
406 // read the incoming packet
407 int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL);
408 if (len < 0) {
409 perror("recvfrom");
410 }
411
412 // parse the incomming packet
413 if (len < 14 + sizeof(ArpHdr))
414 continue;
415
416 // look only at ARP packets
417 if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256))
418 continue;
419
420 ArpHdr hdr;
421 memcpy(&hdr, frame + 14, sizeof(ArpHdr));
422
423 if (hdr.opcode == htons(2)) {
424 // check my mac and my address
425 if (memcmp(mac, hdr.target_mac, 6) != 0)
426 continue;
427 uint32_t ip;
428 memcpy(&ip, hdr.target_ip, 4);
429 if (ip != src)
430 continue;
431 memcpy(&ip, hdr.sender_ip, 4);
432 ip = ntohl(ip);
433
434 if (ip == last_ip) // filter duplicates
435 continue;
436 last_ip = ip;
437
438 // printing
439 if (header_printed == 0) {
440 printf(" Network scan:\n");
441
442 // print parent interface
443 if (cfg.bridge0.configured && cfg.bridge0.ip && cfg.bridge0.macvlan &&
444 (cfg.bridge0.ip & cfg.bridge0.mask) == (ifip & cfg.bridge0.mask))
445 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
446 PRINT_MAC(cfg.bridge0.mac), PRINT_IP(cfg.bridge0.ip));
447
448 if (cfg.bridge1.configured && cfg.bridge1.ip && cfg.bridge1.macvlan &&
449 (cfg.bridge1.ip & cfg.bridge1.mask) == (ifip & cfg.bridge1.mask))
450 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
451 PRINT_MAC(cfg.bridge1.mac), PRINT_IP(cfg.bridge1.ip));
452
453 if (cfg.bridge2.configured && cfg.bridge2.ip && cfg.bridge2.macvlan &&
454 (cfg.bridge2.ip & cfg.bridge2.mask) == (ifip & cfg.bridge2.mask))
455 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
456 PRINT_MAC(cfg.bridge2.mac), PRINT_IP(cfg.bridge2.ip));
457
458 if (cfg.bridge3.configured && cfg.bridge3.ip && cfg.bridge3.macvlan &&
459 (cfg.bridge3.ip & cfg.bridge3.mask) == (ifip & cfg.bridge3.mask))
460 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
461 PRINT_MAC(cfg.bridge3.mac), PRINT_IP(cfg.bridge3.ip));
462
463 header_printed = 1;
464 }
465 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
466 PRINT_MAC(hdr.sender_mac), PRINT_IP(ip));
467 }
468 }
469 }
470
471 close(sock);
472}
473
474