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