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