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