aboutsummaryrefslogtreecommitdiffstats
path: root/src/fnet
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-10-30 15:54:05 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2016-10-30 15:54:05 -0400
commitf898290fd79e0e64d13ceef56fc5960da879d179 (patch)
tree7112345d8121d1d61f90995e09754bbfbfbf467f /src/fnet
parentMerge pull request #878 from msva/patch-1 (diff)
downloadfirejail-f898290fd79e0e64d13ceef56fc5960da879d179.tar.gz
firejail-f898290fd79e0e64d13ceef56fc5960da879d179.tar.zst
firejail-f898290fd79e0e64d13ceef56fc5960da879d179.zip
major cleanup
Diffstat (limited to 'src/fnet')
-rw-r--r--src/fnet/arp.c208
-rw-r--r--src/fnet/fnet.h9
-rw-r--r--src/fnet/interface.c212
-rw-r--r--src/fnet/main.c39
4 files changed, 465 insertions, 3 deletions
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
index 58efbbed5..0c5e5baef 100644
--- a/src/fnet/fnet.h
+++ b/src/fnet/fnet.h
@@ -36,5 +36,14 @@ void net_bridge_add_interface(const char *bridge, const char *dev);
36void net_if_up(const char *ifname); 36void net_if_up(const char *ifname);
37int net_get_mtu(const char *ifname); 37int net_get_mtu(const char *ifname);
38void net_set_mtu(const char *ifname, int mtu); 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);
39 48
40#endif 49#endif
diff --git a/src/fnet/interface.c b/src/fnet/interface.c
index b1903dd46..67af062bf 100644
--- a/src/fnet/interface.c
+++ b/src/fnet/interface.c
@@ -180,4 +180,216 @@ void net_set_mtu(const char *ifname, int mtu) {
180 close(s); 180 close(s);
181} 181}
182 182
183// scan interfaces in current namespace and print IP address/mask for each interface
184void net_ifprint(int scan) {
185 uint32_t ip;
186 uint32_t mask;
187 struct ifaddrs *ifaddr, *ifa;
183 188
189 if (getifaddrs(&ifaddr) == -1)
190 errExit("getifaddrs");
191
192 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
193 "Interface", "MAC", "IP", "Mask", "Status");
194 // walk through the linked list
195 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
196 if (ifa->ifa_addr == NULL)
197 continue;
198
199 if (ifa->ifa_addr->sa_family == AF_INET) {
200 struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask;
201 mask = ntohl(si->sin_addr.s_addr);
202 si = (struct sockaddr_in *) ifa->ifa_addr;
203 ip = ntohl(si->sin_addr.s_addr);
204
205 // interface status
206 char *status;
207 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
208 status = "UP";
209 else
210 status = "DOWN";
211
212 // ip address and mask
213 char ipstr[30];
214 sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip));
215 char maskstr[30];
216 sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask));
217
218 // mac address
219 unsigned char mac[6];
220 net_get_mac(ifa->ifa_name, mac);
221 char macstr[30];
222 if (strcmp(ifa->ifa_name, "lo") == 0)
223 macstr[0] = '\0';
224 else
225 sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac));
226
227 // print
228 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
229 ifa->ifa_name, macstr, ipstr, maskstr, status);
230
231 // network scanning
232 if (!scan) // scanning disabled
233 continue;
234 if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning
235 continue;
236 if (mask2bits(mask) < 16) // not scanning large networks
237 continue;
238 if (!ip) // if not configured
239 continue;
240 // only if the interface is up and running
241 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
242 arp_scan(ifa->ifa_name, ip, mask);
243 }
244 }
245 freeifaddrs(ifaddr);
246}
247
248int net_get_mac(const char *ifname, unsigned char mac[6]) {
249
250 struct ifreq ifr;
251 int sock;
252
253 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
254 errExit("socket");
255
256 memset(&ifr, 0, sizeof(ifr));
257 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
258 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
259
260 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1)
261 errExit("ioctl");
262 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
263
264 close(sock);
265 return 0;
266}
267
268// configure interface ipv4 address
269void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) {
270 if (strlen(ifname) > IFNAMSIZ) {
271 fprintf(stderr, "Error: invalid network device name %s\n", ifname);
272 exit(1);
273 }
274
275 int sock = socket(AF_INET,SOCK_DGRAM,0);
276 if (sock < 0)
277 errExit("socket");
278
279 struct ifreq ifr;
280 memset(&ifr, 0, sizeof(ifr));
281 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
282 ifr.ifr_addr.sa_family = AF_INET;
283
284 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip);
285 if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) {
286 close(sock);
287 errExit("ioctl");
288 }
289
290 if (ip != 0) {
291 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask);
292 if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) {
293 close(sock);
294 errExit("ioctl");
295 }
296 }
297
298 // configure mtu
299 if (mtu > 0) {
300 ifr.ifr_mtu = mtu;
301 if (ioctl( sock, SIOCSIFMTU, &ifr ) < 0) {
302 close(sock);
303 errExit("ioctl");
304 }
305 }
306
307 close(sock);
308 usleep(10000); // sleep 10ms
309}
310
311int net_if_mac(const char *ifname, const unsigned char mac[6]) {
312 struct ifreq ifr;
313 int sock;
314
315 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
316 errExit("socket");
317
318 memset(&ifr, 0, sizeof(ifr));
319 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
320 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
321 memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
322
323 if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1)
324 errExit("ioctl");
325 close(sock);
326 return 0;
327}
328
329// configure interface ipv6 address
330// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64
331struct ifreq6 {
332 struct in6_addr ifr6_addr;
333 uint32_t ifr6_prefixlen;
334 unsigned int ifr6_ifindex;
335};
336void net_if_ip6(const char *ifname, const char *addr6) {
337 if (strchr(addr6, ':') == NULL) {
338 fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6);
339 exit(1);
340 }
341
342 // extract prefix
343 unsigned long prefix;
344 char *ptr;
345 if ((ptr = strchr(addr6, '/'))) {
346 prefix = atol(ptr + 1);
347 if (prefix > 128) {
348 fprintf(stderr, "Error fnet: invalid prefix for IPv6 address %s\n", addr6);
349 exit(1);
350 }
351 *ptr = '\0'; // mark the end of the address
352 }
353 else
354 prefix = 128;
355
356 // extract address
357 struct sockaddr_in6 sin6;
358 memset(&sin6, 0, sizeof(sin6));
359 sin6.sin6_family = AF_INET6;
360 int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr);
361 if (rv <= 0) {
362 fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6);
363 exit(1);
364 }
365
366 // open socket
367 int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
368 if (sock < 0) {
369 fprintf(stderr, "Error fnet: IPv6 is not supported on this system\n");
370 exit(1);
371 }
372
373 // find interface index
374 struct ifreq ifr;
375 memset(&ifr, 0, sizeof(ifr));
376 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
377 ifr.ifr_addr.sa_family = AF_INET;
378 if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) {
379 perror("ioctl SIOGIFINDEX");
380 exit(1);
381 }
382
383 // configure address
384 struct ifreq6 ifr6;
385 memset(&ifr6, 0, sizeof(ifr6));
386 ifr6.ifr6_prefixlen = prefix;
387 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
388 memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr));
389 if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) {
390 perror("ioctl SIOCSIFADDR");
391 exit(1);
392 }
393
394 close(sock);
395}
diff --git a/src/fnet/main.c b/src/fnet/main.c
index f17287cb9..4ae9eb6e3 100644
--- a/src/fnet/main.c
+++ b/src/fnet/main.c
@@ -24,12 +24,18 @@ static void usage(void) {
24 printf("\tfnet create veth dev1 dev2 bridge child\n"); 24 printf("\tfnet create veth dev1 dev2 bridge child\n");
25 printf("\tfnet create macvlan dev parent child\n"); 25 printf("\tfnet create macvlan dev parent child\n");
26 printf("\tfnet moveif dev proc\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");
27} 33}
28 34
29int main(int argc, char **argv) { 35int main(int argc, char **argv) {
30#if 0 36#if 0
31{ 37{
32system("cat /proc/self/status"); 38//system("cat /proc/self/status");
33int i; 39int i;
34for (i = 0; i < argc; i++) 40for (i = 0; i < argc; i++)
35 printf("*%s* ", argv[i]); 41 printf("*%s* ", argv[i]);
@@ -45,22 +51,49 @@ printf("\n");
45 usage(); 51 usage();
46 return 0; 52 return 0;
47 } 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 }
48 else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) { 63 else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) {
49 // create veth pair and move one end in the the namespace 64 // create veth pair and move one end in the the namespace
50 net_create_veth(argv[3], argv[4], atoi(argv[6])); 65 net_create_veth(argv[3], argv[4], atoi(argv[6]));
51
52 // connect the ohter veth end to the bridge ... 66 // connect the ohter veth end to the bridge ...
53 net_bridge_add_interface(argv[5], argv[3]); 67 net_bridge_add_interface(argv[5], argv[3]);
54
55 // ... and bring it up 68 // ... and bring it up
56 net_if_up(argv[3]); 69 net_if_up(argv[3]);
57 } 70 }
58 else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) { 71 else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) {
59 net_create_macvlan(argv[3], argv[4], atoi(argv[5])); 72 net_create_macvlan(argv[3], argv[4], atoi(argv[5]));
60 } 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 }
61 else if (argc == 4 && strcmp(argv[1], "moveif") == 0) { 91 else if (argc == 4 && strcmp(argv[1], "moveif") == 0) {
62 net_move_interface(argv[2], atoi(argv[3])); 92 net_move_interface(argv[2], atoi(argv[3]));
63 } 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 }
64 else { 97 else {
65 fprintf(stderr, "Error fnet: invalid arguments\n"); 98 fprintf(stderr, "Error fnet: invalid arguments\n");
66 return 1; 99 return 1;