aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/network.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/network.c')
-rw-r--r--src/firejail/network.c349
1 files changed, 36 insertions, 313 deletions
diff --git a/src/firejail/network.c b/src/firejail/network.c
index 4473ef099..6d09d770f 100644
--- a/src/firejail/network.c
+++ b/src/firejail/network.c
@@ -28,70 +28,6 @@
28#include <net/route.h> 28#include <net/route.h>
29#include <linux/if_bridge.h> 29#include <linux/if_bridge.h>
30 30
31// scan interfaces in current namespace and print IP address/mask for each interface
32void net_ifprint(void) {
33 uint32_t ip;
34 uint32_t mask;
35 struct ifaddrs *ifaddr, *ifa;
36
37 if (getifaddrs(&ifaddr) == -1)
38 errExit("getifaddrs");
39
40 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
41 "Interface", "MAC", "IP", "Mask", "Status");
42 // walk through the linked list
43 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
44 if (ifa->ifa_addr == NULL)
45 continue;
46
47 if (ifa->ifa_addr->sa_family == AF_INET) {
48 struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask;
49 mask = ntohl(si->sin_addr.s_addr);
50 si = (struct sockaddr_in *) ifa->ifa_addr;
51 ip = ntohl(si->sin_addr.s_addr);
52
53 // interface status
54 char *status;
55 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
56 status = "UP";
57 else
58 status = "DOWN";
59
60 // ip address and mask
61 char ipstr[30];
62 sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip));
63 char maskstr[30];
64 sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask));
65
66 // mac address
67 unsigned char mac[6];
68 net_get_mac(ifa->ifa_name, mac);
69 char macstr[30];
70 if (strcmp(ifa->ifa_name, "lo") == 0)
71 macstr[0] = '\0';
72 else
73 sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac));
74
75 // print
76 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
77 ifa->ifa_name, macstr, ipstr, maskstr, status);
78
79 // network scanning
80 if (!arg_scan) // scanning disabled
81 continue;
82 if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning
83 continue;
84 if (mask2bits(mask) < 16) // not scanning large networks
85 continue;
86 if (!ip) // if not configured
87 continue;
88 // only if the interface is up and running
89 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
90 arp_scan(ifa->ifa_name, ip, mask);
91 }
92 }
93 freeifaddrs(ifaddr);
94}
95 31
96int net_get_mtu(const char *ifname) { 32int net_get_mtu(const char *ifname) {
97 int mtu = 0; 33 int mtu = 0;
@@ -190,101 +126,11 @@ void net_if_up(const char *ifname) {
190 fprintf(stderr, "Error: invalid network device name %s\n", ifname); 126 fprintf(stderr, "Error: invalid network device name %s\n", ifname);
191 exit(1); 127 exit(1);
192 } 128 }
193 129 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3,
194 int sock = socket(AF_INET,SOCK_DGRAM,0); 130 PATH_FNET, "ifup", ifname);
195 if (sock < 0) 131}
196 errExit("socket");
197
198 // get the existing interface flags
199 struct ifreq ifr;
200 memset(&ifr, 0, sizeof(ifr));
201 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
202 ifr.ifr_addr.sa_family = AF_INET;
203
204 // read the existing flags
205 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
206 close(sock);
207 printf("Error: cannot bring up interface %s\n", ifname);
208 errExit("ioctl");
209 }
210 132
211 ifr.ifr_flags |= IFF_UP;
212 133
213 // set the new flags
214 if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) {
215 close(sock);
216 printf("Error: cannot bring up interface %s\n", ifname);
217 errExit("ioctl");
218 }
219
220 // checking
221 // read the existing flags
222 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
223 close(sock);
224 printf("Error: cannot bring up interface %s\n", ifname);
225 errExit("ioctl");
226 }
227
228 // wait not more than 500ms for the interface to come up
229 int cnt = 0;
230 while (cnt < 50) {
231 usleep(10000); // sleep 10ms
232
233 // read the existing flags
234 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
235 close(sock);
236 printf("Error: cannot bring up interface %s\n", ifname);
237 errExit("ioctl");
238 }
239 if (ifr.ifr_flags & IFF_RUNNING)
240 break;
241 cnt++;
242 }
243
244 close(sock);
245}
246
247// bring interface up
248void net_if_down(const char *ifname) {
249 if (strlen(ifname) > IFNAMSIZ) {
250 fprintf(stderr, "Error: invalid network device name %s\n", ifname);
251 exit(1);
252 }
253
254 int sock = socket(AF_INET,SOCK_DGRAM,0);
255 if (sock < 0)
256 errExit("socket");
257
258 // get the existing interface flags
259 struct ifreq ifr;
260 memset(&ifr, 0, sizeof(ifr));
261 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
262 ifr.ifr_addr.sa_family = AF_INET;
263
264 // read the existing flags
265 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
266 close(sock);
267 printf("Error: cannot shut down interface %s\n", ifname);
268 errExit("ioctl");
269 }
270
271 ifr.ifr_flags &= ~IFF_UP;
272
273 // set the new flags
274 if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) {
275 close(sock);
276 printf("Error: cannot shut down interface %s\n", ifname);
277 errExit("ioctl");
278 }
279
280 close(sock);
281}
282
283struct ifreq6 {
284 struct in6_addr ifr6_addr;
285 uint32_t ifr6_prefixlen;
286 unsigned int ifr6_ifindex;
287};
288// configure interface ipv6 address 134// configure interface ipv6 address
289// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64 135// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64
290void net_if_ip6(const char *ifname, const char *addr6) { 136void net_if_ip6(const char *ifname, const char *addr6) {
@@ -293,107 +139,11 @@ void net_if_ip6(const char *ifname, const char *addr6) {
293 exit(1); 139 exit(1);
294 } 140 }
295 141
296 // extract prefix 142 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 5,
297 unsigned long prefix; 143 PATH_FNET, "config", "ipv6", ifname, addr6);
298 char *ptr;
299 if ((ptr = strchr(addr6, '/'))) {
300 prefix = atol(ptr + 1);
301 if (prefix > 128) {
302 fprintf(stderr, "Error: invalid prefix for IPv6 address %s\n", addr6);
303 exit(1);
304 }
305 *ptr = '\0'; // mark the end of the address
306 }
307 else
308 prefix = 128;
309
310 // extract address
311 struct sockaddr_in6 sin6;
312 memset(&sin6, 0, sizeof(sin6));
313 sin6.sin6_family = AF_INET6;
314 int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr);
315 if (rv <= 0) {
316 fprintf(stderr, "Error: invalid IPv6 address %s\n", addr6);
317 exit(1);
318 }
319
320 // open socket
321 int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
322 if (sock < 0) {
323 fprintf(stderr, "Error: IPv6 is not supported on this system\n");
324 exit(1);
325 }
326
327 // find interface index
328 struct ifreq ifr;
329 memset(&ifr, 0, sizeof(ifr));
330 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
331 ifr.ifr_addr.sa_family = AF_INET;
332 if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) {
333 perror("ioctl SIOGIFINDEX");
334 exit(1);
335 }
336
337 // configure address
338 struct ifreq6 ifr6;
339 memset(&ifr6, 0, sizeof(ifr6));
340 ifr6.ifr6_prefixlen = prefix;
341 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
342 memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr));
343 if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) {
344 perror("ioctl SIOCSIFADDR");
345 exit(1);
346 }
347
348 close(sock);
349}
350
351// configure interface ipv4 address
352void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) {
353 if (strlen(ifname) > IFNAMSIZ) {
354 fprintf(stderr, "Error: invalid network device name %s\n", ifname);
355 exit(1);
356 }
357 if (arg_debug)
358 printf("configure interface %s\n", ifname);
359
360 int sock = socket(AF_INET,SOCK_DGRAM,0);
361 if (sock < 0)
362 errExit("socket");
363
364 struct ifreq ifr;
365 memset(&ifr, 0, sizeof(ifr));
366 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
367 ifr.ifr_addr.sa_family = AF_INET;
368
369 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip);
370 if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) {
371 close(sock);
372 errExit("ioctl");
373 }
374
375 if (ip != 0) {
376 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask);
377 if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) {
378 close(sock);
379 errExit("ioctl");
380 }
381 }
382
383 // configure mtu
384 if (mtu > 0) {
385 ifr.ifr_mtu = mtu;
386 if (ioctl( sock, SIOCSIFMTU, &ifr ) < 0) {
387 close(sock);
388 errExit("ioctl");
389 }
390 }
391 144
392 close(sock);
393 usleep(10000); // sleep 10ms
394} 145}
395 146
396
397// add an IP route, return -1 if error, 0 if the route was added 147// add an IP route, return -1 if error, 0 if the route was added
398int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) { 148int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) {
399 int sock; 149 int sock;
@@ -431,52 +181,6 @@ int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) {
431} 181}
432 182
433 183
434// add a veth device to a bridge
435void net_bridge_add_interface(const char *bridge, const char *dev) {
436 if (strlen(bridge) > IFNAMSIZ) {
437 fprintf(stderr, "Error: invalid network device name %s\n", bridge);
438 exit(1);
439 }
440
441 // somehow adding the interface to the bridge resets MTU on bridge device!!!
442 // workaround: restore MTU on the bridge device
443 // todo: put a real fix in
444 int mtu1 = net_get_mtu(bridge);
445
446 struct ifreq ifr;
447 int err;
448 int ifindex = if_nametoindex(dev);
449
450 if (ifindex <= 0)
451 errExit("if_nametoindex");
452
453 int sock;
454 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
455 errExit("socket");
456
457 memset(&ifr, 0, sizeof(ifr));
458 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
459#ifdef SIOCBRADDIF
460 ifr.ifr_ifindex = ifindex;
461 err = ioctl(sock, SIOCBRADDIF, &ifr);
462 if (err < 0)
463#endif
464 {
465 unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 };
466
467 ifr.ifr_data = (char *) args;
468 err = ioctl(sock, SIOCDEVPRIVATE, &ifr);
469 }
470 (void) err;
471 close(sock);
472
473 int mtu2 = net_get_mtu(bridge);
474 if (mtu1 != mtu2) {
475 if (arg_debug)
476 printf("Restoring MTU for %s\n", bridge);
477 net_set_mtu(bridge, mtu1);
478 }
479}
480 184
481#define BUFSIZE 1024 185#define BUFSIZE 1024
482uint32_t network_get_defaultgw(void) { 186uint32_t network_get_defaultgw(void) {
@@ -510,20 +214,15 @@ uint32_t network_get_defaultgw(void) {
510} 214}
511 215
512int net_config_mac(const char *ifname, const unsigned char mac[6]) { 216int net_config_mac(const char *ifname, const unsigned char mac[6]) {
513 struct ifreq ifr; 217 char *macstr;
514 int sock; 218 if (asprintf(&macstr, "%02x:%02x:%02x:%02x:%02x:%02x",
515 219 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) == -1)
516 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 220 errExit("asprintf");
517 errExit("socket");
518 221
519 memset(&ifr, 0, sizeof(ifr)); 222 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 5,
520 strncpy(ifr.ifr_name, ifname, IFNAMSIZ); 223 PATH_FNET, "config", "mac", ifname, macstr);
521 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
522 memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
523 224
524 if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1) 225 free(macstr);
525 errExit("ioctl");
526 close(sock);
527 return 0; 226 return 0;
528} 227}
529 228
@@ -546,3 +245,27 @@ int net_get_mac(const char *ifname, unsigned char mac[6]) {
546 close(sock); 245 close(sock);
547 return 0; 246 return 0;
548} 247}
248
249void net_config_interface(const char *dev, uint32_t ip, uint32_t mask, int mtu) {
250 assert(dev);
251
252 char *ipstr;
253 if (asprintf(&ipstr, "%llu", (long long unsigned) ip) == -1)
254 errExit("asprintf");
255
256 char *maskstr;
257 if (asprintf(&maskstr, "%llu", (long long unsigned) mask) == -1)
258 errExit("asprintf");
259
260 char *mtustr;
261 if (asprintf(&mtustr, "%d", mtu) == -1)
262 errExit("asprintf");
263
264 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 7,
265 PATH_FNET, "config", "interface", dev, ipstr, maskstr, mtustr);
266
267 free(ipstr);
268 free(maskstr);
269 free(mtustr);
270}
271