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