aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/network_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/network_main.c')
-rw-r--r--src/firejail/network_main.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c
new file mode 100644
index 000000000..c2459b0cd
--- /dev/null
+++ b/src/firejail/network_main.c
@@ -0,0 +1,268 @@
1/*
2 * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com)
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 "firejail.h"
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <net/if.h>
26
27// configure bridge structure
28// - extract ip address and mask from the bridge interface
29void net_configure_bridge(Bridge *br, char *dev_name) {
30 assert(br);
31 assert(dev_name);
32
33 br->dev = dev_name;
34
35 // check the bridge device exists
36 char sysbridge[30 + strlen(br->dev)];
37 sprintf(sysbridge, "/sys/class/net/%s/bridge", br->dev);
38 struct stat s;
39 int rv = stat(sysbridge, &s);
40 if (rv == 0) {
41 // this is a bridge device
42 br->macvlan = 0;
43 }
44 else {
45 // is this a regular Ethernet interface
46 if (if_nametoindex(br->dev) > 0) {
47 br->macvlan = 1;
48 char *newname;
49 if (asprintf(&newname, "%s-%u", br->devsandbox, getpid()) == -1)
50 errExit("asprintf");
51 br->devsandbox = newname;
52 }
53 else {
54 fprintf(stderr, "Error: cannot find network device %s\n", br->dev);
55 exit(1);
56 }
57 }
58
59 if (net_get_if_addr(br->dev, &br->ip, &br->mask, br->mac)) {
60 fprintf(stderr, "Error: interface %s is not configured\n", br->dev);
61 exit(1);
62 }
63 if (arg_debug) {
64 if (br->macvlan == 0)
65 printf("Bridge device %s at %d.%d.%d.%d/%d\n",
66 br->dev, PRINT_IP(br->ip), mask2bits(br->mask));
67 else
68 printf("macvlan parent device %s at %d.%d.%d.%d/%d\n",
69 br->dev, PRINT_IP(br->ip), mask2bits(br->mask));
70 }
71
72 uint32_t range = ~br->mask + 1; // the number of potential addresses
73 // this software is not supported for /31 networks
74 if (range < 4) {
75 fprintf(stderr, "Error: the software is not supported for /31 networks\n");
76 exit(1);
77 }
78 br->configured = 1;
79}
80
81
82void net_configure_sandbox_ip(Bridge *br) {
83 assert(br);
84 if (br->configured == 0)
85 return;
86
87 if (br->arg_ip_none)
88 br->ipsandbox = 0;
89 else if (br->ipsandbox) {
90 // check network range
91 char *rv = in_netrange(br->ipsandbox, br->ip, br->mask);
92 if (rv) {
93 fprintf(stderr, "%s", rv);
94 exit(1);
95 }
96 // send an ARP request and check if there is anybody on this IP address
97 if (arp_check(br->dev, br->ipsandbox, br->ip)) {
98 fprintf(stderr, "Error: IP address %d.%d.%d.%d is already in use\n", PRINT_IP(br->ipsandbox));
99 exit(1);
100 }
101 }
102 else
103 // ip address assigned by arp-scan for a bridge device
104 br->ipsandbox = arp_assign(br->dev, br); //br->ip, br->mask);
105}
106
107
108// create a veth pair
109// - br - bridge device
110// - ifname - interface name in sandbox namespace
111// - child - child process running the namespace
112
113void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child) {
114 assert(br);
115 if (br->configured == 0)
116 return;
117
118 // create a veth pair
119 char *dev;
120 if (asprintf(&dev, "veth%u%s", getpid(), ifname) < 0)
121 errExit("asprintf");
122 net_create_veth(dev, ifname, child);
123
124 // bring up the interface
125 net_if_up(dev);
126
127 // add interface to the bridge
128 net_bridge_add_interface(br->dev, dev);
129
130 char *msg;
131 if (asprintf(&msg, "%d.%d.%d.%d address assigned to sandbox", PRINT_IP(br->ipsandbox)) == -1)
132 errExit("asprintf");
133 logmsg(msg);
134 fflush(0);
135 free(msg);
136}
137
138// the default address should be in the range of at least on of the bridge devices
139void check_default_gw(uint32_t defaultgw) {
140 assert(defaultgw);
141
142 if (cfg.bridge0.configured) {
143 char *rv = in_netrange(defaultgw, cfg.bridge0.ip, cfg.bridge0.mask);
144 if (rv == 0)
145 return;
146 }
147 if (cfg.bridge1.configured) {
148 char *rv = in_netrange(defaultgw, cfg.bridge1.ip, cfg.bridge1.mask);
149 if (rv == 0)
150 return;
151 }
152 if (cfg.bridge2.configured) {
153 char *rv = in_netrange(defaultgw, cfg.bridge2.ip, cfg.bridge2.mask);
154 if (rv == 0)
155 return;
156 }
157 if (cfg.bridge3.configured) {
158 char *rv = in_netrange(defaultgw, cfg.bridge3.ip, cfg.bridge3.mask);
159 if (rv == 0)
160 return;
161 }
162
163 fprintf(stderr, "Error: default gateway %d.%d.%d.%d is not in the range of any network\n", PRINT_IP(defaultgw));
164 exit(1);
165}
166
167void net_check_cfg(void) {
168 int net_configured = 0;
169 if (cfg.bridge0.configured)
170 net_configured++;
171 if (cfg.bridge1.configured)
172 net_configured++;
173 if (cfg.bridge2.configured)
174 net_configured++;
175 if (cfg.bridge3.configured)
176 net_configured++;
177
178 // --defaultgw requires a network
179 if (cfg.defaultgw && net_configured == 0) {
180 fprintf(stderr, "Error: option --defaultgw requires at least one network to be configured\n");
181 exit(1);
182 }
183
184 if (net_configured == 0) // nothing to check
185 return;
186
187 // --net=none
188 if (arg_nonetwork && net_configured) {
189 fprintf(stderr, "Error: --net and --net=none are mutually exclusive\n");
190 exit(1);
191 }
192
193 // check default gateway address or assign one
194 assert(cfg.bridge0.configured);
195 if (cfg.defaultgw)
196 check_default_gw(cfg.defaultgw);
197 else {
198 // first network is a regular bridge
199 if (cfg.bridge0.macvlan == 0)
200 cfg.defaultgw = cfg.bridge0.ip;
201 // first network is a mac device
202 else {
203 // get the host default gw
204 uint32_t gw = network_get_defaultgw();
205 // check the gateway is network range
206 if (in_netrange(gw, cfg.bridge0.ip, cfg.bridge0.mask))
207 gw = 0;
208 cfg.defaultgw = gw;
209 }
210 }
211}
212
213
214
215void net_dns_print_name(const char *name) {
216 if (!name || strlen(name) == 0) {
217 fprintf(stderr, "Error: invalid sandbox name\n");
218 exit(1);
219 }
220 pid_t pid;
221 if (name2pid(name, &pid)) {
222 fprintf(stderr, "Error: cannot find sandbox %s\n", name);
223 exit(1);
224 }
225
226 net_dns_print(pid);
227}
228
229#define MAXBUF 4096
230void net_dns_print(pid_t pid) {
231 // drop privileges - will not be able to read /etc/resolv.conf for --noroot option
232// drop_privs(1);
233
234 // if the pid is that of a firejail process, use the pid of the first child process
235 char *comm = pid_proc_comm(pid);
236 if (comm) {
237 // remove \n
238 char *ptr = strchr(comm, '\n');
239 if (ptr)
240 *ptr = '\0';
241 if (strcmp(comm, "firejail") == 0) {
242 pid_t child;
243 if (find_child(pid, &child) == 0) {
244 pid = child;
245 }
246 }
247 free(comm);
248 }
249
250 char *fname;
251 if (asprintf(&fname, "/proc/%d/root/etc/resolv.conf", pid) == -1)
252 errExit("asprintf");
253
254 // access /etc/resolv.conf
255 FILE *fp = fopen(fname, "r");
256 if (!fp) {
257 fprintf(stderr, "Error: cannot access /etc/resolv.conf\n");
258 exit(1);
259 }
260
261 char buf[MAXBUF];
262 while (fgets(buf, MAXBUF, fp))
263 printf("%s", buf);
264 printf("\n");
265 fclose(fp);
266 free(fname);
267 exit(0);
268}