Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <sys/socket.h>
3 : : #include <linux/netlink.h>
4 : : #include <linux/rtnetlink.h>
5 : : #include <string.h>
6 : : #include <net/if_arp.h>
7 : : #include <sys/wait.h>
8 : : #include <sched.h>
9 : : #include "syscall-types.h"
10 : : #include "namespaces.h"
11 : : #include "net.h"
12 : : #include "libnetlink.h"
13 : : #include "crtools.h"
14 : : #include "sk-inet.h"
15 : :
16 : : #include "protobuf.h"
17 : : #include "protobuf/netdev.pb-c.h"
18 : :
19 : : static int ns_fd = -1;
20 : :
21 : 0 : void show_netdevices(int fd, struct cr_options *opt)
22 : : {
23 : 0 : pb_show_plain_pretty(fd, PB_NETDEV, "2:%d");
24 : 0 : }
25 : :
26 : 76 : static int dump_one_netdev(int type, struct ifinfomsg *ifi,
27 : : struct rtattr **tb, struct cr_fdset *fds)
28 : : {
29 : 76 : NetDeviceEntry netdev = NET_DEVICE_ENTRY__INIT;
30 : :
31 [ - + ]: 76 : if (!tb[IFLA_IFNAME]) {
32 : 0 : pr_err("No name for link %d\n", ifi->ifi_index);
33 : : return -1;
34 : : }
35 : :
36 : 76 : netdev.type = type;
37 : 76 : netdev.ifindex = ifi->ifi_index;
38 : 76 : netdev.mtu = *(int *)RTA_DATA(tb[IFLA_MTU]);
39 : 76 : netdev.flags = ifi->ifi_flags;
40 : 76 : netdev.name = RTA_DATA(tb[IFLA_IFNAME]);
41 : :
42 : 76 : return pb_write_one(fdset_fd(fds, CR_FD_NETDEV), &netdev, PB_NETDEV);
43 : : }
44 : :
45 : 0 : static int dump_one_ethernet(struct ifinfomsg *ifi,
46 : : struct rtattr **tb, struct cr_fdset *fds)
47 : : {
48 : : struct rtattr *linkinfo[IFLA_INFO_MAX + 1];
49 : : char *kind;
50 : :
51 [ # # ]: 0 : if (!tb[IFLA_LINKINFO]) {
52 : 0 : pr_err("No linkinfo for eth link %d\n", ifi->ifi_index);
53 : : return -1;
54 : : }
55 : :
56 : 0 : parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
57 [ # # ]: 0 : if (!linkinfo[IFLA_INFO_KIND]) {
58 : 0 : pr_err("No kind for eth link %d\n", ifi->ifi_index);
59 : : return -1;
60 : : }
61 : :
62 : 0 : kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]);
63 [ # # ]: 0 : if (!strcmp(kind, "veth"))
64 : : /*
65 : : * This is not correct. The peer of the veth device may
66 : : * be either outside or inside the netns we're working
67 : : * on, but there's currently no way of finding this out.
68 : : *
69 : : * Sigh... we have to assume, that the veth device is a
70 : : * connection to the outer world and just dump this end :(
71 : : */
72 : 0 : return dump_one_netdev(ND_TYPE__VETH, ifi, tb, fds);
73 : :
74 : 0 : pr_err("Unknown eth kind %s link %d\n", kind, ifi->ifi_index);
75 : : return -1;
76 : : }
77 : :
78 : 76 : static int dump_one_link(struct nlmsghdr *hdr, void *arg)
79 : : {
80 : 76 : struct cr_fdset *fds = arg;
81 : : struct ifinfomsg *ifi;
82 : 76 : int ret = 0, len = hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
83 : : struct rtattr *tb[IFLA_MAX + 1];
84 : :
85 : 76 : ifi = NLMSG_DATA(hdr);
86 : :
87 [ - + ]: 76 : if (len < 0) {
88 : 0 : pr_err("No iflas for link %d\n", ifi->ifi_index);
89 : : return -1;
90 : : }
91 : :
92 : 76 : parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
93 : :
94 : 76 : pr_info("\tLD: Got link %d, type %d\n", ifi->ifi_index, ifi->ifi_type);
95 : :
96 [ + - - ]: 76 : switch (ifi->ifi_type) {
97 : : case ARPHRD_LOOPBACK:
98 : 76 : ret = dump_one_netdev(ND_TYPE__LOOPBACK, ifi, tb, fds);
99 : 76 : break;
100 : : case ARPHRD_ETHER:
101 : 0 : ret = dump_one_ethernet(ifi, tb, fds);
102 : 0 : break;
103 : : default:
104 : 0 : pr_err("Unsupported link type %d\n", ifi->ifi_type);
105 : 0 : ret = 0; /* just skip for now */
106 : 76 : break;
107 : : }
108 : :
109 : : return ret;
110 : : }
111 : :
112 : 76 : static int do_dump_links(int (*cb)(struct nlmsghdr *h, void *), void *arg)
113 : : {
114 : : int sk, ret;
115 : : struct {
116 : : struct nlmsghdr nlh;
117 : : struct rtgenmsg g;
118 : : } req;
119 : :
120 : 76 : ret = sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
121 [ - + ]: 76 : if (sk < 0) {
122 : 0 : pr_perror("Can't open rtnl sock for net dump");
123 : 0 : goto out;
124 : : }
125 : :
126 : 76 : memset(&req, 0, sizeof(req));
127 : 76 : req.nlh.nlmsg_len = sizeof(req);
128 : 76 : req.nlh.nlmsg_type = RTM_GETLINK;
129 : 76 : req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
130 : : req.nlh.nlmsg_pid = 0;
131 : 76 : req.nlh.nlmsg_seq = CR_NLMSG_SEQ;
132 : 76 : req.g.rtgen_family = AF_PACKET;
133 : :
134 : 76 : ret = do_rtnl_req(sk, &req, sizeof(req), cb, arg);
135 : 76 : close(sk);
136 : : out:
137 : 76 : return ret;
138 : : }
139 : :
140 : 76 : static int dump_links(struct cr_fdset *fds)
141 : : {
142 : 76 : pr_info("Dumping netns links\n");
143 : :
144 : 76 : return do_dump_links(dump_one_link, fds);
145 : : }
146 : :
147 : 0 : static int restore_link_cb(struct nlmsghdr *hdr, void *arg)
148 : : {
149 : 0 : pr_info("Got responce on SETLINK =)\n");
150 : 0 : return 0;
151 : : }
152 : :
153 : : struct newlink_req {
154 : : struct nlmsghdr h;
155 : : struct ifinfomsg i;
156 : : char buf[1024];
157 : : };
158 : :
159 : 76 : static int restore_one_link(NetDeviceEntry *nde, int nlsk,
160 : : int (*link_info)(NetDeviceEntry *, struct newlink_req *))
161 : : {
162 : : struct newlink_req req;
163 : :
164 : 76 : memset(&req, 0, sizeof(req));
165 : :
166 : 76 : req.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
167 : 76 : req.h.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE;
168 : 76 : req.h.nlmsg_type = RTM_NEWLINK;
169 : 76 : req.h.nlmsg_seq = CR_NLMSG_SEQ;
170 : 76 : req.i.ifi_family = AF_PACKET;
171 : 76 : req.i.ifi_index = nde->ifindex;
172 : 76 : req.i.ifi_flags = nde->flags;
173 : :
174 : 76 : addattr_l(&req.h, sizeof(req), IFLA_IFNAME, nde->name, strlen(nde->name));
175 : 76 : addattr_l(&req.h, sizeof(req), IFLA_MTU, &nde->mtu, sizeof(nde->mtu));
176 : :
177 [ - + ]: 76 : if (link_info) {
178 : : struct rtattr *linkinfo;
179 : : int ret;
180 : :
181 : 0 : linkinfo = NLMSG_TAIL(&req.h);
182 : 0 : addattr_l(&req.h, sizeof(req), IFLA_LINKINFO, NULL, 0);
183 : :
184 : 0 : ret = link_info(nde, &req);
185 [ # # ]: 0 : if (ret < 0)
186 : : return ret;
187 : :
188 : 0 : linkinfo->rta_len = (void *)NLMSG_TAIL(&req.h) - (void *)linkinfo;
189 : : }
190 : :
191 : 76 : pr_info("Restoring netdev idx %d\n", nde->ifindex);
192 : 76 : return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL);
193 : : }
194 : :
195 : : #ifndef VETH_INFO_MAX
196 : : enum {
197 : : VETH_INFO_UNSPEC,
198 : : VETH_INFO_PEER,
199 : :
200 : : __VETH_INFO_MAX
201 : : #define VETH_INFO_MAX (__VETH_INFO_MAX - 1)
202 : : };
203 : : #endif
204 : :
205 : : #if IFLA_MAX <= 28
206 : : #define IFLA_NET_NS_FD 28
207 : : #endif
208 : :
209 : 0 : static int veth_link_info(NetDeviceEntry *nde, struct newlink_req *req)
210 : : {
211 : : struct rtattr *veth_data, *peer_data;
212 : : struct ifinfomsg ifm;
213 : : struct veth_pair *n;
214 : :
215 [ # # ]: 0 : BUG_ON(ns_fd < 0);
216 : :
217 : 0 : addattr_l(&req->h, sizeof(*req), IFLA_INFO_KIND, "veth", 4);
218 : :
219 : 0 : veth_data = NLMSG_TAIL(&req->h);
220 : 0 : addattr_l(&req->h, sizeof(*req), IFLA_INFO_DATA, NULL, 0);
221 : 0 : peer_data = NLMSG_TAIL(&req->h);
222 : 0 : memset(&ifm, 0, sizeof(ifm));
223 : 0 : addattr_l(&req->h, sizeof(*req), VETH_INFO_PEER, &ifm, sizeof(ifm));
224 [ # # ]: 0 : list_for_each_entry(n, &opts.veth_pairs, node) {
225 [ # # ]: 0 : if (!strcmp(nde->name, n->inside))
226 : : break;
227 : : }
228 [ # # ]: 0 : if (&n->node != &opts.veth_pairs)
229 : 0 : addattr_l(&req->h, sizeof(*req), IFLA_IFNAME, n->outside, strlen(n->outside));
230 : 0 : addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_FD, &ns_fd, sizeof(ns_fd));
231 : 0 : peer_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)peer_data;
232 : 0 : veth_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)veth_data;
233 : :
234 : 0 : return 0;
235 : : }
236 : :
237 : 76 : static int restore_link(NetDeviceEntry *nde, int nlsk)
238 : : {
239 : 76 : pr_info("Restoring link type %d\n", nde->type);
240 : :
241 [ + - - ]: 76 : switch (nde->type) {
242 : : case ND_TYPE__LOOPBACK:
243 : 76 : return restore_one_link(nde, nlsk, NULL);
244 : : case ND_TYPE__VETH:
245 : 0 : return restore_one_link(nde, nlsk, veth_link_info);
246 : : }
247 : :
248 : 0 : BUG();
249 : 76 : return -1;
250 : : }
251 : :
252 : 76 : static int restore_links(int pid)
253 : : {
254 : : int fd, nlsk, ret;
255 : : NetDeviceEntry *nde;
256 : :
257 : 76 : fd = open_image_ro(CR_FD_NETDEV, pid);
258 [ + - ]: 76 : if (fd < 0)
259 : : return -1;
260 : :
261 : 76 : nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
262 [ - + ]: 76 : if (nlsk < 0) {
263 : 0 : pr_perror("Can't create nlk socket");
264 : 76 : close_safe(&fd);
265 : : return -1;
266 : : }
267 : :
268 : : while (1) {
269 : 152 : ret = pb_read_one_eof(fd, &nde, PB_NETDEV);
270 [ + + ]: 152 : if (ret <= 0)
271 : : break;
272 : :
273 : 76 : ret = restore_link(nde, nlsk);
274 : 76 : net_device_entry__free_unpacked(nde, NULL);
275 [ + - ]: 76 : if (ret)
276 : : break;
277 : : }
278 : :
279 : 76 : close(nlsk);
280 : 76 : close(fd);
281 : : return ret;
282 : : }
283 : :
284 : 304 : static int run_ip_tool(char *arg1, char *arg2, int fdin, int fdout)
285 : : {
286 : : char *ip_tool_cmd;
287 : : int ret;
288 : :
289 : 304 : pr_debug("\tRunning ip %s %s\n", arg1, arg2);
290 : :
291 : 304 : ip_tool_cmd = getenv("CR_IP_TOOL");
292 [ - + ]: 304 : if (!ip_tool_cmd)
293 : 0 : ip_tool_cmd = "ip";
294 : :
295 : 304 : ret = cr_system(fdin, fdout, -1, ip_tool_cmd,
296 : 304 : (char *[]) { "ip", arg1, arg2, NULL });
297 [ - + ]: 445 : if (ret) {
298 : 0 : pr_err("IP tool failed on %s %s\n", arg1, arg2);
299 : 445 : return -1;
300 : : }
301 : :
302 : : return 0;
303 : : }
304 : :
305 : 76 : static inline int dump_ifaddr(struct cr_fdset *fds)
306 : : {
307 : 76 : return run_ip_tool("addr", "save", -1, fdset_fd(fds, CR_FD_IFADDR));
308 : : }
309 : :
310 : 76 : static inline int dump_route(struct cr_fdset *fds)
311 : : {
312 : 76 : return run_ip_tool("route", "save", -1, fdset_fd(fds, CR_FD_ROUTE));
313 : : }
314 : :
315 : 152 : static int restore_ip_dump(int type, int pid, char *cmd)
316 : : {
317 : : int fd, ret;
318 : :
319 : 152 : ret = fd = open_image_ro(type, pid);
320 [ + - ]: 152 : if (fd > 0) {
321 : 152 : ret = run_ip_tool(cmd, "restore", fd, -1);
322 : 293 : close(fd);
323 : : }
324 : :
325 : 293 : return ret;
326 : : }
327 : :
328 : 76 : static inline int restore_ifaddr(int pid)
329 : : {
330 : 76 : return restore_ip_dump(CR_FD_IFADDR, pid, "addr");
331 : : }
332 : :
333 : 76 : static inline int restore_route(int pid)
334 : : {
335 : 76 : return restore_ip_dump(CR_FD_ROUTE, pid, "route");
336 : : }
337 : :
338 : 76 : int dump_net_ns(int pid, struct cr_fdset *fds)
339 : : {
340 : : int ret;
341 : :
342 : 76 : ret = switch_ns(pid, CLONE_NEWNET, "net", NULL);
343 [ + - ]: 76 : if (!ret)
344 : 76 : ret = dump_links(fds);
345 [ + - ]: 76 : if (!ret)
346 : 76 : ret = dump_ifaddr(fds);
347 [ + - ]: 76 : if (!ret)
348 : 76 : ret = dump_route(fds);
349 : :
350 : 76 : return ret;
351 : : }
352 : :
353 : 76 : int prepare_net_ns(int pid)
354 : : {
355 : : int ret;
356 : :
357 : 76 : ret = restore_links(pid);
358 [ + - ]: 76 : if (!ret)
359 : 76 : ret = restore_ifaddr(pid);
360 [ + - ]: 76 : if (!ret)
361 : 76 : ret = restore_route(pid);
362 : :
363 : 217 : close(ns_fd);
364 : :
365 : 217 : return ret;
366 : : }
367 : :
368 : 152 : int netns_pre_create(void)
369 : : {
370 : 152 : ns_fd = open("/proc/self/ns/net", O_RDONLY);
371 [ - + ]: 152 : if (ns_fd < 0) {
372 : 0 : pr_perror("Can't cache net fd");
373 : 0 : return -1;
374 : : }
375 : :
376 : 152 : pr_info("Saved netns fd for links restore\n");
377 : 152 : return 0;
378 : : }
379 : :
380 : 166 : int network_lock(void)
381 : : {
382 : 166 : pr_info("Lock network\n");
383 : :
384 : : /* Each connection will be locked on dump */
385 [ + + ]: 166 : if (!(opts.namespaces_flags & CLONE_NEWNET))
386 : : return 0;
387 : :
388 : 166 : return run_scripts("network-lock");
389 : : }
390 : :
391 : 166 : void network_unlock(void)
392 : : {
393 : 166 : pr_info("Unlock network\n");
394 : :
395 [ + + ]: 166 : if (!(opts.namespaces_flags & CLONE_NEWNET)) {
396 : 90 : cpt_unlock_tcp_connections();
397 : 90 : rst_unlock_tcp_connections();
398 : :
399 : 166 : return;
400 : : }
401 : :
402 : 76 : run_scripts("network-unlock");
403 : 152 : }
404 : :
|