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