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