aboutsummaryrefslogtreecommitdiffstats
path: root/src/fnet
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-10-27 08:58:48 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2016-10-27 08:58:48 -0400
commitabe5cb027416771da3d01c9b55d12a8f70618ed8 (patch)
tree8b97584d4948238eb104afb96d0691ec3d164fe8 /src/fnet
parentremoved ping blacklisting (diff)
downloadfirejail-abe5cb027416771da3d01c9b55d12a8f70618ed8.tar.gz
firejail-abe5cb027416771da3d01c9b55d12a8f70618ed8.tar.zst
firejail-abe5cb027416771da3d01c9b55d12a8f70618ed8.zip
network code split
Diffstat (limited to 'src/fnet')
-rw-r--r--src/fnet/Makefile.in43
-rw-r--r--src/fnet/fnet.h40
-rw-r--r--src/fnet/interface.c183
-rw-r--r--src/fnet/main.c63
-rw-r--r--src/fnet/veth.c230
5 files changed, 559 insertions, 0 deletions
diff --git a/src/fnet/Makefile.in b/src/fnet/Makefile.in
new file mode 100644
index 000000000..1bfb4c68d
--- /dev/null
+++ b/src/fnet/Makefile.in
@@ -0,0 +1,43 @@
1all: fnet
2
3prefix=@prefix@
4exec_prefix=@exec_prefix@
5libdir=@libdir@
6sysconfdir=@sysconfdir@
7
8VERSION=@PACKAGE_VERSION@
9NAME=@PACKAGE_NAME@
10HAVE_SECCOMP_H=@HAVE_SECCOMP_H@
11HAVE_SECCOMP=@HAVE_SECCOMP@
12HAVE_CHROOT=@HAVE_CHROOT@
13HAVE_BIND=@HAVE_BIND@
14HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@
15HAVE_NETWORK=@HAVE_NETWORK@
16HAVE_USERNS=@HAVE_USERNS@
17HAVE_X11=@HAVE_X11@
18HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@
19HAVE_WHITELIST=@HAVE_WHITELIST@
20HAVE_GLOBALCFG=@HAVE_GLOBALCFG@
21HAVE_APPARMOR=@HAVE_APPARMOR@
22HAVE_OVERLAYFS=@HAVE_OVERLAYFS@
23HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@
24EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@
25
26H_FILE_LIST = $(sort $(wildcard *.[h]))
27C_FILE_LIST = $(sort $(wildcard *.c))
28OBJS = $(C_FILE_LIST:.c=.o)
29BINOBJS = $(foreach file, $(OBJS), $file)
30CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -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
31LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread
32
33%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h
34 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
35
36fnet: $(OBJS) ../lib/libnetlink.o ../lib/common.o
37 $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS)
38
39clean:; rm -f *.o fnet
40
41distclean: clean
42 rm -fr Makefile
43
diff --git a/src/fnet/fnet.h b/src/fnet/fnet.h
new file mode 100644
index 000000000..58efbbed5
--- /dev/null
+++ b/src/fnet/fnet.h
@@ -0,0 +1,40 @@
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
30int net_create_veth(const char *dev, const char *nsdev, unsigned pid);
31int net_create_macvlan(const char *dev, const char *parent, unsigned pid);
32int net_move_interface(const char *dev, unsigned pid);
33
34// interface.c
35void net_bridge_add_interface(const char *bridge, const char *dev);
36void net_if_up(const char *ifname);
37int net_get_mtu(const char *ifname);
38void net_set_mtu(const char *ifname, int mtu);
39
40#endif
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
33void 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
79void 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
138int 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
162void 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
diff --git a/src/fnet/main.c b/src/fnet/main.c
new file mode 100644
index 000000000..ae780c2ea
--- /dev/null
+++ b/src/fnet/main.c
@@ -0,0 +1,63 @@
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 <stdio.h>
21#include <stdlib.h>
22#include <errno.h>
23#include <sys/prctl.h>
24#include <linux/capability.h>
25
26static void usage(void) {
27 printf("Usage:\n");
28 printf("\tfnet create veth dev1 dev2 bridge child\n");
29 printf("\tfnet create macvlan dev parent child\n");
30 printf("\tfnet moveif dev proc\n");
31}
32
33int main(int argc, char **argv) {
34 if (argc < 2)
35 return 1;
36
37 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
38 usage();
39 return 0;
40 }
41 else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) {
42 // create veth pair and move one end in the the namespace
43 net_create_veth(argv[3], argv[4], atoi(argv[6]));
44
45 // connect the ohter veth end to the bridge ...
46 net_bridge_add_interface(argv[5], argv[3]);
47
48 // ... and bring it up
49 net_if_up(argv[3]);
50 }
51 else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) {
52 net_create_macvlan(argv[3], argv[4], atoi(argv[5]));
53 }
54 else if (argc == 4 && strcmp(argv[1], "moveif") == 0) {
55 net_move_interface(argv[2], atoi(argv[3]));
56 }
57 else {
58 fprintf(stderr, "Error fnet: invalid arguments\n");
59 return 1;
60 }
61
62 return 0;
63}
diff --git a/src/fnet/veth.c b/src/fnet/veth.c
new file mode 100644
index 000000000..d06bc9256
--- /dev/null
+++ b/src/fnet/veth.c
@@ -0,0 +1,230 @@
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
53struct iplink_req
54{
55 struct nlmsghdr n;
56 struct ifinfomsg i;
57 char buf[1024];
58};
59
60static struct rtnl_handle rth = { .fd = -1 };
61
62int 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 return 0;
115}
116
117
118int net_create_macvlan(const char *dev, const char *parent, unsigned pid) {
119 int len;
120 struct iplink_req req;
121 assert(dev);
122 assert(parent);
123
124 if (rtnl_open(&rth, 0) < 0) {
125 fprintf(stderr, "cannot open netlink\n");
126 exit(1);
127 }
128
129 memset(&req, 0, sizeof(req));
130
131 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
132 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
133 req.n.nlmsg_type = RTM_NEWLINK;
134 req.i.ifi_family = 0;
135
136 // find parent ifindex
137 int parent_ifindex = if_nametoindex(parent);
138 if (parent_ifindex <= 0) {
139 fprintf(stderr, "Error: cannot find network device %s\n", parent);
140 exit(1);
141 }
142
143 // add parent
144 addattr_l(&req.n, sizeof(req), IFLA_LINK, &parent_ifindex, 4);
145
146 // add new interface name
147 len = strlen(dev) + 1;
148 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len);
149
150 // place the interface in child namespace
151 addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4);
152
153
154 // add link info for the new interface
155 struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
156 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
157 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "macvlan", strlen("macvlan"));
158
159 // set macvlan bridge mode
160 struct rtattr * data = NLMSG_TAIL(&req.n);
161 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
162 int macvlan_type = MACVLAN_MODE_BRIDGE;
163 addattr_l (&req.n, sizeof(req), IFLA_INFO_KIND, &macvlan_type, 4);
164
165 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
166// req.n.nlmsg_len += sizeof(struct ifinfomsg);
167
168
169 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
170 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
171
172 // send message
173 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
174 exit(2);
175
176 return 0;
177}
178
179// move the interface dev in namespace of program pid
180// when the interface is moved, netlink does not preserve interface configuration
181int net_move_interface(const char *dev, unsigned pid) {
182 struct iplink_req req;
183 assert(dev);
184
185 if (rtnl_open(&rth, 0) < 0) {
186 fprintf(stderr, "cannot open netlink\n");
187 exit(1);
188 }
189
190 memset(&req, 0, sizeof(req));
191
192 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
193 req.n.nlmsg_flags = NLM_F_REQUEST;
194 req.n.nlmsg_type = RTM_NEWLINK;
195 req.i.ifi_family = 0;
196
197 // find ifindex
198 int ifindex = if_nametoindex(dev);
199 if (ifindex <= 0) {
200 fprintf(stderr, "Error: cannot find interface %s\n", dev);
201 exit(1);
202 }
203 req.i.ifi_index = ifindex;
204
205 // place the interface in child namespace
206 addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4);
207
208 // send message
209 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
210 exit(2);
211
212 return 0;
213}
214
215/*
216int main(int argc, char **argv) {
217 printf("Hello\n");
218
219
220 char *dev = argv[3];
221 char *nsdev = argv[8];
222 unsigned pid;
223 sscanf(argv[10], "%u", &pid);
224
225
226 net_create_veth(dev, nsdev, pid);
227
228 return 0;
229}
230*/ \ No newline at end of file