]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
networkd: manager do not unef netlink and gennetlink early
[thirdparty/systemd.git] / src / network / networkd-network.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f579559b 2
01234e1f 3#include <linux/netdevice.h>
69a93e7d 4
b5efdb8a 5#include "alloc-util.h"
f579559b
TG
6#include "conf-files.h"
7#include "conf-parser.h"
37de2509 8#include "dns-domain.h"
3ffd4af2 9#include "fd-util.h"
07630cea 10#include "hostname-util.h"
88295a05 11#include "in-addr-util.h"
fc2f9534 12#include "network-internal.h"
23f53b99 13#include "networkd-manager.h"
3ffd4af2 14#include "networkd-network.h"
6bedfcbb 15#include "parse-util.h"
8a516214 16#include "set.h"
cebe1257 17#include "socket-util.h"
8fcde012 18#include "stat-util.h"
8b43440b 19#include "string-table.h"
07630cea 20#include "string-util.h"
700f1186 21#include "strv.h"
07630cea 22#include "util.h"
f579559b 23
c448459d
ZJS
24/* Let's assume that anything above this number is a user misconfiguration. */
25#define MAX_NTP_SERVERS 128
26
add8d07d 27/* Set defaults following RFC7844 */
28void network_apply_anonymize_if_set(Network *network) {
29 if (!network->dhcp_anonymize)
30 return;
31 /* RFC7844 3.7
32 SHOULD NOT send the Host Name option */
33 network->dhcp_send_hostname = false;
34 /* RFC7844 section 3.:
35 MAY contain the Client Identifier option
36 Section 3.5:
37 clients MUST use client identifiers based solely
38 on the link-layer address */
39 /* NOTE: Using MAC, as it does not reveal extra information,
40 * and some servers might not answer if this option is not sent */
41 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
42 /* RFC 7844 3.10:
43 SHOULD NOT use the Vendor Class Identifier option */
727ba17f 44 network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
add8d07d 45 /* RFC7844 section 3.6.:
46 The client intending to protect its privacy SHOULD only request a
47 minimal number of options in the PRL and SHOULD also randomly shuffle
48 the ordering of option codes in the PRL. If this random ordering
49 cannot be implemented, the client MAY order the option codes in the
50 PRL by option code number (lowest to highest).
51 */
52 /* NOTE: dhcp_use_mtu is false by default,
53 * though it was not initiallized to any value in network_load_one.
54 * Maybe there should be another var called *send*?
55 * (to use the MTU sent by the server but to do not send
56 * the option in the PRL). */
57 network->dhcp_use_mtu = false;
28522b0d 58 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
59 * but this is needed to use them. */
60 network->dhcp_use_routes = true;
add8d07d 61 /* RFC7844 section 3.6.
62 * same comments as previous option */
63 network->dhcp_use_timezone = false;
64}
65
cebe1257
YW
66static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) {
67 const char *kind_string;
68 NetDev *netdev;
69 int r;
70
96db6412
YW
71 /* For test-networkd-conf, the check must be earlier than the assertions. */
72 if (!name)
73 return 0;
74
cebe1257
YW
75 assert(network);
76 assert(network->manager);
77 assert(network->filename);
78 assert(ret_netdev);
79
cebe1257
YW
80 if (kind == _NETDEV_KIND_TUNNEL)
81 kind_string = "tunnel";
82 else {
83 kind_string = netdev_kind_to_string(kind);
84 if (!kind_string)
85 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
86 "%s: Invalid NetDev kind of %s, ignoring assignment.",
87 network->filename, name);
88 }
89
90 r = netdev_get(network->manager, name, &netdev);
91 if (r < 0)
92 return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
93 network->filename, name);
94
95 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
96 IN_SET(netdev->kind,
97 NETDEV_KIND_IPIP,
98 NETDEV_KIND_SIT,
99 NETDEV_KIND_GRE,
100 NETDEV_KIND_GRETAP,
101 NETDEV_KIND_IP6GRE,
102 NETDEV_KIND_IP6GRETAP,
103 NETDEV_KIND_VTI,
104 NETDEV_KIND_VTI6,
9282f75b
YW
105 NETDEV_KIND_IP6TNL,
106 NETDEV_KIND_ERSPAN)))
cebe1257
YW
107 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
108 "%s: NetDev %s is not a %s, ignoring assignment",
109 network->filename, name, kind_string);
110
111 *ret_netdev = netdev_ref(netdev);
112 return 1;
113}
114
115static int network_resolve_stacked_netdevs(Network *network) {
116 void *name, *kind;
117 Iterator i;
118 int r;
119
120 assert(network);
121
122 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names, i) {
123 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
124
125 r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev);
126 if (r <= 0)
127 continue;
128
129 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
130 if (r < 0)
131 return log_oom();
132
133 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
134 if (r < 0)
135 return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m",
136 network->filename, (const char *) name);
137
138 netdev = NULL;
139 }
140
141 return 0;
142}
143
40288ece
YW
144static uint32_t network_get_stacked_netdevs_mtu(Network *network) {
145 uint32_t mtu = 0;
146 NetDev *dev;
147 Iterator i;
148
149 HASHMAP_FOREACH(dev, network->stacked_netdevs, i)
150 if (dev->kind == NETDEV_KIND_VLAN && dev->mtu > 0)
151 /* See vlan_dev_change_mtu() in kernel.
152 * Note that the additional 4bytes may not be necessary for all devices. */
153 mtu = MAX(mtu, dev->mtu + 4);
154
155 else if (dev->kind == NETDEV_KIND_MACVLAN && dev->mtu > mtu)
156 /* See macvlan_change_mtu() in kernel. */
157 mtu = dev->mtu;
158
159 return mtu;
160}
161
96db6412 162int network_verify(Network *network) {
4bec2f23
YW
163 Address *address, *address_next;
164 Route *route, *route_next;
fcbf4cb7
YW
165 FdbEntry *fdb, *fdb_next;
166 Neighbor *neighbor, *neighbor_next;
167 AddressLabel *label, *label_next;
168 Prefix *prefix, *prefix_next;
169 RoutingPolicyRule *rule, *rule_next;
40288ece 170 uint32_t mtu;
0321cea7
YW
171
172 assert(network);
173 assert(network->filename);
174
84ea567e
YW
175 if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
176 strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
177 strv_isempty(network->match_name) && !network->conditions)
178 log_warning("%s: No valid settings found in the [Match] section. "
179 "The file will match all interfaces. "
180 "If that is intended, please add Name=* in the [Match] section.",
181 network->filename);
182
cebe1257 183 /* skip out early if configuration does not match the environment */
c4f58dea 184 if (!condition_test_list(network->conditions, NULL, NULL, NULL))
cebe1257 185 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
3772cfde
ZJS
186 "%s: Conditions in the file do not match the system environment, skipping.",
187 network->filename);
cebe1257
YW
188
189 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
190 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
191 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
192 (void) network_resolve_stacked_netdevs(network);
193
194 /* Free unnecessary entries. */
195 network->bond_name = mfree(network->bond_name);
196 network->bridge_name = mfree(network->bridge_name);
197 network->vrf_name = mfree(network->vrf_name);
198 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
199
0321cea7
YW
200 if (network->bond) {
201 /* Bonding slave does not support addressing. */
202 if (network->ipv6_accept_ra > 0) {
ab24039f
ZJS
203 log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
204 network->filename);
0321cea7
YW
205 network->ipv6_accept_ra = 0;
206 }
207 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
208 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
209 network->filename);
0321cea7
YW
210 network->link_local = ADDRESS_FAMILY_NO;
211 }
212 if (network->dhcp != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
213 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
214 network->filename);
0321cea7
YW
215 network->dhcp = ADDRESS_FAMILY_NO;
216 }
217 if (network->dhcp_server) {
ab24039f
ZJS
218 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
219 network->filename);
0321cea7
YW
220 network->dhcp_server = false;
221 }
222 if (network->n_static_addresses > 0) {
ab24039f
ZJS
223 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
224 network->filename);
0321cea7
YW
225 while ((address = network->static_addresses))
226 address_free(address);
227 }
228 if (network->n_static_routes > 0) {
ab24039f
ZJS
229 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
230 network->filename);
0321cea7
YW
231 while ((route = network->static_routes))
232 route_free(route);
233 }
234 }
235
236 if (network->link_local < 0)
8f191801
YW
237 network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
238
29e81083
YW
239 if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
240 !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
241 log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
242 "Disabling the fallback assignment.", network->filename);
243 SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
244 }
245
8f191801
YW
246 if (network->ipv6_accept_ra < 0 && network->bridge)
247 network->ipv6_accept_ra = false;
0321cea7
YW
248
249 /* IPMasquerade=yes implies IPForward=yes */
250 if (network->ip_masquerade)
251 network->ip_forward |= ADDRESS_FAMILY_IPV4;
252
40288ece
YW
253 network->mtu_is_set = network->mtu > 0;
254 mtu = network_get_stacked_netdevs_mtu(network);
255 if (network->mtu < mtu) {
256 if (network->mtu_is_set)
257 log_notice("%s: Bumping MTUBytes= from %"PRIu32" to %"PRIu32" because of stacked device",
258 network->filename, network->mtu, mtu);
259 network->mtu = mtu;
260 }
261
262 if (network->mtu_is_set && 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
4bec2f23 268 LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
fcbf4cb7 269 if (address_section_verify(address) < 0)
4bec2f23 270 address_free(address);
4bec2f23 271
fcbf4cb7
YW
272 LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
273 if (route_section_verify(route, network) < 0)
4bec2f23 274 route_free(route);
0321cea7 275
fcbf4cb7
YW
276 LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
277 if (section_is_invalid(fdb->section))
278 fdb_entry_free(fdb);
279
280 LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
281 if (section_is_invalid(neighbor->section))
282 neighbor_free(neighbor);
283
284 LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
285 if (section_is_invalid(label->section))
286 address_label_free(label);
287
288 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
289 if (section_is_invalid(prefix->section))
290 prefix_free(prefix);
291
292 LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
293 if (section_is_invalid(rule->section))
294 routing_policy_rule_free(rule);
4912ab77 295
0321cea7
YW
296 return 0;
297}
298
212bd73c 299int network_load_one(Manager *manager, const char *filename) {
838b2f7a 300 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 301 _cleanup_(network_unrefp) Network *network = NULL;
f579559b 302 _cleanup_fclose_ FILE *file = NULL;
047a0dac 303 const char *dropin_dirname;
838b2f7a 304 char *d;
f579559b
TG
305 int r;
306
bf1bc670
TA
307 assert(manager);
308 assert(filename);
309
f579559b
TG
310 file = fopen(filename, "re");
311 if (!file) {
312 if (errno == ENOENT)
313 return 0;
1e7a0e21
LP
314
315 return -errno;
f579559b
TG
316 }
317
ed88bcfb
ZJS
318 if (null_or_empty_fd(fileno(file))) {
319 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
320 return 0;
321 }
322
838b2f7a
YW
323 fname = strdup(filename);
324 if (!fname)
325 return log_oom();
326
327 name = strdup(basename(filename));
328 if (!name)
329 return log_oom();
330
331 d = strrchr(name, '.');
332 if (!d)
333 return -EINVAL;
334
335 *d = '\0';
336
337 dropin_dirname = strjoina(name, ".network.d");
338
17f9c355 339 network = new(Network, 1);
f579559b
TG
340 if (!network)
341 return log_oom();
342
17f9c355 343 *network = (Network) {
838b2f7a
YW
344 .filename = TAKE_PTR(fname),
345 .name = TAKE_PTR(name),
17f9c355 346
35ac3b76
YW
347 .n_ref = 1,
348
17f9c355 349 .required_for_online = true,
4ac77d63 350 .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
17f9c355
YW
351 .dhcp = ADDRESS_FAMILY_NO,
352 .dhcp_use_ntp = true,
353 .dhcp_use_dns = true,
354 .dhcp_use_hostname = true,
355 .dhcp_use_routes = true,
5238e957 356 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
357 .dhcp_send_hostname = true,
358 /* To enable/disable RFC7844 Anonymity Profiles */
359 .dhcp_anonymize = false,
360 .dhcp_route_metric = DHCP_ROUTE_METRIC,
c9c908a6 361 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
362 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
363 .dhcp_route_table = RT_TABLE_MAIN,
364 .dhcp_route_table_set = false,
365 /* NOTE: from man: UseMTU=... Defaults to false*/
366 .dhcp_use_mtu = false,
367 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
368 .dhcp_use_timezone = false,
369 .rapid_commit = true,
370
371 .dhcp_server_emit_dns = true,
372 .dhcp_server_emit_ntp = true,
373 .dhcp_server_emit_router = true,
374 .dhcp_server_emit_timezone = true,
375
376 .router_emit_dns = true,
377 .router_emit_domains = true,
378
379 .use_bpdu = -1,
380 .hairpin = -1,
381 .fast_leave = -1,
382 .allow_port_to_be_root = -1,
383 .unicast_flood = -1,
7f15b714 384 .multicast_flood = -1,
d3aa8b49 385 .multicast_to_unicast = -1,
7f15b714
TJ
386 .neighbor_suppression = -1,
387 .learning = -1,
17f9c355
YW
388 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
389
390 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
391
7ece6f58 392 .dns_default_route = -1,
17f9c355
YW
393 .llmnr = RESOLVE_SUPPORT_YES,
394 .mdns = RESOLVE_SUPPORT_NO,
395 .dnssec_mode = _DNSSEC_MODE_INVALID,
396 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
397
0321cea7
YW
398 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
399 .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID,
17f9c355
YW
400
401 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
402 .ipv6_accept_ra = -1,
403 .ipv6_dad_transmits = -1,
404 .ipv6_hop_limit = -1,
405 .ipv6_proxy_ndp = -1,
406 .duid.type = _DUID_TYPE_INVALID,
407 .proxy_arp = -1,
408 .arp = -1,
409 .multicast = -1,
410 .allmulticast = -1,
411 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
412 .ipv6_accept_ra_use_autonomous_prefix = true,
413 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 414 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 415 .ipv6_accept_ra_route_table_set = false,
c423be28
CG
416
417 .can_triple_sampling = -1,
17f9c355 418 };
f579559b 419
dc0d4078 420 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
23bb31aa
ZJS
421 "Match\0"
422 "Link\0"
423 "Network\0"
424 "Address\0"
e4a71bf3 425 "Neighbor\0"
95b74ef6 426 "IPv6AddressLabel\0"
bce67bbe 427 "RoutingPolicyRule\0"
23bb31aa
ZJS
428 "Route\0"
429 "DHCP\0"
430 "DHCPv4\0" /* compat */
431 "DHCPServer\0"
432 "IPv6AcceptRA\0"
a0e5c15d 433 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
434 "Bridge\0"
435 "BridgeFDB\0"
9d5d0090 436 "BridgeVLAN\0"
7d5cac19 437 "IPv6PrefixDelegation\0"
06828bb6
HP
438 "IPv6Prefix\0"
439 "CAN\0",
23bb31aa 440 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 441 CONFIG_PARSE_WARN, network);
102bc043 442 if (r < 0)
f579559b 443 return r;
f579559b 444
add8d07d 445 network_apply_anonymize_if_set(network);
446
fa7cd711
YW
447 r = network_add_ipv4ll_route(network);
448 if (r < 0)
449 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
450
f579559b 451 LIST_PREPEND(networks, manager->networks, network);
102bc043 452 network->manager = manager;
b3070dc0 453
dbffab87
TG
454 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
455 if (r < 0)
456 return r;
457
458 r = hashmap_put(manager->networks_by_name, network->name, network);
459 if (r < 0)
460 return r;
461
0321cea7
YW
462 if (network_verify(network) < 0)
463 return 0;
b3070dc0 464
f579559b 465 network = NULL;
f579559b
TG
466 return 0;
467}
468
469int network_load(Manager *manager) {
470 Network *network;
477e73b5
ZJS
471 _cleanup_strv_free_ char **files = NULL;
472 char **f;
f579559b
TG
473 int r;
474
475 assert(manager);
476
477 while ((network = manager->networks))
35ac3b76 478 network_unref(network);
f579559b 479
dc0d4078 480 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
481 if (r < 0)
482 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b
TG
483
484 STRV_FOREACH_BACKWARDS(f, files) {
485 r = network_load_one(manager, *f);
486 if (r < 0)
487 return r;
488 }
489
f579559b
TG
490 return 0;
491}
492
35ac3b76 493static Network *network_free(Network *network) {
a0e5c15d 494 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
495 RoutingPolicyRule *rule;
496 FdbEntry *fdb_entry;
e4a71bf3 497 Neighbor *neighbor;
95b74ef6 498 AddressLabel *label;
057abfd8 499 Prefix *prefix;
bce67bbe 500 Address *address;
bce67bbe 501 Route *route;
f579559b
TG
502
503 if (!network)
35ac3b76 504 return NULL;
f579559b
TG
505
506 free(network->filename);
507
e90d0374 508 set_free_free(network->match_mac);
5256e00e
TG
509 strv_free(network->match_path);
510 strv_free(network->match_driver);
511 strv_free(network->match_type);
512 strv_free(network->match_name);
c4f58dea 513 condition_free_list(network->conditions);
f579559b
TG
514
515 free(network->description);
edb85f0d 516 free(network->dhcp_vendor_class_identifier);
af1c0de0 517 strv_free(network->dhcp_user_class);
27cb34f5 518 free(network->dhcp_hostname);
f579559b 519
c106cc36
TG
520 free(network->mac);
521
b0e39c82 522 strv_free(network->ntp);
5512a963 523 free(network->dns);
5e2a51d5
ZJS
524 ordered_set_free_free(network->search_domains);
525 ordered_set_free_free(network->route_domains);
0d4ad91d 526 strv_free(network->bind_carrier);
cdd7812b 527
5e2a51d5 528 ordered_set_free_free(network->router_search_domains);
cdd7812b 529 free(network->router_dns);
3bef724f 530
cebe1257
YW
531 free(network->bridge_name);
532 free(network->bond_name);
533 free(network->vrf_name);
534 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 535 netdev_unref(network->bridge);
47e2dc31 536 netdev_unref(network->bond);
6cb955c6 537 netdev_unref(network->vrf);
fa6f1e54 538 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 539
f048a16b 540 while ((route = network->static_routes))
f579559b
TG
541 route_free(route);
542
f048a16b 543 while ((address = network->static_addresses))
f579559b
TG
544 address_free(address);
545
b98b483b
AR
546 while ((fdb_entry = network->static_fdb_entries))
547 fdb_entry_free(fdb_entry);
548
a0e5c15d
FK
549 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
550 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
551
e4a71bf3
WKI
552 while ((neighbor = network->neighbors))
553 neighbor_free(neighbor);
554
95b74ef6
SS
555 while ((label = network->address_labels))
556 address_label_free(label);
557
057abfd8
PF
558 while ((prefix = network->static_prefixes))
559 prefix_free(prefix);
560
bce67bbe
SS
561 while ((rule = network->rules))
562 routing_policy_rule_free(rule);
563
6ae115c1
TG
564 hashmap_free(network->addresses_by_section);
565 hashmap_free(network->routes_by_section);
b98b483b 566 hashmap_free(network->fdb_entries_by_section);
e4a71bf3 567 hashmap_free(network->neighbors_by_section);
95b74ef6 568 hashmap_free(network->address_labels_by_section);
057abfd8 569 hashmap_free(network->prefixes_by_section);
bce67bbe 570 hashmap_free(network->rules_by_section);
6ae115c1 571
dbffab87
TG
572 if (network->manager) {
573 if (network->manager->networks)
574 LIST_REMOVE(networks, network->manager->networks, network);
575
e512c6c1 576 if (network->manager->networks_by_name && network->name)
dbffab87 577 hashmap_remove(network->manager->networks_by_name, network->name);
27dfc982
YW
578
579 if (network->manager->duids_requesting_uuid)
580 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
581 }
582
583 free(network->name);
f579559b 584
8eb9058d 585 free(network->dhcp_server_timezone);
1a04db0f
LP
586 free(network->dhcp_server_dns);
587 free(network->dhcp_server_ntp);
8eb9058d 588
8a516214
LP
589 set_free_free(network->dnssec_negative_trust_anchors);
590
35ac3b76 591 return mfree(network);
f579559b
TG
592}
593
35ac3b76
YW
594DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
595
dbffab87
TG
596int network_get_by_name(Manager *manager, const char *name, Network **ret) {
597 Network *network;
598
599 assert(manager);
600 assert(name);
601 assert(ret);
602
603 network = hashmap_get(manager->networks_by_name, name);
604 if (!network)
605 return -ENOENT;
606
607 *ret = network;
608
609 return 0;
610}
611
51517f9e 612int network_get(Manager *manager, sd_device *device,
505f8da7
TG
613 const char *ifname, const struct ether_addr *address,
614 Network **ret) {
4f4daf41 615 const char *path = NULL, *driver = NULL, *devtype = NULL;
51517f9e 616 Network *network;
f579559b
TG
617
618 assert(manager);
f579559b 619 assert(ret);
af3aa302 620
24c083df 621 if (device) {
51517f9e 622 (void) sd_device_get_property_value(device, "ID_PATH", &path);
af3aa302 623
51517f9e 624 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
af3aa302 625
51517f9e 626 (void) sd_device_get_devtype(device, &devtype);
24c083df 627 }
f579559b 628
f579559b
TG
629 LIST_FOREACH(networks, network, manager->networks) {
630 if (net_match_config(network->match_mac, network->match_path,
505f8da7 631 network->match_driver, network->match_type,
c4f58dea 632 network->match_name,
4f4daf41 633 address, path, driver, devtype, ifname)) {
24c083df 634 if (network->match_name && device) {
ca6038b8
TG
635 const char *attr;
636 uint8_t name_assign_type = NET_NAME_UNKNOWN;
637
51517f9e 638 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 639 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
640
641 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
642 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
643 ifname, network->filename);
32bc8adc 644 else
a2fae7bb 645 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 646 } else
a2fae7bb 647 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 648
f579559b
TG
649 *ret = network;
650 return 0;
651 }
652 }
653
654 *ret = NULL;
655
656 return -ENOENT;
657}
658
7d342c03 659int network_apply(Network *network, Link *link) {
c4a03a56
TG
660 assert(network);
661 assert(link);
662
c9c908a6 663 link->network = network_ref(network);
f579559b 664
5512a963 665 if (network->n_dns > 0 ||
3df9bec5 666 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
667 !ordered_set_isempty(network->search_domains) ||
668 !ordered_set_isempty(network->route_domains))
84de38c5 669 link_dirty(link);
3bef724f 670
f579559b
TG
671 return 0;
672}
02b59d57 673
439689c6
SS
674bool network_has_static_ipv6_addresses(Network *network) {
675 Address *address;
676
677 assert(network);
678
679 LIST_FOREACH(addresses, address, network->static_addresses) {
680 if (address->family == AF_INET6)
681 return true;
682 }
683
684 return false;
685}
686
cebe1257 687int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
688 const char *filename,
689 unsigned line,
690 const char *section,
691 unsigned section_line,
692 const char *lvalue,
693 int ltype,
694 const char *rvalue,
695 void *data,
696 void *userdata) {
95dba435
YW
697 _cleanup_free_ char *name = NULL;
698 NetDevKind kind = ltype;
cebe1257 699 Hashmap **h = data;
02b59d57
TG
700 int r;
701
702 assert(filename);
703 assert(lvalue);
704 assert(rvalue);
705 assert(data);
95dba435
YW
706 assert(IN_SET(kind,
707 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
3a56e697 708 NETDEV_KIND_IPVLAN, NETDEV_KIND_VXLAN, NETDEV_KIND_L2TP,
81962db7 709 NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL));
54abf461 710
cebe1257 711 if (!ifname_valid(rvalue)) {
3772cfde
ZJS
712 log_syntax(unit, LOG_ERR, filename, line, 0,
713 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
714 return 0;
715 }
716
cebe1257
YW
717 name = strdup(rvalue);
718 if (!name)
719 return log_oom();
3e570042 720
cebe1257
YW
721 r = hashmap_ensure_allocated(h, &string_hash_ops);
722 if (r < 0)
723 return log_oom();
326cb406 724
cebe1257 725 r = hashmap_put(*h, name, INT_TO_PTR(kind));
83ec4592 726 if (r < 0)
3772cfde 727 log_syntax(unit, LOG_ERR, filename, line, r,
83ec4592
ZJS
728 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
729 else if (r == 0)
730 log_syntax(unit, LOG_DEBUG, filename, line, r,
731 "NetDev '%s' specified twice, ignoring.", name);
732 else
733 name = NULL;
47e2dc31 734
fe6b2d55
TG
735 return 0;
736}
7951dea2 737
3df9bec5
LP
738int config_parse_domains(
739 const char *unit,
740 const char *filename,
741 unsigned line,
742 const char *section,
743 unsigned section_line,
744 const char *lvalue,
745 int ltype,
746 const char *rvalue,
747 void *data,
748 void *userdata) {
749
750 const char *p;
751 Network *n = data;
6192b846
TG
752 int r;
753
3df9bec5
LP
754 assert(n);
755 assert(lvalue);
756 assert(rvalue);
6192b846 757
3df9bec5 758 if (isempty(rvalue)) {
5e2a51d5
ZJS
759 n->search_domains = ordered_set_free_free(n->search_domains);
760 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
761 return 0;
762 }
67272d15 763
3df9bec5
LP
764 p = rvalue;
765 for (;;) {
766 _cleanup_free_ char *w = NULL, *normalized = NULL;
767 const char *domain;
768 bool is_route;
769
770 r = extract_first_word(&p, &w, NULL, 0);
771 if (r < 0) {
ab24039f
ZJS
772 log_syntax(unit, LOG_ERR, filename, line, r,
773 "Failed to extract search or route domain, ignoring: %s", rvalue);
3df9bec5
LP
774 break;
775 }
776 if (r == 0)
777 break;
778
779 is_route = w[0] == '~';
780 domain = is_route ? w + 1 : w;
781
782 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
783 /* If the root domain appears as is, or the special token "*" is found, we'll
784 * consider this as routing domain, unconditionally. */
3df9bec5 785 is_route = true;
ab24039f
ZJS
786 domain = "."; /* make sure we don't allow empty strings, thus write the root
787 * domain as "." */
3df9bec5 788 } else {
7470cc4c 789 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 790 if (r < 0) {
ab24039f
ZJS
791 log_syntax(unit, LOG_ERR, filename, line, r,
792 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
793 continue;
794 }
795
796 domain = normalized;
797
798 if (is_localhost(domain)) {
ab24039f
ZJS
799 log_syntax(unit, LOG_ERR, filename, line, 0,
800 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
801 domain);
37de2509 802 continue;
3df9bec5 803 }
37de2509 804 }
40274ed6 805
5e2a51d5
ZJS
806 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
807 r = ordered_set_ensure_allocated(set, &string_hash_ops);
808 if (r < 0)
809 return r;
810
811 r = ordered_set_put_strdup(*set, domain);
09451975
LP
812 if (r < 0)
813 return log_oom();
40274ed6 814 }
f15b6e5a 815
6192b846
TG
816 return 0;
817}
818
d0d6a4cd
TG
819int config_parse_ipv4ll(
820 const char* unit,
821 const char *filename,
822 unsigned line,
823 const char *section,
824 unsigned section_line,
825 const char *lvalue,
826 int ltype,
827 const char *rvalue,
828 void *data,
829 void *userdata) {
830
831 AddressFamilyBoolean *link_local = data;
810ae0dc 832 int r;
d0d6a4cd
TG
833
834 assert(filename);
835 assert(lvalue);
836 assert(rvalue);
837 assert(data);
838
839 /* Note that this is mostly like
840 * config_parse_address_family_boolean(), except that it
841 * applies only to IPv4 */
842
810ae0dc
YW
843 r = parse_boolean(rvalue);
844 if (r < 0) {
845 log_syntax(unit, LOG_ERR, filename, line, r,
846 "Failed to parse %s=%s, ignoring assignment. "
847 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
848 lvalue, rvalue, lvalue);
849 return 0;
850 }
851
852 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
853
854 log_syntax(unit, LOG_WARNING, filename, line, 0,
855 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
856 lvalue, rvalue, address_family_boolean_to_string(*link_local));
d0d6a4cd
TG
857
858 return 0;
859}
860
bd8f6538
TG
861int config_parse_dhcp(
862 const char* unit,
863 const char *filename,
864 unsigned line,
865 const char *section,
866 unsigned section_line,
867 const char *lvalue,
868 int ltype,
869 const char *rvalue,
870 void *data,
871 void *userdata) {
872
cb9fc36a 873 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
874
875 assert(filename);
876 assert(lvalue);
877 assert(rvalue);
878 assert(data);
879
769d324c
LP
880 /* Note that this is mostly like
881 * config_parse_address_family_boolean(), except that it
882 * understands some old names for the enum values */
883
cb9fc36a
LP
884 s = address_family_boolean_from_string(rvalue);
885 if (s < 0) {
886
887 /* Previously, we had a slightly different enum here,
5238e957 888 * support its values for compatibility. */
cb9fc36a
LP
889
890 if (streq(rvalue, "none"))
891 s = ADDRESS_FAMILY_NO;
892 else if (streq(rvalue, "v4"))
893 s = ADDRESS_FAMILY_IPV4;
894 else if (streq(rvalue, "v6"))
895 s = ADDRESS_FAMILY_IPV6;
896 else if (streq(rvalue, "both"))
897 s = ADDRESS_FAMILY_YES;
898 else {
ab24039f
ZJS
899 log_syntax(unit, LOG_ERR, filename, line, 0,
900 "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
901 return 0;
902 }
41f62acc
YW
903
904 log_syntax(unit, LOG_WARNING, filename, line, 0,
905 "DHCP=%s is deprecated, please use DHCP=%s instead.",
906 rvalue, address_family_boolean_to_string(s));
bd8f6538
TG
907 }
908
cb9fc36a 909 *dhcp = s;
bd8f6538
TG
910 return 0;
911}
912
3e43b2cd
JJ
913static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
914 [DHCP_CLIENT_ID_MAC] = "mac",
dace710c
YW
915 [DHCP_CLIENT_ID_DUID] = "duid",
916 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
3e43b2cd
JJ
917};
918
499d555a 919DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
ab24039f
ZJS
920DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
921 "Failed to parse client identifier type");
3e43b2cd 922
60c35566 923int config_parse_ipv6token(
7f77697a
TG
924 const char* unit,
925 const char *filename,
926 unsigned line,
927 const char *section,
928 unsigned section_line,
929 const char *lvalue,
930 int ltype,
931 const char *rvalue,
932 void *data,
933 void *userdata) {
934
935 union in_addr_union buffer;
936 struct in6_addr *token = data;
937 int r;
938
939 assert(filename);
940 assert(lvalue);
941 assert(rvalue);
942 assert(token);
943
944 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
945 if (r < 0) {
ab24039f
ZJS
946 log_syntax(unit, LOG_ERR, filename, line, r,
947 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
948 return 0;
949 }
950
c606db69 951 if (in_addr_is_null(AF_INET6, &buffer)) {
ab24039f
ZJS
952 log_syntax(unit, LOG_ERR, filename, line, 0,
953 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
954 return 0;
955 }
956
957 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
ab24039f
ZJS
958 log_syntax(unit, LOG_ERR, filename, line, 0,
959 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
960 return 0;
961 }
962
963 *token = buffer.in6;
964
965 return 0;
966}
8add5f79 967
49092e22 968static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
969 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
970 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
971 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
972};
973
974DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
975
976int config_parse_ipv6_privacy_extensions(
977 const char* unit,
978 const char *filename,
979 unsigned line,
980 const char *section,
981 unsigned section_line,
982 const char *lvalue,
983 int ltype,
984 const char *rvalue,
985 void *data,
986 void *userdata) {
987
988 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
989 int k;
990
991 assert(filename);
992 assert(lvalue);
993 assert(rvalue);
994 assert(ipv6_privacy_extensions);
995
996 /* Our enum shall be a superset of booleans, hence first try
997 * to parse as boolean, and then as enum */
998
999 k = parse_boolean(rvalue);
1000 if (k > 0)
1f0d9695 1001 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 1002 else if (k == 0)
1f0d9695 1003 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 1004 else {
1f0d9695 1005 IPv6PrivacyExtensions s;
49092e22
SS
1006
1007 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
1008 if (s < 0) {
1009
1010 if (streq(rvalue, "kernel"))
1011 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
1012 else {
ab24039f
ZJS
1013 log_syntax(unit, LOG_ERR, filename, line, 0,
1014 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1f0d9695
LP
1015 return 0;
1016 }
49092e22
SS
1017 }
1018
1019 *ipv6_privacy_extensions = s;
1020 }
1021
1022 return 0;
1023}
a7d0ef44 1024
1ac608c9
LP
1025int config_parse_hostname(
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
6528693a
YW
1037 _cleanup_free_ char *hn = NULL;
1038 char **hostname = data;
a7d0ef44
SS
1039 int r;
1040
1041 assert(filename);
1042 assert(lvalue);
1043 assert(rvalue);
1044
1ac608c9 1045 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
1046 if (r < 0)
1047 return r;
1048
1ac608c9 1049 if (!hostname_is_valid(hn, false)) {
ab24039f
ZJS
1050 log_syntax(unit, LOG_ERR, filename, line, 0,
1051 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
1052 return 0;
1053 }
1054
6528693a
YW
1055 r = dns_name_is_valid(hn);
1056 if (r < 0) {
ab24039f
ZJS
1057 log_syntax(unit, LOG_ERR, filename, line, r,
1058 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
1059 return 0;
1060 }
1061 if (r == 0) {
ab24039f
ZJS
1062 log_syntax(unit, LOG_ERR, filename, line, 0,
1063 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
1064 return 0;
1065 }
1066
1067 return free_and_replace(*hostname, hn);
a7d0ef44 1068}
8eb9058d
LP
1069
1070int config_parse_timezone(
1071 const char *unit,
1072 const char *filename,
1073 unsigned line,
1074 const char *section,
1075 unsigned section_line,
1076 const char *lvalue,
1077 int ltype,
1078 const char *rvalue,
1079 void *data,
1080 void *userdata) {
1081
19f9e4e2
YW
1082 _cleanup_free_ char *tz = NULL;
1083 char **datap = data;
8eb9058d
LP
1084 int r;
1085
1086 assert(filename);
1087 assert(lvalue);
1088 assert(rvalue);
1089
1090 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1091 if (r < 0)
1092 return r;
1093
089fb865 1094 if (!timezone_is_valid(tz, LOG_ERR)) {
ab24039f
ZJS
1095 log_syntax(unit, LOG_ERR, filename, line, 0,
1096 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1097 return 0;
1098 }
1099
19f9e4e2 1100 return free_and_replace(*datap, tz);
8eb9058d 1101}
1a04db0f
LP
1102
1103int config_parse_dhcp_server_dns(
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
1115 Network *n = data;
1116 const char *p = rvalue;
1117 int r;
1118
1119 assert(filename);
1120 assert(lvalue);
1121 assert(rvalue);
1122
1123 for (;;) {
1124 _cleanup_free_ char *w = NULL;
1125 struct in_addr a, *m;
1126
1127 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1128 if (r == -ENOMEM)
1129 return log_oom();
1a04db0f 1130 if (r < 0) {
ab24039f
ZJS
1131 log_syntax(unit, LOG_ERR, filename, line, r,
1132 "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1133 return 0;
1134 }
1a04db0f 1135 if (r == 0)
fa105ce6 1136 break;
1a04db0f
LP
1137
1138 if (inet_pton(AF_INET, w, &a) <= 0) {
ab24039f
ZJS
1139 log_syntax(unit, LOG_ERR, filename, line, 0,
1140 "Failed to parse DNS server address, ignoring: %s", w);
1a04db0f
LP
1141 continue;
1142 }
1143
62d74c78 1144 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1a04db0f
LP
1145 if (!m)
1146 return log_oom();
1147
1148 m[n->n_dhcp_server_dns++] = a;
1149 n->dhcp_server_dns = m;
1150 }
fa105ce6 1151
88295a05
PF
1152 return 0;
1153}
1154
1155int config_parse_radv_dns(
1156 const char *unit,
1157 const char *filename,
1158 unsigned line,
1159 const char *section,
1160 unsigned section_line,
1161 const char *lvalue,
1162 int ltype,
1163 const char *rvalue,
1164 void *data,
1165 void *userdata) {
1166
1167 Network *n = data;
1168 const char *p = rvalue;
1169 int r;
1170
1171 assert(filename);
1172 assert(lvalue);
1173 assert(rvalue);
1174
1175 for (;;) {
1176 _cleanup_free_ char *w = NULL;
1177 union in_addr_union a;
1178
1179 r = extract_first_word(&p, &w, NULL, 0);
1180 if (r == -ENOMEM)
1181 return log_oom();
1182 if (r < 0) {
ab24039f
ZJS
1183 log_syntax(unit, LOG_ERR, filename, line, r,
1184 "Failed to extract word, ignoring: %s", rvalue);
88295a05
PF
1185 return 0;
1186 }
1187 if (r == 0)
1188 break;
1189
1190 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1191 struct in6_addr *m;
1192
62d74c78 1193 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
88295a05
PF
1194 if (!m)
1195 return log_oom();
1196
1197 m[n->n_router_dns++] = a.in6;
1198 n->router_dns = m;
1199
1200 } else
ab24039f
ZJS
1201 log_syntax(unit, LOG_ERR, filename, line, 0,
1202 "Failed to parse DNS server address, ignoring: %s", w);
88295a05
PF
1203 }
1204
700f1186
PF
1205 return 0;
1206}
1207
1208int config_parse_radv_search_domains(
1209 const char *unit,
1210 const char *filename,
1211 unsigned line,
1212 const char *section,
1213 unsigned section_line,
1214 const char *lvalue,
1215 int ltype,
1216 const char *rvalue,
1217 void *data,
1218 void *userdata) {
1219
1220 Network *n = data;
1221 const char *p = rvalue;
1222 int r;
1223
1224 assert(filename);
1225 assert(lvalue);
1226 assert(rvalue);
1227
1228 for (;;) {
7a99f98b 1229 _cleanup_free_ char *w = NULL, *idna = NULL;
700f1186
PF
1230
1231 r = extract_first_word(&p, &w, NULL, 0);
1232 if (r == -ENOMEM)
1233 return log_oom();
1234 if (r < 0) {
ab24039f
ZJS
1235 log_syntax(unit, LOG_ERR, filename, line, r,
1236 "Failed to extract word, ignoring: %s", rvalue);
700f1186
PF
1237 return 0;
1238 }
1239 if (r == 0)
1240 break;
1241
1242 r = dns_name_apply_idna(w, &idna);
7a99f98b 1243 if (r < 0) {
ab24039f
ZJS
1244 log_syntax(unit, LOG_ERR, filename, line, r,
1245 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
7a99f98b 1246 continue;
5e2a51d5
ZJS
1247 } else if (r == 0)
1248 /* transfer ownership to simplify subsequent operations */
1249 idna = TAKE_PTR(w);
1250
1251 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
1252 if (r < 0)
1253 return r;
1254
1255 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1256 if (r < 0)
1257 return r;
700f1186
PF
1258 }
1259
fa105ce6 1260 return 0;
1a04db0f
LP
1261}
1262
1263int config_parse_dhcp_server_ntp(
1264 const char *unit,
1265 const char *filename,
1266 unsigned line,
1267 const char *section,
1268 unsigned section_line,
1269 const char *lvalue,
1270 int ltype,
1271 const char *rvalue,
1272 void *data,
1273 void *userdata) {
1274
1275 Network *n = data;
1276 const char *p = rvalue;
1277 int r;
1278
1279 assert(filename);
1280 assert(lvalue);
1281 assert(rvalue);
1282
1283 for (;;) {
1284 _cleanup_free_ char *w = NULL;
1285 struct in_addr a, *m;
1286
1287 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1288 if (r == -ENOMEM)
1289 return log_oom();
1a04db0f 1290 if (r < 0) {
ab24039f
ZJS
1291 log_syntax(unit, LOG_ERR, filename, line, r,
1292 "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1293 return 0;
1294 }
1a04db0f
LP
1295 if (r == 0)
1296 return 0;
1297
1298 if (inet_pton(AF_INET, w, &a) <= 0) {
ab24039f
ZJS
1299 log_syntax(unit, LOG_ERR, filename, line, 0,
1300 "Failed to parse NTP server address, ignoring: %s", w);
1a04db0f
LP
1301 continue;
1302 }
1303
62d74c78 1304 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1a04db0f
LP
1305 if (!m)
1306 return log_oom();
1307
1308 m[n->n_dhcp_server_ntp++] = a;
1309 n->dhcp_server_ntp = m;
1310 }
1311}
8a516214 1312
53253824
SS
1313int config_parse_dns(
1314 const char *unit,
1315 const char *filename,
1316 unsigned line,
1317 const char *section,
1318 unsigned section_line,
1319 const char *lvalue,
1320 int ltype,
1321 const char *rvalue,
1322 void *data,
1323 void *userdata) {
1324
1325 Network *n = userdata;
1326 int r;
1327
1328 assert(filename);
1329 assert(lvalue);
1330 assert(rvalue);
1331
1332 for (;;) {
1333 _cleanup_free_ char *w = NULL;
1334 union in_addr_union a;
5512a963 1335 struct in_addr_data *m;
53253824
SS
1336 int family;
1337
5512a963 1338 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1339 if (r == -ENOMEM)
1340 return log_oom();
1341 if (r < 0) {
ab24039f
ZJS
1342 log_syntax(unit, LOG_ERR, filename, line, r,
1343 "Invalid syntax, ignoring: %s", rvalue);
53253824
SS
1344 break;
1345 }
5512a963
LP
1346 if (r == 0)
1347 break;
53253824
SS
1348
1349 r = in_addr_from_string_auto(w, &family, &a);
1350 if (r < 0) {
ab24039f
ZJS
1351 log_syntax(unit, LOG_ERR, filename, line, r,
1352 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1353 continue;
1354 }
1355
62d74c78 1356 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1357 if (!m)
53253824
SS
1358 return log_oom();
1359
5512a963
LP
1360 m[n->n_dns++] = (struct in_addr_data) {
1361 .family = family,
1362 .address = a,
1363 };
1364
1365 n->dns = m;
53253824
SS
1366 }
1367
1368 return 0;
1369}
1370
8a516214
LP
1371int config_parse_dnssec_negative_trust_anchors(
1372 const char *unit,
1373 const char *filename,
1374 unsigned line,
1375 const char *section,
1376 unsigned section_line,
1377 const char *lvalue,
1378 int ltype,
1379 const char *rvalue,
1380 void *data,
1381 void *userdata) {
1382
1383 const char *p = rvalue;
1384 Network *n = data;
1385 int r;
1386
3df9bec5 1387 assert(n);
8a516214
LP
1388 assert(lvalue);
1389 assert(rvalue);
1390
1391 if (isempty(rvalue)) {
1392 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1393 return 0;
1394 }
1395
1396 for (;;) {
1397 _cleanup_free_ char *w = NULL;
1398
1399 r = extract_first_word(&p, &w, NULL, 0);
1400 if (r < 0) {
ab24039f
ZJS
1401 log_syntax(unit, LOG_ERR, filename, line, r,
1402 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
8a516214
LP
1403 break;
1404 }
1405 if (r == 0)
1406 break;
1407
1408 r = dns_name_is_valid(w);
1409 if (r <= 0) {
ab24039f
ZJS
1410 log_syntax(unit, LOG_ERR, filename, line, r,
1411 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1412 continue;
1413 }
1414
cbbf38ae
LP
1415 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1416 if (r < 0)
1417 return log_oom();
1418
8a516214
LP
1419 r = set_put(n->dnssec_negative_trust_anchors, w);
1420 if (r < 0)
1421 return log_oom();
1422 if (r > 0)
1423 w = NULL;
1424 }
1425
1426 return 0;
1427}
b2a81c0b 1428
26575990
LP
1429int config_parse_ntp(
1430 const char *unit,
1431 const char *filename,
1432 unsigned line,
1433 const char *section,
1434 unsigned section_line,
1435 const char *lvalue,
1436 int ltype,
1437 const char *rvalue,
1438 void *data,
1439 void *userdata) {
1440
1441 char ***l = data;
1442 int r;
1443
1444 assert(l);
1445 assert(lvalue);
1446 assert(rvalue);
1447
1448 if (isempty(rvalue)) {
1449 *l = strv_free(*l);
1450 return 0;
1451 }
1452
1453 for (;;) {
1454 _cleanup_free_ char *w = NULL;
1455
1456 r = extract_first_word(&rvalue, &w, NULL, 0);
1457 if (r == -ENOMEM)
1458 return log_oom();
1459 if (r < 0) {
ab24039f
ZJS
1460 log_syntax(unit, LOG_ERR, filename, line, r,
1461 "Failed to extract NTP server name, ignoring: %s", rvalue);
26575990
LP
1462 break;
1463 }
1464 if (r == 0)
1465 break;
1466
1467 r = dns_name_is_valid_or_address(w);
1468 if (r <= 0) {
ab24039f
ZJS
1469 log_syntax(unit, LOG_ERR, filename, line, r,
1470 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1471 continue;
af1c0de0
SS
1472 }
1473
c448459d
ZJS
1474 if (strv_length(*l) > MAX_NTP_SERVERS) {
1475 log_syntax(unit, LOG_WARNING, filename, line, 0,
1476 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1477 MAX_NTP_SERVERS, w);
1478 break;
1479 }
1480
1481 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1482 if (r < 0)
1483 return log_oom();
af1c0de0
SS
1484 }
1485
1486 return 0;
1487}
1488
1489int config_parse_dhcp_user_class(
1490 const char *unit,
1491 const char *filename,
1492 unsigned line,
1493 const char *section,
1494 unsigned section_line,
1495 const char *lvalue,
1496 int ltype,
1497 const char *rvalue,
1498 void *data,
1499 void *userdata) {
1500
1501 char ***l = data;
1502 int r;
1503
1504 assert(l);
1505 assert(lvalue);
1506 assert(rvalue);
1507
1508 if (isempty(rvalue)) {
1509 *l = strv_free(*l);
1510 return 0;
1511 }
1512
1513 for (;;) {
1514 _cleanup_free_ char *w = NULL;
1515
1516 r = extract_first_word(&rvalue, &w, NULL, 0);
1517 if (r == -ENOMEM)
1518 return log_oom();
1519 if (r < 0) {
ab24039f
ZJS
1520 log_syntax(unit, LOG_ERR, filename, line, r,
1521 "Failed to split user classes option, ignoring: %s", rvalue);
af1c0de0
SS
1522 break;
1523 }
1524 if (r == 0)
1525 break;
1526
1527 if (strlen(w) > 255) {
80be3de3 1528 log_syntax(unit, LOG_ERR, filename, line, 0,
ab24039f 1529 "%s length is not in the range 1-255, ignoring.", w);
af1c0de0 1530 continue;
26575990
LP
1531 }
1532
1533 r = strv_push(l, w);
1534 if (r < 0)
1535 return log_oom();
1536
1537 w = NULL;
1538 }
1539
1540 return 0;
1541}
1542
d5fa3339
YW
1543int config_parse_section_route_table(
1544 const char *unit,
1545 const char *filename,
1546 unsigned line,
1547 const char *section,
1548 unsigned section_line,
1549 const char *lvalue,
1550 int ltype,
1551 const char *rvalue,
1552 void *data,
1553 void *userdata) {
1554
fc1ba79d 1555 Network *network = data;
f594276b
JK
1556 uint32_t rt;
1557 int r;
1558
1559 assert(filename);
1560 assert(lvalue);
1561 assert(rvalue);
1562 assert(data);
1563
1564 r = safe_atou32(rvalue, &rt);
1565 if (r < 0) {
1566 log_syntax(unit, LOG_ERR, filename, line, r,
d5fa3339 1567 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
f594276b
JK
1568 return 0;
1569 }
1570
d5fa3339
YW
1571 if (streq_ptr(section, "DHCP")) {
1572 network->dhcp_route_table = rt;
1573 network->dhcp_route_table_set = true;
1574 } else { /* section is IPv6AcceptRA */
1575 network->ipv6_accept_ra_route_table = rt;
1576 network->ipv6_accept_ra_route_table_set = true;
1577 }
f594276b
JK
1578
1579 return 0;
1580}
1581
ab24039f
ZJS
1582DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
1583 "Failed to parse DHCP use domains setting");
b2a81c0b
LP
1584
1585static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1586 [DHCP_USE_DOMAINS_NO] = "no",
1587 [DHCP_USE_DOMAINS_ROUTE] = "route",
1588 [DHCP_USE_DOMAINS_YES] = "yes",
1589};
1590
1591DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
34437b4f
LP
1592
1593DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1594
1595static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1596 [LLDP_MODE_NO] = "no",
1597 [LLDP_MODE_YES] = "yes",
1598 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1599};
1600
1601DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
8217ed5e
TH
1602
1603int config_parse_iaid(const char *unit,
1604 const char *filename,
1605 unsigned line,
1606 const char *section,
1607 unsigned section_line,
1608 const char *lvalue,
1609 int ltype,
1610 const char *rvalue,
1611 void *data,
1612 void *userdata) {
1613 Network *network = data;
1614 uint32_t iaid;
1615 int r;
1616
1617 assert(filename);
1618 assert(lvalue);
1619 assert(rvalue);
1620 assert(network);
1621
1622 r = safe_atou32(rvalue, &iaid);
1623 if (r < 0) {
1624 log_syntax(unit, LOG_ERR, filename, line, r,
1625 "Unable to read IAID, ignoring assignment: %s", rvalue);
1626 return 0;
1627 }
1628
1629 network->iaid = iaid;
1630 network->iaid_set = true;
1631
1632 return 0;
1633}
4ac77d63
YW
1634
1635int config_parse_required_for_online(
1636 const char *unit,
1637 const char *filename,
1638 unsigned line,
1639 const char *section,
1640 unsigned section_line,
1641 const char *lvalue,
1642 int ltype,
1643 const char *rvalue,
1644 void *data,
1645 void *userdata) {
1646
1647 Network *network = data;
1648 LinkOperationalState s;
1649 bool required = true;
1650 int r;
1651
1652 if (isempty(rvalue)) {
1653 network->required_for_online = true;
1654 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1655 return 0;
1656 }
1657
1658 s = link_operstate_from_string(rvalue);
1659 if (s < 0) {
1660 r = parse_boolean(rvalue);
1661 if (r < 0) {
1662 log_syntax(unit, LOG_ERR, filename, line, r,
1663 "Failed to parse %s= setting, ignoring assignment: %s",
1664 lvalue, rvalue);
1665 return 0;
1666 }
1667
1668 required = r;
1669 s = LINK_OPERSTATE_DEGRADED;
1670 }
1671
1672 network->required_for_online = required;
1673 network->required_operstate_for_online = s;
1674
1675 return 0;
1676}