diff options
Diffstat (limited to 'src/fnet')
-rw-r--r-- | src/fnet/Makefile.in | 45 | ||||
-rw-r--r-- | src/fnet/arp.c | 208 | ||||
-rw-r--r-- | src/fnet/fnet.h | 49 | ||||
-rw-r--r-- | src/fnet/interface.c | 370 | ||||
-rw-r--r-- | src/fnet/main.c | 103 | ||||
-rw-r--r-- | src/fnet/veth.c | 236 |
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 @@ | |||
1 | all: fnet | ||
2 | |||
3 | prefix=@prefix@ | ||
4 | exec_prefix=@exec_prefix@ | ||
5 | libdir=@libdir@ | ||
6 | sysconfdir=@sysconfdir@ | ||
7 | |||
8 | VERSION=@PACKAGE_VERSION@ | ||
9 | NAME=@PACKAGE_NAME@ | ||
10 | HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ | ||
11 | HAVE_SECCOMP=@HAVE_SECCOMP@ | ||
12 | HAVE_CHROOT=@HAVE_CHROOT@ | ||
13 | HAVE_BIND=@HAVE_BIND@ | ||
14 | HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ | ||
15 | HAVE_NETWORK=@HAVE_NETWORK@ | ||
16 | HAVE_USERNS=@HAVE_USERNS@ | ||
17 | HAVE_X11=@HAVE_X11@ | ||
18 | HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ | ||
19 | HAVE_WHITELIST=@HAVE_WHITELIST@ | ||
20 | HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ | ||
21 | HAVE_APPARMOR=@HAVE_APPARMOR@ | ||
22 | HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ | ||
23 | HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ | ||
24 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ | ||
25 | HAVE_GCOV=@HAVE_GCOV@ | ||
26 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ | ||
27 | |||
28 | H_FILE_LIST = $(sort $(wildcard *.[h])) | ||
29 | C_FILE_LIST = $(sort $(wildcard *.c)) | ||
30 | OBJS = $(C_FILE_LIST:.c=.o) | ||
31 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
32 | CFLAGS += -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 | ||
33 | LDFLAGS += -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 | |||
38 | fnet: $(OBJS) ../lib/libnetlink.o | ||
39 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o $(LIBS) $(EXTRA_LDFLAGS) | ||
40 | |||
41 | clean:; rm -f *.o fnet *.gcov *.gcda *.gcno | ||
42 | |||
43 | distclean: 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 | |||
31 | typedef 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) | ||
45 | void 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 | ||
30 | int net_create_veth(const char *dev, const char *nsdev, unsigned pid); | ||
31 | int net_create_macvlan(const char *dev, const char *parent, unsigned pid); | ||
32 | int net_move_interface(const char *dev, unsigned pid); | ||
33 | |||
34 | // interface.c | ||
35 | void net_bridge_add_interface(const char *bridge, const char *dev); | ||
36 | void net_if_up(const char *ifname); | ||
37 | int net_get_mtu(const char *ifname); | ||
38 | void net_set_mtu(const char *ifname, int mtu); | ||
39 | void net_ifprint(int scan); | ||
40 | int net_get_mac(const char *ifname, unsigned char mac[6]); | ||
41 | void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu); | ||
42 | int net_if_mac(const char *ifname, const unsigned char mac[6]); | ||
43 | void net_if_ip6(const char *ifname, const char *addr6); | ||
44 | |||
45 | |||
46 | // arp.c | ||
47 | void 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 | |||
32 | static 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 | ||
40 | void 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 | ||
83 | void 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 | |||
127 | int 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 | |||
147 | void 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 | ||
165 | void 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 | |||
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 | |||
229 | int 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 | ||
251 | void 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 | |||
284 | int 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 | ||
305 | struct ifreq6 { | ||
306 | struct in6_addr ifr6_addr; | ||
307 | uint32_t ifr6_prefixlen; | ||
308 | unsigned int ifr6_ifindex; | ||
309 | }; | ||
310 | void 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 | |||
22 | static 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 | |||
35 | int main(int argc, char **argv) { | ||
36 | #if 0 | ||
37 | { | ||
38 | //system("cat /proc/self/status"); | ||
39 | int i; | ||
40 | for (i = 0; i < argc; i++) | ||
41 | printf("*%s* ", argv[i]); | ||
42 | printf("\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 | |||
53 | struct iplink_req | ||
54 | { | ||
55 | struct nlmsghdr n; | ||
56 | struct ifinfomsg i; | ||
57 | char buf[1024]; | ||
58 | }; | ||
59 | |||
60 | static struct rtnl_handle rth = { .fd = -1 }; | ||
61 | |||
62 | int 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 | |||
120 | int 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 | ||
185 | int 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 | /* | ||
222 | int 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 | ||