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