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