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