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