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