]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Merge pull request #13583 from keszybz/networkd-hash-compare-equality
[thirdparty/systemd.git] / src / network / networkd-network.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <net/if.h>
4 #include <netinet/in.h>
5 #include <linux/netdevice.h>
6
7 #include "alloc-util.h"
8 #include "conf-files.h"
9 #include "conf-parser.h"
10 #include "dns-domain.h"
11 #include "fd-util.h"
12 #include "hostname-util.h"
13 #include "in-addr-util.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 int network_verify(Network *network) {
147 Address *address, *address_next;
148 Route *route, *route_next;
149 FdbEntry *fdb, *fdb_next;
150 Neighbor *neighbor, *neighbor_next;
151 AddressLabel *label, *label_next;
152 Prefix *prefix, *prefix_next;
153 RoutingPolicyRule *rule, *rule_next;
154
155 assert(network);
156 assert(network->filename);
157
158 if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
159 strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
160 strv_isempty(network->match_name) && strv_isempty(network->match_property) &&
161 !network->conditions)
162 log_warning("%s: No valid settings found in the [Match] section. "
163 "The file will match all interfaces. "
164 "If that is intended, please add Name=* in the [Match] section.",
165 network->filename);
166
167 /* skip out early if configuration does not match the environment */
168 if (!condition_test_list(network->conditions, NULL, NULL, NULL))
169 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
170 "%s: Conditions in the file do not match the system environment, skipping.",
171 network->filename);
172
173 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
174 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
175 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
176 (void) network_resolve_stacked_netdevs(network);
177
178 /* Free unnecessary entries. */
179 network->bond_name = mfree(network->bond_name);
180 network->bridge_name = mfree(network->bridge_name);
181 network->vrf_name = mfree(network->vrf_name);
182 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
183
184 if (network->bond) {
185 /* Bonding slave does not support addressing. */
186 if (network->ipv6_accept_ra > 0) {
187 log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
188 network->filename);
189 network->ipv6_accept_ra = 0;
190 }
191 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
192 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
193 network->filename);
194 network->link_local = ADDRESS_FAMILY_NO;
195 }
196 if (network->dhcp != ADDRESS_FAMILY_NO) {
197 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
198 network->filename);
199 network->dhcp = ADDRESS_FAMILY_NO;
200 }
201 if (network->dhcp_server) {
202 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
203 network->filename);
204 network->dhcp_server = false;
205 }
206 if (network->n_static_addresses > 0) {
207 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
208 network->filename);
209 while ((address = network->static_addresses))
210 address_free(address);
211 }
212 if (network->n_static_routes > 0) {
213 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
214 network->filename);
215 while ((route = network->static_routes))
216 route_free(route);
217 }
218 }
219
220 if (network->link_local < 0)
221 network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
222
223 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
224 if (network->ipv6_accept_ra > 0) {
225 log_warning("%s: IPv6AcceptRA= is enabled by the .network file but IPv6 link local addressing is disabled. "
226 "Disabling IPv6AcceptRA=.", network->filename);
227 network->ipv6_accept_ra = false;
228 }
229
230 if (FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV6)) {
231 log_warning("%s: DHCPv6 client is enabled by the .network file but IPv6 link local addressing is disabled. "
232 "Disabling DHCPv6 client.", network->filename);
233 SET_FLAG(network->dhcp, ADDRESS_FAMILY_IPV6, false);
234 }
235
236 if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) {
237 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
238 "Disabling IPv6PrefixDelegation=.", network->filename);
239 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
240 }
241 }
242
243 if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
244 !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
245 log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
246 "Disabling the fallback assignment.", network->filename);
247 SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
248 }
249
250 if (network->ipv6_accept_ra < 0 && network->bridge)
251 network->ipv6_accept_ra = false;
252
253 /* IPMasquerade=yes implies IPForward=yes */
254 if (network->ip_masquerade)
255 network->ip_forward |= ADDRESS_FAMILY_IPV4;
256
257 if (network->mtu > 0 && network->dhcp_use_mtu) {
258 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
259 "Disabling UseMTU=.", network->filename);
260 network->dhcp_use_mtu = false;
261 }
262
263 if (network->dhcp_critical >= 0) {
264 if (network->keep_configuration >= 0)
265 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
266 "Ignoring CriticalConnection=.", network->filename);
267 else if (network->dhcp_critical)
268 /* CriticalConnection=yes also preserve foreign static configurations. */
269 network->keep_configuration = KEEP_CONFIGURATION_YES;
270 else
271 /* For backward compatibility, we do not release DHCP addresses on manager stop. */
272 network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
273 }
274
275 if (network->keep_configuration < 0)
276 /* For backward compatibility, we do not release DHCP addresses on manager stop. */
277 network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
278
279 LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
280 if (address_section_verify(address) < 0)
281 address_free(address);
282
283 LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
284 if (route_section_verify(route, network) < 0)
285 route_free(route);
286
287 LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
288 if (section_is_invalid(fdb->section))
289 fdb_entry_free(fdb);
290
291 LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
292 if (neighbor_section_verify(neighbor) < 0)
293 neighbor_free(neighbor);
294
295 LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
296 if (section_is_invalid(label->section))
297 address_label_free(label);
298
299 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
300 if (section_is_invalid(prefix->section))
301 prefix_free(prefix);
302
303 LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
304 if (routing_policy_rule_section_verify(rule) < 0)
305 routing_policy_rule_free(rule);
306
307 return 0;
308 }
309
310 int network_load_one(Manager *manager, const char *filename) {
311 _cleanup_free_ char *fname = NULL, *name = NULL;
312 _cleanup_(network_unrefp) Network *network = NULL;
313 _cleanup_fclose_ FILE *file = NULL;
314 const char *dropin_dirname;
315 char *d;
316 int r;
317
318 assert(manager);
319 assert(filename);
320
321 file = fopen(filename, "re");
322 if (!file) {
323 if (errno == ENOENT)
324 return 0;
325
326 return -errno;
327 }
328
329 if (null_or_empty_fd(fileno(file))) {
330 log_debug("Skipping empty file: %s", filename);
331 return 0;
332 }
333
334 fname = strdup(filename);
335 if (!fname)
336 return log_oom();
337
338 name = strdup(basename(filename));
339 if (!name)
340 return log_oom();
341
342 d = strrchr(name, '.');
343 if (!d)
344 return -EINVAL;
345
346 *d = '\0';
347
348 dropin_dirname = strjoina(name, ".network.d");
349
350 network = new(Network, 1);
351 if (!network)
352 return log_oom();
353
354 *network = (Network) {
355 .filename = TAKE_PTR(fname),
356 .name = TAKE_PTR(name),
357
358 .manager = manager,
359 .n_ref = 1,
360
361 .required_for_online = true,
362 .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
363 .dhcp = ADDRESS_FAMILY_NO,
364 .dhcp_critical = -1,
365 .dhcp_use_ntp = true,
366 .dhcp_use_dns = true,
367 .dhcp_use_hostname = true,
368 .dhcp_use_routes = true,
369 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
370 .dhcp_send_hostname = true,
371 /* To enable/disable RFC7844 Anonymity Profiles */
372 .dhcp_anonymize = false,
373 .dhcp_route_metric = DHCP_ROUTE_METRIC,
374 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
375 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
376 .dhcp_route_table = RT_TABLE_MAIN,
377 .dhcp_route_table_set = false,
378 /* NOTE: from man: UseMTU=... Defaults to false*/
379 .dhcp_use_mtu = false,
380 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
381 .dhcp_use_timezone = false,
382 .rapid_commit = true,
383
384 .dhcp6_use_ntp = true,
385 .dhcp6_use_dns = true,
386
387 .dhcp_server_emit_dns = true,
388 .dhcp_server_emit_ntp = true,
389 .dhcp_server_emit_router = true,
390 .dhcp_server_emit_timezone = true,
391
392 .router_emit_dns = true,
393 .router_emit_domains = true,
394
395 .use_bpdu = -1,
396 .hairpin = -1,
397 .fast_leave = -1,
398 .allow_port_to_be_root = -1,
399 .unicast_flood = -1,
400 .multicast_flood = -1,
401 .multicast_to_unicast = -1,
402 .neighbor_suppression = -1,
403 .learning = -1,
404 .bridge_proxy_arp = -1,
405 .bridge_proxy_arp_wifi = -1,
406 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
407 .multicast_router = _MULTICAST_ROUTER_INVALID,
408
409 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
410
411 .dns_default_route = -1,
412 .llmnr = RESOLVE_SUPPORT_YES,
413 .mdns = RESOLVE_SUPPORT_NO,
414 .dnssec_mode = _DNSSEC_MODE_INVALID,
415 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
416
417 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
418 .link_local = _ADDRESS_FAMILY_INVALID,
419
420 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
421 .ipv6_accept_ra = -1,
422 .ipv6_dad_transmits = -1,
423 .ipv6_hop_limit = -1,
424 .ipv6_proxy_ndp = -1,
425 .duid.type = _DUID_TYPE_INVALID,
426 .proxy_arp = -1,
427 .arp = -1,
428 .multicast = -1,
429 .allmulticast = -1,
430 .ipv6_accept_ra_use_dns = true,
431 .ipv6_accept_ra_use_autonomous_prefix = true,
432 .ipv6_accept_ra_use_onlink_prefix = true,
433 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
434 .ipv6_accept_ra_route_table_set = false,
435
436 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
437
438 .can_triple_sampling = -1,
439 };
440
441 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
442 "Match\0"
443 "Link\0"
444 "Network\0"
445 "Address\0"
446 "Neighbor\0"
447 "IPv6AddressLabel\0"
448 "RoutingPolicyRule\0"
449 "Route\0"
450 "DHCP\0"
451 "DHCPv4\0" /* compat */
452 "DHCPv6\0"
453 "DHCPServer\0"
454 "IPv6AcceptRA\0"
455 "IPv6NDPProxyAddress\0"
456 "Bridge\0"
457 "BridgeFDB\0"
458 "BridgeVLAN\0"
459 "IPv6PrefixDelegation\0"
460 "IPv6Prefix\0"
461 "IPv6RoutePrefix\0"
462 "CAN\0",
463 config_item_perf_lookup, network_network_gperf_lookup,
464 CONFIG_PARSE_WARN, network);
465 if (r < 0)
466 return r;
467
468 network_apply_anonymize_if_set(network);
469
470 r = network_add_ipv4ll_route(network);
471 if (r < 0)
472 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
473
474 r = network_add_default_route_on_device(network);
475 if (r < 0)
476 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
477 network->filename);
478
479 r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
480 if (r < 0)
481 return r;
482
483 r = ordered_hashmap_put(manager->networks, network->name, network);
484 if (r < 0)
485 return r;
486
487 if (network_verify(network) < 0)
488 return 0;
489
490 network = NULL;
491 return 0;
492 }
493
494 int network_load(Manager *manager) {
495 _cleanup_strv_free_ char **files = NULL;
496 char **f;
497 int r;
498
499 assert(manager);
500
501 ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
502
503 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
504 if (r < 0)
505 return log_error_errno(r, "Failed to enumerate network files: %m");
506
507 STRV_FOREACH(f, files) {
508 r = network_load_one(manager, *f);
509 if (r < 0)
510 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
511 }
512
513 return 0;
514 }
515
516 static Network *network_free(Network *network) {
517 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
518 RoutingPolicyRule *rule;
519 FdbEntry *fdb_entry;
520 Neighbor *neighbor;
521 AddressLabel *label;
522 Prefix *prefix;
523 Address *address;
524 Route *route;
525
526 if (!network)
527 return NULL;
528
529 free(network->filename);
530
531 set_free_free(network->match_mac);
532 strv_free(network->match_path);
533 strv_free(network->match_driver);
534 strv_free(network->match_type);
535 strv_free(network->match_name);
536 strv_free(network->match_property);
537 condition_free_list(network->conditions);
538
539 free(network->description);
540 free(network->dhcp_vendor_class_identifier);
541 strv_free(network->dhcp_user_class);
542 free(network->dhcp_hostname);
543 set_free(network->dhcp_black_listed_ip);
544 free(network->mac);
545
546 strv_free(network->ntp);
547 free(network->dns);
548 ordered_set_free_free(network->search_domains);
549 ordered_set_free_free(network->route_domains);
550 strv_free(network->bind_carrier);
551
552 ordered_set_free_free(network->router_search_domains);
553 free(network->router_dns);
554 set_free_free(network->ndisc_black_listed_prefix);
555
556 free(network->bridge_name);
557 free(network->bond_name);
558 free(network->vrf_name);
559 hashmap_free_free_key(network->stacked_netdev_names);
560 netdev_unref(network->bridge);
561 netdev_unref(network->bond);
562 netdev_unref(network->vrf);
563 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
564
565 while ((route = network->static_routes))
566 route_free(route);
567
568 while ((address = network->static_addresses))
569 address_free(address);
570
571 while ((fdb_entry = network->static_fdb_entries))
572 fdb_entry_free(fdb_entry);
573
574 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
575 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
576
577 while ((neighbor = network->neighbors))
578 neighbor_free(neighbor);
579
580 while ((label = network->address_labels))
581 address_label_free(label);
582
583 while ((prefix = network->static_prefixes))
584 prefix_free(prefix);
585
586 while ((rule = network->rules))
587 routing_policy_rule_free(rule);
588
589 hashmap_free(network->addresses_by_section);
590 hashmap_free(network->routes_by_section);
591 hashmap_free(network->fdb_entries_by_section);
592 hashmap_free(network->neighbors_by_section);
593 hashmap_free(network->address_labels_by_section);
594 hashmap_free(network->prefixes_by_section);
595 hashmap_free(network->rules_by_section);
596
597 if (network->manager) {
598 if (network->manager->networks && network->name)
599 ordered_hashmap_remove(network->manager->networks, network->name);
600
601 if (network->manager->duids_requesting_uuid)
602 set_remove(network->manager->duids_requesting_uuid, &network->duid);
603 }
604
605 free(network->name);
606
607 free(network->dhcp_server_timezone);
608 free(network->dhcp_server_dns);
609 free(network->dhcp_server_ntp);
610
611 set_free_free(network->dnssec_negative_trust_anchors);
612
613 return mfree(network);
614 }
615
616 DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
617
618 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
619 Network *network;
620
621 assert(manager);
622 assert(name);
623 assert(ret);
624
625 network = ordered_hashmap_get(manager->networks, name);
626 if (!network)
627 return -ENOENT;
628
629 *ret = network;
630
631 return 0;
632 }
633
634 int network_get(Manager *manager, sd_device *device,
635 const char *ifname, const struct ether_addr *address,
636 Network **ret) {
637 Network *network;
638 Iterator i;
639
640 assert(manager);
641 assert(ret);
642
643 ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
644 if (net_match_config(network->match_mac, network->match_path, network->match_driver,
645 network->match_type, network->match_name, network->match_property,
646 device, address, ifname)) {
647 if (network->match_name && device) {
648 const char *attr;
649 uint8_t name_assign_type = NET_NAME_UNKNOWN;
650
651 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
652 (void) safe_atou8(attr, &name_assign_type);
653
654 if (name_assign_type == NET_NAME_ENUM)
655 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
656 ifname, network->filename);
657 else
658 log_debug("%s: found matching network '%s'", ifname, network->filename);
659 } else
660 log_debug("%s: found matching network '%s'", ifname, network->filename);
661
662 *ret = network;
663 return 0;
664 }
665
666 *ret = NULL;
667
668 return -ENOENT;
669 }
670
671 int network_apply(Network *network, Link *link) {
672 assert(network);
673 assert(link);
674
675 link->network = network_ref(network);
676
677 if (network->n_dns > 0 ||
678 !strv_isempty(network->ntp) ||
679 !ordered_set_isempty(network->search_domains) ||
680 !ordered_set_isempty(network->route_domains))
681 link_dirty(link);
682
683 return 0;
684 }
685
686 bool network_has_static_ipv6_configurations(Network *network) {
687 Address *address;
688 Route *route;
689 FdbEntry *fdb;
690 Neighbor *neighbor;
691
692 assert(network);
693
694 LIST_FOREACH(addresses, address, network->static_addresses)
695 if (address->family == AF_INET6)
696 return true;
697
698 LIST_FOREACH(routes, route, network->static_routes)
699 if (route->family == AF_INET6)
700 return true;
701
702 LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
703 if (fdb->family == AF_INET6)
704 return true;
705
706 LIST_FOREACH(neighbors, neighbor, network->neighbors)
707 if (neighbor->family == AF_INET6)
708 return true;
709
710 if (!LIST_IS_EMPTY(network->address_labels))
711 return true;
712
713 if (!LIST_IS_EMPTY(network->static_prefixes))
714 return true;
715
716 return false;
717 }
718
719 int config_parse_stacked_netdev(const char *unit,
720 const char *filename,
721 unsigned line,
722 const char *section,
723 unsigned section_line,
724 const char *lvalue,
725 int ltype,
726 const char *rvalue,
727 void *data,
728 void *userdata) {
729 _cleanup_free_ char *name = NULL;
730 NetDevKind kind = ltype;
731 Hashmap **h = data;
732 int r;
733
734 assert(filename);
735 assert(lvalue);
736 assert(rvalue);
737 assert(data);
738 assert(IN_SET(kind,
739 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
740 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
741 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
742 NETDEV_KIND_XFRM));
743
744 if (!ifname_valid(rvalue)) {
745 log_syntax(unit, LOG_ERR, filename, line, 0,
746 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
747 return 0;
748 }
749
750 name = strdup(rvalue);
751 if (!name)
752 return log_oom();
753
754 r = hashmap_ensure_allocated(h, &string_hash_ops);
755 if (r < 0)
756 return log_oom();
757
758 r = hashmap_put(*h, name, INT_TO_PTR(kind));
759 if (r < 0)
760 log_syntax(unit, LOG_ERR, filename, line, r,
761 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
762 else if (r == 0)
763 log_syntax(unit, LOG_DEBUG, filename, line, r,
764 "NetDev '%s' specified twice, ignoring.", name);
765 else
766 name = NULL;
767
768 return 0;
769 }
770
771 int config_parse_domains(
772 const char *unit,
773 const char *filename,
774 unsigned line,
775 const char *section,
776 unsigned section_line,
777 const char *lvalue,
778 int ltype,
779 const char *rvalue,
780 void *data,
781 void *userdata) {
782
783 const char *p;
784 Network *n = data;
785 int r;
786
787 assert(n);
788 assert(lvalue);
789 assert(rvalue);
790
791 if (isempty(rvalue)) {
792 n->search_domains = ordered_set_free_free(n->search_domains);
793 n->route_domains = ordered_set_free_free(n->route_domains);
794 return 0;
795 }
796
797 p = rvalue;
798 for (;;) {
799 _cleanup_free_ char *w = NULL, *normalized = NULL;
800 const char *domain;
801 bool is_route;
802
803 r = extract_first_word(&p, &w, NULL, 0);
804 if (r < 0) {
805 log_syntax(unit, LOG_ERR, filename, line, r,
806 "Failed to extract search or route domain, ignoring: %s", rvalue);
807 break;
808 }
809 if (r == 0)
810 break;
811
812 is_route = w[0] == '~';
813 domain = is_route ? w + 1 : w;
814
815 if (dns_name_is_root(domain) || streq(domain, "*")) {
816 /* If the root domain appears as is, or the special token "*" is found, we'll
817 * consider this as routing domain, unconditionally. */
818 is_route = true;
819 domain = "."; /* make sure we don't allow empty strings, thus write the root
820 * domain as "." */
821 } else {
822 r = dns_name_normalize(domain, 0, &normalized);
823 if (r < 0) {
824 log_syntax(unit, LOG_ERR, filename, line, r,
825 "'%s' is not a valid domain name, ignoring.", domain);
826 continue;
827 }
828
829 domain = normalized;
830
831 if (is_localhost(domain)) {
832 log_syntax(unit, LOG_ERR, filename, line, 0,
833 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
834 domain);
835 continue;
836 }
837 }
838
839 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
840 r = ordered_set_ensure_allocated(set, &string_hash_ops);
841 if (r < 0)
842 return r;
843
844 r = ordered_set_put_strdup(*set, domain);
845 if (r < 0)
846 return log_oom();
847 }
848
849 return 0;
850 }
851
852 int config_parse_ipv6token(
853 const char* unit,
854 const char *filename,
855 unsigned line,
856 const char *section,
857 unsigned section_line,
858 const char *lvalue,
859 int ltype,
860 const char *rvalue,
861 void *data,
862 void *userdata) {
863
864 union in_addr_union buffer;
865 struct in6_addr *token = data;
866 int r;
867
868 assert(filename);
869 assert(lvalue);
870 assert(rvalue);
871 assert(token);
872
873 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
874 if (r < 0) {
875 log_syntax(unit, LOG_ERR, filename, line, r,
876 "Failed to parse IPv6 token, ignoring: %s", rvalue);
877 return 0;
878 }
879
880 if (in_addr_is_null(AF_INET6, &buffer)) {
881 log_syntax(unit, LOG_ERR, filename, line, 0,
882 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
883 return 0;
884 }
885
886 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
887 log_syntax(unit, LOG_ERR, filename, line, 0,
888 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
889 return 0;
890 }
891
892 *token = buffer.in6;
893
894 return 0;
895 }
896
897 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
898 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
899 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
900 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
901 };
902
903 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
904 IPV6_PRIVACY_EXTENSIONS_YES);
905
906 int config_parse_ipv6_privacy_extensions(
907 const char* unit,
908 const char *filename,
909 unsigned line,
910 const char *section,
911 unsigned section_line,
912 const char *lvalue,
913 int ltype,
914 const char *rvalue,
915 void *data,
916 void *userdata) {
917
918 IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
919
920 assert(filename);
921 assert(lvalue);
922 assert(rvalue);
923 assert(ipv6_privacy_extensions);
924
925 s = ipv6_privacy_extensions_from_string(rvalue);
926 if (s < 0) {
927 if (streq(rvalue, "kernel"))
928 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
929 else {
930 log_syntax(unit, LOG_ERR, filename, line, 0,
931 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
932 return 0;
933 }
934 }
935
936 *ipv6_privacy_extensions = s;
937
938 return 0;
939 }
940
941 int config_parse_hostname(
942 const char *unit,
943 const char *filename,
944 unsigned line,
945 const char *section,
946 unsigned section_line,
947 const char *lvalue,
948 int ltype,
949 const char *rvalue,
950 void *data,
951 void *userdata) {
952
953 _cleanup_free_ char *hn = NULL;
954 char **hostname = data;
955 int r;
956
957 assert(filename);
958 assert(lvalue);
959 assert(rvalue);
960
961 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
962 if (r < 0)
963 return r;
964
965 if (!hostname_is_valid(hn, false)) {
966 log_syntax(unit, LOG_ERR, filename, line, 0,
967 "Hostname is not valid, ignoring assignment: %s", rvalue);
968 return 0;
969 }
970
971 r = dns_name_is_valid(hn);
972 if (r < 0) {
973 log_syntax(unit, LOG_ERR, filename, line, r,
974 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
975 return 0;
976 }
977 if (r == 0) {
978 log_syntax(unit, LOG_ERR, filename, line, 0,
979 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
980 return 0;
981 }
982
983 return free_and_replace(*hostname, hn);
984 }
985
986 int config_parse_timezone(
987 const char *unit,
988 const char *filename,
989 unsigned line,
990 const char *section,
991 unsigned section_line,
992 const char *lvalue,
993 int ltype,
994 const char *rvalue,
995 void *data,
996 void *userdata) {
997
998 _cleanup_free_ char *tz = NULL;
999 char **datap = data;
1000 int r;
1001
1002 assert(filename);
1003 assert(lvalue);
1004 assert(rvalue);
1005
1006 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1007 if (r < 0)
1008 return r;
1009
1010 if (!timezone_is_valid(tz, LOG_ERR)) {
1011 log_syntax(unit, LOG_ERR, filename, line, 0,
1012 "Timezone is not valid, ignoring assignment: %s", rvalue);
1013 return 0;
1014 }
1015
1016 return free_and_replace(*datap, tz);
1017 }
1018
1019 int config_parse_dns(
1020 const char *unit,
1021 const char *filename,
1022 unsigned line,
1023 const char *section,
1024 unsigned section_line,
1025 const char *lvalue,
1026 int ltype,
1027 const char *rvalue,
1028 void *data,
1029 void *userdata) {
1030
1031 Network *n = userdata;
1032 int r;
1033
1034 assert(filename);
1035 assert(lvalue);
1036 assert(rvalue);
1037
1038 for (;;) {
1039 _cleanup_free_ char *w = NULL;
1040 union in_addr_union a;
1041 struct in_addr_data *m;
1042 int family;
1043
1044 r = extract_first_word(&rvalue, &w, NULL, 0);
1045 if (r == -ENOMEM)
1046 return log_oom();
1047 if (r < 0) {
1048 log_syntax(unit, LOG_ERR, filename, line, r,
1049 "Invalid syntax, ignoring: %s", rvalue);
1050 break;
1051 }
1052 if (r == 0)
1053 break;
1054
1055 r = in_addr_from_string_auto(w, &family, &a);
1056 if (r < 0) {
1057 log_syntax(unit, LOG_ERR, filename, line, r,
1058 "Failed to parse dns server address, ignoring: %s", w);
1059 continue;
1060 }
1061
1062 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
1063 if (!m)
1064 return log_oom();
1065
1066 m[n->n_dns++] = (struct in_addr_data) {
1067 .family = family,
1068 .address = a,
1069 };
1070
1071 n->dns = m;
1072 }
1073
1074 return 0;
1075 }
1076
1077 int config_parse_dnssec_negative_trust_anchors(
1078 const char *unit,
1079 const char *filename,
1080 unsigned line,
1081 const char *section,
1082 unsigned section_line,
1083 const char *lvalue,
1084 int ltype,
1085 const char *rvalue,
1086 void *data,
1087 void *userdata) {
1088
1089 const char *p = rvalue;
1090 Network *n = data;
1091 int r;
1092
1093 assert(n);
1094 assert(lvalue);
1095 assert(rvalue);
1096
1097 if (isempty(rvalue)) {
1098 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1099 return 0;
1100 }
1101
1102 for (;;) {
1103 _cleanup_free_ char *w = NULL;
1104
1105 r = extract_first_word(&p, &w, NULL, 0);
1106 if (r < 0) {
1107 log_syntax(unit, LOG_ERR, filename, line, r,
1108 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1109 break;
1110 }
1111 if (r == 0)
1112 break;
1113
1114 r = dns_name_is_valid(w);
1115 if (r <= 0) {
1116 log_syntax(unit, LOG_ERR, filename, line, r,
1117 "%s is not a valid domain name, ignoring.", w);
1118 continue;
1119 }
1120
1121 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1122 if (r < 0)
1123 return log_oom();
1124
1125 r = set_put(n->dnssec_negative_trust_anchors, w);
1126 if (r < 0)
1127 return log_oom();
1128 if (r > 0)
1129 w = NULL;
1130 }
1131
1132 return 0;
1133 }
1134
1135 int config_parse_ntp(
1136 const char *unit,
1137 const char *filename,
1138 unsigned line,
1139 const char *section,
1140 unsigned section_line,
1141 const char *lvalue,
1142 int ltype,
1143 const char *rvalue,
1144 void *data,
1145 void *userdata) {
1146
1147 char ***l = data;
1148 int r;
1149
1150 assert(l);
1151 assert(lvalue);
1152 assert(rvalue);
1153
1154 if (isempty(rvalue)) {
1155 *l = strv_free(*l);
1156 return 0;
1157 }
1158
1159 for (;;) {
1160 _cleanup_free_ char *w = NULL;
1161
1162 r = extract_first_word(&rvalue, &w, NULL, 0);
1163 if (r == -ENOMEM)
1164 return log_oom();
1165 if (r < 0) {
1166 log_syntax(unit, LOG_ERR, filename, line, r,
1167 "Failed to extract NTP server name, ignoring: %s", rvalue);
1168 break;
1169 }
1170 if (r == 0)
1171 break;
1172
1173 r = dns_name_is_valid_or_address(w);
1174 if (r <= 0) {
1175 log_syntax(unit, LOG_ERR, filename, line, r,
1176 "%s is not a valid domain name or IP address, ignoring.", w);
1177 continue;
1178 }
1179
1180 if (strv_length(*l) > MAX_NTP_SERVERS) {
1181 log_syntax(unit, LOG_WARNING, filename, line, 0,
1182 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1183 MAX_NTP_SERVERS, w);
1184 break;
1185 }
1186
1187 r = strv_consume(l, TAKE_PTR(w));
1188 if (r < 0)
1189 return log_oom();
1190 }
1191
1192 return 0;
1193 }
1194
1195 int config_parse_required_for_online(
1196 const char *unit,
1197 const char *filename,
1198 unsigned line,
1199 const char *section,
1200 unsigned section_line,
1201 const char *lvalue,
1202 int ltype,
1203 const char *rvalue,
1204 void *data,
1205 void *userdata) {
1206
1207 Network *network = data;
1208 LinkOperationalState s;
1209 bool required = true;
1210 int r;
1211
1212 if (isempty(rvalue)) {
1213 network->required_for_online = true;
1214 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1215 return 0;
1216 }
1217
1218 s = link_operstate_from_string(rvalue);
1219 if (s < 0) {
1220 r = parse_boolean(rvalue);
1221 if (r < 0) {
1222 log_syntax(unit, LOG_ERR, filename, line, r,
1223 "Failed to parse %s= setting, ignoring assignment: %s",
1224 lvalue, rvalue);
1225 return 0;
1226 }
1227
1228 required = r;
1229 s = LINK_OPERSTATE_DEGRADED;
1230 }
1231
1232 network->required_for_online = required;
1233 network->required_operstate_for_online = s;
1234
1235 return 0;
1236 }
1237
1238 DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1239 "Failed to parse KeepConfiguration= setting");
1240
1241 static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1242 [KEEP_CONFIGURATION_NO] = "no",
1243 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1244 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1245 [KEEP_CONFIGURATION_STATIC] = "static",
1246 [KEEP_CONFIGURATION_YES] = "yes",
1247 };
1248
1249 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);