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