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