aboutsummaryrefslogtreecommitdiffstats
path: root/src/fnet
diff options
context:
space:
mode:
Diffstat (limited to 'src/fnet')
-rw-r--r--src/fnet/Makefile.in45
-rw-r--r--src/fnet/arp.c208
-rw-r--r--src/fnet/fnet.h49
-rw-r--r--src/fnet/interface.c370
-rw-r--r--src/fnet/main.c103
-rw-r--r--src/fnet/veth.c236
6 files changed, 1011 insertions, 0 deletions
diff --git a/src/fnet/Makefile.in b/src/fnet/Makefile.in
new file mode 100644
index 000000000..32f08882a
--- /dev/null
+++ b/src/fnet/Makefile.in
@@ -0,0 +1,45 @@
1all: fnet
2
3prefix=@prefix@
4exec_prefix=@exec_prefix@
5libdir=@libdir@
6sysconfdir=@sysconfdir@
7
8VERSION=@PACKAGE_VERSION@
9NAME=@PACKAGE_NAME@
10HAVE_SECCOMP_H=@HAVE_SECCOMP_H@
11HAVE_SECCOMP=@HAVE_SECCOMP@
12HAVE_CHROOT=@HAVE_CHROOT@
13HAVE_BIND=@HAVE_BIND@
14HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@
15HAVE_NETWORK=@HAVE_NETWORK@
16HAVE_USERNS=@HAVE_USERNS@
17HAVE_X11=@HAVE_X11@
18HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@
19HAVE_WHITELIST=@HAVE_WHITELIST@
20HAVE_GLOBALCFG=@HAVE_GLOBALCFG@
21HAVE_APPARMOR=@HAVE_APPARMOR@
22HAVE_OVERLAYFS=@HAVE_OVERLAYFS@
23HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@
24EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@
25HAVE_GCOV=@HAVE_GCOV@
26EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@
27
28H_FILE_LIST = $(sort $(wildcard *.[h]))
29C_FILE_LIST = $(sort $(wildcard *.c))
30OBJS = $(C_FILE_LIST:.c=.o)
31BINOBJS = $(foreach file, $(OBJS), $file)
32CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security
33LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread
34
35%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/libnetlink.h
36 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
37
38fnet: $(OBJS) ../lib/libnetlink.o
39 $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o $(LIBS) $(EXTRA_LDFLAGS)
40
41clean:; rm -f *.o fnet *.gcov *.gcda *.gcno
42
43distclean: clean
44 rm -fr Makefile
45
diff --git a/src/fnet/arp.c b/src/fnet/arp.c
new file mode 100644
index 000000000..96684fdf9
--- /dev/null
+++ b/src/fnet/arp.c
@@ -0,0 +1,208 @@
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#include "fnet.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
44// scan interface (--scan option)
45void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) {
46 assert(dev);
47 assert(ifip);
48
49// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n",
50// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask));
51
52 if (strlen(dev) > IFNAMSIZ) {
53 fprintf(stderr, "Error: invalid network device name %s\n", dev);
54 exit(1);
55 }
56
57 // find interface mac address
58 int sock;
59 if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
60 errExit("socket");
61 struct ifreq ifr;
62 memset(&ifr, 0, sizeof (ifr));
63 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
64 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
65 errExit("ioctl");
66 close(sock);
67 uint8_t mac[6];
68 memcpy (mac, ifr.ifr_hwaddr.sa_data, 6);
69
70 // open layer2 socket
71 if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
72 errExit("socket");
73
74 // try all possible ip addresses in ascending order
75 uint32_t range = ~ifmask + 1; // the number of potential addresses
76 // this software is not supported for /31 networks
77 if (range < 4) {
78 fprintf(stderr, "Warning: this option is not supported for /31 networks\n");
79 close(sock);
80 return;
81 }
82
83 uint32_t dest = (ifip & ifmask) + 1;
84 uint32_t last = dest + range - 1;
85 uint32_t src = htonl(ifip);
86
87 // wait not more than one second for an answer
88 int header_printed = 0;
89 uint32_t last_ip = 0;
90 struct timeval ts;
91 ts.tv_sec = 2; // 2 seconds receive timeout
92 ts.tv_usec = 0;
93
94 while (1) {
95 fd_set rfds;
96 FD_ZERO(&rfds);
97 FD_SET(sock, &rfds);
98 fd_set wfds;
99 FD_ZERO(&wfds);
100 FD_SET(sock, &wfds);
101 int maxfd = sock;
102
103 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
104 memset(frame, 0, ETH_FRAME_LEN);
105
106 int nready;
107 if (dest < last)
108 nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL);
109 else
110 nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts);
111
112 if (nready < 0)
113 errExit("select");
114
115 if (nready == 0) { // timeout
116 break;
117 }
118
119 if (FD_ISSET(sock, &wfds) && dest < last) {
120 // configure layer2 socket address information
121 struct sockaddr_ll addr;
122 memset(&addr, 0, sizeof(addr));
123 if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
124 errExit("if_nametoindex");
125 addr.sll_family = AF_PACKET;
126 memcpy (addr.sll_addr, mac, 6);
127 addr.sll_halen = htons(6);
128
129 // build the arp packet header
130 ArpHdr hdr;
131 memset(&hdr, 0, sizeof(hdr));
132 hdr.htype = htons(1);
133 hdr.ptype = htons(ETH_P_IP);
134 hdr.hlen = 6;
135 hdr.plen = 4;
136 hdr.opcode = htons(1); //ARPOP_REQUEST
137 memcpy(hdr.sender_mac, mac, 6);
138 memcpy(hdr.sender_ip, (uint8_t *)&src, 4);
139 uint32_t dst = htonl(dest);
140 memcpy(hdr.target_ip, (uint8_t *)&dst, 4);
141
142 // build ethernet frame
143 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
144 memset(frame, 0, sizeof(frame));
145 frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
146 memcpy(frame + 6, mac, 6);
147 frame[12] = ETH_P_ARP / 256;
148 frame[13] = ETH_P_ARP % 256;
149 memcpy (frame + 14, &hdr, sizeof(hdr));
150
151 // send packet
152 int len;
153 if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
154 errExit("send");
155//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest));
156 fflush(0);
157 dest++;
158 }
159
160 if (FD_ISSET(sock, &rfds)) {
161 // read the incoming packet
162 int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL);
163 if (len < 0) {
164 perror("recvfrom");
165 }
166
167 // parse the incoming packet
168 if ((unsigned int) len < 14 + sizeof(ArpHdr))
169 continue;
170
171 // look only at ARP packets
172 if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256))
173 continue;
174
175 ArpHdr hdr;
176 memcpy(&hdr, frame + 14, sizeof(ArpHdr));
177
178 if (hdr.opcode == htons(2)) {
179 // check my mac and my address
180 if (memcmp(mac, hdr.target_mac, 6) != 0)
181 continue;
182 uint32_t ip;
183 memcpy(&ip, hdr.target_ip, 4);
184 if (ip != src)
185 continue;
186 memcpy(&ip, hdr.sender_ip, 4);
187 ip = ntohl(ip);
188
189 if (ip == last_ip) // filter duplicates
190 continue;
191 last_ip = ip;
192
193 // printing
194 if (header_printed == 0) {
195 printf(" Network scan:\n");
196 header_printed = 1;
197 }
198 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
199 PRINT_MAC(hdr.sender_mac), PRINT_IP(ip));
200 }
201 }
202 }
203
204 close(sock);
205}
206
207
208
diff --git a/src/fnet/fnet.h b/src/fnet/fnet.h
new file mode 100644
index 000000000..0c5e5baef
--- /dev/null
+++ b/src/fnet/fnet.h
@@ -0,0 +1,49 @@
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#ifndef FNET_H
21#define FNET_H
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <assert.h>
27#include "../include/common.h"
28
29// veth.c
30int net_create_veth(const char *dev, const char *nsdev, unsigned pid);
31int net_create_macvlan(const char *dev, const char *parent, unsigned pid);
32int net_move_interface(const char *dev, unsigned pid);
33
34// interface.c
35void net_bridge_add_interface(const char *bridge, const char *dev);
36void net_if_up(const char *ifname);
37int net_get_mtu(const char *ifname);
38void net_set_mtu(const char *ifname, int mtu);
39void net_ifprint(int scan);
40int net_get_mac(const char *ifname, unsigned char mac[6]);
41void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu);
42int net_if_mac(const char *ifname, const unsigned char mac[6]);
43void net_if_ip6(const char *ifname, const char *addr6);
44
45
46// arp.c
47void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask);
48
49#endif
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}
diff --git a/src/fnet/main.c b/src/fnet/main.c
new file mode 100644
index 000000000..4ae9eb6e3
--- /dev/null
+++ b/src/fnet/main.c
@@ -0,0 +1,103 @@
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#include "fnet.h"
21
22static void usage(void) {
23 printf("Usage:\n");
24 printf("\tfnet create veth dev1 dev2 bridge child\n");
25 printf("\tfnet create macvlan dev parent child\n");
26 printf("\tfnet moveif dev proc\n");
27 printf("\tfnet printif\n");
28 printf("\tfnet printif scan\n");
29 printf("\tfnet config interface dev ip mask mtu\n");
30 printf("\tfnet config mac addr\n");
31 printf("\tfnet config ipv6 dev ipn");
32 printf("\tfmet ifup dev\n");
33}
34
35int main(int argc, char **argv) {
36#if 0
37{
38//system("cat /proc/self/status");
39int i;
40for (i = 0; i < argc; i++)
41 printf("*%s* ", argv[i]);
42printf("\n");
43}
44#endif
45 if (argc < 2)
46 return 1;
47
48
49
50 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
51 usage();
52 return 0;
53 }
54 else if (argc == 3 && strcmp(argv[1], "ifup") == 0) {
55 net_if_up(argv[2]);
56 }
57 else if (argc == 2 && strcmp(argv[1], "printif") == 0) {
58 net_ifprint(0);
59 }
60 else if (argc == 3 && strcmp(argv[1], "printif") == 0 && strcmp(argv[2], "scan") == 0) {
61 net_ifprint(1);
62 }
63 else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) {
64 // create veth pair and move one end in the the namespace
65 net_create_veth(argv[3], argv[4], atoi(argv[6]));
66 // connect the ohter veth end to the bridge ...
67 net_bridge_add_interface(argv[5], argv[3]);
68 // ... and bring it up
69 net_if_up(argv[3]);
70 }
71 else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) {
72 net_create_macvlan(argv[3], argv[4], atoi(argv[5]));
73 }
74 else if (argc == 7 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "interface") == 0) {
75 char *dev = argv[3];
76 uint32_t ip = (uint32_t) atoll(argv[4]);
77 uint32_t mask = (uint32_t) atoll(argv[5]);
78 int mtu = atoi(argv[6]);
79 // configure interface
80 net_if_ip(dev, ip, mask, mtu);
81 // ... and bring it up
82 net_if_up(dev);
83 }
84 else if (argc == 5 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "mac") == 0) {
85 unsigned char mac[6];
86 if (atomac(argv[4], mac)) {
87 fprintf(stderr, "Error fnet: invalid mac address %s\n", argv[4]);
88 }
89 net_if_mac(argv[3], mac);
90 }
91 else if (argc == 4 && strcmp(argv[1], "moveif") == 0) {
92 net_move_interface(argv[2], atoi(argv[3]));
93 }
94 else if (argc == 5 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "ipv6") == 0) {
95 net_if_ip6(argv[3], argv[4]);
96 }
97 else {
98 fprintf(stderr, "Error fnet: invalid arguments\n");
99 return 1;
100 }
101
102 return 0;
103}
diff --git a/src/fnet/veth.c b/src/fnet/veth.c
new file mode 100644
index 000000000..546fafcec
--- /dev/null
+++ b/src/fnet/veth.c
@@ -0,0 +1,236 @@
1/* code based on iproute2 ip/iplink.c, modified to be included in firejail project
2 *
3 * Original source code:
4 *
5 * Information:
6 * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2
7 *
8 * Download:
9 * http://www.kernel.org/pub/linux/utils/net/iproute2/
10 *
11 * Repository:
12 * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
13 *
14 * License: GPL v2
15 *
16 * Original copyright header
17 *
18 * iplink.c "ip link".
19 *
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version
23 * 2 of the License, or (at your option) any later version.
24 *
25 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
26 *
27 */
28 /*
29 * Copyright (C) 2014-2016 Firejail Authors
30 *
31 * This file is part of firejail project
32 *
33 * This program is free software; you can redistribute it and/or modify
34 * it under the terms of the GNU General Public License as published by
35 * the Free Software Foundation; either version 2 of the License, or
36 * (at your option) any later version.
37 *
38 * This program is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 * GNU General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License along
44 * with this program; if not, write to the Free Software Foundation, Inc.,
45 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
46*/
47
48#include "fnet.h"
49#include "../include/libnetlink.h"
50#include <linux/veth.h>
51#include <net/if.h>
52
53struct iplink_req
54{
55 struct nlmsghdr n;
56 struct ifinfomsg i;
57 char buf[1024];
58};
59
60static struct rtnl_handle rth = { .fd = -1 };
61
62int net_create_veth(const char *dev, const char *nsdev, unsigned pid) {
63 int len;
64 struct iplink_req req;
65
66 assert(dev);
67 assert(nsdev);
68 assert(pid);
69
70 if (rtnl_open(&rth, 0) < 0) {
71 fprintf(stderr, "cannot open netlink\n");
72 exit(1);
73 }
74
75 memset(&req, 0, sizeof(req));
76
77 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
78 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
79 req.n.nlmsg_type = RTM_NEWLINK;
80 req.i.ifi_family = 0;
81
82 if (dev) {
83 len = strlen(dev) + 1;
84 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len);
85 }
86
87 struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
88 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
89 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "veth", strlen("veth"));
90
91 struct rtattr * data = NLMSG_TAIL(&req.n);
92 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
93
94 struct rtattr * peerdata = NLMSG_TAIL(&req.n);
95 addattr_l (&req.n, sizeof(req), VETH_INFO_PEER, NULL, 0);
96 req.n.nlmsg_len += sizeof(struct ifinfomsg);
97
98 // place the link in the child namespace
99 addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4);
100
101 if (nsdev) {
102 int len = strlen(nsdev) + 1;
103 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, nsdev, len);
104 }
105 peerdata->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)peerdata;
106
107 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
108 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
109
110 // send message
111 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
112 exit(2);
113
114 rtnl_close(&rth);
115
116 return 0;
117}
118
119
120int net_create_macvlan(const char *dev, const char *parent, unsigned pid) {
121 int len;
122 struct iplink_req req;
123 assert(dev);
124 assert(parent);
125
126 if (rtnl_open(&rth, 0) < 0) {
127 fprintf(stderr, "cannot open netlink\n");
128 exit(1);
129 }
130
131 memset(&req, 0, sizeof(req));
132
133 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
134 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
135 req.n.nlmsg_type = RTM_NEWLINK;
136 req.i.ifi_family = 0;
137
138 // find parent ifindex
139 int parent_ifindex = if_nametoindex(parent);
140 if (parent_ifindex <= 0) {
141 fprintf(stderr, "Error: cannot find network device %s\n", parent);
142 exit(1);
143 }
144
145 // add parent
146 addattr_l(&req.n, sizeof(req), IFLA_LINK, &parent_ifindex, 4);
147
148 // add new interface name
149 len = strlen(dev) + 1;
150 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len);
151
152 // place the interface in child namespace
153 addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4);
154
155
156 // add link info for the new interface
157 struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
158 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
159 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "macvlan", strlen("macvlan"));
160
161 // set macvlan bridge mode
162 struct rtattr * data = NLMSG_TAIL(&req.n);
163 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
164 int macvlan_type = MACVLAN_MODE_BRIDGE;
165 addattr_l (&req.n, sizeof(req), IFLA_INFO_KIND, &macvlan_type, 4);
166
167 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
168// req.n.nlmsg_len += sizeof(struct ifinfomsg);
169
170
171 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
172 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
173
174 // send message
175 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
176 exit(2);
177
178 rtnl_close(&rth);
179
180 return 0;
181}
182
183// move the interface dev in namespace of program pid
184// when the interface is moved, netlink does not preserve interface configuration
185int net_move_interface(const char *dev, unsigned pid) {
186 struct iplink_req req;
187 assert(dev);
188
189 if (rtnl_open(&rth, 0) < 0) {
190 fprintf(stderr, "cannot open netlink\n");
191 exit(1);
192 }
193
194 memset(&req, 0, sizeof(req));
195
196 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
197 req.n.nlmsg_flags = NLM_F_REQUEST;
198 req.n.nlmsg_type = RTM_NEWLINK;
199 req.i.ifi_family = 0;
200
201 // find ifindex
202 int ifindex = if_nametoindex(dev);
203 if (ifindex <= 0) {
204 fprintf(stderr, "Error: cannot find interface %s\n", dev);
205 exit(1);
206 }
207 req.i.ifi_index = ifindex;
208
209 // place the interface in child namespace
210 addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4);
211
212 // send message
213 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
214 exit(2);
215
216 rtnl_close(&rth);
217
218 return 0;
219}
220
221/*
222int main(int argc, char **argv) {
223 printf("Hello\n");
224
225
226 char *dev = argv[3];
227 char *nsdev = argv[8];
228 unsigned pid;
229 sscanf(argv[10], "%u", &pid);
230
231
232 net_create_veth(dev, nsdev, pid);
233
234 return 0;
235}
236*/ \ No newline at end of file