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