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