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