aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2015-09-22 08:18:56 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2015-09-22 08:18:56 -0400
commit56bf7c836e8cbc74b36ded08429b2112096f6d8e (patch)
tree8fbcfceb69e8b51556802dcb08a2e408b4942f59 /src
parentfixed macvlan problem (diff)
downloadfirejail-56bf7c836e8cbc74b36ded08429b2112096f6d8e.tar.gz
firejail-56bf7c836e8cbc74b36ded08429b2112096f6d8e.tar.zst
firejail-56bf7c836e8cbc74b36ded08429b2112096f6d8e.zip
added --interface option
Diffstat (limited to 'src')
-rw-r--r--src/firejail/firejail.h24
-rw-r--r--src/firejail/main.c116
-rw-r--r--src/firejail/sandbox.c32
-rw-r--r--src/firejail/usage.c4
-rw-r--r--src/firejail/veth.c38
-rw-r--r--src/man/firejail.txt12
6 files changed, 193 insertions, 33 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index aa8144a40..cef4b673c 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -55,6 +55,16 @@ typedef struct bridge_t {
55 uint8_t scan; // set by --scan 55 uint8_t scan; // set by --scan
56} Bridge; 56} Bridge;
57 57
58typedef struct interface_t {
59 char *dev;
60 uint32_t ip;
61 uint32_t mask;
62 uint8_t mac[6];
63 // todo: add mtu
64
65 uint8_t configured;
66} Interface;
67
58typedef struct profile_entry_t { 68typedef struct profile_entry_t {
59 struct profile_entry_t *next; 69 struct profile_entry_t *next;
60 char *data; 70 char *data;
@@ -81,6 +91,10 @@ typedef struct config_t {
81 Bridge bridge1; 91 Bridge bridge1;
82 Bridge bridge2; 92 Bridge bridge2;
83 Bridge bridge3; 93 Bridge bridge3;
94 Interface interface0;
95 Interface interface1;
96 Interface interface2;
97 Interface interface3;
84 uint32_t dns1; // up to 3 IP addresses for dns servers 98 uint32_t dns1; // up to 3 IP addresses for dns servers
85 uint32_t dns2; 99 uint32_t dns2;
86 uint32_t dns3; 100 uint32_t dns3;
@@ -107,7 +121,14 @@ typedef struct config_t {
107extern Config cfg; 121extern Config cfg;
108 122
109static inline int any_bridge_configured(void) { 123static inline int any_bridge_configured(void) {
110 if (cfg.bridge3.configured || cfg.bridge2.configured || cfg.bridge1.configured || cfg.bridge0.configured) 124 if (cfg.bridge0.configured || cfg.bridge1.configured || cfg.bridge2.configured || cfg.bridge3.configured)
125 return 1;
126 else
127 return 0;
128}
129
130static inline int any_interface_configured(void) {
131 if (cfg.interface0.configured || cfg.interface1.configured || cfg.interface2.configured || cfg.interface3.configured)
111 return 1; 132 return 1;
112 else 133 else
113 return 0; 134 return 0;
@@ -243,6 +264,7 @@ void arp_scan(const char *dev, uint32_t srcaddr, uint32_t srcmask);
243// veth.c 264// veth.c
244int net_create_veth(const char *dev, const char *nsdev, unsigned pid); 265int net_create_veth(const char *dev, const char *nsdev, unsigned pid);
245int net_create_macvlan(const char *dev, const char *parent, unsigned pid); 266int net_create_macvlan(const char *dev, const char *parent, unsigned pid);
267int net_move_interface(const char *dev, unsigned pid);
246 268
247// util.c 269// util.c
248void drop_privs(int nogroups); 270void drop_privs(int nogroups);
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 82d17264a..9d94630ef 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -754,6 +754,45 @@ int main(int argc, char **argv) {
754 //************************************* 754 //*************************************
755 // network 755 // network
756 //************************************* 756 //*************************************
757 else if (strncmp(argv[i], "--interface=", 12) == 0) {
758 // checks
759 if (arg_nonetwork) {
760 fprintf(stderr, "Error: --network=none and --interface are incompatible\n");
761 exit(1);
762 }
763 if (strcmp(argv[i] + 12, "lo") == 0) {
764 fprintf(stderr, "Error: cannot use lo device in --interface command\n");
765 exit(1);
766 }
767 int ifindex = if_nametoindex(argv[i] + 12);
768 if (ifindex <= 0) {
769 fprintf(stderr, "Error: cannot find interface %s\n", argv[i] + 12);
770 exit(1);
771 }
772
773 Interface *intf;
774 if (cfg.interface0.configured == 0)
775 intf = &cfg.interface0;
776 else if (cfg.interface1.configured == 0)
777 intf = &cfg.interface1;
778 else if (cfg.interface2.configured == 0)
779 intf = &cfg.interface2;
780 else if (cfg.interface3.configured == 0)
781 intf = &cfg.interface3;
782 else {
783 fprintf(stderr, "Error: maximum 4 interfaces are allowed\n");
784 return 1;
785 }
786
787 intf->dev = strdup(argv[i] + 12);
788 if (!intf->dev)
789 errExit("strdup");
790
791 if (net_get_if_addr(intf->dev, &intf->ip, &intf->mask, intf->mac)) {
792 fprintf(stderr, "Warning: interface %s is not configured\n", intf->dev);
793 }
794 intf->configured = 1;
795 }
757 else if (strncmp(argv[i], "--net=", 6) == 0) { 796 else if (strncmp(argv[i], "--net=", 6) == 0) {
758 if (strcmp(argv[i] + 6, "none") == 0) { 797 if (strcmp(argv[i] + 6, "none") == 0) {
759 arg_nonetwork = 1; 798 arg_nonetwork = 1;
@@ -761,6 +800,10 @@ int main(int argc, char **argv) {
761 cfg.bridge1.configured = 0; 800 cfg.bridge1.configured = 0;
762 cfg.bridge2.configured = 0; 801 cfg.bridge2.configured = 0;
763 cfg.bridge3.configured = 0; 802 cfg.bridge3.configured = 0;
803 cfg.interface0.configured = 0;
804 cfg.interface1.configured = 0;
805 cfg.interface2.configured = 0;
806 cfg.interface3.configured = 0;
764 continue; 807 continue;
765 } 808 }
766 if (strcmp(argv[i] + 6, "lo") == 0) { 809 if (strcmp(argv[i] + 6, "lo") == 0) {
@@ -778,7 +821,7 @@ int main(int argc, char **argv) {
778 else if (cfg.bridge3.configured == 0) 821 else if (cfg.bridge3.configured == 0)
779 br = &cfg.bridge3; 822 br = &cfg.bridge3;
780 else { 823 else {
781 fprintf(stderr, "Error: maximum 4 network devices allowed\n"); 824 fprintf(stderr, "Error: maximum 4 network devices are allowed\n");
782 return 1; 825 return 1;
783 } 826 }
784 net_configure_bridge(br, argv[i] + 6); 827 net_configure_bridge(br, argv[i] + 6);
@@ -1130,7 +1173,7 @@ int main(int argc, char **argv) {
1130 if (getuid() == 0 || arg_ipc) 1173 if (getuid() == 0 || arg_ipc)
1131 flags |= CLONE_NEWIPC; 1174 flags |= CLONE_NEWIPC;
1132 1175
1133 if (any_bridge_configured() || arg_nonetwork) { 1176 if (any_bridge_configured() || any_interface_configured() || arg_nonetwork) {
1134 flags |= CLONE_NEWNET; 1177 flags |= CLONE_NEWNET;
1135 } 1178 }
1136 else if (arg_debug) 1179 else if (arg_debug)
@@ -1151,34 +1194,49 @@ int main(int argc, char **argv) {
1151 } 1194 }
1152 1195
1153 1196
1154 1197 if (!arg_nonetwork) {
1155 // create veth pair or macvlan device 1198 // create veth pair or macvlan device
1156 if (cfg.bridge0.configured && !arg_nonetwork) { 1199 if (cfg.bridge0.configured) {
1157 if (cfg.bridge0.macvlan == 0) 1200 if (cfg.bridge0.macvlan == 0)
1158 net_configure_veth_pair(&cfg.bridge0, "eth0", child); 1201 net_configure_veth_pair(&cfg.bridge0, "eth0", child);
1159 else 1202 else
1160 net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child); 1203 net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child);
1161 } 1204 }
1162 1205
1163 if (cfg.bridge1.configured && !arg_nonetwork) { 1206 if (cfg.bridge1.configured) {
1164 if (cfg.bridge1.macvlan == 0) 1207 if (cfg.bridge1.macvlan == 0)
1165 net_configure_veth_pair(&cfg.bridge1, "eth1", child); 1208 net_configure_veth_pair(&cfg.bridge1, "eth1", child);
1166 else 1209 else
1167 net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child); 1210 net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child);
1168 } 1211 }
1169 1212
1170 if (cfg.bridge2.configured && !arg_nonetwork) { 1213 if (cfg.bridge2.configured) {
1171 if (cfg.bridge2.macvlan == 0) 1214 if (cfg.bridge2.macvlan == 0)
1172 net_configure_veth_pair(&cfg.bridge2, "eth2", child); 1215 net_configure_veth_pair(&cfg.bridge2, "eth2", child);
1173 else 1216 else
1174 net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child); 1217 net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child);
1175 } 1218 }
1219
1220 if (cfg.bridge3.configured) {
1221 if (cfg.bridge3.macvlan == 0)
1222 net_configure_veth_pair(&cfg.bridge3, "eth3", child);
1223 else
1224 net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child);
1225 }
1176 1226
1177 if (cfg.bridge3.configured && !arg_nonetwork) { 1227 // move interfaces in sandbox
1178 if (cfg.bridge3.macvlan == 0) 1228 if (cfg.interface0.configured) {
1179 net_configure_veth_pair(&cfg.bridge3, "eth3", child); 1229 net_move_interface(cfg.interface0.dev, child);
1180 else 1230 }
1181 net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child); 1231 if (cfg.interface1.configured) {
1232 net_move_interface(cfg.interface1.dev, child);
1233 }
1234 if (cfg.interface2.configured) {
1235 net_move_interface(cfg.interface2.dev, child);
1236 }
1237 if (cfg.interface3.configured) {
1238 net_move_interface(cfg.interface3.dev, child);
1239 }
1182 } 1240 }
1183 1241
1184 // close each end of the unused pipes 1242 // close each end of the unused pipes
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 41fc20084..c1a6d92ec 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -277,7 +277,7 @@ int sandbox(void* sandbox_arg) {
277 if (arg_debug) 277 if (arg_debug)
278 printf("Network namespace enabled, only loopback interface available\n"); 278 printf("Network namespace enabled, only loopback interface available\n");
279 } 279 }
280 else if (any_bridge_configured()) { 280 else if (any_bridge_configured() || any_interface_configured()) {
281 // configure lo and eth0...eth3 281 // configure lo and eth0...eth3
282 net_if_up("lo"); 282 net_if_up("lo");
283 283
@@ -303,6 +303,32 @@ int sandbox(void* sandbox_arg) {
303 if (net_add_route(0, 0, cfg.defaultgw)) 303 if (net_add_route(0, 0, cfg.defaultgw))
304 fprintf(stderr, "Warning: cannot configure default route\n"); 304 fprintf(stderr, "Warning: cannot configure default route\n");
305 } 305 }
306
307 // enable interfaces
308 if (cfg.interface0.configured && cfg.interface0.ip) {
309 if (arg_debug)
310 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev);
311 net_if_ip(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask);
312 net_if_up(cfg.interface0.dev);
313 }
314 if (cfg.interface1.configured && cfg.interface1.ip) {
315 if (arg_debug)
316 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev);
317 net_if_ip(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask);
318 net_if_up(cfg.interface1.dev);
319 }
320 if (cfg.interface2.configured && cfg.interface2.ip) {
321 if (arg_debug)
322 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev);
323 net_if_ip(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask);
324 net_if_up(cfg.interface2.dev);
325 }
326 if (cfg.interface3.configured && cfg.interface3.ip) {
327 if (arg_debug)
328 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev);
329 net_if_ip(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask);
330 net_if_up(cfg.interface3.dev);
331 }
306 332
307 if (arg_debug) 333 if (arg_debug)
308 printf("Network namespace enabled\n"); 334 printf("Network namespace enabled\n");
@@ -312,9 +338,9 @@ int sandbox(void* sandbox_arg) {
312 fs_resolvconf(); 338 fs_resolvconf();
313 339
314 // print network configuration 340 // print network configuration
315 if (any_bridge_configured() || cfg.defaultgw || cfg.dns1) { 341 if (any_bridge_configured() || any_interface_configured() || cfg.defaultgw || cfg.dns1) {
316 printf("\n"); 342 printf("\n");
317 if (any_bridge_configured()) 343 if (any_bridge_configured() || any_interface_configured())
318 net_ifprint(); 344 net_ifprint();
319 if (cfg.defaultgw != 0) 345 if (cfg.defaultgw != 0)
320 printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw)); 346 printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw));
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 1f611001d..13e3d87e2 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -82,6 +82,10 @@ void usage(void) {
82 printf("\t--env=name=value - set environment variable in the new sandbox\n"); 82 printf("\t--env=name=value - set environment variable in the new sandbox\n");
83 83
84 printf("\t--help, -? - this help screen.\n\n"); 84 printf("\t--help, -? - this help screen.\n\n");
85
86 printf("\t--interface=name - move interface in a new network namespace. Up to\n");
87 printf("\t\tfour --interface options can be sepcified.\n\n");
88
85 printf("\t--ip=address - set interface IP address.\n\n"); 89 printf("\t--ip=address - set interface IP address.\n\n");
86 printf("\t--ip=none - no IP address and no default gateway address are configured\n"); 90 printf("\t--ip=none - no IP address and no default gateway address are configured\n");
87 printf("\t\tin the new network namespace. Use this option in case you intend\n"); 91 printf("\t\tin the new network namespace. Use this option in case you intend\n");
diff --git a/src/firejail/veth.c b/src/firejail/veth.c
index 0db55709b..45bf815aa 100644
--- a/src/firejail/veth.c
+++ b/src/firejail/veth.c
@@ -179,6 +179,44 @@ int net_create_macvlan(const char *dev, const char *parent, unsigned pid) {
179 return 0; 179 return 0;
180} 180}
181 181
182// move the interface dev in namespace of program pid
183// when the interface is moved, netlink does not preserve interface configuration
184int net_move_interface(const char *dev, unsigned pid) {
185 int len;
186 struct iplink_req req;
187 if (arg_debug)
188 printf("move device %s inside the namespace\n", dev);
189 assert(dev);
190
191 if (rtnl_open(&rth, 0) < 0) {
192 fprintf(stderr, "cannot open netlink\n");
193 exit(1);
194 }
195
196 memset(&req, 0, sizeof(req));
197
198 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
199 req.n.nlmsg_flags = NLM_F_REQUEST;
200 req.n.nlmsg_type = RTM_NEWLINK;
201 req.i.ifi_family = 0;
202
203 // find ifindex
204 int ifindex = if_nametoindex(dev);
205 if (ifindex <= 0) {
206 fprintf(stderr, "Error: cannot find interface %s\n", dev);
207 exit(1);
208 }
209 req.i.ifi_index = ifindex;
210
211 // place the interface in child namespace
212 addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4);
213
214 // send message
215 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
216 exit(2);
217
218 return 0;
219}
182 220
183/* 221/*
184int main(int argc, char **argv) { 222int main(int argc, char **argv) {
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 4bf537c95..3f4fba00e 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -320,6 +320,18 @@ $ firejail \-\-env=LD_LIBRARY_PATH=/opt/test/lib
320.TP 320.TP
321\fB\-?\fR, \fB\-\-help\fR 321\fB\-?\fR, \fB\-\-help\fR
322Print options end exit. 322Print options end exit.
323
324
325.TP
326\fB\-\-interface=interface
327Move interface in a new network namespace. Up to four --interface options can be sepcified.
328.br
329
330.br
331Example:
332.br
333$ firejail \-\-interface=eth1 \-\-interface=eth0.vlan100
334
323.TP 335.TP
324\fB\-\-ip=address 336\fB\-\-ip=address
325Assign IP addresses to the last network interface defined by a \-\-net option. A 337Assign IP addresses to the last network interface defined by a \-\-net option. A