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