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