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