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