]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nspawn/nspawn-network.c
util-lib: add new ifname_valid() call that validates interface names
[thirdparty/systemd.git] / src / nspawn / nspawn-network.c
CommitLineData
9a2a5625
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2015 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <linux/veth.h>
21#include <net/if.h>
22
b4bbcaa9 23#include "libudev.h"
9a2a5625
LP
24#include "sd-id128.h"
25#include "sd-netlink.h"
9a2a5625 26
b5efdb8a 27#include "alloc-util.h"
9a2a5625 28#include "ether-addr-util.h"
9a2a5625 29#include "netlink-util.h"
cf0fbc49 30#include "nspawn-network.h"
07630cea 31#include "siphash24.h"
ef76dff2
LP
32#include "socket-util.h"
33#include "stat-util.h"
07630cea 34#include "string-util.h"
9a2a5625 35#include "udev-util.h"
07630cea 36#include "util.h"
9a2a5625
LP
37
38#define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
39#define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
f6d6bad1
LP
40#define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66)
41#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
9a2a5625
LP
42#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
43
44static int generate_mac(
45 const char *machine_name,
46 struct ether_addr *mac,
47 sd_id128_t hash_key,
48 uint64_t idx) {
49
dbe81cbd 50 uint64_t result;
9a2a5625
LP
51 size_t l, sz;
52 uint8_t *v, *i;
53 int r;
54
55 l = strlen(machine_name);
56 sz = sizeof(sd_id128_t) + l;
57 if (idx > 0)
58 sz += sizeof(idx);
59
60 v = alloca(sz);
61
62 /* fetch some persistent data unique to the host */
63 r = sd_id128_get_machine((sd_id128_t*) v);
64 if (r < 0)
65 return r;
66
67 /* combine with some data unique (on this host) to this
68 * container instance */
69 i = mempcpy(v + sizeof(sd_id128_t), machine_name, l);
70 if (idx > 0) {
71 idx = htole64(idx);
72 memcpy(i, &idx, sizeof(idx));
73 }
74
75 /* Let's hash the host machine ID plus the container name. We
76 * use a fixed, but originally randomly created hash key here. */
933f9cae 77 result = htole64(siphash24(v, sz, hash_key.bytes));
9a2a5625
LP
78
79 assert_cc(ETH_ALEN <= sizeof(result));
dbe81cbd 80 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
9a2a5625
LP
81
82 /* see eth_random_addr in the kernel */
83 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
84 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
85
86 return 0;
87}
88
f6d6bad1
LP
89static int add_veth(
90 sd_netlink *rtnl,
91 pid_t pid,
92 const char *ifname_host,
93 const struct ether_addr *mac_host,
94 const char *ifname_container,
95 const struct ether_addr *mac_container) {
9a2a5625 96
4afd3348 97 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
f6d6bad1 98 int r;
9a2a5625 99
f6d6bad1
LP
100 assert(rtnl);
101 assert(ifname_host);
102 assert(mac_host);
103 assert(ifname_container);
104 assert(mac_container);
9a2a5625
LP
105
106 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
107 if (r < 0)
108 return log_error_errno(r, "Failed to allocate netlink message: %m");
109
f6d6bad1 110 r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_host);
9a2a5625
LP
111 if (r < 0)
112 return log_error_errno(r, "Failed to add netlink interface name: %m");
113
f6d6bad1 114 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_host);
9a2a5625
LP
115 if (r < 0)
116 return log_error_errno(r, "Failed to add netlink MAC address: %m");
117
118 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
119 if (r < 0)
120 return log_error_errno(r, "Failed to open netlink container: %m");
121
122 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth");
123 if (r < 0)
124 return log_error_errno(r, "Failed to open netlink container: %m");
125
126 r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
127 if (r < 0)
128 return log_error_errno(r, "Failed to open netlink container: %m");
129
f6d6bad1 130 r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_container);
9a2a5625
LP
131 if (r < 0)
132 return log_error_errno(r, "Failed to add netlink interface name: %m");
133
f6d6bad1 134 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_container);
9a2a5625
LP
135 if (r < 0)
136 return log_error_errno(r, "Failed to add netlink MAC address: %m");
137
138 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
139 if (r < 0)
140 return log_error_errno(r, "Failed to add netlink namespace field: %m");
141
142 r = sd_netlink_message_close_container(m);
143 if (r < 0)
144 return log_error_errno(r, "Failed to close netlink container: %m");
145
146 r = sd_netlink_message_close_container(m);
147 if (r < 0)
148 return log_error_errno(r, "Failed to close netlink container: %m");
149
150 r = sd_netlink_message_close_container(m);
151 if (r < 0)
152 return log_error_errno(r, "Failed to close netlink container: %m");
153
154 r = sd_netlink_call(rtnl, m, 0, NULL);
155 if (r < 0)
f6d6bad1
LP
156 return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container);
157
158 return 0;
159}
160
161int setup_veth(const char *machine_name,
162 pid_t pid,
163 char iface_name[IFNAMSIZ],
164 bool bridge) {
165
4afd3348 166 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
f6d6bad1
LP
167 struct ether_addr mac_host, mac_container;
168 int r, i;
169
170 assert(machine_name);
171 assert(pid > 0);
172 assert(iface_name);
173
174 /* Use two different interface name prefixes depending whether
175 * we are in bridge mode or not. */
176 snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
177 bridge ? "vb" : "ve", machine_name);
178
179 r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
180 if (r < 0)
181 return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m");
182
183 r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0);
184 if (r < 0)
185 return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
186
187 r = sd_netlink_open(&rtnl);
188 if (r < 0)
189 return log_error_errno(r, "Failed to connect to netlink: %m");
190
191 r = add_veth(rtnl, pid, iface_name, &mac_host, "host0", &mac_container);
192 if (r < 0)
193 return r;
9a2a5625
LP
194
195 i = (int) if_nametoindex(iface_name);
196 if (i <= 0)
197 return log_error_errno(errno, "Failed to resolve interface %s: %m", iface_name);
198
199 return i;
200}
201
f6d6bad1
LP
202int setup_veth_extra(
203 const char *machine_name,
204 pid_t pid,
205 char **pairs) {
206
4afd3348 207 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
f6d6bad1
LP
208 uint64_t idx = 0;
209 char **a, **b;
210 int r;
211
212 assert(machine_name);
213 assert(pid > 0);
214
215 if (strv_isempty(pairs))
216 return 0;
217
218 r = sd_netlink_open(&rtnl);
219 if (r < 0)
220 return log_error_errno(r, "Failed to connect to netlink: %m");
221
222 STRV_FOREACH_PAIR(a, b, pairs) {
223 struct ether_addr mac_host, mac_container;
224
225 r = generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx);
226 if (r < 0)
227 return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
228
229 r = generate_mac(machine_name, &mac_host, VETH_EXTRA_HOST_HASH_KEY, idx);
230 if (r < 0)
231 return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
232
233 r = add_veth(rtnl, pid, *a, &mac_host, *b, &mac_container);
234 if (r < 0)
235 return r;
236
313cefa1 237 idx++;
f6d6bad1
LP
238 }
239
240 return 0;
241}
242
9a2a5625 243int setup_bridge(const char *veth_name, const char *bridge_name) {
4afd3348
LP
244 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
245 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
9a2a5625
LP
246 int r, bridge_ifi;
247
248 assert(veth_name);
249 assert(bridge_name);
250
251 bridge_ifi = (int) if_nametoindex(bridge_name);
252 if (bridge_ifi <= 0)
253 return log_error_errno(errno, "Failed to resolve interface %s: %m", bridge_name);
254
255 r = sd_netlink_open(&rtnl);
256 if (r < 0)
257 return log_error_errno(r, "Failed to connect to netlink: %m");
258
259 r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
260 if (r < 0)
261 return log_error_errno(r, "Failed to allocate netlink message: %m");
262
263 r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
264 if (r < 0)
265 return log_error_errno(r, "Failed to set IFF_UP flag: %m");
266
267 r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
268 if (r < 0)
269 return log_error_errno(r, "Failed to add netlink interface name field: %m");
270
271 r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi);
272 if (r < 0)
273 return log_error_errno(r, "Failed to add netlink master field: %m");
274
275 r = sd_netlink_call(rtnl, m, 0, NULL);
276 if (r < 0)
277 return log_error_errno(r, "Failed to add veth interface to bridge: %m");
278
279 return bridge_ifi;
280}
281
282static int parse_interface(struct udev *udev, const char *name) {
283 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
284 char ifi_str[2 + DECIMAL_STR_MAX(int)];
285 int ifi;
286
287 ifi = (int) if_nametoindex(name);
288 if (ifi <= 0)
289 return log_error_errno(errno, "Failed to resolve interface %s: %m", name);
290
291 sprintf(ifi_str, "n%i", ifi);
292 d = udev_device_new_from_device_id(udev, ifi_str);
293 if (!d)
294 return log_error_errno(errno, "Failed to get udev device for interface %s: %m", name);
295
296 if (udev_device_get_is_initialized(d) <= 0) {
297 log_error("Network interface %s is not initialized yet.", name);
298 return -EBUSY;
299 }
300
301 return ifi;
302}
303
304int move_network_interfaces(pid_t pid, char **ifaces) {
305 _cleanup_udev_unref_ struct udev *udev = NULL;
4afd3348 306 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
9a2a5625
LP
307 char **i;
308 int r;
309
310 if (strv_isempty(ifaces))
311 return 0;
312
313 r = sd_netlink_open(&rtnl);
314 if (r < 0)
315 return log_error_errno(r, "Failed to connect to netlink: %m");
316
317 udev = udev_new();
318 if (!udev) {
319 log_error("Failed to connect to udev.");
320 return -ENOMEM;
321 }
322
323 STRV_FOREACH(i, ifaces) {
4afd3348 324 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
9a2a5625
LP
325 int ifi;
326
327 ifi = parse_interface(udev, *i);
328 if (ifi < 0)
329 return ifi;
330
331 r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi);
332 if (r < 0)
333 return log_error_errno(r, "Failed to allocate netlink message: %m");
334
335 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
336 if (r < 0)
337 return log_error_errno(r, "Failed to append namespace PID to netlink message: %m");
338
339 r = sd_netlink_call(rtnl, m, 0, NULL);
340 if (r < 0)
341 return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
342 }
343
344 return 0;
345}
346
347int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
348 _cleanup_udev_unref_ struct udev *udev = NULL;
4afd3348 349 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
9a2a5625
LP
350 unsigned idx = 0;
351 char **i;
352 int r;
353
354 if (strv_isempty(ifaces))
355 return 0;
356
357 r = sd_netlink_open(&rtnl);
358 if (r < 0)
359 return log_error_errno(r, "Failed to connect to netlink: %m");
360
361 udev = udev_new();
362 if (!udev) {
363 log_error("Failed to connect to udev.");
364 return -ENOMEM;
365 }
366
367 STRV_FOREACH(i, ifaces) {
4afd3348 368 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
9a2a5625
LP
369 _cleanup_free_ char *n = NULL;
370 struct ether_addr mac;
371 int ifi;
372
373 ifi = parse_interface(udev, *i);
374 if (ifi < 0)
375 return ifi;
376
377 r = generate_mac(machine_name, &mac, MACVLAN_HASH_KEY, idx++);
378 if (r < 0)
379 return log_error_errno(r, "Failed to create MACVLAN MAC address: %m");
380
381 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
382 if (r < 0)
383 return log_error_errno(r, "Failed to allocate netlink message: %m");
384
385 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
386 if (r < 0)
387 return log_error_errno(r, "Failed to add netlink interface index: %m");
388
389 n = strappend("mv-", *i);
390 if (!n)
391 return log_oom();
392
393 strshorten(n, IFNAMSIZ-1);
394
395 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
396 if (r < 0)
397 return log_error_errno(r, "Failed to add netlink interface name: %m");
398
399 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
400 if (r < 0)
401 return log_error_errno(r, "Failed to add netlink MAC address: %m");
402
403 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
404 if (r < 0)
405 return log_error_errno(r, "Failed to add netlink namespace field: %m");
406
407 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
408 if (r < 0)
409 return log_error_errno(r, "Failed to open netlink container: %m");
410
411 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "macvlan");
412 if (r < 0)
413 return log_error_errno(r, "Failed to open netlink container: %m");
414
415 r = sd_netlink_message_append_u32(m, IFLA_MACVLAN_MODE, MACVLAN_MODE_BRIDGE);
416 if (r < 0)
417 return log_error_errno(r, "Failed to append macvlan mode: %m");
418
419 r = sd_netlink_message_close_container(m);
420 if (r < 0)
421 return log_error_errno(r, "Failed to close netlink container: %m");
422
423 r = sd_netlink_message_close_container(m);
424 if (r < 0)
425 return log_error_errno(r, "Failed to close netlink container: %m");
426
427 r = sd_netlink_call(rtnl, m, 0, NULL);
428 if (r < 0)
429 return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
430 }
431
432 return 0;
433}
434
435int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
436 _cleanup_udev_unref_ struct udev *udev = NULL;
4afd3348 437 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
9a2a5625
LP
438 char **i;
439 int r;
440
441 if (strv_isempty(ifaces))
442 return 0;
443
444 r = sd_netlink_open(&rtnl);
445 if (r < 0)
446 return log_error_errno(r, "Failed to connect to netlink: %m");
447
448 udev = udev_new();
449 if (!udev) {
450 log_error("Failed to connect to udev.");
451 return -ENOMEM;
452 }
453
454 STRV_FOREACH(i, ifaces) {
4afd3348 455 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
9a2a5625
LP
456 _cleanup_free_ char *n = NULL;
457 int ifi;
458
459 ifi = parse_interface(udev, *i);
460 if (ifi < 0)
461 return ifi;
462
463 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
464 if (r < 0)
465 return log_error_errno(r, "Failed to allocate netlink message: %m");
466
467 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
468 if (r < 0)
469 return log_error_errno(r, "Failed to add netlink interface index: %m");
470
471 n = strappend("iv-", *i);
472 if (!n)
473 return log_oom();
474
475 strshorten(n, IFNAMSIZ-1);
476
477 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
478 if (r < 0)
479 return log_error_errno(r, "Failed to add netlink interface name: %m");
480
481 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
482 if (r < 0)
483 return log_error_errno(r, "Failed to add netlink namespace field: %m");
484
485 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
486 if (r < 0)
487 return log_error_errno(r, "Failed to open netlink container: %m");
488
489 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "ipvlan");
490 if (r < 0)
491 return log_error_errno(r, "Failed to open netlink container: %m");
492
493 r = sd_netlink_message_append_u16(m, IFLA_IPVLAN_MODE, IPVLAN_MODE_L2);
494 if (r < 0)
495 return log_error_errno(r, "Failed to add ipvlan mode: %m");
496
497 r = sd_netlink_message_close_container(m);
498 if (r < 0)
499 return log_error_errno(r, "Failed to close netlink container: %m");
500
501 r = sd_netlink_message_close_container(m);
502 if (r < 0)
503 return log_error_errno(r, "Failed to close netlink container: %m");
504
505 r = sd_netlink_call(rtnl, m, 0, NULL);
506 if (r < 0)
507 return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
508 }
509
510 return 0;
511}
f6d6bad1
LP
512
513int veth_extra_parse(char ***l, const char *p) {
514 _cleanup_free_ char *a = NULL, *b = NULL;
515 int r;
516
517 r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
518 if (r < 0)
519 return r;
ef76dff2 520 if (r == 0 || !ifname_valid(a))
f6d6bad1
LP
521 return -EINVAL;
522
523 r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
524 if (r < 0)
525 return r;
ef76dff2 526 if (r == 0 || !ifname_valid(b)) {
f6d6bad1
LP
527 free(b);
528 b = strdup(a);
529 if (!b)
530 return -ENOMEM;
531 }
532
533 if (p)
534 return -EINVAL;
535
536 r = strv_push_pair(l, a, b);
537 if (r < 0)
538 return -ENOMEM;
539
540 a = b = NULL;
541 return 0;
542}
ef3b2aa7
LP
543
544static int remove_one_veth_link(sd_netlink *rtnl, const char *name) {
545 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
546 int r;
547
548 if (isempty(name))
549 return 0;
550
551 r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0);
552 if (r < 0)
553 return log_error_errno(r, "Failed to allocate netlink message: %m");
554
555 r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
556 if (r < 0)
557 return log_error_errno(r, "Failed to add netlink interface name: %m");
558
559 r = sd_netlink_call(rtnl, m, 0, NULL);
560 if (r == -ENODEV) /* Already gone */
561 return 0;
562 if (r < 0)
563 return log_error_errno(r, "Failed to remove veth interface %s: %m", name);
564
565 return 1;
566}
567
568int remove_veth_links(const char *primary, char **pairs) {
569 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
570 char **a, **b;
571 int r;
572
573 /* In some cases the kernel might pin the veth links between host and container even after the namespace
574 * died. Hence, let's better remove them explicitly too. */
575
576 if (isempty(primary) && strv_isempty(pairs))
577 return 0;
578
579 r = sd_netlink_open(&rtnl);
580 if (r < 0)
581 return log_error_errno(r, "Failed to connect to netlink: %m");
582
583 remove_one_veth_link(rtnl, primary);
584
585 STRV_FOREACH_PAIR(a, b, pairs)
586 remove_one_veth_link(rtnl, *a);
587
588 return 0;
589}