]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: TC - introduce BFIFO
[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"
c853f594 489 "BFIFO\0"
ad8352f4 490 "CAKE\0"
18de0969 491 "ControlledDelay\0"
f5fc0441 492 "DeficitRoundRobinScheduler\0"
ad365c5d 493 "DeficitRoundRobinSchedulerClass\0"
a7476065 494 "PFIFO\0"
ca58d00c 495 "FairQueueing\0"
18de0969 496 "FairQueueingControlledDelay\0"
609e8340 497 "GenericRandomEarlyDetection\0"
b934ac3d 498 "HierarchyTokenBucket\0"
19f86a63 499 "HierarchyTokenBucketClass\0"
18de0969 500 "NetworkEmulator\0"
bde4ae88 501 "PIE\0"
982998b0 502 "StochasticFairBlue\0"
18de0969 503 "StochasticFairnessQueueing\0"
9b749c11
YW
504 "TokenBucketFilter\0"
505 "TrivialLinkEqualizer\0",
23bb31aa 506 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 507 CONFIG_PARSE_WARN, network);
102bc043 508 if (r < 0)
f579559b 509 return r;
f579559b 510
add8d07d 511 network_apply_anonymize_if_set(network);
512
fa7cd711
YW
513 r = network_add_ipv4ll_route(network);
514 if (r < 0)
515 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
516
5d5003ab
YW
517 r = network_add_default_route_on_device(network);
518 if (r < 0)
519 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
520 network->filename);
521
7f06b3e1
YW
522 struct stat stats;
523 if (stat(filename, &stats) < 0)
524 return -errno;
525 network->timestamp = timespec_load(&stats.st_mtim);
526
527 if (network_verify(network) < 0)
528 /* Ignore .network files that do not match the conditions. */
529 return 0;
530
531 r = ordered_hashmap_ensure_allocated(networks, &string_hash_ops);
dbffab87
TG
532 if (r < 0)
533 return r;
534
7f06b3e1 535 r = ordered_hashmap_put(*networks, network->name, network);
dbffab87
TG
536 if (r < 0)
537 return r;
538
f579559b 539 network = NULL;
f579559b
TG
540 return 0;
541}
542
7f06b3e1 543int network_load(Manager *manager, OrderedHashmap **networks) {
477e73b5
ZJS
544 _cleanup_strv_free_ char **files = NULL;
545 char **f;
f579559b
TG
546 int r;
547
548 assert(manager);
549
7f06b3e1 550 ordered_hashmap_clear_with_destructor(*networks, network_unref);
f579559b 551
dc0d4078 552 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
553 if (r < 0)
554 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 555
715d398e 556 STRV_FOREACH(f, files) {
7f06b3e1 557 r = network_load_one(manager, networks, *f);
f579559b 558 if (r < 0)
be711082 559 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
f579559b
TG
560 }
561
f579559b
TG
562 return 0;
563}
564
7f06b3e1
YW
565int network_reload(Manager *manager) {
566 OrderedHashmap *new_networks = NULL;
567 Network *n, *old;
568 Iterator i;
569 int r;
570
571 assert(manager);
572
573 r = network_load(manager, &new_networks);
574 if (r < 0)
575 goto failure;
576
577 ORDERED_HASHMAP_FOREACH(n, new_networks, i) {
578 r = network_get_by_name(manager, n->name, &old);
579 if (r < 0)
580 continue; /* The .network file is new. */
581
582 if (n->timestamp != old->timestamp)
583 continue; /* The .network file is modified. */
584
585 if (!streq(n->filename, old->filename))
586 continue;
587
588 r = ordered_hashmap_replace(new_networks, old->name, old);
589 if (r < 0)
590 goto failure;
591
592 network_ref(old);
593 network_unref(n);
594 }
595
596 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
597 manager->networks = new_networks;
598
599 return 0;
600
601failure:
602 ordered_hashmap_free_with_destructor(new_networks, network_unref);
603
604 return r;
605}
606
35ac3b76 607static Network *network_free(Network *network) {
a0e5c15d 608 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
95081e08 609 RoutePrefix *route_prefix;
bce67bbe 610 RoutingPolicyRule *rule;
95081e08 611 AddressLabel *label;
bce67bbe 612 FdbEntry *fdb_entry;
e4a71bf3 613 Neighbor *neighbor;
bce67bbe 614 Address *address;
c16c7808
SS
615 NextHop *nexthop;
616 Prefix *prefix;
bce67bbe 617 Route *route;
f579559b
TG
618
619 if (!network)
35ac3b76 620 return NULL;
f579559b
TG
621
622 free(network->filename);
623
e90d0374 624 set_free_free(network->match_mac);
4bb7cc82 625 set_free_free(network->match_permanent_mac);
5256e00e
TG
626 strv_free(network->match_path);
627 strv_free(network->match_driver);
628 strv_free(network->match_type);
629 strv_free(network->match_name);
44005bfb 630 strv_free(network->match_property);
78404d22 631 strv_free(network->match_wlan_iftype);
8d968fdd 632 strv_free(network->match_ssid);
277ba8d1 633 set_free_free(network->match_bssid);
c4f58dea 634 condition_free_list(network->conditions);
f579559b
TG
635
636 free(network->description);
edb85f0d 637 free(network->dhcp_vendor_class_identifier);
af1c0de0 638 strv_free(network->dhcp_user_class);
27cb34f5 639 free(network->dhcp_hostname);
727b5734 640 set_free(network->dhcp_black_listed_ip);
5bc945be 641 set_free(network->dhcp_request_options);
c106cc36
TG
642 free(network->mac);
643
0f3ff4ea
SS
644 if (network->dhcp_acd)
645 sd_ipv4acd_unref(network->dhcp_acd);
646
b0e39c82 647 strv_free(network->ntp);
5512a963 648 free(network->dns);
299d578f 649 strv_free(network->sip);
5e2a51d5
ZJS
650 ordered_set_free_free(network->search_domains);
651 ordered_set_free_free(network->route_domains);
0d4ad91d 652 strv_free(network->bind_carrier);
cdd7812b 653
5e2a51d5 654 ordered_set_free_free(network->router_search_domains);
cdd7812b 655 free(network->router_dns);
e520ce64 656 set_free_free(network->ndisc_black_listed_prefix);
3bef724f 657
cebe1257
YW
658 free(network->bridge_name);
659 free(network->bond_name);
660 free(network->vrf_name);
661 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 662 netdev_unref(network->bridge);
47e2dc31 663 netdev_unref(network->bond);
6cb955c6 664 netdev_unref(network->vrf);
fa6f1e54 665 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 666
f048a16b 667 while ((route = network->static_routes))
f579559b
TG
668 route_free(route);
669
c16c7808
SS
670 while ((nexthop = network->static_nexthops))
671 nexthop_free(nexthop);
672
f048a16b 673 while ((address = network->static_addresses))
f579559b
TG
674 address_free(address);
675
b98b483b
AR
676 while ((fdb_entry = network->static_fdb_entries))
677 fdb_entry_free(fdb_entry);
678
a0e5c15d
FK
679 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
680 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
681
e4a71bf3
WKI
682 while ((neighbor = network->neighbors))
683 neighbor_free(neighbor);
684
95b74ef6
SS
685 while ((label = network->address_labels))
686 address_label_free(label);
687
057abfd8
PF
688 while ((prefix = network->static_prefixes))
689 prefix_free(prefix);
690
95081e08
YW
691 while ((route_prefix = network->static_route_prefixes))
692 route_prefix_free(route_prefix);
9be6ae77 693
bce67bbe
SS
694 while ((rule = network->rules))
695 routing_policy_rule_free(rule);
696
6ae115c1
TG
697 hashmap_free(network->addresses_by_section);
698 hashmap_free(network->routes_by_section);
c16c7808 699 hashmap_free(network->nexthops_by_section);
b98b483b 700 hashmap_free(network->fdb_entries_by_section);
e4a71bf3 701 hashmap_free(network->neighbors_by_section);
95b74ef6 702 hashmap_free(network->address_labels_by_section);
057abfd8 703 hashmap_free(network->prefixes_by_section);
9be6ae77 704 hashmap_free(network->route_prefixes_by_section);
bce67bbe 705 hashmap_free(network->rules_by_section);
34658df2 706 ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
6ae115c1 707
7f06b3e1
YW
708 if (network->manager &&
709 network->manager->duids_requesting_uuid)
710 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
711
712 free(network->name);
f579559b 713
8eb9058d 714 free(network->dhcp_server_timezone);
1a04db0f
LP
715 free(network->dhcp_server_dns);
716 free(network->dhcp_server_ntp);
299d578f 717 free(network->dhcp_server_sip);
8eb9058d 718
8a516214
LP
719 set_free_free(network->dnssec_negative_trust_anchors);
720
0e96961d
YW
721 ordered_hashmap_free(network->dhcp_client_send_options);
722 ordered_hashmap_free(network->dhcp_server_send_options);
5f506a55 723 ordered_hashmap_free(network->ipv6_tokens);
cb29c156 724
35ac3b76 725 return mfree(network);
f579559b
TG
726}
727
35ac3b76
YW
728DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
729
dbffab87
TG
730int network_get_by_name(Manager *manager, const char *name, Network **ret) {
731 Network *network;
732
733 assert(manager);
734 assert(name);
735 assert(ret);
736
715d398e 737 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
738 if (!network)
739 return -ENOENT;
740
741 *ret = network;
742
743 return 0;
744}
745
ef62949a 746int network_get(Manager *manager, unsigned short iftype, sd_device *device,
4bb7cc82
YW
747 const char *ifname, char * const *alternative_names,
748 const struct ether_addr *address, const struct ether_addr *permanent_address,
78404d22
YW
749 enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
750 Network **ret) {
51517f9e 751 Network *network;
715d398e 752 Iterator i;
f579559b
TG
753
754 assert(manager);
f579559b 755 assert(ret);
af3aa302 756
715d398e 757 ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
4bb7cc82
YW
758 if (net_match_config(network->match_mac, network->match_permanent_mac,
759 network->match_path, network->match_driver,
44005bfb 760 network->match_type, network->match_name, network->match_property,
78404d22 761 network->match_wlan_iftype, network->match_ssid, network->match_bssid,
ef62949a 762 iftype, device, address, permanent_address,
4bb7cc82 763 ifname, alternative_names, wlan_iftype, ssid, bssid)) {
24c083df 764 if (network->match_name && device) {
ca6038b8
TG
765 const char *attr;
766 uint8_t name_assign_type = NET_NAME_UNKNOWN;
767
51517f9e 768 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 769 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
770
771 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
772 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
773 ifname, network->filename);
32bc8adc 774 else
a2fae7bb 775 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 776 } else
a2fae7bb 777 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 778
f579559b
TG
779 *ret = network;
780 return 0;
781 }
f579559b
TG
782
783 *ret = NULL;
784
785 return -ENOENT;
786}
787
7d342c03 788int network_apply(Network *network, Link *link) {
c4a03a56
TG
789 assert(network);
790 assert(link);
791
c9c908a6 792 link->network = network_ref(network);
f579559b 793
5512a963 794 if (network->n_dns > 0 ||
3df9bec5 795 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
796 !ordered_set_isempty(network->search_domains) ||
797 !ordered_set_isempty(network->route_domains))
84de38c5 798 link_dirty(link);
3bef724f 799
f579559b
TG
800 return 0;
801}
02b59d57 802
adfeee49 803bool network_has_static_ipv6_configurations(Network *network) {
439689c6 804 Address *address;
adfeee49
YW
805 Route *route;
806 FdbEntry *fdb;
807 Neighbor *neighbor;
439689c6
SS
808
809 assert(network);
810
adfeee49 811 LIST_FOREACH(addresses, address, network->static_addresses)
439689c6
SS
812 if (address->family == AF_INET6)
813 return true;
adfeee49
YW
814
815 LIST_FOREACH(routes, route, network->static_routes)
816 if (route->family == AF_INET6)
817 return true;
818
819 LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
820 if (fdb->family == AF_INET6)
821 return true;
822
823 LIST_FOREACH(neighbors, neighbor, network->neighbors)
824 if (neighbor->family == AF_INET6)
825 return true;
826
827 if (!LIST_IS_EMPTY(network->address_labels))
828 return true;
829
830 if (!LIST_IS_EMPTY(network->static_prefixes))
831 return true;
439689c6
SS
832
833 return false;
834}
835
cebe1257 836int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
837 const char *filename,
838 unsigned line,
839 const char *section,
840 unsigned section_line,
841 const char *lvalue,
842 int ltype,
843 const char *rvalue,
844 void *data,
845 void *userdata) {
95dba435
YW
846 _cleanup_free_ char *name = NULL;
847 NetDevKind kind = ltype;
cebe1257 848 Hashmap **h = data;
02b59d57
TG
849 int r;
850
851 assert(filename);
852 assert(lvalue);
853 assert(rvalue);
854 assert(data);
95dba435
YW
855 assert(IN_SET(kind,
856 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 857 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 858 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
859 NETDEV_KIND_XFRM));
54abf461 860
cebe1257 861 if (!ifname_valid(rvalue)) {
3772cfde
ZJS
862 log_syntax(unit, LOG_ERR, filename, line, 0,
863 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
864 return 0;
865 }
866
cebe1257
YW
867 name = strdup(rvalue);
868 if (!name)
869 return log_oom();
3e570042 870
cebe1257
YW
871 r = hashmap_ensure_allocated(h, &string_hash_ops);
872 if (r < 0)
873 return log_oom();
326cb406 874
cebe1257 875 r = hashmap_put(*h, name, INT_TO_PTR(kind));
83ec4592 876 if (r < 0)
3772cfde 877 log_syntax(unit, LOG_ERR, filename, line, r,
83ec4592
ZJS
878 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
879 else if (r == 0)
880 log_syntax(unit, LOG_DEBUG, filename, line, r,
881 "NetDev '%s' specified twice, ignoring.", name);
882 else
883 name = NULL;
47e2dc31 884
fe6b2d55
TG
885 return 0;
886}
7951dea2 887
3df9bec5
LP
888int config_parse_domains(
889 const char *unit,
890 const char *filename,
891 unsigned line,
892 const char *section,
893 unsigned section_line,
894 const char *lvalue,
895 int ltype,
896 const char *rvalue,
897 void *data,
898 void *userdata) {
899
900 const char *p;
901 Network *n = data;
6192b846
TG
902 int r;
903
3df9bec5
LP
904 assert(n);
905 assert(lvalue);
906 assert(rvalue);
6192b846 907
3df9bec5 908 if (isempty(rvalue)) {
5e2a51d5
ZJS
909 n->search_domains = ordered_set_free_free(n->search_domains);
910 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
911 return 0;
912 }
67272d15 913
3df9bec5
LP
914 p = rvalue;
915 for (;;) {
916 _cleanup_free_ char *w = NULL, *normalized = NULL;
917 const char *domain;
918 bool is_route;
919
920 r = extract_first_word(&p, &w, NULL, 0);
921 if (r < 0) {
ab24039f
ZJS
922 log_syntax(unit, LOG_ERR, filename, line, r,
923 "Failed to extract search or route domain, ignoring: %s", rvalue);
3df9bec5
LP
924 break;
925 }
926 if (r == 0)
927 break;
928
929 is_route = w[0] == '~';
930 domain = is_route ? w + 1 : w;
931
932 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
933 /* If the root domain appears as is, or the special token "*" is found, we'll
934 * consider this as routing domain, unconditionally. */
3df9bec5 935 is_route = true;
ab24039f
ZJS
936 domain = "."; /* make sure we don't allow empty strings, thus write the root
937 * domain as "." */
3df9bec5 938 } else {
7470cc4c 939 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 940 if (r < 0) {
ab24039f
ZJS
941 log_syntax(unit, LOG_ERR, filename, line, r,
942 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
943 continue;
944 }
945
946 domain = normalized;
947
948 if (is_localhost(domain)) {
ab24039f
ZJS
949 log_syntax(unit, LOG_ERR, filename, line, 0,
950 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
951 domain);
37de2509 952 continue;
3df9bec5 953 }
37de2509 954 }
40274ed6 955
5e2a51d5
ZJS
956 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
957 r = ordered_set_ensure_allocated(set, &string_hash_ops);
958 if (r < 0)
959 return r;
960
961 r = ordered_set_put_strdup(*set, domain);
09451975
LP
962 if (r < 0)
963 return log_oom();
40274ed6 964 }
f15b6e5a 965
6192b846
TG
966 return 0;
967}
968
60c35566 969int config_parse_ipv6token(
7f77697a
TG
970 const char* unit,
971 const char *filename,
972 unsigned line,
973 const char *section,
974 unsigned section_line,
975 const char *lvalue,
976 int ltype,
977 const char *rvalue,
978 void *data,
979 void *userdata) {
980
981 union in_addr_union buffer;
982 struct in6_addr *token = data;
983 int r;
984
985 assert(filename);
986 assert(lvalue);
987 assert(rvalue);
988 assert(token);
989
990 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
991 if (r < 0) {
ab24039f
ZJS
992 log_syntax(unit, LOG_ERR, filename, line, r,
993 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
994 return 0;
995 }
996
c606db69 997 if (in_addr_is_null(AF_INET6, &buffer)) {
ab24039f
ZJS
998 log_syntax(unit, LOG_ERR, filename, line, 0,
999 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
1000 return 0;
1001 }
1002
1003 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
ab24039f
ZJS
1004 log_syntax(unit, LOG_ERR, filename, line, 0,
1005 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
1006 return 0;
1007 }
1008
1009 *token = buffer.in6;
1010
1011 return 0;
1012}
8add5f79 1013
49092e22 1014static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
1015 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
1016 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
1017 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
1018};
1019
b146ad71
YW
1020DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
1021 IPV6_PRIVACY_EXTENSIONS_YES);
49092e22
SS
1022
1023int config_parse_ipv6_privacy_extensions(
1024 const char* unit,
1025 const char *filename,
1026 unsigned line,
1027 const char *section,
1028 unsigned section_line,
1029 const char *lvalue,
1030 int ltype,
1031 const char *rvalue,
1032 void *data,
1033 void *userdata) {
1034
b146ad71 1035 IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
49092e22
SS
1036
1037 assert(filename);
1038 assert(lvalue);
1039 assert(rvalue);
1040 assert(ipv6_privacy_extensions);
1041
b146ad71
YW
1042 s = ipv6_privacy_extensions_from_string(rvalue);
1043 if (s < 0) {
1044 if (streq(rvalue, "kernel"))
1045 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
1046 else {
1047 log_syntax(unit, LOG_ERR, filename, line, 0,
1048 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1049 return 0;
49092e22 1050 }
49092e22
SS
1051 }
1052
b146ad71
YW
1053 *ipv6_privacy_extensions = s;
1054
49092e22
SS
1055 return 0;
1056}
a7d0ef44 1057
1ac608c9
LP
1058int config_parse_hostname(
1059 const char *unit,
1060 const char *filename,
1061 unsigned line,
1062 const char *section,
1063 unsigned section_line,
1064 const char *lvalue,
1065 int ltype,
1066 const char *rvalue,
1067 void *data,
1068 void *userdata) {
1069
6528693a
YW
1070 _cleanup_free_ char *hn = NULL;
1071 char **hostname = data;
a7d0ef44
SS
1072 int r;
1073
1074 assert(filename);
1075 assert(lvalue);
1076 assert(rvalue);
1077
1ac608c9 1078 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
1079 if (r < 0)
1080 return r;
1081
1ac608c9 1082 if (!hostname_is_valid(hn, false)) {
ab24039f
ZJS
1083 log_syntax(unit, LOG_ERR, filename, line, 0,
1084 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
1085 return 0;
1086 }
1087
6528693a
YW
1088 r = dns_name_is_valid(hn);
1089 if (r < 0) {
ab24039f
ZJS
1090 log_syntax(unit, LOG_ERR, filename, line, r,
1091 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
1092 return 0;
1093 }
1094 if (r == 0) {
ab24039f
ZJS
1095 log_syntax(unit, LOG_ERR, filename, line, 0,
1096 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
1097 return 0;
1098 }
1099
1100 return free_and_replace(*hostname, hn);
a7d0ef44 1101}
8eb9058d
LP
1102
1103int config_parse_timezone(
1104 const char *unit,
1105 const char *filename,
1106 unsigned line,
1107 const char *section,
1108 unsigned section_line,
1109 const char *lvalue,
1110 int ltype,
1111 const char *rvalue,
1112 void *data,
1113 void *userdata) {
1114
19f9e4e2
YW
1115 _cleanup_free_ char *tz = NULL;
1116 char **datap = data;
8eb9058d
LP
1117 int r;
1118
1119 assert(filename);
1120 assert(lvalue);
1121 assert(rvalue);
1122
1123 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1124 if (r < 0)
1125 return r;
1126
089fb865 1127 if (!timezone_is_valid(tz, LOG_ERR)) {
ab24039f
ZJS
1128 log_syntax(unit, LOG_ERR, filename, line, 0,
1129 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1130 return 0;
1131 }
1132
19f9e4e2 1133 return free_and_replace(*datap, tz);
8eb9058d 1134}
1a04db0f 1135
53253824
SS
1136int config_parse_dns(
1137 const char *unit,
1138 const char *filename,
1139 unsigned line,
1140 const char *section,
1141 unsigned section_line,
1142 const char *lvalue,
1143 int ltype,
1144 const char *rvalue,
1145 void *data,
1146 void *userdata) {
1147
1148 Network *n = userdata;
1149 int r;
1150
1151 assert(filename);
1152 assert(lvalue);
1153 assert(rvalue);
1154
1155 for (;;) {
1156 _cleanup_free_ char *w = NULL;
1157 union in_addr_union a;
5512a963 1158 struct in_addr_data *m;
53253824
SS
1159 int family;
1160
5512a963 1161 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1162 if (r == -ENOMEM)
1163 return log_oom();
1164 if (r < 0) {
ab24039f
ZJS
1165 log_syntax(unit, LOG_ERR, filename, line, r,
1166 "Invalid syntax, ignoring: %s", rvalue);
53253824
SS
1167 break;
1168 }
5512a963
LP
1169 if (r == 0)
1170 break;
53253824
SS
1171
1172 r = in_addr_from_string_auto(w, &family, &a);
1173 if (r < 0) {
ab24039f
ZJS
1174 log_syntax(unit, LOG_ERR, filename, line, r,
1175 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1176 continue;
1177 }
1178
62d74c78 1179 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1180 if (!m)
53253824
SS
1181 return log_oom();
1182
5512a963
LP
1183 m[n->n_dns++] = (struct in_addr_data) {
1184 .family = family,
1185 .address = a,
1186 };
1187
1188 n->dns = m;
53253824
SS
1189 }
1190
1191 return 0;
1192}
1193
8a516214
LP
1194int config_parse_dnssec_negative_trust_anchors(
1195 const char *unit,
1196 const char *filename,
1197 unsigned line,
1198 const char *section,
1199 unsigned section_line,
1200 const char *lvalue,
1201 int ltype,
1202 const char *rvalue,
1203 void *data,
1204 void *userdata) {
1205
1206 const char *p = rvalue;
1207 Network *n = data;
1208 int r;
1209
3df9bec5 1210 assert(n);
8a516214
LP
1211 assert(lvalue);
1212 assert(rvalue);
1213
1214 if (isempty(rvalue)) {
1215 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1216 return 0;
1217 }
1218
1219 for (;;) {
1220 _cleanup_free_ char *w = NULL;
1221
1222 r = extract_first_word(&p, &w, NULL, 0);
1223 if (r < 0) {
ab24039f
ZJS
1224 log_syntax(unit, LOG_ERR, filename, line, r,
1225 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
8a516214
LP
1226 break;
1227 }
1228 if (r == 0)
1229 break;
1230
1231 r = dns_name_is_valid(w);
1232 if (r <= 0) {
ab24039f
ZJS
1233 log_syntax(unit, LOG_ERR, filename, line, r,
1234 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1235 continue;
1236 }
1237
cbbf38ae
LP
1238 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1239 if (r < 0)
1240 return log_oom();
1241
8a516214
LP
1242 r = set_put(n->dnssec_negative_trust_anchors, w);
1243 if (r < 0)
1244 return log_oom();
1245 if (r > 0)
1246 w = NULL;
1247 }
1248
1249 return 0;
1250}
b2a81c0b 1251
26575990
LP
1252int config_parse_ntp(
1253 const char *unit,
1254 const char *filename,
1255 unsigned line,
1256 const char *section,
1257 unsigned section_line,
1258 const char *lvalue,
1259 int ltype,
1260 const char *rvalue,
1261 void *data,
1262 void *userdata) {
1263
1264 char ***l = data;
1265 int r;
1266
1267 assert(l);
1268 assert(lvalue);
1269 assert(rvalue);
1270
1271 if (isempty(rvalue)) {
1272 *l = strv_free(*l);
1273 return 0;
1274 }
1275
1276 for (;;) {
1277 _cleanup_free_ char *w = NULL;
1278
1279 r = extract_first_word(&rvalue, &w, NULL, 0);
1280 if (r == -ENOMEM)
1281 return log_oom();
1282 if (r < 0) {
ab24039f
ZJS
1283 log_syntax(unit, LOG_ERR, filename, line, r,
1284 "Failed to extract NTP server name, ignoring: %s", rvalue);
26575990
LP
1285 break;
1286 }
1287 if (r == 0)
1288 break;
1289
1290 r = dns_name_is_valid_or_address(w);
1291 if (r <= 0) {
ab24039f
ZJS
1292 log_syntax(unit, LOG_ERR, filename, line, r,
1293 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1294 continue;
af1c0de0
SS
1295 }
1296
c448459d
ZJS
1297 if (strv_length(*l) > MAX_NTP_SERVERS) {
1298 log_syntax(unit, LOG_WARNING, filename, line, 0,
1299 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1300 MAX_NTP_SERVERS, w);
1301 break;
1302 }
1303
1304 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1305 if (r < 0)
1306 return log_oom();
af1c0de0
SS
1307 }
1308
1309 return 0;
1310}
1311
4ac77d63
YW
1312int config_parse_required_for_online(
1313 const char *unit,
1314 const char *filename,
1315 unsigned line,
1316 const char *section,
1317 unsigned section_line,
1318 const char *lvalue,
1319 int ltype,
1320 const char *rvalue,
1321 void *data,
1322 void *userdata) {
1323
1324 Network *network = data;
75cd4a5d 1325 LinkOperationalStateRange range;
4ac77d63
YW
1326 bool required = true;
1327 int r;
1328
1329 if (isempty(rvalue)) {
1330 network->required_for_online = true;
75cd4a5d 1331 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1332 return 0;
1333 }
1334
75cd4a5d
DDM
1335 r = parse_operational_state_range(rvalue, &range);
1336 if (r < 0) {
4ac77d63
YW
1337 r = parse_boolean(rvalue);
1338 if (r < 0) {
1339 log_syntax(unit, LOG_ERR, filename, line, r,
1340 "Failed to parse %s= setting, ignoring assignment: %s",
1341 lvalue, rvalue);
1342 return 0;
1343 }
1344
1345 required = r;
75cd4a5d 1346 range = LINK_OPERSTATE_RANGE_DEFAULT;
4ac77d63
YW
1347 }
1348
1349 network->required_for_online = required;
75cd4a5d 1350 network->required_operstate_for_online = range;
4ac77d63
YW
1351
1352 return 0;
1353}
7da377ef
SS
1354
1355DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1356 "Failed to parse KeepConfiguration= setting");
1357
1358static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1359 [KEEP_CONFIGURATION_NO] = "no",
1360 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1361 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1362 [KEEP_CONFIGURATION_STATIC] = "static",
1363 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1364};
1365
1366DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);