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