]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Merge pull request #11746 from yuwata/udev-rules-cleanup
[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 .ipv6_accept_ra_route_table_set = false,
213 };
214
215 r = config_parse_many(filename, network_dirs, dropin_dirname,
216 "Match\0"
217 "Link\0"
218 "Network\0"
219 "Address\0"
220 "Neighbor\0"
221 "IPv6AddressLabel\0"
222 "RoutingPolicyRule\0"
223 "Route\0"
224 "DHCP\0"
225 "DHCPv4\0" /* compat */
226 "DHCPServer\0"
227 "IPv6AcceptRA\0"
228 "IPv6NDPProxyAddress\0"
229 "Bridge\0"
230 "BridgeFDB\0"
231 "BridgeVLAN\0"
232 "IPv6PrefixDelegation\0"
233 "IPv6Prefix\0"
234 "CAN\0",
235 config_item_perf_lookup, network_network_gperf_lookup,
236 CONFIG_PARSE_WARN, network);
237 if (r < 0) {
238 /* Unset manager here. Otherwise, LIST_REMOVE() in network_free() fails. */
239 network->manager = NULL;
240 return r;
241 }
242
243 network_apply_anonymize_if_set(network);
244
245 /* IPMasquerade=yes implies IPForward=yes */
246 if (network->ip_masquerade)
247 network->ip_forward |= ADDRESS_FAMILY_IPV4;
248
249 if (network->mtu > 0 && network->dhcp_use_mtu) {
250 log_warning("MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set in %s. "
251 "Disabling UseMTU=.", filename);
252 network->dhcp_use_mtu = false;
253 }
254
255 LIST_PREPEND(networks, manager->networks, network);
256
257 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
258 if (r < 0)
259 return r;
260
261 r = hashmap_put(manager->networks_by_name, network->name, network);
262 if (r < 0)
263 return r;
264
265 LIST_FOREACH(routes, route, network->static_routes)
266 if (!route->family) {
267 log_warning("Route section without Gateway field configured in %s. "
268 "Ignoring", filename);
269 return 0;
270 }
271
272 LIST_FOREACH(addresses, address, network->static_addresses)
273 if (!address->family) {
274 log_warning("Address section without Address field configured in %s. "
275 "Ignoring", filename);
276 return 0;
277 }
278
279 network = NULL;
280
281 return 0;
282 }
283
284 int network_load(Manager *manager) {
285 Network *network;
286 _cleanup_strv_free_ char **files = NULL;
287 char **f;
288 int r;
289
290 assert(manager);
291
292 while ((network = manager->networks))
293 network_free(network);
294
295 r = conf_files_list_strv(&files, ".network", NULL, 0, network_dirs);
296 if (r < 0)
297 return log_error_errno(r, "Failed to enumerate network files: %m");
298
299 STRV_FOREACH_BACKWARDS(f, files) {
300 r = network_load_one(manager, *f);
301 if (r < 0)
302 return r;
303 }
304
305 return 0;
306 }
307
308 void network_free(Network *network) {
309 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
310 RoutingPolicyRule *rule;
311 FdbEntry *fdb_entry;
312 Neighbor *neighbor;
313 AddressLabel *label;
314 Prefix *prefix;
315 Address *address;
316 Route *route;
317
318 if (!network)
319 return;
320
321 free(network->filename);
322
323 set_free_free(network->match_mac);
324 strv_free(network->match_path);
325 strv_free(network->match_driver);
326 strv_free(network->match_type);
327 strv_free(network->match_name);
328
329 free(network->description);
330 free(network->dhcp_vendor_class_identifier);
331 strv_free(network->dhcp_user_class);
332 free(network->dhcp_hostname);
333
334 free(network->mac);
335
336 strv_free(network->ntp);
337 free(network->dns);
338 strv_free(network->search_domains);
339 strv_free(network->route_domains);
340 strv_free(network->bind_carrier);
341
342 strv_free(network->router_search_domains);
343 free(network->router_dns);
344
345 netdev_unref(network->bridge);
346 netdev_unref(network->bond);
347 netdev_unref(network->vrf);
348
349 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
350
351 while ((route = network->static_routes))
352 route_free(route);
353
354 while ((address = network->static_addresses))
355 address_free(address);
356
357 while ((fdb_entry = network->static_fdb_entries))
358 fdb_entry_free(fdb_entry);
359
360 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
361 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
362
363 while ((neighbor = network->neighbors))
364 neighbor_free(neighbor);
365
366 while ((label = network->address_labels))
367 address_label_free(label);
368
369 while ((prefix = network->static_prefixes))
370 prefix_free(prefix);
371
372 while ((rule = network->rules))
373 routing_policy_rule_free(rule);
374
375 hashmap_free(network->addresses_by_section);
376 hashmap_free(network->routes_by_section);
377 hashmap_free(network->fdb_entries_by_section);
378 hashmap_free(network->neighbors_by_section);
379 hashmap_free(network->address_labels_by_section);
380 hashmap_free(network->prefixes_by_section);
381 hashmap_free(network->rules_by_section);
382
383 if (network->manager) {
384 if (network->manager->networks)
385 LIST_REMOVE(networks, network->manager->networks, network);
386
387 if (network->manager->networks_by_name && network->name)
388 hashmap_remove(network->manager->networks_by_name, network->name);
389
390 if (network->manager->duids_requesting_uuid)
391 set_remove(network->manager->duids_requesting_uuid, &network->duid);
392 }
393
394 free(network->name);
395
396 condition_free_list(network->match_host);
397 condition_free_list(network->match_virt);
398 condition_free_list(network->match_kernel_cmdline);
399 condition_free_list(network->match_kernel_version);
400 condition_free_list(network->match_arch);
401
402 free(network->dhcp_server_timezone);
403 free(network->dhcp_server_dns);
404 free(network->dhcp_server_ntp);
405
406 set_free_free(network->dnssec_negative_trust_anchors);
407
408 free(network);
409 }
410
411 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
412 Network *network;
413
414 assert(manager);
415 assert(name);
416 assert(ret);
417
418 network = hashmap_get(manager->networks_by_name, name);
419 if (!network)
420 return -ENOENT;
421
422 *ret = network;
423
424 return 0;
425 }
426
427 int network_get(Manager *manager, sd_device *device,
428 const char *ifname, const struct ether_addr *address,
429 Network **ret) {
430 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
431 sd_device *parent;
432 Network *network;
433
434 assert(manager);
435 assert(ret);
436
437 if (device) {
438 (void) sd_device_get_property_value(device, "ID_PATH", &path);
439
440 if (sd_device_get_parent(device, &parent) >= 0)
441 (void) sd_device_get_driver(parent, &parent_driver);
442
443 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
444
445 (void) sd_device_get_devtype(device, &devtype);
446 }
447
448 LIST_FOREACH(networks, network, manager->networks) {
449 if (net_match_config(network->match_mac, network->match_path,
450 network->match_driver, network->match_type,
451 network->match_name, network->match_host,
452 network->match_virt, network->match_kernel_cmdline,
453 network->match_kernel_version, network->match_arch,
454 address, path, parent_driver, driver,
455 devtype, ifname)) {
456 if (network->match_name && device) {
457 const char *attr;
458 uint8_t name_assign_type = NET_NAME_UNKNOWN;
459
460 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
461 (void) safe_atou8(attr, &name_assign_type);
462
463 if (name_assign_type == NET_NAME_ENUM)
464 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
465 ifname, network->filename);
466 else
467 log_debug("%s: found matching network '%s'", ifname, network->filename);
468 } else
469 log_debug("%s: found matching network '%s'", ifname, network->filename);
470
471 *ret = network;
472 return 0;
473 }
474 }
475
476 *ret = NULL;
477
478 return -ENOENT;
479 }
480
481 int network_apply(Network *network, Link *link) {
482 int r;
483
484 assert(network);
485 assert(link);
486
487 link->network = network;
488
489 if (network->ipv4ll_route) {
490 Route *route;
491
492 r = route_new_static(network, NULL, 0, &route);
493 if (r < 0)
494 return r;
495
496 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
497 if (r == 0)
498 return -EINVAL;
499 if (r < 0)
500 return -errno;
501
502 route->family = AF_INET;
503 route->dst_prefixlen = 16;
504 route->scope = RT_SCOPE_LINK;
505 route->priority = IPV4LL_ROUTE_METRIC;
506 route->protocol = RTPROT_STATIC;
507 }
508
509 if (network->n_dns > 0 ||
510 !strv_isempty(network->ntp) ||
511 !strv_isempty(network->search_domains) ||
512 !strv_isempty(network->route_domains))
513 link_dirty(link);
514
515 return 0;
516 }
517
518 bool network_has_static_ipv6_addresses(Network *network) {
519 Address *address;
520
521 assert(network);
522
523 LIST_FOREACH(addresses, address, network->static_addresses) {
524 if (address->family == AF_INET6)
525 return true;
526 }
527
528 return false;
529 }
530
531 int config_parse_netdev(const char *unit,
532 const char *filename,
533 unsigned line,
534 const char *section,
535 unsigned section_line,
536 const char *lvalue,
537 int ltype,
538 const char *rvalue,
539 void *data,
540 void *userdata) {
541 Network *network = userdata;
542 _cleanup_free_ char *kind_string = NULL;
543 char *p;
544 NetDev *netdev;
545 NetDevKind kind;
546 int r;
547
548 assert(filename);
549 assert(lvalue);
550 assert(rvalue);
551 assert(data);
552
553 kind_string = strdup(lvalue);
554 if (!kind_string)
555 return log_oom();
556
557 /* the keys are CamelCase versions of the kind */
558 for (p = kind_string; *p; p++)
559 *p = tolower(*p);
560
561 kind = netdev_kind_from_string(kind_string);
562 if (kind == _NETDEV_KIND_INVALID) {
563 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
564 return 0;
565 }
566
567 r = netdev_get(network->manager, rvalue, &netdev);
568 if (r < 0) {
569 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
570 return 0;
571 }
572
573 if (netdev->kind != kind) {
574 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
575 return 0;
576 }
577
578 switch (kind) {
579 case NETDEV_KIND_BRIDGE:
580 network->bridge = netdev_unref(network->bridge);
581 network->bridge = netdev;
582
583 break;
584 case NETDEV_KIND_BOND:
585 network->bond = netdev_unref(network->bond);
586 network->bond = netdev;
587
588 break;
589 case NETDEV_KIND_VRF:
590 network->vrf = netdev_unref(network->vrf);
591 network->vrf = netdev;
592
593 break;
594 case NETDEV_KIND_VLAN:
595 case NETDEV_KIND_MACVLAN:
596 case NETDEV_KIND_MACVTAP:
597 case NETDEV_KIND_IPVLAN:
598 case NETDEV_KIND_VXLAN:
599 case NETDEV_KIND_VCAN:
600 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
601 if (r < 0)
602 return log_oom();
603
604 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
605 if (r < 0) {
606 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
607 return 0;
608 }
609
610 break;
611 default:
612 assert_not_reached("Cannot parse NetDev");
613 }
614
615 netdev_ref(netdev);
616
617 return 0;
618 }
619
620 int config_parse_domains(
621 const char *unit,
622 const char *filename,
623 unsigned line,
624 const char *section,
625 unsigned section_line,
626 const char *lvalue,
627 int ltype,
628 const char *rvalue,
629 void *data,
630 void *userdata) {
631
632 const char *p;
633 Network *n = data;
634 int r;
635
636 assert(n);
637 assert(lvalue);
638 assert(rvalue);
639
640 if (isempty(rvalue)) {
641 n->search_domains = strv_free(n->search_domains);
642 n->route_domains = strv_free(n->route_domains);
643 return 0;
644 }
645
646 p = rvalue;
647 for (;;) {
648 _cleanup_free_ char *w = NULL, *normalized = NULL;
649 const char *domain;
650 bool is_route;
651
652 r = extract_first_word(&p, &w, NULL, 0);
653 if (r < 0) {
654 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
655 break;
656 }
657 if (r == 0)
658 break;
659
660 is_route = w[0] == '~';
661 domain = is_route ? w + 1 : w;
662
663 if (dns_name_is_root(domain) || streq(domain, "*")) {
664 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
665 * routing domain, unconditionally. */
666 is_route = true;
667 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
668 } else {
669 r = dns_name_normalize(domain, 0, &normalized);
670 if (r < 0) {
671 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
672 continue;
673 }
674
675 domain = normalized;
676
677 if (is_localhost(domain)) {
678 log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain);
679 continue;
680 }
681 }
682
683 if (is_route)
684 r = strv_extend(&n->route_domains, domain);
685 else
686 r = strv_extend(&n->search_domains, domain);
687 if (r < 0)
688 return log_oom();
689 }
690
691 strv_uniq(n->route_domains);
692 strv_uniq(n->search_domains);
693
694 return 0;
695 }
696
697 int config_parse_tunnel(const char *unit,
698 const char *filename,
699 unsigned line,
700 const char *section,
701 unsigned section_line,
702 const char *lvalue,
703 int ltype,
704 const char *rvalue,
705 void *data,
706 void *userdata) {
707 Network *network = userdata;
708 NetDev *netdev;
709 int r;
710
711 assert(filename);
712 assert(lvalue);
713 assert(rvalue);
714 assert(data);
715
716 r = netdev_get(network->manager, rvalue, &netdev);
717 if (r < 0) {
718 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
719 return 0;
720 }
721
722 if (!IN_SET(netdev->kind,
723 NETDEV_KIND_IPIP,
724 NETDEV_KIND_SIT,
725 NETDEV_KIND_GRE,
726 NETDEV_KIND_GRETAP,
727 NETDEV_KIND_IP6GRE,
728 NETDEV_KIND_IP6GRETAP,
729 NETDEV_KIND_VTI,
730 NETDEV_KIND_VTI6,
731 NETDEV_KIND_IP6TNL)) {
732 log_syntax(unit, LOG_ERR, filename, line, 0,
733 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
734 return 0;
735 }
736
737 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
738 if (r < 0)
739 return log_oom();
740
741 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
742 if (r < 0) {
743 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
744 return 0;
745 }
746
747 netdev_ref(netdev);
748
749 return 0;
750 }
751
752 int config_parse_ipv4ll(
753 const char* unit,
754 const char *filename,
755 unsigned line,
756 const char *section,
757 unsigned section_line,
758 const char *lvalue,
759 int ltype,
760 const char *rvalue,
761 void *data,
762 void *userdata) {
763
764 AddressFamilyBoolean *link_local = data;
765
766 assert(filename);
767 assert(lvalue);
768 assert(rvalue);
769 assert(data);
770
771 /* Note that this is mostly like
772 * config_parse_address_family_boolean(), except that it
773 * applies only to IPv4 */
774
775 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
776
777 return 0;
778 }
779
780 int config_parse_dhcp(
781 const char* unit,
782 const char *filename,
783 unsigned line,
784 const char *section,
785 unsigned section_line,
786 const char *lvalue,
787 int ltype,
788 const char *rvalue,
789 void *data,
790 void *userdata) {
791
792 AddressFamilyBoolean *dhcp = data, s;
793
794 assert(filename);
795 assert(lvalue);
796 assert(rvalue);
797 assert(data);
798
799 /* Note that this is mostly like
800 * config_parse_address_family_boolean(), except that it
801 * understands some old names for the enum values */
802
803 s = address_family_boolean_from_string(rvalue);
804 if (s < 0) {
805
806 /* Previously, we had a slightly different enum here,
807 * support its values for compatbility. */
808
809 if (streq(rvalue, "none"))
810 s = ADDRESS_FAMILY_NO;
811 else if (streq(rvalue, "v4"))
812 s = ADDRESS_FAMILY_IPV4;
813 else if (streq(rvalue, "v6"))
814 s = ADDRESS_FAMILY_IPV6;
815 else if (streq(rvalue, "both"))
816 s = ADDRESS_FAMILY_YES;
817 else {
818 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
819 return 0;
820 }
821 }
822
823 *dhcp = s;
824 return 0;
825 }
826
827 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
828 [DHCP_CLIENT_ID_MAC] = "mac",
829 [DHCP_CLIENT_ID_DUID] = "duid",
830 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
831 };
832
833 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
834 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
835
836 int config_parse_ipv6token(
837 const char* unit,
838 const char *filename,
839 unsigned line,
840 const char *section,
841 unsigned section_line,
842 const char *lvalue,
843 int ltype,
844 const char *rvalue,
845 void *data,
846 void *userdata) {
847
848 union in_addr_union buffer;
849 struct in6_addr *token = data;
850 int r;
851
852 assert(filename);
853 assert(lvalue);
854 assert(rvalue);
855 assert(token);
856
857 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
858 if (r < 0) {
859 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
860 return 0;
861 }
862
863 if (in_addr_is_null(AF_INET6, &buffer)) {
864 log_syntax(unit, LOG_ERR, filename, line, 0, "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_section_route_table(
1428 const char *unit,
1429 const char *filename,
1430 unsigned line,
1431 const char *section,
1432 unsigned section_line,
1433 const char *lvalue,
1434 int ltype,
1435 const char *rvalue,
1436 void *data,
1437 void *userdata) {
1438
1439 Network *network = data;
1440 uint32_t rt;
1441 int r;
1442
1443 assert(filename);
1444 assert(lvalue);
1445 assert(rvalue);
1446 assert(data);
1447
1448 r = safe_atou32(rvalue, &rt);
1449 if (r < 0) {
1450 log_syntax(unit, LOG_ERR, filename, line, r,
1451 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
1452 return 0;
1453 }
1454
1455 if (streq_ptr(section, "DHCP")) {
1456 network->dhcp_route_table = rt;
1457 network->dhcp_route_table_set = true;
1458 } else { /* section is IPv6AcceptRA */
1459 network->ipv6_accept_ra_route_table = rt;
1460 network->ipv6_accept_ra_route_table_set = true;
1461 }
1462
1463 return 0;
1464 }
1465
1466 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1467
1468 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1469 [DHCP_USE_DOMAINS_NO] = "no",
1470 [DHCP_USE_DOMAINS_ROUTE] = "route",
1471 [DHCP_USE_DOMAINS_YES] = "yes",
1472 };
1473
1474 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1475
1476 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1477
1478 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1479 [LLDP_MODE_NO] = "no",
1480 [LLDP_MODE_YES] = "yes",
1481 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1482 };
1483
1484 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
1485
1486 int config_parse_iaid(const char *unit,
1487 const char *filename,
1488 unsigned line,
1489 const char *section,
1490 unsigned section_line,
1491 const char *lvalue,
1492 int ltype,
1493 const char *rvalue,
1494 void *data,
1495 void *userdata) {
1496 Network *network = data;
1497 uint32_t iaid;
1498 int r;
1499
1500 assert(filename);
1501 assert(lvalue);
1502 assert(rvalue);
1503 assert(network);
1504
1505 r = safe_atou32(rvalue, &iaid);
1506 if (r < 0) {
1507 log_syntax(unit, LOG_ERR, filename, line, r,
1508 "Unable to read IAID, ignoring assignment: %s", rvalue);
1509 return 0;
1510 }
1511
1512 network->iaid = iaid;
1513 network->iaid_set = true;
1514
1515 return 0;
1516 }