diff options
Diffstat (limited to 'src/fnet/interface.c')
-rw-r--r-- | src/fnet/interface.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/fnet/interface.c b/src/fnet/interface.c new file mode 100644 index 000000000..b1903dd46 --- /dev/null +++ b/src/fnet/interface.c | |||
@@ -0,0 +1,183 @@ | |||
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 | // add a veth device to a bridge | ||
33 | void net_bridge_add_interface(const char *bridge, const char *dev) { | ||
34 | if (strlen(bridge) > IFNAMSIZ) { | ||
35 | fprintf(stderr, "Error fnet: invalid network device name %s\n", bridge); | ||
36 | exit(1); | ||
37 | } | ||
38 | |||
39 | // somehow adding the interface to the bridge resets MTU on bridge device!!! | ||
40 | // workaround: restore MTU on the bridge device | ||
41 | // todo: put a real fix in | ||
42 | int mtu1 = net_get_mtu(bridge); | ||
43 | |||
44 | struct ifreq ifr; | ||
45 | int err; | ||
46 | int ifindex = if_nametoindex(dev); | ||
47 | |||
48 | if (ifindex <= 0) | ||
49 | errExit("if_nametoindex"); | ||
50 | |||
51 | int sock; | ||
52 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) | ||
53 | errExit("socket"); | ||
54 | |||
55 | memset(&ifr, 0, sizeof(ifr)); | ||
56 | strncpy(ifr.ifr_name, bridge, IFNAMSIZ); | ||
57 | #ifdef SIOCBRADDIF | ||
58 | ifr.ifr_ifindex = ifindex; | ||
59 | err = ioctl(sock, SIOCBRADDIF, &ifr); | ||
60 | if (err < 0) | ||
61 | #endif | ||
62 | { | ||
63 | unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; | ||
64 | |||
65 | ifr.ifr_data = (char *) args; | ||
66 | err = ioctl(sock, SIOCDEVPRIVATE, &ifr); | ||
67 | } | ||
68 | (void) err; | ||
69 | close(sock); | ||
70 | |||
71 | int mtu2 = net_get_mtu(bridge); | ||
72 | if (mtu1 != mtu2) { | ||
73 | net_set_mtu(bridge, mtu1); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | |||
78 | // bring interface up | ||
79 | void net_if_up(const char *ifname) { | ||
80 | if (strlen(ifname) > IFNAMSIZ) { | ||
81 | fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname); | ||
82 | exit(1); | ||
83 | } | ||
84 | |||
85 | int sock = socket(AF_INET,SOCK_DGRAM,0); | ||
86 | if (sock < 0) | ||
87 | errExit("socket"); | ||
88 | |||
89 | // get the existing interface flags | ||
90 | struct ifreq ifr; | ||
91 | memset(&ifr, 0, sizeof(ifr)); | ||
92 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
93 | ifr.ifr_addr.sa_family = AF_INET; | ||
94 | |||
95 | // read the existing flags | ||
96 | if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { | ||
97 | close(sock); | ||
98 | printf("Error fnet: cannot bring up interface %s\n", ifname); | ||
99 | errExit("ioctl"); | ||
100 | } | ||
101 | |||
102 | ifr.ifr_flags |= IFF_UP; | ||
103 | |||
104 | // set the new flags | ||
105 | if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) { | ||
106 | close(sock); | ||
107 | printf("Error fnet: cannot bring up interface %s\n", ifname); | ||
108 | errExit("ioctl"); | ||
109 | } | ||
110 | |||
111 | // checking | ||
112 | // read the existing flags | ||
113 | if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { | ||
114 | close(sock); | ||
115 | printf("Error fnet: cannot bring up interface %s\n", ifname); | ||
116 | errExit("ioctl"); | ||
117 | } | ||
118 | |||
119 | // wait not more than 500ms for the interface to come up | ||
120 | int cnt = 0; | ||
121 | while (cnt < 50) { | ||
122 | usleep(10000); // sleep 10ms | ||
123 | |||
124 | // read the existing flags | ||
125 | if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { | ||
126 | close(sock); | ||
127 | printf("Error fnet: cannot bring up interface %s\n", ifname); | ||
128 | errExit("ioctl"); | ||
129 | } | ||
130 | if (ifr.ifr_flags & IFF_RUNNING) | ||
131 | break; | ||
132 | cnt++; | ||
133 | } | ||
134 | |||
135 | close(sock); | ||
136 | } | ||
137 | |||
138 | int net_get_mtu(const char *ifname) { | ||
139 | int mtu = 0; | ||
140 | if (strlen(ifname) > IFNAMSIZ) { | ||
141 | fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname); | ||
142 | exit(1); | ||
143 | } | ||
144 | |||
145 | int s; | ||
146 | struct ifreq ifr; | ||
147 | |||
148 | if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) | ||
149 | errExit("socket"); | ||
150 | |||
151 | memset(&ifr, 0, sizeof(ifr)); | ||
152 | ifr.ifr_addr.sa_family = AF_INET; | ||
153 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
154 | if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) | ||
155 | mtu = ifr.ifr_mtu; | ||
156 | close(s); | ||
157 | |||
158 | |||
159 | return mtu; | ||
160 | } | ||
161 | |||
162 | void net_set_mtu(const char *ifname, int mtu) { | ||
163 | if (strlen(ifname) > IFNAMSIZ) { | ||
164 | fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname); | ||
165 | exit(1); | ||
166 | } | ||
167 | |||
168 | int s; | ||
169 | struct ifreq ifr; | ||
170 | |||
171 | if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) | ||
172 | errExit("socket"); | ||
173 | |||
174 | memset(&ifr, 0, sizeof(ifr)); | ||
175 | ifr.ifr_addr.sa_family = AF_INET; | ||
176 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
177 | ifr.ifr_mtu = mtu; | ||
178 | if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) != 0) | ||
179 | fprintf(stderr, "Warning fnet: cannot set mtu for interface %s\n", ifname); | ||
180 | close(s); | ||
181 | } | ||
182 | |||
183 | |||