]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Merge pull request #8399 from keszybz/systemctl-kexec
[thirdparty/systemd.git] / src / network / networkd-network.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <ctype.h>
22 #include <net/if.h>
23
24 #include "alloc-util.h"
25 #include "conf-files.h"
26 #include "conf-parser.h"
27 #include "dns-domain.h"
28 #include "fd-util.h"
29 #include "hostname-util.h"
30 #include "in-addr-util.h"
31 #include "network-internal.h"
32 #include "networkd-manager.h"
33 #include "networkd-network.h"
34 #include "parse-util.h"
35 #include "set.h"
36 #include "stat-util.h"
37 #include "string-table.h"
38 #include "string-util.h"
39 #include "strv.h"
40 #include "util.h"
41
42 static void network_config_hash_func(const void *p, struct siphash *state) {
43 const NetworkConfigSection *c = p;
44
45 siphash24_compress(c->filename, strlen(c->filename), state);
46 siphash24_compress(&c->line, sizeof(c->line), state);
47 }
48
49 static int network_config_compare_func(const void *a, const void *b) {
50 const NetworkConfigSection *x = a, *y = b;
51 int r;
52
53 r = strcmp(x->filename, y->filename);
54 if (r != 0)
55 return r;
56
57 return y->line - x->line;
58 }
59
60 const struct hash_ops network_config_hash_ops = {
61 .hash = network_config_hash_func,
62 .compare = network_config_compare_func,
63 };
64
65 int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
66 NetworkConfigSection *cs;
67
68 cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
69 if (!cs)
70 return -ENOMEM;
71
72 strcpy(cs->filename, filename);
73 cs->line = line;
74
75 *s = cs;
76 cs = NULL;
77
78 return 0;
79 }
80
81 void network_config_section_free(NetworkConfigSection *cs) {
82 free(cs);
83 }
84
85 /* Set defaults following RFC7844 */
86 void network_apply_anonymize_if_set(Network *network) {
87 if (!network->dhcp_anonymize)
88 return;
89 /* RFC7844 3.7
90 SHOULD NOT send the Host Name option */
91 network->dhcp_send_hostname = false;
92 /* RFC7844 section 3.:
93 MAY contain the Client Identifier option
94 Section 3.5:
95 clients MUST use client identifiers based solely
96 on the link-layer address */
97 /* NOTE: Using MAC, as it does not reveal extra information,
98 * and some servers might not answer if this option is not sent */
99 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
100 /* RFC 7844 3.10:
101 SHOULD NOT use the Vendor Class Identifier option */
102 /* NOTE: it was not initiallized to any value in network_load_one. */
103 network->dhcp_vendor_class_identifier = false;
104 /* RFC7844 section 3.6.:
105 The client intending to protect its privacy SHOULD only request a
106 minimal number of options in the PRL and SHOULD also randomly shuffle
107 the ordering of option codes in the PRL. If this random ordering
108 cannot be implemented, the client MAY order the option codes in the
109 PRL by option code number (lowest to highest).
110 */
111 /* NOTE: dhcp_use_mtu is false by default,
112 * though it was not initiallized to any value in network_load_one.
113 * Maybe there should be another var called *send*?
114 * (to use the MTU sent by the server but to do not send
115 * the option in the PRL). */
116 network->dhcp_use_mtu = false;
117 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
118 * but this is needed to use them. */
119 network->dhcp_use_routes = true;
120 /* RFC7844 section 3.6.
121 * same comments as previous option */
122 network->dhcp_use_timezone = false;
123 }
124
125 static int network_load_one(Manager *manager, const char *filename) {
126 _cleanup_network_free_ Network *network = NULL;
127 _cleanup_fclose_ FILE *file = NULL;
128 char *d;
129 const char *dropin_dirname;
130 Route *route;
131 Address *address;
132 int r;
133
134 assert(manager);
135 assert(filename);
136
137 file = fopen(filename, "re");
138 if (!file) {
139 if (errno == ENOENT)
140 return 0;
141
142 return -errno;
143 }
144
145 if (null_or_empty_fd(fileno(file))) {
146 log_debug("Skipping empty file: %s", filename);
147 return 0;
148 }
149
150 network = new0(Network, 1);
151 if (!network)
152 return log_oom();
153
154 network->manager = manager;
155
156 LIST_HEAD_INIT(network->static_addresses);
157 LIST_HEAD_INIT(network->static_routes);
158 LIST_HEAD_INIT(network->static_fdb_entries);
159 LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
160 LIST_HEAD_INIT(network->address_labels);
161 LIST_HEAD_INIT(network->static_prefixes);
162 LIST_HEAD_INIT(network->rules);
163
164 network->stacked_netdevs = hashmap_new(&string_hash_ops);
165 if (!network->stacked_netdevs)
166 return log_oom();
167
168 network->addresses_by_section = hashmap_new(&network_config_hash_ops);
169 if (!network->addresses_by_section)
170 return log_oom();
171
172 network->routes_by_section = hashmap_new(&network_config_hash_ops);
173 if (!network->routes_by_section)
174 return log_oom();
175
176 network->fdb_entries_by_section = hashmap_new(NULL);
177 if (!network->fdb_entries_by_section)
178 return log_oom();
179
180 network->address_labels_by_section = hashmap_new(&network_config_hash_ops);
181 if (!network->address_labels_by_section)
182 log_oom();
183
184 network->prefixes_by_section = hashmap_new(&network_config_hash_ops);
185 if (!network->prefixes_by_section)
186 return log_oom();
187
188 network->rules_by_section = hashmap_new(&network_config_hash_ops);
189 if (!network->rules_by_section)
190 return log_oom();
191
192 network->filename = strdup(filename);
193 if (!network->filename)
194 return log_oom();
195
196 network->name = strdup(basename(filename));
197 if (!network->name)
198 return log_oom();
199
200 d = strrchr(network->name, '.');
201 if (!d)
202 return -EINVAL;
203
204 assert(streq(d, ".network"));
205
206 *d = '\0';
207
208 network->required_for_online = true;
209 network->dhcp = ADDRESS_FAMILY_NO;
210 network->dhcp_use_ntp = true;
211 network->dhcp_use_dns = true;
212 network->dhcp_use_hostname = true;
213 network->dhcp_use_routes = true;
214 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
215 network->dhcp_send_hostname = true;
216 /* To enable/disable RFC7844 Anonymity Profiles */
217 network->dhcp_anonymize = false;
218 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
219 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
220 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
221 network->dhcp_route_table = RT_TABLE_MAIN;
222 network->dhcp_route_table_set = false;
223 /* NOTE: the following vars were not set to any default,
224 * even if they are commented in the man?
225 * These vars might be overwriten by network_apply_anonymize_if_set */
226 network->dhcp_vendor_class_identifier = false;
227 /* NOTE: from man: UseMTU=... Defaults to false*/
228 network->dhcp_use_mtu = false;
229 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
230 network->dhcp_use_timezone = false;
231 network->rapid_commit = true;
232
233 network->dhcp_server_emit_dns = true;
234 network->dhcp_server_emit_ntp = true;
235 network->dhcp_server_emit_router = true;
236 network->dhcp_server_emit_timezone = true;
237
238 network->router_emit_dns = true;
239 network->router_emit_domains = true;
240
241 network->use_bpdu = true;
242 network->allow_port_to_be_root = true;
243 network->unicast_flood = true;
244 network->priority = LINK_BRIDGE_PORT_PRIORITY_INVALID;
245
246 network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
247
248 network->llmnr = RESOLVE_SUPPORT_YES;
249 network->mdns = RESOLVE_SUPPORT_NO;
250 network->dnssec_mode = _DNSSEC_MODE_INVALID;
251
252 network->link_local = ADDRESS_FAMILY_IPV6;
253
254 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
255 network->ipv6_accept_ra = -1;
256 network->ipv6_dad_transmits = -1;
257 network->ipv6_hop_limit = -1;
258 network->ipv6_proxy_ndp = -1;
259 network->duid.type = _DUID_TYPE_INVALID;
260 network->proxy_arp = -1;
261 network->arp = -1;
262 network->ipv6_accept_ra_use_dns = true;
263 network->ipv6_accept_ra_route_table = RT_TABLE_MAIN;
264
265 dropin_dirname = strjoina(network->name, ".network.d");
266
267 r = config_parse_many(filename, network_dirs, dropin_dirname,
268 "Match\0"
269 "Link\0"
270 "Network\0"
271 "Address\0"
272 "IPv6AddressLabel\0"
273 "RoutingPolicyRule\0"
274 "Route\0"
275 "DHCP\0"
276 "DHCPv4\0" /* compat */
277 "DHCPServer\0"
278 "IPv6AcceptRA\0"
279 "IPv6NDPProxyAddress\0"
280 "Bridge\0"
281 "BridgeFDB\0"
282 "BridgeVLAN\0"
283 "IPv6PrefixDelegation\0"
284 "IPv6Prefix\0",
285 config_item_perf_lookup, network_network_gperf_lookup,
286 CONFIG_PARSE_WARN, network);
287 if (r < 0)
288 return r;
289
290 network_apply_anonymize_if_set(network);
291
292 /* IPMasquerade=yes implies IPForward=yes */
293 if (network->ip_masquerade)
294 network->ip_forward |= ADDRESS_FAMILY_IPV4;
295
296 LIST_PREPEND(networks, manager->networks, network);
297
298 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
299 if (r < 0)
300 return r;
301
302 r = hashmap_put(manager->networks_by_name, network->name, network);
303 if (r < 0)
304 return r;
305
306 LIST_FOREACH(routes, route, network->static_routes) {
307 if (!route->family) {
308 log_warning("Route section without Gateway field configured in %s. "
309 "Ignoring", filename);
310 return 0;
311 }
312 }
313
314 LIST_FOREACH(addresses, address, network->static_addresses) {
315 if (!address->family) {
316 log_warning("Address section without Address field configured in %s. "
317 "Ignoring", filename);
318 return 0;
319 }
320 }
321
322 network = NULL;
323
324 return 0;
325 }
326
327 int network_load(Manager *manager) {
328 Network *network;
329 _cleanup_strv_free_ char **files = NULL;
330 char **f;
331 int r;
332
333 assert(manager);
334
335 while ((network = manager->networks))
336 network_free(network);
337
338 r = conf_files_list_strv(&files, ".network", NULL, 0, network_dirs);
339 if (r < 0)
340 return log_error_errno(r, "Failed to enumerate network files: %m");
341
342 STRV_FOREACH_BACKWARDS(f, files) {
343 r = network_load_one(manager, *f);
344 if (r < 0)
345 return r;
346 }
347
348 return 0;
349 }
350
351 void network_free(Network *network) {
352 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
353 RoutingPolicyRule *rule;
354 FdbEntry *fdb_entry;
355 AddressLabel *label;
356 Prefix *prefix;
357 Address *address;
358 NetDev *netdev;
359 Route *route;
360 Iterator i;
361
362 if (!network)
363 return;
364
365 free(network->filename);
366
367 free(network->match_mac);
368 strv_free(network->match_path);
369 strv_free(network->match_driver);
370 strv_free(network->match_type);
371 strv_free(network->match_name);
372
373 free(network->description);
374 free(network->dhcp_vendor_class_identifier);
375 free(network->dhcp_hostname);
376
377 free(network->mac);
378
379 strv_free(network->ntp);
380 free(network->dns);
381 strv_free(network->search_domains);
382 strv_free(network->route_domains);
383 strv_free(network->bind_carrier);
384
385 netdev_unref(network->bridge);
386 netdev_unref(network->bond);
387 netdev_unref(network->vrf);
388
389 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
390 hashmap_remove(network->stacked_netdevs, netdev->ifname);
391 netdev_unref(netdev);
392 }
393 hashmap_free(network->stacked_netdevs);
394
395 while ((route = network->static_routes))
396 route_free(route);
397
398 while ((address = network->static_addresses))
399 address_free(address);
400
401 while ((fdb_entry = network->static_fdb_entries))
402 fdb_entry_free(fdb_entry);
403
404 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
405 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
406
407 while ((label = network->address_labels))
408 address_label_free(label);
409
410 while ((prefix = network->static_prefixes))
411 prefix_free(prefix);
412
413 while ((rule = network->rules))
414 routing_policy_rule_free(rule);
415
416 hashmap_free(network->addresses_by_section);
417 hashmap_free(network->routes_by_section);
418 hashmap_free(network->fdb_entries_by_section);
419 hashmap_free(network->address_labels_by_section);
420 hashmap_free(network->prefixes_by_section);
421 hashmap_free(network->rules_by_section);
422
423 if (network->manager) {
424 if (network->manager->networks)
425 LIST_REMOVE(networks, network->manager->networks, network);
426
427 if (network->manager->networks_by_name)
428 hashmap_remove(network->manager->networks_by_name, network->name);
429 }
430
431 free(network->name);
432
433 condition_free_list(network->match_host);
434 condition_free_list(network->match_virt);
435 condition_free_list(network->match_kernel_cmdline);
436 condition_free_list(network->match_kernel_version);
437 condition_free_list(network->match_arch);
438
439 free(network->dhcp_server_timezone);
440 free(network->dhcp_server_dns);
441 free(network->dhcp_server_ntp);
442
443 set_free_free(network->dnssec_negative_trust_anchors);
444
445 free(network);
446 }
447
448 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
449 Network *network;
450
451 assert(manager);
452 assert(name);
453 assert(ret);
454
455 network = hashmap_get(manager->networks_by_name, name);
456 if (!network)
457 return -ENOENT;
458
459 *ret = network;
460
461 return 0;
462 }
463
464 int network_get(Manager *manager, struct udev_device *device,
465 const char *ifname, const struct ether_addr *address,
466 Network **ret) {
467 Network *network;
468 struct udev_device *parent;
469 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
470
471 assert(manager);
472 assert(ret);
473
474 if (device) {
475 path = udev_device_get_property_value(device, "ID_PATH");
476
477 parent = udev_device_get_parent(device);
478 if (parent)
479 parent_driver = udev_device_get_driver(parent);
480
481 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
482
483 devtype = udev_device_get_devtype(device);
484 }
485
486 LIST_FOREACH(networks, network, manager->networks) {
487 if (net_match_config(network->match_mac, network->match_path,
488 network->match_driver, network->match_type,
489 network->match_name, network->match_host,
490 network->match_virt, network->match_kernel_cmdline,
491 network->match_kernel_version, network->match_arch,
492 address, path, parent_driver, driver,
493 devtype, ifname)) {
494 if (network->match_name && device) {
495 const char *attr;
496 uint8_t name_assign_type = NET_NAME_UNKNOWN;
497
498 attr = udev_device_get_sysattr_value(device, "name_assign_type");
499 if (attr)
500 (void) safe_atou8(attr, &name_assign_type);
501
502 if (name_assign_type == NET_NAME_ENUM)
503 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
504 ifname, network->filename);
505 else
506 log_debug("%s: found matching network '%s'", ifname, network->filename);
507 } else
508 log_debug("%s: found matching network '%s'", ifname, network->filename);
509
510 *ret = network;
511 return 0;
512 }
513 }
514
515 *ret = NULL;
516
517 return -ENOENT;
518 }
519
520 int network_apply(Network *network, Link *link) {
521 int r;
522
523 assert(network);
524 assert(link);
525
526 link->network = network;
527
528 if (network->ipv4ll_route) {
529 Route *route;
530
531 r = route_new_static(network, NULL, 0, &route);
532 if (r < 0)
533 return r;
534
535 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
536 if (r == 0)
537 return -EINVAL;
538 if (r < 0)
539 return -errno;
540
541 route->family = AF_INET;
542 route->dst_prefixlen = 16;
543 route->scope = RT_SCOPE_LINK;
544 route->priority = IPV4LL_ROUTE_METRIC;
545 route->protocol = RTPROT_STATIC;
546 }
547
548 if (network->n_dns > 0 ||
549 !strv_isempty(network->ntp) ||
550 !strv_isempty(network->search_domains) ||
551 !strv_isempty(network->route_domains))
552 link_dirty(link);
553
554 return 0;
555 }
556
557 bool network_has_static_ipv6_addresses(Network *network) {
558 Address *address;
559
560 assert(network);
561
562 LIST_FOREACH(addresses, address, network->static_addresses) {
563 if (address->family == AF_INET6)
564 return true;
565 }
566
567 return false;
568 }
569
570 int config_parse_netdev(const char *unit,
571 const char *filename,
572 unsigned line,
573 const char *section,
574 unsigned section_line,
575 const char *lvalue,
576 int ltype,
577 const char *rvalue,
578 void *data,
579 void *userdata) {
580 Network *network = userdata;
581 _cleanup_free_ char *kind_string = NULL;
582 char *p;
583 NetDev *netdev;
584 NetDevKind kind;
585 int r;
586
587 assert(filename);
588 assert(lvalue);
589 assert(rvalue);
590 assert(data);
591
592 kind_string = strdup(lvalue);
593 if (!kind_string)
594 return log_oom();
595
596 /* the keys are CamelCase versions of the kind */
597 for (p = kind_string; *p; p++)
598 *p = tolower(*p);
599
600 kind = netdev_kind_from_string(kind_string);
601 if (kind == _NETDEV_KIND_INVALID) {
602 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
603 return 0;
604 }
605
606 r = netdev_get(network->manager, rvalue, &netdev);
607 if (r < 0) {
608 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
609 return 0;
610 }
611
612 if (netdev->kind != kind) {
613 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
614 return 0;
615 }
616
617 switch (kind) {
618 case NETDEV_KIND_BRIDGE:
619 network->bridge = netdev;
620
621 break;
622 case NETDEV_KIND_BOND:
623 network->bond = netdev;
624
625 break;
626 case NETDEV_KIND_VRF:
627 network->vrf = netdev;
628
629 break;
630 case NETDEV_KIND_VLAN:
631 case NETDEV_KIND_MACVLAN:
632 case NETDEV_KIND_MACVTAP:
633 case NETDEV_KIND_IPVLAN:
634 case NETDEV_KIND_VXLAN:
635 case NETDEV_KIND_VCAN:
636 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
637 if (r < 0) {
638 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
639 return 0;
640 }
641
642 break;
643 default:
644 assert_not_reached("Cannot parse NetDev");
645 }
646
647 netdev_ref(netdev);
648
649 return 0;
650 }
651
652 int config_parse_domains(
653 const char *unit,
654 const char *filename,
655 unsigned line,
656 const char *section,
657 unsigned section_line,
658 const char *lvalue,
659 int ltype,
660 const char *rvalue,
661 void *data,
662 void *userdata) {
663
664 const char *p;
665 Network *n = data;
666 int r;
667
668 assert(n);
669 assert(lvalue);
670 assert(rvalue);
671
672 if (isempty(rvalue)) {
673 n->search_domains = strv_free(n->search_domains);
674 n->route_domains = strv_free(n->route_domains);
675 return 0;
676 }
677
678 p = rvalue;
679 for (;;) {
680 _cleanup_free_ char *w = NULL, *normalized = NULL;
681 const char *domain;
682 bool is_route;
683
684 r = extract_first_word(&p, &w, NULL, 0);
685 if (r < 0) {
686 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
687 break;
688 }
689 if (r == 0)
690 break;
691
692 is_route = w[0] == '~';
693 domain = is_route ? w + 1 : w;
694
695 if (dns_name_is_root(domain) || streq(domain, "*")) {
696 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
697 * routing domain, unconditionally. */
698 is_route = true;
699 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
700
701 } else {
702 r = dns_name_normalize(domain, &normalized);
703 if (r < 0) {
704 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
705 continue;
706 }
707
708 domain = normalized;
709
710 if (is_localhost(domain)) {
711 log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain);
712 continue;
713 }
714 }
715
716 if (is_route) {
717 r = strv_extend(&n->route_domains, domain);
718 if (r < 0)
719 return log_oom();
720
721 } else {
722 r = strv_extend(&n->search_domains, domain);
723 if (r < 0)
724 return log_oom();
725 }
726 }
727
728 strv_uniq(n->route_domains);
729 strv_uniq(n->search_domains);
730
731 return 0;
732 }
733
734 int config_parse_tunnel(const char *unit,
735 const char *filename,
736 unsigned line,
737 const char *section,
738 unsigned section_line,
739 const char *lvalue,
740 int ltype,
741 const char *rvalue,
742 void *data,
743 void *userdata) {
744 Network *network = userdata;
745 NetDev *netdev;
746 int r;
747
748 assert(filename);
749 assert(lvalue);
750 assert(rvalue);
751 assert(data);
752
753 r = netdev_get(network->manager, rvalue, &netdev);
754 if (r < 0) {
755 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
756 return 0;
757 }
758
759 if (!IN_SET(netdev->kind,
760 NETDEV_KIND_IPIP,
761 NETDEV_KIND_SIT,
762 NETDEV_KIND_GRE,
763 NETDEV_KIND_GRETAP,
764 NETDEV_KIND_IP6GRE,
765 NETDEV_KIND_IP6GRETAP,
766 NETDEV_KIND_VTI,
767 NETDEV_KIND_VTI6,
768 NETDEV_KIND_IP6TNL)) {
769 log_syntax(unit, LOG_ERR, filename, line, 0,
770 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
771 return 0;
772 }
773
774 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
775 if (r < 0) {
776 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
777 return 0;
778 }
779
780 netdev_ref(netdev);
781
782 return 0;
783 }
784
785 int config_parse_ipv4ll(
786 const char* unit,
787 const char *filename,
788 unsigned line,
789 const char *section,
790 unsigned section_line,
791 const char *lvalue,
792 int ltype,
793 const char *rvalue,
794 void *data,
795 void *userdata) {
796
797 AddressFamilyBoolean *link_local = data;
798
799 assert(filename);
800 assert(lvalue);
801 assert(rvalue);
802 assert(data);
803
804 /* Note that this is mostly like
805 * config_parse_address_family_boolean(), except that it
806 * applies only to IPv4 */
807
808 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
809
810 return 0;
811 }
812
813 int config_parse_dhcp(
814 const char* unit,
815 const char *filename,
816 unsigned line,
817 const char *section,
818 unsigned section_line,
819 const char *lvalue,
820 int ltype,
821 const char *rvalue,
822 void *data,
823 void *userdata) {
824
825 AddressFamilyBoolean *dhcp = data, s;
826
827 assert(filename);
828 assert(lvalue);
829 assert(rvalue);
830 assert(data);
831
832 /* Note that this is mostly like
833 * config_parse_address_family_boolean(), except that it
834 * understands some old names for the enum values */
835
836 s = address_family_boolean_from_string(rvalue);
837 if (s < 0) {
838
839 /* Previously, we had a slightly different enum here,
840 * support its values for compatbility. */
841
842 if (streq(rvalue, "none"))
843 s = ADDRESS_FAMILY_NO;
844 else if (streq(rvalue, "v4"))
845 s = ADDRESS_FAMILY_IPV4;
846 else if (streq(rvalue, "v6"))
847 s = ADDRESS_FAMILY_IPV6;
848 else if (streq(rvalue, "both"))
849 s = ADDRESS_FAMILY_YES;
850 else {
851 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
852 return 0;
853 }
854 }
855
856 *dhcp = s;
857 return 0;
858 }
859
860 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
861 [DHCP_CLIENT_ID_MAC] = "mac",
862 [DHCP_CLIENT_ID_DUID] = "duid",
863 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
864 };
865
866 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
867 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
868
869 int config_parse_ipv6token(
870 const char* unit,
871 const char *filename,
872 unsigned line,
873 const char *section,
874 unsigned section_line,
875 const char *lvalue,
876 int ltype,
877 const char *rvalue,
878 void *data,
879 void *userdata) {
880
881 union in_addr_union buffer;
882 struct in6_addr *token = data;
883 int r;
884
885 assert(filename);
886 assert(lvalue);
887 assert(rvalue);
888 assert(token);
889
890 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
891 if (r < 0) {
892 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
893 return 0;
894 }
895
896 r = in_addr_is_null(AF_INET6, &buffer);
897 if (r != 0) {
898 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
899 return 0;
900 }
901
902 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
903 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
904 return 0;
905 }
906
907 *token = buffer.in6;
908
909 return 0;
910 }
911
912 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
913 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
914 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
915 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
916 };
917
918 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
919
920 int config_parse_ipv6_privacy_extensions(
921 const char* unit,
922 const char *filename,
923 unsigned line,
924 const char *section,
925 unsigned section_line,
926 const char *lvalue,
927 int ltype,
928 const char *rvalue,
929 void *data,
930 void *userdata) {
931
932 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
933 int k;
934
935 assert(filename);
936 assert(lvalue);
937 assert(rvalue);
938 assert(ipv6_privacy_extensions);
939
940 /* Our enum shall be a superset of booleans, hence first try
941 * to parse as boolean, and then as enum */
942
943 k = parse_boolean(rvalue);
944 if (k > 0)
945 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
946 else if (k == 0)
947 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
948 else {
949 IPv6PrivacyExtensions s;
950
951 s = ipv6_privacy_extensions_from_string(rvalue);
952 if (s < 0) {
953
954 if (streq(rvalue, "kernel"))
955 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
956 else {
957 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
958 return 0;
959 }
960 }
961
962 *ipv6_privacy_extensions = s;
963 }
964
965 return 0;
966 }
967
968 int config_parse_hostname(
969 const char *unit,
970 const char *filename,
971 unsigned line,
972 const char *section,
973 unsigned section_line,
974 const char *lvalue,
975 int ltype,
976 const char *rvalue,
977 void *data,
978 void *userdata) {
979
980 char **hostname = data, *hn = NULL;
981 int r;
982
983 assert(filename);
984 assert(lvalue);
985 assert(rvalue);
986
987 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
988 if (r < 0)
989 return r;
990
991 if (!hostname_is_valid(hn, false)) {
992 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
993 free(hn);
994 return 0;
995 }
996
997 free(*hostname);
998 *hostname = hostname_cleanup(hn);
999 return 0;
1000 }
1001
1002 int config_parse_timezone(
1003 const char *unit,
1004 const char *filename,
1005 unsigned line,
1006 const char *section,
1007 unsigned section_line,
1008 const char *lvalue,
1009 int ltype,
1010 const char *rvalue,
1011 void *data,
1012 void *userdata) {
1013
1014 char **datap = data, *tz = NULL;
1015 int r;
1016
1017 assert(filename);
1018 assert(lvalue);
1019 assert(rvalue);
1020
1021 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1022 if (r < 0)
1023 return r;
1024
1025 if (!timezone_is_valid(tz)) {
1026 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
1027 free(tz);
1028 return 0;
1029 }
1030
1031 free(*datap);
1032 *datap = tz;
1033
1034 return 0;
1035 }
1036
1037 int config_parse_dhcp_server_dns(
1038 const char *unit,
1039 const char *filename,
1040 unsigned line,
1041 const char *section,
1042 unsigned section_line,
1043 const char *lvalue,
1044 int ltype,
1045 const char *rvalue,
1046 void *data,
1047 void *userdata) {
1048
1049 Network *n = data;
1050 const char *p = rvalue;
1051 int r;
1052
1053 assert(filename);
1054 assert(lvalue);
1055 assert(rvalue);
1056
1057 for (;;) {
1058 _cleanup_free_ char *w = NULL;
1059 struct in_addr a, *m;
1060
1061 r = extract_first_word(&p, &w, NULL, 0);
1062 if (r == -ENOMEM)
1063 return log_oom();
1064 if (r < 0) {
1065 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1066 return 0;
1067 }
1068 if (r == 0)
1069 break;
1070
1071 if (inet_pton(AF_INET, w, &a) <= 0) {
1072 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1073 continue;
1074 }
1075
1076 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1077 if (!m)
1078 return log_oom();
1079
1080 m[n->n_dhcp_server_dns++] = a;
1081 n->dhcp_server_dns = m;
1082 }
1083
1084 return 0;
1085 }
1086
1087 int config_parse_radv_dns(
1088 const char *unit,
1089 const char *filename,
1090 unsigned line,
1091 const char *section,
1092 unsigned section_line,
1093 const char *lvalue,
1094 int ltype,
1095 const char *rvalue,
1096 void *data,
1097 void *userdata) {
1098
1099 Network *n = data;
1100 const char *p = rvalue;
1101 int r;
1102
1103 assert(filename);
1104 assert(lvalue);
1105 assert(rvalue);
1106
1107 for (;;) {
1108 _cleanup_free_ char *w = NULL;
1109 union in_addr_union a;
1110
1111 r = extract_first_word(&p, &w, NULL, 0);
1112 if (r == -ENOMEM)
1113 return log_oom();
1114 if (r < 0) {
1115 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1116 return 0;
1117 }
1118 if (r == 0)
1119 break;
1120
1121 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1122 struct in6_addr *m;
1123
1124 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
1125 if (!m)
1126 return log_oom();
1127
1128 m[n->n_router_dns++] = a.in6;
1129 n->router_dns = m;
1130
1131 } else
1132 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1133
1134 }
1135
1136 return 0;
1137 }
1138
1139 int config_parse_radv_search_domains(
1140 const char *unit,
1141 const char *filename,
1142 unsigned line,
1143 const char *section,
1144 unsigned section_line,
1145 const char *lvalue,
1146 int ltype,
1147 const char *rvalue,
1148 void *data,
1149 void *userdata) {
1150
1151 Network *n = data;
1152 const char *p = rvalue;
1153 int r;
1154
1155 assert(filename);
1156 assert(lvalue);
1157 assert(rvalue);
1158
1159 for (;;) {
1160 _cleanup_free_ char *w = NULL;
1161 _cleanup_free_ char *idna = NULL;
1162
1163 r = extract_first_word(&p, &w, NULL, 0);
1164 if (r == -ENOMEM)
1165 return log_oom();
1166 if (r < 0) {
1167 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1168 return 0;
1169 }
1170 if (r == 0)
1171 break;
1172
1173 r = dns_name_apply_idna(w, &idna);
1174 if (r > 0) {
1175 r = strv_push(&n->router_search_domains, idna);
1176 if (r >= 0)
1177 idna = NULL;
1178 } else if (r == 0) {
1179 r = strv_push(&n->router_search_domains, w);
1180 if (r >= 0)
1181 w = NULL;
1182 }
1183 }
1184
1185 return 0;
1186 }
1187
1188 int config_parse_dhcp_server_ntp(
1189 const char *unit,
1190 const char *filename,
1191 unsigned line,
1192 const char *section,
1193 unsigned section_line,
1194 const char *lvalue,
1195 int ltype,
1196 const char *rvalue,
1197 void *data,
1198 void *userdata) {
1199
1200 Network *n = data;
1201 const char *p = rvalue;
1202 int r;
1203
1204 assert(filename);
1205 assert(lvalue);
1206 assert(rvalue);
1207
1208 for (;;) {
1209 _cleanup_free_ char *w = NULL;
1210 struct in_addr a, *m;
1211
1212 r = extract_first_word(&p, &w, NULL, 0);
1213 if (r == -ENOMEM)
1214 return log_oom();
1215 if (r < 0) {
1216 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1217 return 0;
1218 }
1219 if (r == 0)
1220 return 0;
1221
1222 if (inet_pton(AF_INET, w, &a) <= 0) {
1223 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1224 continue;
1225 }
1226
1227 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1228 if (!m)
1229 return log_oom();
1230
1231 m[n->n_dhcp_server_ntp++] = a;
1232 n->dhcp_server_ntp = m;
1233 }
1234 }
1235
1236 int config_parse_dns(
1237 const char *unit,
1238 const char *filename,
1239 unsigned line,
1240 const char *section,
1241 unsigned section_line,
1242 const char *lvalue,
1243 int ltype,
1244 const char *rvalue,
1245 void *data,
1246 void *userdata) {
1247
1248 Network *n = userdata;
1249 int r;
1250
1251 assert(filename);
1252 assert(lvalue);
1253 assert(rvalue);
1254
1255 for (;;) {
1256 _cleanup_free_ char *w = NULL;
1257 union in_addr_union a;
1258 struct in_addr_data *m;
1259 int family;
1260
1261 r = extract_first_word(&rvalue, &w, NULL, 0);
1262 if (r == -ENOMEM)
1263 return log_oom();
1264 if (r < 0) {
1265 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1266 break;
1267 }
1268 if (r == 0)
1269 break;
1270
1271 r = in_addr_from_string_auto(w, &family, &a);
1272 if (r < 0) {
1273 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
1274 continue;
1275 }
1276
1277 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
1278 if (!m)
1279 return log_oom();
1280
1281 m[n->n_dns++] = (struct in_addr_data) {
1282 .family = family,
1283 .address = a,
1284 };
1285
1286 n->dns = m;
1287 }
1288
1289 return 0;
1290 }
1291
1292 int config_parse_dnssec_negative_trust_anchors(
1293 const char *unit,
1294 const char *filename,
1295 unsigned line,
1296 const char *section,
1297 unsigned section_line,
1298 const char *lvalue,
1299 int ltype,
1300 const char *rvalue,
1301 void *data,
1302 void *userdata) {
1303
1304 const char *p = rvalue;
1305 Network *n = data;
1306 int r;
1307
1308 assert(n);
1309 assert(lvalue);
1310 assert(rvalue);
1311
1312 if (isempty(rvalue)) {
1313 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1314 return 0;
1315 }
1316
1317 for (;;) {
1318 _cleanup_free_ char *w = NULL;
1319
1320 r = extract_first_word(&p, &w, NULL, 0);
1321 if (r < 0) {
1322 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1323 break;
1324 }
1325 if (r == 0)
1326 break;
1327
1328 r = dns_name_is_valid(w);
1329 if (r <= 0) {
1330 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1331 continue;
1332 }
1333
1334 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1335 if (r < 0)
1336 return log_oom();
1337
1338 r = set_put(n->dnssec_negative_trust_anchors, w);
1339 if (r < 0)
1340 return log_oom();
1341 if (r > 0)
1342 w = NULL;
1343 }
1344
1345 return 0;
1346 }
1347
1348 int config_parse_ntp(
1349 const char *unit,
1350 const char *filename,
1351 unsigned line,
1352 const char *section,
1353 unsigned section_line,
1354 const char *lvalue,
1355 int ltype,
1356 const char *rvalue,
1357 void *data,
1358 void *userdata) {
1359
1360 char ***l = data;
1361 int r;
1362
1363 assert(l);
1364 assert(lvalue);
1365 assert(rvalue);
1366
1367 if (isempty(rvalue)) {
1368 *l = strv_free(*l);
1369 return 0;
1370 }
1371
1372 for (;;) {
1373 _cleanup_free_ char *w = NULL;
1374
1375 r = extract_first_word(&rvalue, &w, NULL, 0);
1376 if (r == -ENOMEM)
1377 return log_oom();
1378 if (r < 0) {
1379 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1380 break;
1381 }
1382 if (r == 0)
1383 break;
1384
1385 r = dns_name_is_valid_or_address(w);
1386 if (r <= 0) {
1387 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1388 continue;
1389 }
1390
1391 r = strv_push(l, w);
1392 if (r < 0)
1393 return log_oom();
1394
1395 w = NULL;
1396 }
1397
1398 return 0;
1399 }
1400
1401 int config_parse_dhcp_route_table(const char *unit,
1402 const char *filename,
1403 unsigned line,
1404 const char *section,
1405 unsigned section_line,
1406 const char *lvalue,
1407 int ltype,
1408 const char *rvalue,
1409 void *data,
1410 void *userdata) {
1411 Network *network = data;
1412 uint32_t rt;
1413 int r;
1414
1415 assert(filename);
1416 assert(lvalue);
1417 assert(rvalue);
1418 assert(data);
1419
1420 r = safe_atou32(rvalue, &rt);
1421 if (r < 0) {
1422 log_syntax(unit, LOG_ERR, filename, line, r,
1423 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1424 return 0;
1425 }
1426
1427 network->dhcp_route_table = rt;
1428 network->dhcp_route_table_set = true;
1429
1430 return 0;
1431 }
1432
1433 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1434
1435 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1436 [DHCP_USE_DOMAINS_NO] = "no",
1437 [DHCP_USE_DOMAINS_ROUTE] = "route",
1438 [DHCP_USE_DOMAINS_YES] = "yes",
1439 };
1440
1441 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1442
1443 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1444
1445 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1446 [LLDP_MODE_NO] = "no",
1447 [LLDP_MODE_YES] = "yes",
1448 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1449 };
1450
1451 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);