]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: rename Neighbor.MACAddress= to Neighbor.LinkLayerAddress=
[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
caa8ca42
SS
364 .dhcp6_use_ntp = true,
365 .dhcp6_use_dns = true,
366
17f9c355
YW
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,
7f15b714 380 .multicast_flood = -1,
d3aa8b49 381 .multicast_to_unicast = -1,
7f15b714
TJ
382 .neighbor_suppression = -1,
383 .learning = -1,
1087623b
SS
384 .bridge_proxy_arp = -1,
385 .bridge_proxy_arp_wifi = -1,
17f9c355 386 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 387 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355
YW
388
389 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
390
7ece6f58 391 .dns_default_route = -1,
17f9c355
YW
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
0321cea7
YW
397 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
398 .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID,
17f9c355
YW
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,
062c2eea
SS
411 .ipv6_accept_ra_use_autonomous_prefix = true,
412 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 413 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 414 .ipv6_accept_ra_route_table_set = false,
c423be28 415
7da377ef
SS
416 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
417
c423be28 418 .can_triple_sampling = -1,
17f9c355 419 };
f579559b 420
dc0d4078 421 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
23bb31aa
ZJS
422 "Match\0"
423 "Link\0"
424 "Network\0"
425 "Address\0"
e4a71bf3 426 "Neighbor\0"
95b74ef6 427 "IPv6AddressLabel\0"
bce67bbe 428 "RoutingPolicyRule\0"
23bb31aa
ZJS
429 "Route\0"
430 "DHCP\0"
431 "DHCPv4\0" /* compat */
caa8ca42 432 "DHCPv6\0"
23bb31aa
ZJS
433 "DHCPServer\0"
434 "IPv6AcceptRA\0"
a0e5c15d 435 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
436 "Bridge\0"
437 "BridgeFDB\0"
9d5d0090 438 "BridgeVLAN\0"
7d5cac19 439 "IPv6PrefixDelegation\0"
06828bb6
HP
440 "IPv6Prefix\0"
441 "CAN\0",
23bb31aa 442 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 443 CONFIG_PARSE_WARN, network);
102bc043 444 if (r < 0)
f579559b 445 return r;
f579559b 446
add8d07d 447 network_apply_anonymize_if_set(network);
448
fa7cd711
YW
449 r = network_add_ipv4ll_route(network);
450 if (r < 0)
451 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
452
5d5003ab
YW
453 r = network_add_default_route_on_device(network);
454 if (r < 0)
455 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
456 network->filename);
457
715d398e 458 r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
dbffab87
TG
459 if (r < 0)
460 return r;
461
715d398e 462 r = ordered_hashmap_put(manager->networks, network->name, network);
dbffab87
TG
463 if (r < 0)
464 return r;
465
0321cea7
YW
466 if (network_verify(network) < 0)
467 return 0;
b3070dc0 468
f579559b 469 network = NULL;
f579559b
TG
470 return 0;
471}
472
473int network_load(Manager *manager) {
477e73b5
ZJS
474 _cleanup_strv_free_ char **files = NULL;
475 char **f;
f579559b
TG
476 int r;
477
478 assert(manager);
479
715d398e 480 ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
f579559b 481
dc0d4078 482 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
483 if (r < 0)
484 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 485
715d398e 486 STRV_FOREACH(f, files) {
f579559b
TG
487 r = network_load_one(manager, *f);
488 if (r < 0)
489 return r;
490 }
491
f579559b
TG
492 return 0;
493}
494
35ac3b76 495static Network *network_free(Network *network) {
a0e5c15d 496 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
497 RoutingPolicyRule *rule;
498 FdbEntry *fdb_entry;
e4a71bf3 499 Neighbor *neighbor;
95b74ef6 500 AddressLabel *label;
057abfd8 501 Prefix *prefix;
bce67bbe 502 Address *address;
bce67bbe 503 Route *route;
f579559b
TG
504
505 if (!network)
35ac3b76 506 return NULL;
f579559b
TG
507
508 free(network->filename);
509
e90d0374 510 set_free_free(network->match_mac);
5256e00e
TG
511 strv_free(network->match_path);
512 strv_free(network->match_driver);
513 strv_free(network->match_type);
514 strv_free(network->match_name);
44005bfb 515 strv_free(network->match_property);
c4f58dea 516 condition_free_list(network->conditions);
f579559b
TG
517
518 free(network->description);
edb85f0d 519 free(network->dhcp_vendor_class_identifier);
af1c0de0 520 strv_free(network->dhcp_user_class);
27cb34f5 521 free(network->dhcp_hostname);
727b5734 522 set_free(network->dhcp_black_listed_ip);
c106cc36
TG
523 free(network->mac);
524
b0e39c82 525 strv_free(network->ntp);
5512a963 526 free(network->dns);
5e2a51d5
ZJS
527 ordered_set_free_free(network->search_domains);
528 ordered_set_free_free(network->route_domains);
0d4ad91d 529 strv_free(network->bind_carrier);
cdd7812b 530
5e2a51d5 531 ordered_set_free_free(network->router_search_domains);
cdd7812b 532 free(network->router_dns);
e520ce64 533 set_free_free(network->ndisc_black_listed_prefix);
3bef724f 534
cebe1257
YW
535 free(network->bridge_name);
536 free(network->bond_name);
537 free(network->vrf_name);
538 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 539 netdev_unref(network->bridge);
47e2dc31 540 netdev_unref(network->bond);
6cb955c6 541 netdev_unref(network->vrf);
fa6f1e54 542 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 543
f048a16b 544 while ((route = network->static_routes))
f579559b
TG
545 route_free(route);
546
f048a16b 547 while ((address = network->static_addresses))
f579559b
TG
548 address_free(address);
549
b98b483b
AR
550 while ((fdb_entry = network->static_fdb_entries))
551 fdb_entry_free(fdb_entry);
552
a0e5c15d
FK
553 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
554 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
555
e4a71bf3
WKI
556 while ((neighbor = network->neighbors))
557 neighbor_free(neighbor);
558
95b74ef6
SS
559 while ((label = network->address_labels))
560 address_label_free(label);
561
057abfd8
PF
562 while ((prefix = network->static_prefixes))
563 prefix_free(prefix);
564
bce67bbe
SS
565 while ((rule = network->rules))
566 routing_policy_rule_free(rule);
567
6ae115c1
TG
568 hashmap_free(network->addresses_by_section);
569 hashmap_free(network->routes_by_section);
b98b483b 570 hashmap_free(network->fdb_entries_by_section);
e4a71bf3 571 hashmap_free(network->neighbors_by_section);
95b74ef6 572 hashmap_free(network->address_labels_by_section);
057abfd8 573 hashmap_free(network->prefixes_by_section);
bce67bbe 574 hashmap_free(network->rules_by_section);
6ae115c1 575
dbffab87 576 if (network->manager) {
715d398e
YW
577 if (network->manager->networks && network->name)
578 ordered_hashmap_remove(network->manager->networks, network->name);
27dfc982
YW
579
580 if (network->manager->duids_requesting_uuid)
581 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
582 }
583
584 free(network->name);
f579559b 585
8eb9058d 586 free(network->dhcp_server_timezone);
1a04db0f
LP
587 free(network->dhcp_server_dns);
588 free(network->dhcp_server_ntp);
8eb9058d 589
8a516214
LP
590 set_free_free(network->dnssec_negative_trust_anchors);
591
35ac3b76 592 return mfree(network);
f579559b
TG
593}
594
35ac3b76
YW
595DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
596
dbffab87
TG
597int network_get_by_name(Manager *manager, const char *name, Network **ret) {
598 Network *network;
599
600 assert(manager);
601 assert(name);
602 assert(ret);
603
715d398e 604 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
605 if (!network)
606 return -ENOENT;
607
608 *ret = network;
609
610 return 0;
611}
612
51517f9e 613int network_get(Manager *manager, sd_device *device,
505f8da7
TG
614 const char *ifname, const struct ether_addr *address,
615 Network **ret) {
51517f9e 616 Network *network;
715d398e 617 Iterator i;
f579559b
TG
618
619 assert(manager);
f579559b 620 assert(ret);
af3aa302 621
715d398e 622 ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
44005bfb
YW
623 if (net_match_config(network->match_mac, network->match_path, network->match_driver,
624 network->match_type, network->match_name, network->match_property,
b38de0e9 625 device, address, ifname)) {
24c083df 626 if (network->match_name && device) {
ca6038b8
TG
627 const char *attr;
628 uint8_t name_assign_type = NET_NAME_UNKNOWN;
629
51517f9e 630 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 631 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
632
633 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
634 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
635 ifname, network->filename);
32bc8adc 636 else
a2fae7bb 637 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 638 } else
a2fae7bb 639 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 640
f579559b
TG
641 *ret = network;
642 return 0;
643 }
f579559b
TG
644
645 *ret = NULL;
646
647 return -ENOENT;
648}
649
7d342c03 650int network_apply(Network *network, Link *link) {
c4a03a56
TG
651 assert(network);
652 assert(link);
653
c9c908a6 654 link->network = network_ref(network);
f579559b 655
5512a963 656 if (network->n_dns > 0 ||
3df9bec5 657 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
658 !ordered_set_isempty(network->search_domains) ||
659 !ordered_set_isempty(network->route_domains))
84de38c5 660 link_dirty(link);
3bef724f 661
f579559b
TG
662 return 0;
663}
02b59d57 664
439689c6
SS
665bool network_has_static_ipv6_addresses(Network *network) {
666 Address *address;
667
668 assert(network);
669
670 LIST_FOREACH(addresses, address, network->static_addresses) {
671 if (address->family == AF_INET6)
672 return true;
673 }
674
675 return false;
676}
677
cebe1257 678int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
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) {
95dba435
YW
688 _cleanup_free_ char *name = NULL;
689 NetDevKind kind = ltype;
cebe1257 690 Hashmap **h = data;
02b59d57
TG
691 int r;
692
693 assert(filename);
694 assert(lvalue);
695 assert(rvalue);
696 assert(data);
95dba435
YW
697 assert(IN_SET(kind,
698 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 699 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 700 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
701 NETDEV_KIND_XFRM));
54abf461 702
cebe1257 703 if (!ifname_valid(rvalue)) {
3772cfde
ZJS
704 log_syntax(unit, LOG_ERR, filename, line, 0,
705 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
706 return 0;
707 }
708
cebe1257
YW
709 name = strdup(rvalue);
710 if (!name)
711 return log_oom();
3e570042 712
cebe1257
YW
713 r = hashmap_ensure_allocated(h, &string_hash_ops);
714 if (r < 0)
715 return log_oom();
326cb406 716
cebe1257 717 r = hashmap_put(*h, name, INT_TO_PTR(kind));
83ec4592 718 if (r < 0)
3772cfde 719 log_syntax(unit, LOG_ERR, filename, line, r,
83ec4592
ZJS
720 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
721 else if (r == 0)
722 log_syntax(unit, LOG_DEBUG, filename, line, r,
723 "NetDev '%s' specified twice, ignoring.", name);
724 else
725 name = NULL;
47e2dc31 726
fe6b2d55
TG
727 return 0;
728}
7951dea2 729
3df9bec5
LP
730int 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 Network *n = data;
6192b846
TG
744 int r;
745
3df9bec5
LP
746 assert(n);
747 assert(lvalue);
748 assert(rvalue);
6192b846 749
3df9bec5 750 if (isempty(rvalue)) {
5e2a51d5
ZJS
751 n->search_domains = ordered_set_free_free(n->search_domains);
752 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
753 return 0;
754 }
67272d15 755
3df9bec5
LP
756 p = rvalue;
757 for (;;) {
758 _cleanup_free_ char *w = NULL, *normalized = NULL;
759 const char *domain;
760 bool is_route;
761
762 r = extract_first_word(&p, &w, NULL, 0);
763 if (r < 0) {
ab24039f
ZJS
764 log_syntax(unit, LOG_ERR, filename, line, r,
765 "Failed to extract search or route domain, ignoring: %s", rvalue);
3df9bec5
LP
766 break;
767 }
768 if (r == 0)
769 break;
770
771 is_route = w[0] == '~';
772 domain = is_route ? w + 1 : w;
773
774 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
775 /* If the root domain appears as is, or the special token "*" is found, we'll
776 * consider this as routing domain, unconditionally. */
3df9bec5 777 is_route = true;
ab24039f
ZJS
778 domain = "."; /* make sure we don't allow empty strings, thus write the root
779 * domain as "." */
3df9bec5 780 } else {
7470cc4c 781 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 782 if (r < 0) {
ab24039f
ZJS
783 log_syntax(unit, LOG_ERR, filename, line, r,
784 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
785 continue;
786 }
787
788 domain = normalized;
789
790 if (is_localhost(domain)) {
ab24039f
ZJS
791 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);
37de2509 794 continue;
3df9bec5 795 }
37de2509 796 }
40274ed6 797
5e2a51d5
ZJS
798 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
799 r = ordered_set_ensure_allocated(set, &string_hash_ops);
800 if (r < 0)
801 return r;
802
803 r = ordered_set_put_strdup(*set, domain);
09451975
LP
804 if (r < 0)
805 return log_oom();
40274ed6 806 }
f15b6e5a 807
6192b846
TG
808 return 0;
809}
810
60c35566 811int config_parse_ipv6token(
7f77697a
TG
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 struct in6_addr *token = data;
825 int r;
826
827 assert(filename);
828 assert(lvalue);
829 assert(rvalue);
830 assert(token);
831
832 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
833 if (r < 0) {
ab24039f
ZJS
834 log_syntax(unit, LOG_ERR, filename, line, r,
835 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
836 return 0;
837 }
838
c606db69 839 if (in_addr_is_null(AF_INET6, &buffer)) {
ab24039f
ZJS
840 log_syntax(unit, LOG_ERR, filename, line, 0,
841 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
842 return 0;
843 }
844
845 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
ab24039f
ZJS
846 log_syntax(unit, LOG_ERR, filename, line, 0,
847 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
848 return 0;
849 }
850
851 *token = buffer.in6;
852
853 return 0;
854}
8add5f79 855
49092e22 856static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
857 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
858 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
859 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
860};
861
862DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
863
864int 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 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
877 int k;
878
879 assert(filename);
880 assert(lvalue);
881 assert(rvalue);
882 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 k = parse_boolean(rvalue);
888 if (k > 0)
1f0d9695 889 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 890 else if (k == 0)
1f0d9695 891 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 892 else {
1f0d9695 893 IPv6PrivacyExtensions s;
49092e22
SS
894
895 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
896 if (s < 0) {
897
898 if (streq(rvalue, "kernel"))
899 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
900 else {
ab24039f
ZJS
901 log_syntax(unit, LOG_ERR, filename, line, 0,
902 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1f0d9695
LP
903 return 0;
904 }
49092e22
SS
905 }
906
907 *ipv6_privacy_extensions = s;
908 }
909
910 return 0;
911}
a7d0ef44 912
1ac608c9
LP
913int 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
6528693a
YW
925 _cleanup_free_ char *hn = NULL;
926 char **hostname = data;
a7d0ef44
SS
927 int r;
928
929 assert(filename);
930 assert(lvalue);
931 assert(rvalue);
932
1ac608c9 933 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
934 if (r < 0)
935 return r;
936
1ac608c9 937 if (!hostname_is_valid(hn, false)) {
ab24039f
ZJS
938 log_syntax(unit, LOG_ERR, filename, line, 0,
939 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
940 return 0;
941 }
942
6528693a
YW
943 r = dns_name_is_valid(hn);
944 if (r < 0) {
ab24039f
ZJS
945 log_syntax(unit, LOG_ERR, filename, line, r,
946 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
947 return 0;
948 }
949 if (r == 0) {
ab24039f
ZJS
950 log_syntax(unit, LOG_ERR, filename, line, 0,
951 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
952 return 0;
953 }
954
955 return free_and_replace(*hostname, hn);
a7d0ef44 956}
8eb9058d
LP
957
958int 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
19f9e4e2
YW
970 _cleanup_free_ char *tz = NULL;
971 char **datap = data;
8eb9058d
LP
972 int r;
973
974 assert(filename);
975 assert(lvalue);
976 assert(rvalue);
977
978 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
979 if (r < 0)
980 return r;
981
089fb865 982 if (!timezone_is_valid(tz, LOG_ERR)) {
ab24039f
ZJS
983 log_syntax(unit, LOG_ERR, filename, line, 0,
984 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
985 return 0;
986 }
987
19f9e4e2 988 return free_and_replace(*datap, tz);
8eb9058d 989}
1a04db0f 990
53253824
SS
991int 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 Network *n = userdata;
1004 int r;
1005
1006 assert(filename);
1007 assert(lvalue);
1008 assert(rvalue);
1009
1010 for (;;) {
1011 _cleanup_free_ char *w = NULL;
1012 union in_addr_union a;
5512a963 1013 struct in_addr_data *m;
53253824
SS
1014 int family;
1015
5512a963 1016 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1017 if (r == -ENOMEM)
1018 return log_oom();
1019 if (r < 0) {
ab24039f
ZJS
1020 log_syntax(unit, LOG_ERR, filename, line, r,
1021 "Invalid syntax, ignoring: %s", rvalue);
53253824
SS
1022 break;
1023 }
5512a963
LP
1024 if (r == 0)
1025 break;
53253824
SS
1026
1027 r = in_addr_from_string_auto(w, &family, &a);
1028 if (r < 0) {
ab24039f
ZJS
1029 log_syntax(unit, LOG_ERR, filename, line, r,
1030 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1031 continue;
1032 }
1033
62d74c78 1034 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1035 if (!m)
53253824
SS
1036 return log_oom();
1037
5512a963
LP
1038 m[n->n_dns++] = (struct in_addr_data) {
1039 .family = family,
1040 .address = a,
1041 };
1042
1043 n->dns = m;
53253824
SS
1044 }
1045
1046 return 0;
1047}
1048
8a516214
LP
1049int 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 const char *p = rvalue;
1062 Network *n = data;
1063 int r;
1064
3df9bec5 1065 assert(n);
8a516214
LP
1066 assert(lvalue);
1067 assert(rvalue);
1068
1069 if (isempty(rvalue)) {
1070 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1071 return 0;
1072 }
1073
1074 for (;;) {
1075 _cleanup_free_ char *w = NULL;
1076
1077 r = extract_first_word(&p, &w, NULL, 0);
1078 if (r < 0) {
ab24039f
ZJS
1079 log_syntax(unit, LOG_ERR, filename, line, r,
1080 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
8a516214
LP
1081 break;
1082 }
1083 if (r == 0)
1084 break;
1085
1086 r = dns_name_is_valid(w);
1087 if (r <= 0) {
ab24039f
ZJS
1088 log_syntax(unit, LOG_ERR, filename, line, r,
1089 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1090 continue;
1091 }
1092
cbbf38ae
LP
1093 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1094 if (r < 0)
1095 return log_oom();
1096
8a516214
LP
1097 r = set_put(n->dnssec_negative_trust_anchors, w);
1098 if (r < 0)
1099 return log_oom();
1100 if (r > 0)
1101 w = NULL;
1102 }
1103
1104 return 0;
1105}
b2a81c0b 1106
26575990
LP
1107int 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 char ***l = data;
1120 int r;
1121
1122 assert(l);
1123 assert(lvalue);
1124 assert(rvalue);
1125
1126 if (isempty(rvalue)) {
1127 *l = strv_free(*l);
1128 return 0;
1129 }
1130
1131 for (;;) {
1132 _cleanup_free_ char *w = NULL;
1133
1134 r = extract_first_word(&rvalue, &w, NULL, 0);
1135 if (r == -ENOMEM)
1136 return log_oom();
1137 if (r < 0) {
ab24039f
ZJS
1138 log_syntax(unit, LOG_ERR, filename, line, r,
1139 "Failed to extract NTP server name, ignoring: %s", rvalue);
26575990
LP
1140 break;
1141 }
1142 if (r == 0)
1143 break;
1144
1145 r = dns_name_is_valid_or_address(w);
1146 if (r <= 0) {
ab24039f
ZJS
1147 log_syntax(unit, LOG_ERR, filename, line, r,
1148 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1149 continue;
af1c0de0
SS
1150 }
1151
c448459d
ZJS
1152 if (strv_length(*l) > MAX_NTP_SERVERS) {
1153 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 break;
1157 }
1158
1159 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1160 if (r < 0)
1161 return log_oom();
af1c0de0
SS
1162 }
1163
1164 return 0;
1165}
1166
4ac77d63
YW
1167int 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 Network *network = data;
1180 LinkOperationalState s;
1181 bool required = true;
1182 int r;
1183
1184 if (isempty(rvalue)) {
1185 network->required_for_online = true;
1186 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1187 return 0;
1188 }
1189
1190 s = link_operstate_from_string(rvalue);
1191 if (s < 0) {
1192 r = parse_boolean(rvalue);
1193 if (r < 0) {
1194 log_syntax(unit, LOG_ERR, filename, line, r,
1195 "Failed to parse %s= setting, ignoring assignment: %s",
1196 lvalue, rvalue);
1197 return 0;
1198 }
1199
1200 required = r;
1201 s = LINK_OPERSTATE_DEGRADED;
1202 }
1203
1204 network->required_for_online = required;
1205 network->required_operstate_for_online = s;
1206
1207 return 0;
1208}
7da377ef
SS
1209
1210DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1211 "Failed to parse KeepConfiguration= setting");
1212
1213static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
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",
7da377ef
SS
1219};
1220
1221DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);