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