aboutsummaryrefslogtreecommitdiffstats
path: root/src/fnet/interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fnet/interface.c')
-rw-r--r--src/fnet/interface.c370
1 files changed, 370 insertions, 0 deletions
diff --git a/src/fnet/interface.c b/src/fnet/interface.c
new file mode 100644
index 000000000..3958efddd
--- /dev/null
+++ b/src/fnet/interface.c
@@ -0,0 +1,370 @@
1 /*
2 * Copyright (C) 2014-2016 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
21#include "fnet.h"
22#include <arpa/inet.h>
23#include <sys/socket.h>
24#include <sys/ioctl.h>
25#include <netdb.h>
26#include <ifaddrs.h>
27#include <net/if.h>
28#include <net/if_arp.h>
29#include <net/route.h>
30#include <linux/if_bridge.h>
31
32static void check_if_name(const char *ifname) {
33 if (strlen(ifname) > IFNAMSIZ) {
34 fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname);
35 exit(1);
36 }
37}
38
39// add a veth device to a bridge
40void net_bridge_add_interface(const char *bridge, const char *dev) {
41 check_if_name(bridge);
42 check_if_name(dev);
43
44 // somehow adding the interface to the bridge resets MTU on bridge device!!!
45 // workaround: restore MTU on the bridge device
46 // todo: put a real fix in
47 int mtu1 = net_get_mtu(bridge);
48
49 struct ifreq ifr;
50 int err;
51 int ifindex = if_nametoindex(dev);
52
53 if (ifindex <= 0)
54 errExit("if_nametoindex");
55
56 int sock;
57 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
58 errExit("socket");
59
60 memset(&ifr, 0, sizeof(ifr));
61 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
62#ifdef SIOCBRADDIF
63 ifr.ifr_ifindex = ifindex;
64 err = ioctl(sock, SIOCBRADDIF, &ifr);
65 if (err < 0)
66#endif
67 {
68 unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 };
69
70 ifr.ifr_data = (char *) args;
71 err = ioctl(sock, SIOCDEVPRIVATE, &ifr);
72 }
73 (void) err;
74 close(sock);
75
76 int mtu2 = net_get_mtu(bridge);
77 if (mtu1 != mtu2)
78 net_set_mtu(bridge, mtu1);
79}
80
81
82// bring interface up
83void net_if_up(const char *ifname) {
84 check_if_name(ifname);
85
86 int sock = socket(AF_INET,SOCK_DGRAM,0);
87 if (sock < 0)
88 errExit("socket");
89
90 // get the existing interface flags
91 struct ifreq ifr;
92 memset(&ifr, 0, sizeof(ifr));
93 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
94 ifr.ifr_addr.sa_family = AF_INET;
95
96 // read the existing flags
97 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0)
98 errExit("ioctl");
99
100 ifr.ifr_flags |= IFF_UP;
101
102 // set the new flags
103 if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0)
104 errExit("ioctl");
105
106 // checking
107 // read the existing flags
108 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0)
109 errExit("ioctl");
110
111 // wait not more than 500ms for the interface to come up
112 int cnt = 0;
113 while (cnt < 50) {
114 usleep(10000); // sleep 10ms
115
116 // read the existing flags
117 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0)
118 errExit("ioctl");
119 if (ifr.ifr_flags & IFF_RUNNING)
120 break;
121 cnt++;
122 }
123
124 close(sock);
125}
126
127int net_get_mtu(const char *ifname) {
128 check_if_name(ifname);
129 int mtu = 0;
130 int s;
131 struct ifreq ifr;
132
133 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
134 errExit("socket");
135
136 memset(&ifr, 0, sizeof(ifr));
137 ifr.ifr_addr.sa_family = AF_INET;
138 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
139 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0)
140 mtu = ifr.ifr_mtu;
141 close(s);
142
143
144 return mtu;
145}
146
147void net_set_mtu(const char *ifname, int mtu) {
148 check_if_name(ifname);
149 int s;
150 struct ifreq ifr;
151
152 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
153 errExit("socket");
154
155 memset(&ifr, 0, sizeof(ifr));
156 ifr.ifr_addr.sa_family = AF_INET;
157 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
158 ifr.ifr_mtu = mtu;
159 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) != 0)
160 fprintf(stderr, "Warning fnet: cannot set mtu for interface %s\n", ifname);
161 close(s);
162}
163
164// scan interfaces in current namespace and print IP address/mask for each interface
165void net_ifprint(int scan) {
166 uint32_t ip;
167 uint32_t mask;
168 struct ifaddrs *ifaddr, *ifa;
169
170 if (getifaddrs(&ifaddr) == -1)
171 errExit("getifaddrs");
172
173 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
174 "Interface", "MAC", "IP", "Mask", "Status");
175 // walk through the linked list
176 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
177 if (ifa->ifa_addr == NULL)
178 continue;
179
180 if (ifa->ifa_addr->sa_family == AF_INET) {
181 struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask;
182 mask = ntohl(si->sin_addr.s_addr);
183 si = (struct sockaddr_in *) ifa->ifa_addr;
184 ip = ntohl(si->sin_addr.s_addr);
185
186 // interface status
187 char *status;
188 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
189 status = "UP";
190 else
191 status = "DOWN";
192
193 // ip address and mask
194 char ipstr[30];
195 sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip));
196 char maskstr[30];
197 sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask));
198
199 // mac address
200 unsigned char mac[6];
201 net_get_mac(ifa->ifa_name, mac);
202 char macstr[30];
203 if (strcmp(ifa->ifa_name, "lo") == 0)
204 macstr[0] = '\0';
205 else
206 sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac));
207
208 // print
209 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
210 ifa->ifa_name, macstr, ipstr, maskstr, status);
211
212 // network scanning
213 if (!scan) // scanning disabled
214 continue;
215 if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning
216 continue;
217 if (mask2bits(mask) < 16) // not scanning large networks
218 continue;
219 if (!ip) // if not configured
220 continue;
221 // only if the interface is up and running
222 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
223 arp_scan(ifa->ifa_name, ip, mask);
224 }
225 }
226 freeifaddrs(ifaddr);
227}
228
229int net_get_mac(const char *ifname, unsigned char mac[6]) {
230 check_if_name(ifname);
231
232 struct ifreq ifr;
233 int sock;
234
235 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
236 errExit("socket");
237
238 memset(&ifr, 0, sizeof(ifr));
239 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
240 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
241
242 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1)
243 errExit("ioctl");
244 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
245
246 close(sock);
247 return 0;
248}
249
250// configure interface ipv4 address
251void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) {
252 check_if_name(ifname);
253 int sock = socket(AF_INET,SOCK_DGRAM,0);
254 if (sock < 0)
255 errExit("socket");
256
257 struct ifreq ifr;
258 memset(&ifr, 0, sizeof(ifr));
259 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
260 ifr.ifr_addr.sa_family = AF_INET;
261
262 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip);
263 if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0)
264 errExit("ioctl");
265
266 if (ip != 0) {
267 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask);
268 if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0)
269 errExit("ioctl");
270 }
271
272 // configure mtu
273 if (mtu > 0) {
274 ifr.ifr_mtu = mtu;
275 if (ioctl( sock, SIOCSIFMTU, &ifr ) < 0)
276 errExit("ioctl");
277 }
278
279 close(sock);
280 usleep(10000); // sleep 10ms
281 return;
282}
283
284int net_if_mac(const char *ifname, const unsigned char mac[6]) {
285 check_if_name(ifname);
286 struct ifreq ifr;
287 int sock;
288
289 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
290 errExit("socket");
291
292 memset(&ifr, 0, sizeof(ifr));
293 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
294 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
295 memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
296
297 if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1)
298 errExit("ioctl");
299 close(sock);
300 return 0;
301}
302
303// configure interface ipv6 address
304// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64
305struct ifreq6 {
306 struct in6_addr ifr6_addr;
307 uint32_t ifr6_prefixlen;
308 unsigned int ifr6_ifindex;
309};
310void net_if_ip6(const char *ifname, const char *addr6) {
311 check_if_name(ifname);
312 if (strchr(addr6, ':') == NULL) {
313 fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6);
314 exit(1);
315 }
316
317 // extract prefix
318 unsigned long prefix;
319 char *ptr;
320 if ((ptr = strchr(addr6, '/'))) {
321 prefix = atol(ptr + 1);
322 if (prefix > 128) {
323 fprintf(stderr, "Error fnet: invalid prefix for IPv6 address %s\n", addr6);
324 exit(1);
325 }
326 *ptr = '\0'; // mark the end of the address
327 }
328 else
329 prefix = 128;
330
331 // extract address
332 struct sockaddr_in6 sin6;
333 memset(&sin6, 0, sizeof(sin6));
334 sin6.sin6_family = AF_INET6;
335 int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr);
336 if (rv <= 0) {
337 fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6);
338 exit(1);
339 }
340
341 // open socket
342 int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
343 if (sock < 0) {
344 fprintf(stderr, "Error fnet: IPv6 is not supported on this system\n");
345 exit(1);
346 }
347
348 // find interface index
349 struct ifreq ifr;
350 memset(&ifr, 0, sizeof(ifr));
351 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
352 ifr.ifr_addr.sa_family = AF_INET;
353 if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) {
354 perror("ioctl SIOGIFINDEX");
355 exit(1);
356 }
357
358 // configure address
359 struct ifreq6 ifr6;
360 memset(&ifr6, 0, sizeof(ifr6));
361 ifr6.ifr6_prefixlen = prefix;
362 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
363 memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr));
364 if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) {
365 perror("ioctl SIOCSIFADDR");
366 exit(1);
367 }
368
369 close(sock);
370}