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