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