]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: drop unused nexthop_remove() and nexthop_equal()
[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>
a0b191b7 6#include <unistd.h>
69a93e7d 7
b5efdb8a 8#include "alloc-util.h"
f579559b
TG
9#include "conf-files.h"
10#include "conf-parser.h"
37de2509 11#include "dns-domain.h"
3ffd4af2 12#include "fd-util.h"
07630cea 13#include "hostname-util.h"
88295a05 14#include "in-addr-util.h"
564ca984 15#include "networkd-dhcp-server.h"
fc2f9534 16#include "network-internal.h"
23f53b99 17#include "networkd-manager.h"
3ffd4af2 18#include "networkd-network.h"
ca183bf8 19#include "networkd-routing-policy-rule.h"
518cd6b5 20#include "networkd-sriov.h"
6bedfcbb 21#include "parse-util.h"
b0c82192 22#include "path-lookup.h"
8a516214 23#include "set.h"
cebe1257 24#include "socket-util.h"
8fcde012 25#include "stat-util.h"
8b43440b 26#include "string-table.h"
07630cea 27#include "string-util.h"
700f1186 28#include "strv.h"
34658df2 29#include "tc.h"
07630cea 30#include "util.h"
f579559b 31
c448459d
ZJS
32/* Let's assume that anything above this number is a user misconfiguration. */
33#define MAX_NTP_SERVERS 128
34
add8d07d 35/* Set defaults following RFC7844 */
36void network_apply_anonymize_if_set(Network *network) {
37 if (!network->dhcp_anonymize)
38 return;
39 /* RFC7844 3.7
40 SHOULD NOT send the Host Name option */
41 network->dhcp_send_hostname = false;
42 /* RFC7844 section 3.:
43 MAY contain the Client Identifier option
44 Section 3.5:
45 clients MUST use client identifiers based solely
46 on the link-layer address */
47 /* NOTE: Using MAC, as it does not reveal extra information,
48 * and some servers might not answer if this option is not sent */
49 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
50 /* RFC 7844 3.10:
51 SHOULD NOT use the Vendor Class Identifier option */
727ba17f 52 network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
add8d07d 53 /* RFC7844 section 3.6.:
54 The client intending to protect its privacy SHOULD only request a
55 minimal number of options in the PRL and SHOULD also randomly shuffle
43bf2874 56 the ordering of option codes in the PRL. If this random ordering
add8d07d 57 cannot be implemented, the client MAY order the option codes in the
58 PRL by option code number (lowest to highest).
59 */
60 /* NOTE: dhcp_use_mtu is false by default,
61 * though it was not initiallized to any value in network_load_one.
62 * Maybe there should be another var called *send*?
63 * (to use the MTU sent by the server but to do not send
64 * the option in the PRL). */
65 network->dhcp_use_mtu = false;
28522b0d 66 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
67 * but this is needed to use them. */
68 network->dhcp_use_routes = true;
add8d07d 69 /* RFC7844 section 3.6.
70 * same comments as previous option */
71 network->dhcp_use_timezone = false;
72}
73
cebe1257
YW
74static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) {
75 const char *kind_string;
76 NetDev *netdev;
77 int r;
78
96db6412
YW
79 /* For test-networkd-conf, the check must be earlier than the assertions. */
80 if (!name)
81 return 0;
82
cebe1257
YW
83 assert(network);
84 assert(network->manager);
85 assert(network->filename);
86 assert(ret_netdev);
87
cebe1257
YW
88 if (kind == _NETDEV_KIND_TUNNEL)
89 kind_string = "tunnel";
90 else {
91 kind_string = netdev_kind_to_string(kind);
92 if (!kind_string)
93 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
94 "%s: Invalid NetDev kind of %s, ignoring assignment.",
95 network->filename, name);
96 }
97
98 r = netdev_get(network->manager, name, &netdev);
99 if (r < 0)
100 return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
101 network->filename, name);
102
103 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
104 IN_SET(netdev->kind,
105 NETDEV_KIND_IPIP,
106 NETDEV_KIND_SIT,
107 NETDEV_KIND_GRE,
108 NETDEV_KIND_GRETAP,
109 NETDEV_KIND_IP6GRE,
110 NETDEV_KIND_IP6GRETAP,
111 NETDEV_KIND_VTI,
112 NETDEV_KIND_VTI6,
9282f75b
YW
113 NETDEV_KIND_IP6TNL,
114 NETDEV_KIND_ERSPAN)))
cebe1257
YW
115 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
116 "%s: NetDev %s is not a %s, ignoring assignment",
117 network->filename, name, kind_string);
118
119 *ret_netdev = netdev_ref(netdev);
120 return 1;
121}
122
123static int network_resolve_stacked_netdevs(Network *network) {
124 void *name, *kind;
cebe1257
YW
125 int r;
126
127 assert(network);
128
90e74a66 129 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names) {
cebe1257
YW
130 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
131
132 r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev);
133 if (r <= 0)
134 continue;
135
136 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
137 if (r < 0)
138 return log_oom();
139
140 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
141 if (r < 0)
142 return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m",
143 network->filename, (const char *) name);
144
145 netdev = NULL;
146 }
147
148 return 0;
149}
150
96db6412 151int network_verify(Network *network) {
95081e08 152 RoutePrefix *route_prefix, *route_prefix_next;
fcbf4cb7
YW
153 Neighbor *neighbor, *neighbor_next;
154 AddressLabel *label, *label_next;
c16c7808 155 NextHop *nexthop, *nextnop_next;
564ca984
SS
156 Address *address, *address_next;
157 Prefix *prefix, *prefix_next;
158 Route *route, *route_next;
159 FdbEntry *fdb, *fdb_next;
3db468ea 160 MdbEntry *mdb, *mdb_next;
34658df2 161 TrafficControl *tc;
518cd6b5 162 SRIOV *sr_iov;
0321cea7
YW
163
164 assert(network);
165 assert(network->filename);
166
4bb7cc82
YW
167 if (set_isempty(network->match_mac) && set_isempty(network->match_permanent_mac) &&
168 strv_isempty(network->match_path) && strv_isempty(network->match_driver) &&
169 strv_isempty(network->match_type) && strv_isempty(network->match_name) &&
25c86e4c
DDM
170 strv_isempty(network->match_property) && strv_isempty(network->match_wlan_iftype) &&
171 strv_isempty(network->match_ssid) && !network->conditions)
dade7349
ZJS
172 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
173 "%s: No valid settings found in the [Match] section, ignoring file. "
174 "To match all interfaces, add Name=* in the [Match] section.",
175 network->filename);
84ea567e 176
cebe1257 177 /* skip out early if configuration does not match the environment */
a0b191b7 178 if (!condition_test_list(network->conditions, environ, NULL, NULL, NULL))
cebe1257 179 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
3772cfde
ZJS
180 "%s: Conditions in the file do not match the system environment, skipping.",
181 network->filename);
cebe1257
YW
182
183 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
184 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
185 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
186 (void) network_resolve_stacked_netdevs(network);
187
188 /* Free unnecessary entries. */
189 network->bond_name = mfree(network->bond_name);
190 network->bridge_name = mfree(network->bridge_name);
191 network->vrf_name = mfree(network->vrf_name);
192 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
193
0321cea7
YW
194 if (network->bond) {
195 /* Bonding slave does not support addressing. */
196 if (network->ipv6_accept_ra > 0) {
ab24039f
ZJS
197 log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
198 network->filename);
0321cea7
YW
199 network->ipv6_accept_ra = 0;
200 }
201 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
202 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
203 network->filename);
0321cea7
YW
204 network->link_local = ADDRESS_FAMILY_NO;
205 }
206 if (network->dhcp != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
207 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
208 network->filename);
0321cea7
YW
209 network->dhcp = ADDRESS_FAMILY_NO;
210 }
211 if (network->dhcp_server) {
ab24039f
ZJS
212 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
213 network->filename);
0321cea7
YW
214 network->dhcp_server = false;
215 }
216 if (network->n_static_addresses > 0) {
ab24039f
ZJS
217 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
218 network->filename);
0321cea7
YW
219 while ((address = network->static_addresses))
220 address_free(address);
221 }
222 if (network->n_static_routes > 0) {
ab24039f
ZJS
223 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
224 network->filename);
0321cea7
YW
225 while ((route = network->static_routes))
226 route_free(route);
227 }
228 }
229
230 if (network->link_local < 0)
8f191801
YW
231 network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
232
44013aa4
YW
233 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
234 if (network->ipv6_accept_ra > 0) {
235 log_warning("%s: IPv6AcceptRA= is enabled by the .network file but IPv6 link local addressing is disabled. "
236 "Disabling IPv6AcceptRA=.", network->filename);
237 network->ipv6_accept_ra = false;
238 }
239
240 if (FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV6)) {
241 log_warning("%s: DHCPv6 client is enabled by the .network file but IPv6 link local addressing is disabled. "
242 "Disabling DHCPv6 client.", network->filename);
243 SET_FLAG(network->dhcp, ADDRESS_FAMILY_IPV6, false);
244 }
245
246 if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) {
247 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
248 "Disabling IPv6PrefixDelegation=.", network->filename);
249 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
250 }
251 }
252
29e81083
YW
253 if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
254 !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
255 log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
256 "Disabling the fallback assignment.", network->filename);
257 SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
258 }
259
8f191801
YW
260 if (network->ipv6_accept_ra < 0 && network->bridge)
261 network->ipv6_accept_ra = false;
0321cea7
YW
262
263 /* IPMasquerade=yes implies IPForward=yes */
264 if (network->ip_masquerade)
265 network->ip_forward |= ADDRESS_FAMILY_IPV4;
266
933c70a0 267 if (network->mtu > 0 && network->dhcp_use_mtu) {
0321cea7
YW
268 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
269 "Disabling UseMTU=.", network->filename);
270 network->dhcp_use_mtu = false;
271 }
272
589397a2
DS
273 if (network->dhcp_use_gateway < 0)
274 network->dhcp_use_gateway = network->dhcp_use_routes;
275
bd0d471c
DS
276 if (network->ignore_carrier_loss < 0)
277 network->ignore_carrier_loss = network->configure_without_carrier;
278
7da377ef
SS
279 if (network->dhcp_critical >= 0) {
280 if (network->keep_configuration >= 0)
281 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
282 "Ignoring CriticalConnection=.", network->filename);
283 else if (network->dhcp_critical)
284 /* CriticalConnection=yes also preserve foreign static configurations. */
285 network->keep_configuration = KEEP_CONFIGURATION_YES;
286 else
80060352 287 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef
SS
288 }
289
290 if (network->keep_configuration < 0)
80060352 291 network->keep_configuration = KEEP_CONFIGURATION_NO;
7da377ef 292
4bec2f23 293 LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
fcbf4cb7 294 if (address_section_verify(address) < 0)
4bec2f23 295 address_free(address);
4bec2f23 296
fcbf4cb7
YW
297 LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
298 if (route_section_verify(route, network) < 0)
4bec2f23 299 route_free(route);
0321cea7 300
c16c7808
SS
301 LIST_FOREACH_SAFE(nexthops, nexthop, nextnop_next, network->static_nexthops)
302 if (nexthop_section_verify(nexthop) < 0)
303 nexthop_free(nexthop);
304
fcbf4cb7
YW
305 LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
306 if (section_is_invalid(fdb->section))
307 fdb_entry_free(fdb);
308
3db468ea
DM
309 LIST_FOREACH_SAFE(static_mdb_entries, mdb, mdb_next, network->static_mdb_entries)
310 if (mdb_entry_verify(mdb) < 0)
311 mdb_entry_free(mdb);
312
fcbf4cb7 313 LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
044d4b40 314 if (neighbor_section_verify(neighbor) < 0)
fcbf4cb7
YW
315 neighbor_free(neighbor);
316
317 LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
318 if (section_is_invalid(label->section))
319 address_label_free(label);
320
321 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
322 if (section_is_invalid(prefix->section))
323 prefix_free(prefix);
324
95081e08
YW
325 LIST_FOREACH_SAFE(route_prefixes, route_prefix, route_prefix_next, network->static_route_prefixes)
326 if (section_is_invalid(route_prefix->section))
327 route_prefix_free(route_prefix);
714a199e 328
50a3682f 329 network_verify_routing_policy_rules(network);
4912ab77 330
8efb93f0 331 bool has_root = false, has_clsact = false;
90e74a66 332 ORDERED_HASHMAP_FOREACH(tc, network->tc_by_section)
34658df2
YW
333 if (traffic_control_section_verify(tc, &has_root, &has_clsact) < 0)
334 traffic_control_free(tc);
8efb93f0 335
90e74a66 336 ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section)
518cd6b5
SS
337 if (sr_iov_section_verify(sr_iov) < 0)
338 sr_iov_free(sr_iov);
339
0321cea7
YW
340 return 0;
341}
342
7f06b3e1 343int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
838b2f7a 344 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 345 _cleanup_(network_unrefp) Network *network = NULL;
f579559b 346 _cleanup_fclose_ FILE *file = NULL;
047a0dac 347 const char *dropin_dirname;
838b2f7a 348 char *d;
f579559b
TG
349 int r;
350
bf1bc670
TA
351 assert(manager);
352 assert(filename);
353
f579559b
TG
354 file = fopen(filename, "re");
355 if (!file) {
356 if (errno == ENOENT)
357 return 0;
1e7a0e21
LP
358
359 return -errno;
f579559b
TG
360 }
361
ed88bcfb
ZJS
362 if (null_or_empty_fd(fileno(file))) {
363 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
364 return 0;
365 }
366
838b2f7a
YW
367 fname = strdup(filename);
368 if (!fname)
369 return log_oom();
370
371 name = strdup(basename(filename));
372 if (!name)
373 return log_oom();
374
375 d = strrchr(name, '.');
376 if (!d)
377 return -EINVAL;
378
379 *d = '\0';
380
381 dropin_dirname = strjoina(name, ".network.d");
382
17f9c355 383 network = new(Network, 1);
f579559b
TG
384 if (!network)
385 return log_oom();
386
17f9c355 387 *network = (Network) {
838b2f7a
YW
388 .filename = TAKE_PTR(fname),
389 .name = TAKE_PTR(name),
17f9c355 390
715d398e 391 .manager = manager,
35ac3b76
YW
392 .n_ref = 1,
393
17f9c355 394 .required_for_online = true,
75cd4a5d 395 .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
17f9c355 396 .dhcp = ADDRESS_FAMILY_NO,
7da377ef 397 .dhcp_critical = -1,
17f9c355 398 .dhcp_use_ntp = true,
299d578f 399 .dhcp_use_sip = true,
17f9c355
YW
400 .dhcp_use_dns = true,
401 .dhcp_use_hostname = true,
402 .dhcp_use_routes = true,
589397a2 403 .dhcp_use_gateway = -1,
5238e957 404 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355 405 .dhcp_send_hostname = true,
5f3b5f19 406 .dhcp_send_release = true,
17f9c355
YW
407 /* To enable/disable RFC7844 Anonymity Profiles */
408 .dhcp_anonymize = false,
409 .dhcp_route_metric = DHCP_ROUTE_METRIC,
c9c908a6 410 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
411 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
412 .dhcp_route_table = RT_TABLE_MAIN,
413 .dhcp_route_table_set = false,
414 /* NOTE: from man: UseMTU=... Defaults to false*/
415 .dhcp_use_mtu = false,
416 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
417 .dhcp_use_timezone = false,
418 .rapid_commit = true,
419
1bf1bfd9 420 .dhcp6_route_metric = DHCP_ROUTE_METRIC,
caa8ca42
SS
421 .dhcp6_use_ntp = true,
422 .dhcp6_use_dns = true,
423
99e015e2
YW
424 .dhcp6_pd_subnet_id = -1,
425 .dhcp6_pd_assign = true,
9efa8a3c 426
2a71d57f
LP
427 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
428 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
429 .dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
430
17f9c355
YW
431 .dhcp_server_emit_router = true,
432 .dhcp_server_emit_timezone = true,
433
434 .router_emit_dns = true,
435 .router_emit_domains = true,
436
437 .use_bpdu = -1,
438 .hairpin = -1,
439 .fast_leave = -1,
440 .allow_port_to_be_root = -1,
441 .unicast_flood = -1,
7f15b714 442 .multicast_flood = -1,
d3aa8b49 443 .multicast_to_unicast = -1,
7f15b714
TJ
444 .neighbor_suppression = -1,
445 .learning = -1,
1087623b
SS
446 .bridge_proxy_arp = -1,
447 .bridge_proxy_arp_wifi = -1,
17f9c355 448 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 449 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355
YW
450
451 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
452
7ece6f58 453 .dns_default_route = -1,
17f9c355
YW
454 .llmnr = RESOLVE_SUPPORT_YES,
455 .mdns = RESOLVE_SUPPORT_NO,
456 .dnssec_mode = _DNSSEC_MODE_INVALID,
457 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
458
0321cea7 459 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
2d792895 460 .link_local = _ADDRESS_FAMILY_INVALID,
6f6296b9 461 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
17f9c355 462
94d76d07
YW
463 .ipv4_accept_local = -1,
464
17f9c355
YW
465 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
466 .ipv6_accept_ra = -1,
467 .ipv6_dad_transmits = -1,
468 .ipv6_hop_limit = -1,
469 .ipv6_proxy_ndp = -1,
470 .duid.type = _DUID_TYPE_INVALID,
471 .proxy_arp = -1,
472 .arp = -1,
473 .multicast = -1,
474 .allmulticast = -1,
475 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
476 .ipv6_accept_ra_use_autonomous_prefix = true,
477 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 478 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 479 .ipv6_accept_ra_route_table_set = false,
d739fdde 480 .ipv6_accept_ra_start_dhcp6_client = true,
c423be28 481
bd0d471c
DS
482 .configure_without_carrier = false,
483 .ignore_carrier_loss = -1,
7da377ef 484 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
c423be28 485 .can_triple_sampling = -1,
52aa38f1 486 .can_termination = -1,
f594b5fe
CG
487 .can_listen_only = -1,
488 .can_fd_mode = -1,
489 .can_non_iso = -1,
afe42aef 490 .ip_service_type = -1,
17f9c355 491 };
f579559b 492
4f9ff96a
LP
493 r = config_parse_many(
494 filename, NETWORK_DIRS, dropin_dirname,
495 "Match\0"
496 "Link\0"
518cd6b5 497 "SR-IOV\0"
4f9ff96a
LP
498 "Network\0"
499 "Address\0"
500 "Neighbor\0"
501 "IPv6AddressLabel\0"
502 "RoutingPolicyRule\0"
503 "Route\0"
504 "NextHop\0"
505 "DHCP\0" /* compat */
506 "DHCPv4\0"
507 "DHCPv6\0"
b209cff2 508 "DHCPv6PrefixDelegation\0"
4f9ff96a
LP
509 "DHCPServer\0"
510 "IPv6AcceptRA\0"
511 "IPv6NDPProxyAddress\0"
512 "Bridge\0"
513 "BridgeFDB\0"
3db468ea 514 "BridgeMDB\0"
4f9ff96a
LP
515 "BridgeVLAN\0"
516 "IPv6PrefixDelegation\0"
517 "IPv6Prefix\0"
518 "IPv6RoutePrefix\0"
519 "LLDP\0"
520 "TrafficControlQueueingDiscipline\0"
521 "CAN\0"
522 "QDisc\0"
523 "BFIFO\0"
524 "CAKE\0"
525 "ControlledDelay\0"
526 "DeficitRoundRobinScheduler\0"
527 "DeficitRoundRobinSchedulerClass\0"
d474aa51 528 "EnhancedTransmissionSelection\0"
4f9ff96a
LP
529 "FairQueueing\0"
530 "FairQueueingControlledDelay\0"
8f6b6d70 531 "FlowQueuePIE\0"
4f9ff96a
LP
532 "GenericRandomEarlyDetection\0"
533 "HeavyHitterFilter\0"
534 "HierarchyTokenBucket\0"
535 "HierarchyTokenBucketClass\0"
536 "NetworkEmulator\0"
b12aaee5
SS
537 "PFIFO\0"
538 "PFIFOFast\0"
539 "PFIFOHeadDrop\0"
4f9ff96a 540 "PIE\0"
b12aaee5 541 "QuickFairQueueing\0"
4d7ddaf9 542 "QuickFairQueueingClass\0"
4f9ff96a
LP
543 "StochasticFairBlue\0"
544 "StochasticFairnessQueueing\0"
545 "TokenBucketFilter\0"
546 "TrivialLinkEqualizer\0",
547 config_item_perf_lookup, network_network_gperf_lookup,
548 CONFIG_PARSE_WARN,
549 network,
550 &network->timestamp);
102bc043 551 if (r < 0)
f579559b 552 return r;
f579559b 553
add8d07d 554 network_apply_anonymize_if_set(network);
555
fa7cd711
YW
556 r = network_add_ipv4ll_route(network);
557 if (r < 0)
558 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
559
5d5003ab
YW
560 r = network_add_default_route_on_device(network);
561 if (r < 0)
562 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
563 network->filename);
564
7f06b3e1
YW
565 if (network_verify(network) < 0)
566 /* Ignore .network files that do not match the conditions. */
567 return 0;
568
569 r = ordered_hashmap_ensure_allocated(networks, &string_hash_ops);
dbffab87
TG
570 if (r < 0)
571 return r;
572
7f06b3e1 573 r = ordered_hashmap_put(*networks, network->name, network);
dbffab87
TG
574 if (r < 0)
575 return r;
576
f579559b 577 network = NULL;
f579559b
TG
578 return 0;
579}
580
7f06b3e1 581int network_load(Manager *manager, OrderedHashmap **networks) {
477e73b5
ZJS
582 _cleanup_strv_free_ char **files = NULL;
583 char **f;
f579559b
TG
584 int r;
585
586 assert(manager);
587
7f06b3e1 588 ordered_hashmap_clear_with_destructor(*networks, network_unref);
f579559b 589
dc0d4078 590 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
591 if (r < 0)
592 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 593
715d398e 594 STRV_FOREACH(f, files) {
7f06b3e1 595 r = network_load_one(manager, networks, *f);
f579559b 596 if (r < 0)
be711082 597 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
f579559b
TG
598 }
599
f579559b
TG
600 return 0;
601}
602
7f06b3e1
YW
603int network_reload(Manager *manager) {
604 OrderedHashmap *new_networks = NULL;
605 Network *n, *old;
7f06b3e1
YW
606 int r;
607
608 assert(manager);
609
610 r = network_load(manager, &new_networks);
611 if (r < 0)
612 goto failure;
613
90e74a66 614 ORDERED_HASHMAP_FOREACH(n, new_networks) {
7f06b3e1
YW
615 r = network_get_by_name(manager, n->name, &old);
616 if (r < 0)
617 continue; /* The .network file is new. */
618
619 if (n->timestamp != old->timestamp)
620 continue; /* The .network file is modified. */
621
622 if (!streq(n->filename, old->filename))
623 continue;
624
625 r = ordered_hashmap_replace(new_networks, old->name, old);
626 if (r < 0)
627 goto failure;
628
629 network_ref(old);
630 network_unref(n);
631 }
632
633 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
634 manager->networks = new_networks;
635
636 return 0;
637
638failure:
639 ordered_hashmap_free_with_destructor(new_networks, network_unref);
640
641 return r;
642}
643
35ac3b76 644static Network *network_free(Network *network) {
a0e5c15d 645 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
95081e08 646 RoutePrefix *route_prefix;
95081e08 647 AddressLabel *label;
bce67bbe 648 FdbEntry *fdb_entry;
3db468ea 649 MdbEntry *mdb_entry;
e4a71bf3 650 Neighbor *neighbor;
bce67bbe 651 Address *address;
c16c7808
SS
652 NextHop *nexthop;
653 Prefix *prefix;
bce67bbe 654 Route *route;
f579559b
TG
655
656 if (!network)
35ac3b76 657 return NULL;
f579559b
TG
658
659 free(network->filename);
660
e90d0374 661 set_free_free(network->match_mac);
4bb7cc82 662 set_free_free(network->match_permanent_mac);
5256e00e
TG
663 strv_free(network->match_path);
664 strv_free(network->match_driver);
665 strv_free(network->match_type);
666 strv_free(network->match_name);
44005bfb 667 strv_free(network->match_property);
78404d22 668 strv_free(network->match_wlan_iftype);
8d968fdd 669 strv_free(network->match_ssid);
277ba8d1 670 set_free_free(network->match_bssid);
c4f58dea 671 condition_free_list(network->conditions);
f579559b
TG
672
673 free(network->description);
edb85f0d 674 free(network->dhcp_vendor_class_identifier);
7b8d23a9 675 free(network->dhcp_mudurl);
af1c0de0 676 strv_free(network->dhcp_user_class);
27cb34f5 677 free(network->dhcp_hostname);
6b000af4 678 set_free(network->dhcp_deny_listed_ip);
98ebef62 679 set_free(network->dhcp_allow_listed_ip);
5bc945be 680 set_free(network->dhcp_request_options);
35f6a5cb 681 set_free(network->dhcp6_request_options);
c106cc36 682 free(network->mac);
3175a8c2 683 free(network->dhcp6_mudurl);
f37f2a6b 684 strv_free(network->dhcp6_user_class);
ed0d1b2e 685 strv_free(network->dhcp6_vendor_class);
c106cc36 686
0f3ff4ea
SS
687 if (network->dhcp_acd)
688 sd_ipv4acd_unref(network->dhcp_acd);
689
b0e39c82 690 strv_free(network->ntp);
e77bd3fd
YW
691 for (unsigned i = 0; i < network->n_dns; i++)
692 in_addr_full_free(network->dns[i]);
5512a963 693 free(network->dns);
5e2a51d5
ZJS
694 ordered_set_free_free(network->search_domains);
695 ordered_set_free_free(network->route_domains);
0d4ad91d 696 strv_free(network->bind_carrier);
cdd7812b 697
5e2a51d5 698 ordered_set_free_free(network->router_search_domains);
cdd7812b 699 free(network->router_dns);
6b000af4 700 set_free_free(network->ndisc_deny_listed_prefix);
3bef724f 701
cebe1257
YW
702 free(network->bridge_name);
703 free(network->bond_name);
704 free(network->vrf_name);
705 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 706 netdev_unref(network->bridge);
47e2dc31 707 netdev_unref(network->bond);
6cb955c6 708 netdev_unref(network->vrf);
fa6f1e54 709 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 710
f048a16b 711 while ((route = network->static_routes))
f579559b
TG
712 route_free(route);
713
c16c7808
SS
714 while ((nexthop = network->static_nexthops))
715 nexthop_free(nexthop);
716
f048a16b 717 while ((address = network->static_addresses))
f579559b
TG
718 address_free(address);
719
b98b483b
AR
720 while ((fdb_entry = network->static_fdb_entries))
721 fdb_entry_free(fdb_entry);
722
3db468ea
DM
723 while ((mdb_entry = network->static_mdb_entries))
724 mdb_entry_free(mdb_entry);
725
a0e5c15d
FK
726 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
727 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
728
e4a71bf3
WKI
729 while ((neighbor = network->neighbors))
730 neighbor_free(neighbor);
731
95b74ef6
SS
732 while ((label = network->address_labels))
733 address_label_free(label);
734
057abfd8
PF
735 while ((prefix = network->static_prefixes))
736 prefix_free(prefix);
737
95081e08
YW
738 while ((route_prefix = network->static_route_prefixes))
739 route_prefix_free(route_prefix);
9be6ae77 740
6ae115c1
TG
741 hashmap_free(network->addresses_by_section);
742 hashmap_free(network->routes_by_section);
c16c7808 743 hashmap_free(network->nexthops_by_section);
b98b483b 744 hashmap_free(network->fdb_entries_by_section);
3db468ea 745 hashmap_free(network->mdb_entries_by_section);
e4a71bf3 746 hashmap_free(network->neighbors_by_section);
95b74ef6 747 hashmap_free(network->address_labels_by_section);
057abfd8 748 hashmap_free(network->prefixes_by_section);
9be6ae77 749 hashmap_free(network->route_prefixes_by_section);
ca183bf8 750 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
518cd6b5 751 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
34658df2 752 ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
6ae115c1 753
7f06b3e1
YW
754 if (network->manager &&
755 network->manager->duids_requesting_uuid)
756 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
757
758 free(network->name);
f579559b 759
8eb9058d 760 free(network->dhcp_server_timezone);
2a71d57f
LP
761
762 for (sd_dhcp_lease_server_type t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
763 free(network->dhcp_server_emit[t].addresses);
8eb9058d 764
8a516214
LP
765 set_free_free(network->dnssec_negative_trust_anchors);
766
e9a8c550
SS
767 free(network->lldp_mud);
768
0e96961d 769 ordered_hashmap_free(network->dhcp_client_send_options);
7354900d 770 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
0e96961d 771 ordered_hashmap_free(network->dhcp_server_send_options);
7354900d 772 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
2c621495 773 ordered_set_free(network->ipv6_tokens);
1c3ec1cd 774 ordered_hashmap_free(network->dhcp6_client_send_options);
b4ccc5de 775 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
cb29c156 776
35ac3b76 777 return mfree(network);
f579559b
TG
778}
779
35ac3b76
YW
780DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
781
dbffab87
TG
782int network_get_by_name(Manager *manager, const char *name, Network **ret) {
783 Network *network;
784
785 assert(manager);
786 assert(name);
787 assert(ret);
788
715d398e 789 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
790 if (!network)
791 return -ENOENT;
792
793 *ret = network;
794
795 return 0;
796}
797
ef62949a 798int network_get(Manager *manager, unsigned short iftype, sd_device *device,
c643bda5
YW
799 const char *ifname, char * const *alternative_names, const char *driver,
800 const struct ether_addr *mac, const struct ether_addr *permanent_mac,
78404d22
YW
801 enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
802 Network **ret) {
51517f9e 803 Network *network;
f579559b
TG
804
805 assert(manager);
f579559b 806 assert(ret);
af3aa302 807
90e74a66 808 ORDERED_HASHMAP_FOREACH(network, manager->networks)
4bb7cc82
YW
809 if (net_match_config(network->match_mac, network->match_permanent_mac,
810 network->match_path, network->match_driver,
44005bfb 811 network->match_type, network->match_name, network->match_property,
78404d22 812 network->match_wlan_iftype, network->match_ssid, network->match_bssid,
c643bda5 813 device, mac, permanent_mac, driver, iftype,
4bb7cc82 814 ifname, alternative_names, wlan_iftype, ssid, bssid)) {
24c083df 815 if (network->match_name && device) {
ca6038b8
TG
816 const char *attr;
817 uint8_t name_assign_type = NET_NAME_UNKNOWN;
818
51517f9e 819 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 820 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
821
822 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
823 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
824 ifname, network->filename);
32bc8adc 825 else
a2fae7bb 826 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 827 } else
a2fae7bb 828 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 829
f579559b
TG
830 *ret = network;
831 return 0;
832 }
f579559b
TG
833
834 *ret = NULL;
835
836 return -ENOENT;
837}
838
7d342c03 839int network_apply(Network *network, Link *link) {
c4a03a56
TG
840 assert(network);
841 assert(link);
842
c9c908a6 843 link->network = network_ref(network);
f579559b 844
5512a963 845 if (network->n_dns > 0 ||
3df9bec5 846 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
847 !ordered_set_isempty(network->search_domains) ||
848 !ordered_set_isempty(network->route_domains))
84de38c5 849 link_dirty(link);
3bef724f 850
f579559b
TG
851 return 0;
852}
02b59d57 853
adfeee49 854bool network_has_static_ipv6_configurations(Network *network) {
439689c6 855 Address *address;
adfeee49
YW
856 Route *route;
857 FdbEntry *fdb;
3db468ea 858 MdbEntry *mdb;
adfeee49 859 Neighbor *neighbor;
439689c6
SS
860
861 assert(network);
862
adfeee49 863 LIST_FOREACH(addresses, address, network->static_addresses)
439689c6
SS
864 if (address->family == AF_INET6)
865 return true;
adfeee49
YW
866
867 LIST_FOREACH(routes, route, network->static_routes)
868 if (route->family == AF_INET6)
869 return true;
870
871 LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
872 if (fdb->family == AF_INET6)
873 return true;
874
3db468ea
DM
875 LIST_FOREACH(static_mdb_entries, mdb, network->static_mdb_entries)
876 if (mdb->family == AF_INET6)
877 return true;
878
adfeee49
YW
879 LIST_FOREACH(neighbors, neighbor, network->neighbors)
880 if (neighbor->family == AF_INET6)
881 return true;
882
883 if (!LIST_IS_EMPTY(network->address_labels))
884 return true;
885
886 if (!LIST_IS_EMPTY(network->static_prefixes))
887 return true;
439689c6
SS
888
889 return false;
890}
891
cebe1257 892int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
893 const char *filename,
894 unsigned line,
895 const char *section,
896 unsigned section_line,
897 const char *lvalue,
898 int ltype,
899 const char *rvalue,
900 void *data,
901 void *userdata) {
95dba435
YW
902 _cleanup_free_ char *name = NULL;
903 NetDevKind kind = ltype;
cebe1257 904 Hashmap **h = data;
02b59d57
TG
905 int r;
906
907 assert(filename);
908 assert(lvalue);
909 assert(rvalue);
910 assert(data);
95dba435
YW
911 assert(IN_SET(kind,
912 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 913 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 914 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
915 NETDEV_KIND_XFRM));
54abf461 916
cebe1257 917 if (!ifname_valid(rvalue)) {
d96edb2c 918 log_syntax(unit, LOG_WARNING, filename, line, 0,
3772cfde 919 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
920 return 0;
921 }
922
cebe1257
YW
923 name = strdup(rvalue);
924 if (!name)
925 return log_oom();
3e570042 926
cebe1257
YW
927 r = hashmap_ensure_allocated(h, &string_hash_ops);
928 if (r < 0)
929 return log_oom();
326cb406 930
cebe1257 931 r = hashmap_put(*h, name, INT_TO_PTR(kind));
83ec4592 932 if (r < 0)
d96edb2c 933 log_syntax(unit, LOG_WARNING, filename, line, r,
83ec4592
ZJS
934 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
935 else if (r == 0)
936 log_syntax(unit, LOG_DEBUG, filename, line, r,
937 "NetDev '%s' specified twice, ignoring.", name);
938 else
939 name = NULL;
47e2dc31 940
fe6b2d55
TG
941 return 0;
942}
7951dea2 943
3df9bec5
LP
944int config_parse_domains(
945 const char *unit,
946 const char *filename,
947 unsigned line,
948 const char *section,
949 unsigned section_line,
950 const char *lvalue,
951 int ltype,
952 const char *rvalue,
953 void *data,
954 void *userdata) {
955
3df9bec5 956 Network *n = data;
6192b846
TG
957 int r;
958
3df9bec5
LP
959 assert(n);
960 assert(lvalue);
961 assert(rvalue);
6192b846 962
3df9bec5 963 if (isempty(rvalue)) {
5e2a51d5
ZJS
964 n->search_domains = ordered_set_free_free(n->search_domains);
965 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
966 return 0;
967 }
67272d15 968
d96edb2c 969 for (const char *p = rvalue;;) {
3df9bec5
LP
970 _cleanup_free_ char *w = NULL, *normalized = NULL;
971 const char *domain;
972 bool is_route;
973
974 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
975 if (r == -ENOMEM)
976 return log_oom();
3df9bec5 977 if (r < 0) {
d96edb2c 978 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 979 "Failed to extract search or route domain, ignoring: %s", rvalue);
d96edb2c 980 return 0;
3df9bec5
LP
981 }
982 if (r == 0)
d96edb2c 983 return 0;
3df9bec5
LP
984
985 is_route = w[0] == '~';
986 domain = is_route ? w + 1 : w;
987
988 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
989 /* If the root domain appears as is, or the special token "*" is found, we'll
990 * consider this as routing domain, unconditionally. */
3df9bec5 991 is_route = true;
ab24039f
ZJS
992 domain = "."; /* make sure we don't allow empty strings, thus write the root
993 * domain as "." */
3df9bec5 994 } else {
7470cc4c 995 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 996 if (r < 0) {
d96edb2c 997 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 998 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
999 continue;
1000 }
1001
1002 domain = normalized;
1003
1004 if (is_localhost(domain)) {
d96edb2c 1005 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f
ZJS
1006 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
1007 domain);
37de2509 1008 continue;
3df9bec5 1009 }
37de2509 1010 }
40274ed6 1011
5e2a51d5
ZJS
1012 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
1013 r = ordered_set_ensure_allocated(set, &string_hash_ops);
1014 if (r < 0)
d96edb2c 1015 return log_oom();
5e2a51d5
ZJS
1016
1017 r = ordered_set_put_strdup(*set, domain);
09451975
LP
1018 if (r < 0)
1019 return log_oom();
40274ed6 1020 }
6192b846
TG
1021}
1022
60c35566 1023int config_parse_ipv6token(
7f77697a
TG
1024 const char* unit,
1025 const char *filename,
1026 unsigned line,
1027 const char *section,
1028 unsigned section_line,
1029 const char *lvalue,
1030 int ltype,
1031 const char *rvalue,
1032 void *data,
1033 void *userdata) {
1034
1035 union in_addr_union buffer;
1036 struct in6_addr *token = data;
1037 int r;
1038
1039 assert(filename);
1040 assert(lvalue);
1041 assert(rvalue);
1042 assert(token);
1043
1044 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
1045 if (r < 0) {
d96edb2c 1046 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1047 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
1048 return 0;
1049 }
1050
c606db69 1051 if (in_addr_is_null(AF_INET6, &buffer)) {
d96edb2c 1052 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 1053 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
1054 return 0;
1055 }
1056
1057 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
d96edb2c 1058 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 1059 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
1060 return 0;
1061 }
1062
1063 *token = buffer.in6;
1064
1065 return 0;
1066}
8add5f79 1067
49092e22 1068static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
1069 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
1070 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
1071 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
1072};
1073
b146ad71
YW
1074DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
1075 IPV6_PRIVACY_EXTENSIONS_YES);
49092e22
SS
1076
1077int config_parse_ipv6_privacy_extensions(
1078 const char* unit,
1079 const char *filename,
1080 unsigned line,
1081 const char *section,
1082 unsigned section_line,
1083 const char *lvalue,
1084 int ltype,
1085 const char *rvalue,
1086 void *data,
1087 void *userdata) {
1088
b146ad71 1089 IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
49092e22
SS
1090
1091 assert(filename);
1092 assert(lvalue);
1093 assert(rvalue);
1094 assert(ipv6_privacy_extensions);
1095
b146ad71
YW
1096 s = ipv6_privacy_extensions_from_string(rvalue);
1097 if (s < 0) {
1098 if (streq(rvalue, "kernel"))
1099 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
1100 else {
d96edb2c 1101 log_syntax(unit, LOG_WARNING, filename, line, 0,
b146ad71
YW
1102 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1103 return 0;
49092e22 1104 }
49092e22
SS
1105 }
1106
b146ad71
YW
1107 *ipv6_privacy_extensions = s;
1108
49092e22
SS
1109 return 0;
1110}
a7d0ef44 1111
1ac608c9
LP
1112int config_parse_hostname(
1113 const char *unit,
1114 const char *filename,
1115 unsigned line,
1116 const char *section,
1117 unsigned section_line,
1118 const char *lvalue,
1119 int ltype,
1120 const char *rvalue,
1121 void *data,
1122 void *userdata) {
1123
6528693a
YW
1124 _cleanup_free_ char *hn = NULL;
1125 char **hostname = data;
a7d0ef44
SS
1126 int r;
1127
1128 assert(filename);
1129 assert(lvalue);
1130 assert(rvalue);
1131
1ac608c9 1132 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
1133 if (r < 0)
1134 return r;
1135
1ac608c9 1136 if (!hostname_is_valid(hn, false)) {
d96edb2c 1137 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 1138 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
1139 return 0;
1140 }
1141
6528693a
YW
1142 r = dns_name_is_valid(hn);
1143 if (r < 0) {
d96edb2c 1144 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1145 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
1146 return 0;
1147 }
1148 if (r == 0) {
d96edb2c 1149 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 1150 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
1151 return 0;
1152 }
1153
1154 return free_and_replace(*hostname, hn);
a7d0ef44 1155}
8eb9058d
LP
1156
1157int config_parse_timezone(
1158 const char *unit,
1159 const char *filename,
1160 unsigned line,
1161 const char *section,
1162 unsigned section_line,
1163 const char *lvalue,
1164 int ltype,
1165 const char *rvalue,
1166 void *data,
1167 void *userdata) {
1168
19f9e4e2
YW
1169 _cleanup_free_ char *tz = NULL;
1170 char **datap = data;
8eb9058d
LP
1171 int r;
1172
1173 assert(filename);
1174 assert(lvalue);
1175 assert(rvalue);
1176
1177 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1178 if (r < 0)
1179 return r;
1180
d96edb2c
YW
1181 if (!timezone_is_valid(tz, LOG_WARNING)) {
1182 log_syntax(unit, LOG_WARNING, filename, line, 0,
ab24039f 1183 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1184 return 0;
1185 }
1186
19f9e4e2 1187 return free_and_replace(*datap, tz);
8eb9058d 1188}
1a04db0f 1189
53253824
SS
1190int config_parse_dns(
1191 const char *unit,
1192 const char *filename,
1193 unsigned line,
1194 const char *section,
1195 unsigned section_line,
1196 const char *lvalue,
1197 int ltype,
1198 const char *rvalue,
1199 void *data,
1200 void *userdata) {
1201
1202 Network *n = userdata;
1203 int r;
1204
1205 assert(filename);
1206 assert(lvalue);
1207 assert(rvalue);
1208
d96edb2c 1209 if (isempty(rvalue)) {
e77bd3fd
YW
1210 for (unsigned i = 0; i < n->n_dns; i++)
1211 in_addr_full_free(n->dns[i]);
d96edb2c
YW
1212 n->dns = mfree(n->dns);
1213 n->n_dns = 0;
1214 return 0;
1215 }
1216
1217 for (const char *p = rvalue;;) {
e77bd3fd 1218 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
53253824 1219 _cleanup_free_ char *w = NULL;
e77bd3fd 1220 struct in_addr_full **m;
53253824 1221
d96edb2c 1222 r = extract_first_word(&p, &w, NULL, 0);
53253824
SS
1223 if (r == -ENOMEM)
1224 return log_oom();
1225 if (r < 0) {
d96edb2c 1226 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1227 "Invalid syntax, ignoring: %s", rvalue);
d96edb2c 1228 return 0;
53253824 1229 }
5512a963 1230 if (r == 0)
d96edb2c 1231 return 0;
53253824 1232
e77bd3fd 1233 r = in_addr_full_new_from_string(w, &dns);
53253824 1234 if (r < 0) {
d96edb2c 1235 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1236 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1237 continue;
1238 }
1239
e77bd3fd
YW
1240 if (IN_SET(dns->port, 53, 853))
1241 dns->port = 0;
1242
1243 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
5512a963 1244 if (!m)
53253824
SS
1245 return log_oom();
1246
e77bd3fd 1247 m[n->n_dns++] = TAKE_PTR(dns);
5512a963 1248 n->dns = m;
53253824 1249 }
53253824
SS
1250}
1251
8a516214
LP
1252int config_parse_dnssec_negative_trust_anchors(
1253 const char *unit,
1254 const char *filename,
1255 unsigned line,
1256 const char *section,
1257 unsigned section_line,
1258 const char *lvalue,
1259 int ltype,
1260 const char *rvalue,
1261 void *data,
1262 void *userdata) {
1263
8a516214
LP
1264 Network *n = data;
1265 int r;
1266
3df9bec5 1267 assert(n);
8a516214
LP
1268 assert(lvalue);
1269 assert(rvalue);
1270
1271 if (isempty(rvalue)) {
1272 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1273 return 0;
1274 }
1275
d96edb2c 1276 for (const char *p = rvalue;;) {
8a516214
LP
1277 _cleanup_free_ char *w = NULL;
1278
1279 r = extract_first_word(&p, &w, NULL, 0);
d96edb2c
YW
1280 if (r == -ENOMEM)
1281 return log_oom();
8a516214 1282 if (r < 0) {
d96edb2c 1283 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1284 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
d96edb2c 1285 return 0;
8a516214
LP
1286 }
1287 if (r == 0)
d96edb2c 1288 return 0;
8a516214
LP
1289
1290 r = dns_name_is_valid(w);
1291 if (r <= 0) {
d96edb2c 1292 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1293 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1294 continue;
1295 }
1296
35e601d4 1297 r = set_ensure_consume(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops, TAKE_PTR(w));
8a516214
LP
1298 if (r < 0)
1299 return log_oom();
8a516214 1300 }
8a516214 1301}
b2a81c0b 1302
26575990
LP
1303int config_parse_ntp(
1304 const char *unit,
1305 const char *filename,
1306 unsigned line,
1307 const char *section,
1308 unsigned section_line,
1309 const char *lvalue,
1310 int ltype,
1311 const char *rvalue,
1312 void *data,
1313 void *userdata) {
1314
1315 char ***l = data;
1316 int r;
1317
1318 assert(l);
1319 assert(lvalue);
1320 assert(rvalue);
1321
1322 if (isempty(rvalue)) {
1323 *l = strv_free(*l);
1324 return 0;
1325 }
1326
d96edb2c 1327 for (const char *p = rvalue;;) {
26575990
LP
1328 _cleanup_free_ char *w = NULL;
1329
d96edb2c 1330 r = extract_first_word(&p, &w, NULL, 0);
26575990
LP
1331 if (r == -ENOMEM)
1332 return log_oom();
1333 if (r < 0) {
d96edb2c 1334 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1335 "Failed to extract NTP server name, ignoring: %s", rvalue);
d96edb2c 1336 return 0;
26575990
LP
1337 }
1338 if (r == 0)
d96edb2c 1339 return 0;
26575990
LP
1340
1341 r = dns_name_is_valid_or_address(w);
1342 if (r <= 0) {
d96edb2c 1343 log_syntax(unit, LOG_WARNING, filename, line, r,
ab24039f 1344 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1345 continue;
af1c0de0
SS
1346 }
1347
c448459d
ZJS
1348 if (strv_length(*l) > MAX_NTP_SERVERS) {
1349 log_syntax(unit, LOG_WARNING, filename, line, 0,
1350 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1351 MAX_NTP_SERVERS, w);
d96edb2c 1352 return 0;
c448459d
ZJS
1353 }
1354
1355 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1356 if (r < 0)
1357 return log_oom();
af1c0de0 1358 }
af1c0de0
SS
1359}
1360
4ac77d63
YW
1361int config_parse_required_for_online(
1362 const char *unit,
1363 const char *filename,
1364 unsigned line,
1365 const char *section,
1366 unsigned section_line,
1367 const char *lvalue,
1368 int ltype,
1369 const char *rvalue,
1370 void *data,
1371 void *userdata) {
1372
1373 Network *network = data;
75cd4a5d 1374 LinkOperationalStateRange range;
4ac77d63
YW
1375 bool required = true;
1376 int r;
1377
1378 if (isempty(rvalue)) {
1379 network->required_for_online = true;
75cd4a5d 1380 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1381 return 0;
1382 }
1383
75cd4a5d
DDM
1384 r = parse_operational_state_range(rvalue, &range);
1385 if (r < 0) {
4ac77d63
YW
1386 r = parse_boolean(rvalue);
1387 if (r < 0) {
d96edb2c 1388 log_syntax(unit, LOG_WARNING, filename, line, r,
4ac77d63
YW
1389 "Failed to parse %s= setting, ignoring assignment: %s",
1390 lvalue, rvalue);
1391 return 0;
1392 }
1393
1394 required = r;
75cd4a5d 1395 range = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1396 }
1397
1398 network->required_for_online = required;
75cd4a5d 1399 network->required_operstate_for_online = range;
4ac77d63
YW
1400
1401 return 0;
1402}
7da377ef
SS
1403
1404DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1405 "Failed to parse KeepConfiguration= setting");
1406
1407static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1408 [KEEP_CONFIGURATION_NO] = "no",
1409 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1410 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1411 [KEEP_CONFIGURATION_STATIC] = "static",
1412 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1413};
1414
1415DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
6f6296b9
YW
1416
1417static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
1418 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
1419 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
1420 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
1421 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
1422};
1423
1424DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
1425DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_link_local_address_gen_mode, ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode, "Failed to parse IPv6 link local address generation mode");