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