]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
Italian translations: minor updates (#12494)
[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;
8e766630 301 _cleanup_(network_freep) 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
YW
346
347 .required_for_online = true,
4ac77d63 348 .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
17f9c355
YW
349 .dhcp = ADDRESS_FAMILY_NO,
350 .dhcp_use_ntp = true,
351 .dhcp_use_dns = true,
352 .dhcp_use_hostname = true,
353 .dhcp_use_routes = true,
5238e957 354 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
355 .dhcp_send_hostname = true,
356 /* To enable/disable RFC7844 Anonymity Profiles */
357 .dhcp_anonymize = false,
358 .dhcp_route_metric = DHCP_ROUTE_METRIC,
359 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
360 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
361 .dhcp_route_table = RT_TABLE_MAIN,
362 .dhcp_route_table_set = false,
363 /* NOTE: from man: UseMTU=... Defaults to false*/
364 .dhcp_use_mtu = false,
365 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
366 .dhcp_use_timezone = false,
367 .rapid_commit = true,
368
369 .dhcp_server_emit_dns = true,
370 .dhcp_server_emit_ntp = true,
371 .dhcp_server_emit_router = true,
372 .dhcp_server_emit_timezone = true,
373
374 .router_emit_dns = true,
375 .router_emit_domains = true,
376
377 .use_bpdu = -1,
378 .hairpin = -1,
379 .fast_leave = -1,
380 .allow_port_to_be_root = -1,
381 .unicast_flood = -1,
7f15b714 382 .multicast_flood = -1,
d3aa8b49 383 .multicast_to_unicast = -1,
7f15b714
TJ
384 .neighbor_suppression = -1,
385 .learning = -1,
17f9c355
YW
386 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
387
388 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
389
7ece6f58 390 .dns_default_route = -1,
17f9c355
YW
391 .llmnr = RESOLVE_SUPPORT_YES,
392 .mdns = RESOLVE_SUPPORT_NO,
393 .dnssec_mode = _DNSSEC_MODE_INVALID,
394 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
395
0321cea7
YW
396 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
397 .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID,
17f9c355
YW
398
399 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
400 .ipv6_accept_ra = -1,
401 .ipv6_dad_transmits = -1,
402 .ipv6_hop_limit = -1,
403 .ipv6_proxy_ndp = -1,
404 .duid.type = _DUID_TYPE_INVALID,
405 .proxy_arp = -1,
406 .arp = -1,
407 .multicast = -1,
408 .allmulticast = -1,
409 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
410 .ipv6_accept_ra_use_autonomous_prefix = true,
411 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 412 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 413 .ipv6_accept_ra_route_table_set = false,
c423be28
CG
414
415 .can_triple_sampling = -1,
17f9c355 416 };
f579559b 417
dc0d4078 418 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
23bb31aa
ZJS
419 "Match\0"
420 "Link\0"
421 "Network\0"
422 "Address\0"
e4a71bf3 423 "Neighbor\0"
95b74ef6 424 "IPv6AddressLabel\0"
bce67bbe 425 "RoutingPolicyRule\0"
23bb31aa
ZJS
426 "Route\0"
427 "DHCP\0"
428 "DHCPv4\0" /* compat */
429 "DHCPServer\0"
430 "IPv6AcceptRA\0"
a0e5c15d 431 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
432 "Bridge\0"
433 "BridgeFDB\0"
9d5d0090 434 "BridgeVLAN\0"
7d5cac19 435 "IPv6PrefixDelegation\0"
06828bb6
HP
436 "IPv6Prefix\0"
437 "CAN\0",
23bb31aa 438 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 439 CONFIG_PARSE_WARN, network);
102bc043 440 if (r < 0)
f579559b 441 return r;
f579559b 442
add8d07d 443 network_apply_anonymize_if_set(network);
444
fa7cd711
YW
445 r = network_add_ipv4ll_route(network);
446 if (r < 0)
447 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
448
f579559b 449 LIST_PREPEND(networks, manager->networks, network);
102bc043 450 network->manager = manager;
b3070dc0 451
dbffab87
TG
452 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
453 if (r < 0)
454 return r;
455
456 r = hashmap_put(manager->networks_by_name, network->name, network);
457 if (r < 0)
458 return r;
459
0321cea7
YW
460 if (network_verify(network) < 0)
461 return 0;
b3070dc0 462
f579559b 463 network = NULL;
f579559b
TG
464 return 0;
465}
466
467int network_load(Manager *manager) {
468 Network *network;
477e73b5
ZJS
469 _cleanup_strv_free_ char **files = NULL;
470 char **f;
f579559b
TG
471 int r;
472
473 assert(manager);
474
475 while ((network = manager->networks))
476 network_free(network);
477
dc0d4078 478 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
479 if (r < 0)
480 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b
TG
481
482 STRV_FOREACH_BACKWARDS(f, files) {
483 r = network_load_one(manager, *f);
484 if (r < 0)
485 return r;
486 }
487
f579559b
TG
488 return 0;
489}
490
f579559b 491void network_free(Network *network) {
a0e5c15d 492 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
493 RoutingPolicyRule *rule;
494 FdbEntry *fdb_entry;
e4a71bf3 495 Neighbor *neighbor;
95b74ef6 496 AddressLabel *label;
057abfd8 497 Prefix *prefix;
bce67bbe 498 Address *address;
bce67bbe 499 Route *route;
f579559b
TG
500
501 if (!network)
502 return;
503
504 free(network->filename);
505
e90d0374 506 set_free_free(network->match_mac);
5256e00e
TG
507 strv_free(network->match_path);
508 strv_free(network->match_driver);
509 strv_free(network->match_type);
510 strv_free(network->match_name);
c4f58dea 511 condition_free_list(network->conditions);
f579559b
TG
512
513 free(network->description);
edb85f0d 514 free(network->dhcp_vendor_class_identifier);
af1c0de0 515 strv_free(network->dhcp_user_class);
27cb34f5 516 free(network->dhcp_hostname);
f579559b 517
c106cc36
TG
518 free(network->mac);
519
b0e39c82 520 strv_free(network->ntp);
5512a963 521 free(network->dns);
5e2a51d5
ZJS
522 ordered_set_free_free(network->search_domains);
523 ordered_set_free_free(network->route_domains);
0d4ad91d 524 strv_free(network->bind_carrier);
cdd7812b 525
5e2a51d5 526 ordered_set_free_free(network->router_search_domains);
cdd7812b 527 free(network->router_dns);
3bef724f 528
cebe1257
YW
529 free(network->bridge_name);
530 free(network->bond_name);
531 free(network->vrf_name);
532 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 533 netdev_unref(network->bridge);
47e2dc31 534 netdev_unref(network->bond);
6cb955c6 535 netdev_unref(network->vrf);
fa6f1e54 536 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 537
f048a16b 538 while ((route = network->static_routes))
f579559b
TG
539 route_free(route);
540
f048a16b 541 while ((address = network->static_addresses))
f579559b
TG
542 address_free(address);
543
b98b483b
AR
544 while ((fdb_entry = network->static_fdb_entries))
545 fdb_entry_free(fdb_entry);
546
a0e5c15d
FK
547 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
548 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
549
e4a71bf3
WKI
550 while ((neighbor = network->neighbors))
551 neighbor_free(neighbor);
552
95b74ef6
SS
553 while ((label = network->address_labels))
554 address_label_free(label);
555
057abfd8
PF
556 while ((prefix = network->static_prefixes))
557 prefix_free(prefix);
558
bce67bbe
SS
559 while ((rule = network->rules))
560 routing_policy_rule_free(rule);
561
6ae115c1
TG
562 hashmap_free(network->addresses_by_section);
563 hashmap_free(network->routes_by_section);
b98b483b 564 hashmap_free(network->fdb_entries_by_section);
e4a71bf3 565 hashmap_free(network->neighbors_by_section);
95b74ef6 566 hashmap_free(network->address_labels_by_section);
057abfd8 567 hashmap_free(network->prefixes_by_section);
bce67bbe 568 hashmap_free(network->rules_by_section);
6ae115c1 569
dbffab87
TG
570 if (network->manager) {
571 if (network->manager->networks)
572 LIST_REMOVE(networks, network->manager->networks, network);
573
e512c6c1 574 if (network->manager->networks_by_name && network->name)
dbffab87 575 hashmap_remove(network->manager->networks_by_name, network->name);
27dfc982
YW
576
577 if (network->manager->duids_requesting_uuid)
578 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
579 }
580
581 free(network->name);
f579559b 582
8eb9058d 583 free(network->dhcp_server_timezone);
1a04db0f
LP
584 free(network->dhcp_server_dns);
585 free(network->dhcp_server_ntp);
8eb9058d 586
8a516214
LP
587 set_free_free(network->dnssec_negative_trust_anchors);
588
f579559b
TG
589 free(network);
590}
591
dbffab87
TG
592int network_get_by_name(Manager *manager, const char *name, Network **ret) {
593 Network *network;
594
595 assert(manager);
596 assert(name);
597 assert(ret);
598
599 network = hashmap_get(manager->networks_by_name, name);
600 if (!network)
601 return -ENOENT;
602
603 *ret = network;
604
605 return 0;
606}
607
51517f9e 608int network_get(Manager *manager, sd_device *device,
505f8da7
TG
609 const char *ifname, const struct ether_addr *address,
610 Network **ret) {
4f4daf41 611 const char *path = NULL, *driver = NULL, *devtype = NULL;
51517f9e 612 Network *network;
f579559b
TG
613
614 assert(manager);
f579559b 615 assert(ret);
af3aa302 616
24c083df 617 if (device) {
51517f9e 618 (void) sd_device_get_property_value(device, "ID_PATH", &path);
af3aa302 619
51517f9e 620 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
af3aa302 621
51517f9e 622 (void) sd_device_get_devtype(device, &devtype);
24c083df 623 }
f579559b 624
f579559b
TG
625 LIST_FOREACH(networks, network, manager->networks) {
626 if (net_match_config(network->match_mac, network->match_path,
505f8da7 627 network->match_driver, network->match_type,
c4f58dea 628 network->match_name,
4f4daf41 629 address, path, driver, devtype, ifname)) {
24c083df 630 if (network->match_name && device) {
ca6038b8
TG
631 const char *attr;
632 uint8_t name_assign_type = NET_NAME_UNKNOWN;
633
51517f9e 634 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 635 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
636
637 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
638 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
639 ifname, network->filename);
32bc8adc 640 else
a2fae7bb 641 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 642 } else
a2fae7bb 643 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 644
f579559b
TG
645 *ret = network;
646 return 0;
647 }
648 }
649
650 *ret = NULL;
651
652 return -ENOENT;
653}
654
7d342c03 655int network_apply(Network *network, Link *link) {
c4a03a56
TG
656 assert(network);
657 assert(link);
658
f579559b
TG
659 link->network = network;
660
5512a963 661 if (network->n_dns > 0 ||
3df9bec5 662 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
663 !ordered_set_isempty(network->search_domains) ||
664 !ordered_set_isempty(network->route_domains))
84de38c5 665 link_dirty(link);
3bef724f 666
f579559b
TG
667 return 0;
668}
02b59d57 669
439689c6
SS
670bool network_has_static_ipv6_addresses(Network *network) {
671 Address *address;
672
673 assert(network);
674
675 LIST_FOREACH(addresses, address, network->static_addresses) {
676 if (address->family == AF_INET6)
677 return true;
678 }
679
680 return false;
681}
682
cebe1257 683int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
684 const char *filename,
685 unsigned line,
686 const char *section,
687 unsigned section_line,
688 const char *lvalue,
689 int ltype,
690 const char *rvalue,
691 void *data,
692 void *userdata) {
95dba435
YW
693 _cleanup_free_ char *name = NULL;
694 NetDevKind kind = ltype;
cebe1257 695 Hashmap **h = data;
02b59d57
TG
696 int r;
697
698 assert(filename);
699 assert(lvalue);
700 assert(rvalue);
701 assert(data);
95dba435
YW
702 assert(IN_SET(kind,
703 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
3a56e697 704 NETDEV_KIND_IPVLAN, NETDEV_KIND_VXLAN, NETDEV_KIND_L2TP,
81962db7 705 NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL));
54abf461 706
cebe1257 707 if (!ifname_valid(rvalue)) {
3772cfde
ZJS
708 log_syntax(unit, LOG_ERR, filename, line, 0,
709 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
710 return 0;
711 }
712
cebe1257
YW
713 name = strdup(rvalue);
714 if (!name)
715 return log_oom();
3e570042 716
cebe1257
YW
717 r = hashmap_ensure_allocated(h, &string_hash_ops);
718 if (r < 0)
719 return log_oom();
326cb406 720
cebe1257 721 r = hashmap_put(*h, name, INT_TO_PTR(kind));
83ec4592 722 if (r < 0)
3772cfde 723 log_syntax(unit, LOG_ERR, filename, line, r,
83ec4592
ZJS
724 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
725 else if (r == 0)
726 log_syntax(unit, LOG_DEBUG, filename, line, r,
727 "NetDev '%s' specified twice, ignoring.", name);
728 else
729 name = NULL;
47e2dc31 730
fe6b2d55
TG
731 return 0;
732}
7951dea2 733
3df9bec5
LP
734int config_parse_domains(
735 const char *unit,
736 const char *filename,
737 unsigned line,
738 const char *section,
739 unsigned section_line,
740 const char *lvalue,
741 int ltype,
742 const char *rvalue,
743 void *data,
744 void *userdata) {
745
746 const char *p;
747 Network *n = data;
6192b846
TG
748 int r;
749
3df9bec5
LP
750 assert(n);
751 assert(lvalue);
752 assert(rvalue);
6192b846 753
3df9bec5 754 if (isempty(rvalue)) {
5e2a51d5
ZJS
755 n->search_domains = ordered_set_free_free(n->search_domains);
756 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
757 return 0;
758 }
67272d15 759
3df9bec5
LP
760 p = rvalue;
761 for (;;) {
762 _cleanup_free_ char *w = NULL, *normalized = NULL;
763 const char *domain;
764 bool is_route;
765
766 r = extract_first_word(&p, &w, NULL, 0);
767 if (r < 0) {
ab24039f
ZJS
768 log_syntax(unit, LOG_ERR, filename, line, r,
769 "Failed to extract search or route domain, ignoring: %s", rvalue);
3df9bec5
LP
770 break;
771 }
772 if (r == 0)
773 break;
774
775 is_route = w[0] == '~';
776 domain = is_route ? w + 1 : w;
777
778 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
779 /* If the root domain appears as is, or the special token "*" is found, we'll
780 * consider this as routing domain, unconditionally. */
3df9bec5 781 is_route = true;
ab24039f
ZJS
782 domain = "."; /* make sure we don't allow empty strings, thus write the root
783 * domain as "." */
3df9bec5 784 } else {
7470cc4c 785 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 786 if (r < 0) {
ab24039f
ZJS
787 log_syntax(unit, LOG_ERR, filename, line, r,
788 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
789 continue;
790 }
791
792 domain = normalized;
793
794 if (is_localhost(domain)) {
ab24039f
ZJS
795 log_syntax(unit, LOG_ERR, filename, line, 0,
796 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
797 domain);
37de2509 798 continue;
3df9bec5 799 }
37de2509 800 }
40274ed6 801
5e2a51d5
ZJS
802 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
803 r = ordered_set_ensure_allocated(set, &string_hash_ops);
804 if (r < 0)
805 return r;
806
807 r = ordered_set_put_strdup(*set, domain);
09451975
LP
808 if (r < 0)
809 return log_oom();
40274ed6 810 }
f15b6e5a 811
6192b846
TG
812 return 0;
813}
814
d0d6a4cd
TG
815int config_parse_ipv4ll(
816 const char* unit,
817 const char *filename,
818 unsigned line,
819 const char *section,
820 unsigned section_line,
821 const char *lvalue,
822 int ltype,
823 const char *rvalue,
824 void *data,
825 void *userdata) {
826
827 AddressFamilyBoolean *link_local = data;
810ae0dc 828 int r;
d0d6a4cd
TG
829
830 assert(filename);
831 assert(lvalue);
832 assert(rvalue);
833 assert(data);
834
835 /* Note that this is mostly like
836 * config_parse_address_family_boolean(), except that it
837 * applies only to IPv4 */
838
810ae0dc
YW
839 r = parse_boolean(rvalue);
840 if (r < 0) {
841 log_syntax(unit, LOG_ERR, filename, line, r,
842 "Failed to parse %s=%s, ignoring assignment. "
843 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
844 lvalue, rvalue, lvalue);
845 return 0;
846 }
847
848 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
849
850 log_syntax(unit, LOG_WARNING, filename, line, 0,
851 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
852 lvalue, rvalue, address_family_boolean_to_string(*link_local));
d0d6a4cd
TG
853
854 return 0;
855}
856
bd8f6538
TG
857int config_parse_dhcp(
858 const char* unit,
859 const char *filename,
860 unsigned line,
861 const char *section,
862 unsigned section_line,
863 const char *lvalue,
864 int ltype,
865 const char *rvalue,
866 void *data,
867 void *userdata) {
868
cb9fc36a 869 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
870
871 assert(filename);
872 assert(lvalue);
873 assert(rvalue);
874 assert(data);
875
769d324c
LP
876 /* Note that this is mostly like
877 * config_parse_address_family_boolean(), except that it
878 * understands some old names for the enum values */
879
cb9fc36a
LP
880 s = address_family_boolean_from_string(rvalue);
881 if (s < 0) {
882
883 /* Previously, we had a slightly different enum here,
5238e957 884 * support its values for compatibility. */
cb9fc36a
LP
885
886 if (streq(rvalue, "none"))
887 s = ADDRESS_FAMILY_NO;
888 else if (streq(rvalue, "v4"))
889 s = ADDRESS_FAMILY_IPV4;
890 else if (streq(rvalue, "v6"))
891 s = ADDRESS_FAMILY_IPV6;
892 else if (streq(rvalue, "both"))
893 s = ADDRESS_FAMILY_YES;
894 else {
ab24039f
ZJS
895 log_syntax(unit, LOG_ERR, filename, line, 0,
896 "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
897 return 0;
898 }
41f62acc
YW
899
900 log_syntax(unit, LOG_WARNING, filename, line, 0,
901 "DHCP=%s is deprecated, please use DHCP=%s instead.",
902 rvalue, address_family_boolean_to_string(s));
bd8f6538
TG
903 }
904
cb9fc36a 905 *dhcp = s;
bd8f6538
TG
906 return 0;
907}
908
3e43b2cd
JJ
909static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
910 [DHCP_CLIENT_ID_MAC] = "mac",
dace710c
YW
911 [DHCP_CLIENT_ID_DUID] = "duid",
912 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
3e43b2cd
JJ
913};
914
499d555a 915DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
ab24039f
ZJS
916DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
917 "Failed to parse client identifier type");
3e43b2cd 918
60c35566 919int config_parse_ipv6token(
7f77697a
TG
920 const char* unit,
921 const char *filename,
922 unsigned line,
923 const char *section,
924 unsigned section_line,
925 const char *lvalue,
926 int ltype,
927 const char *rvalue,
928 void *data,
929 void *userdata) {
930
931 union in_addr_union buffer;
932 struct in6_addr *token = data;
933 int r;
934
935 assert(filename);
936 assert(lvalue);
937 assert(rvalue);
938 assert(token);
939
940 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
941 if (r < 0) {
ab24039f
ZJS
942 log_syntax(unit, LOG_ERR, filename, line, r,
943 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
944 return 0;
945 }
946
c606db69 947 if (in_addr_is_null(AF_INET6, &buffer)) {
ab24039f
ZJS
948 log_syntax(unit, LOG_ERR, filename, line, 0,
949 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
950 return 0;
951 }
952
953 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
ab24039f
ZJS
954 log_syntax(unit, LOG_ERR, filename, line, 0,
955 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
956 return 0;
957 }
958
959 *token = buffer.in6;
960
961 return 0;
962}
8add5f79 963
49092e22 964static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
965 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
966 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
967 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
968};
969
970DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
971
972int config_parse_ipv6_privacy_extensions(
973 const char* unit,
974 const char *filename,
975 unsigned line,
976 const char *section,
977 unsigned section_line,
978 const char *lvalue,
979 int ltype,
980 const char *rvalue,
981 void *data,
982 void *userdata) {
983
984 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
985 int k;
986
987 assert(filename);
988 assert(lvalue);
989 assert(rvalue);
990 assert(ipv6_privacy_extensions);
991
992 /* Our enum shall be a superset of booleans, hence first try
993 * to parse as boolean, and then as enum */
994
995 k = parse_boolean(rvalue);
996 if (k > 0)
1f0d9695 997 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 998 else if (k == 0)
1f0d9695 999 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 1000 else {
1f0d9695 1001 IPv6PrivacyExtensions s;
49092e22
SS
1002
1003 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
1004 if (s < 0) {
1005
1006 if (streq(rvalue, "kernel"))
1007 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
1008 else {
ab24039f
ZJS
1009 log_syntax(unit, LOG_ERR, filename, line, 0,
1010 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1f0d9695
LP
1011 return 0;
1012 }
49092e22
SS
1013 }
1014
1015 *ipv6_privacy_extensions = s;
1016 }
1017
1018 return 0;
1019}
a7d0ef44 1020
1ac608c9
LP
1021int config_parse_hostname(
1022 const char *unit,
1023 const char *filename,
1024 unsigned line,
1025 const char *section,
1026 unsigned section_line,
1027 const char *lvalue,
1028 int ltype,
1029 const char *rvalue,
1030 void *data,
1031 void *userdata) {
1032
6528693a
YW
1033 _cleanup_free_ char *hn = NULL;
1034 char **hostname = data;
a7d0ef44
SS
1035 int r;
1036
1037 assert(filename);
1038 assert(lvalue);
1039 assert(rvalue);
1040
1ac608c9 1041 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
1042 if (r < 0)
1043 return r;
1044
1ac608c9 1045 if (!hostname_is_valid(hn, false)) {
ab24039f
ZJS
1046 log_syntax(unit, LOG_ERR, filename, line, 0,
1047 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
1048 return 0;
1049 }
1050
6528693a
YW
1051 r = dns_name_is_valid(hn);
1052 if (r < 0) {
ab24039f
ZJS
1053 log_syntax(unit, LOG_ERR, filename, line, r,
1054 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
1055 return 0;
1056 }
1057 if (r == 0) {
ab24039f
ZJS
1058 log_syntax(unit, LOG_ERR, filename, line, 0,
1059 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
1060 return 0;
1061 }
1062
1063 return free_and_replace(*hostname, hn);
a7d0ef44 1064}
8eb9058d
LP
1065
1066int config_parse_timezone(
1067 const char *unit,
1068 const char *filename,
1069 unsigned line,
1070 const char *section,
1071 unsigned section_line,
1072 const char *lvalue,
1073 int ltype,
1074 const char *rvalue,
1075 void *data,
1076 void *userdata) {
1077
19f9e4e2
YW
1078 _cleanup_free_ char *tz = NULL;
1079 char **datap = data;
8eb9058d
LP
1080 int r;
1081
1082 assert(filename);
1083 assert(lvalue);
1084 assert(rvalue);
1085
1086 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1087 if (r < 0)
1088 return r;
1089
089fb865 1090 if (!timezone_is_valid(tz, LOG_ERR)) {
ab24039f
ZJS
1091 log_syntax(unit, LOG_ERR, filename, line, 0,
1092 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1093 return 0;
1094 }
1095
19f9e4e2 1096 return free_and_replace(*datap, tz);
8eb9058d 1097}
1a04db0f
LP
1098
1099int config_parse_dhcp_server_dns(
1100 const char *unit,
1101 const char *filename,
1102 unsigned line,
1103 const char *section,
1104 unsigned section_line,
1105 const char *lvalue,
1106 int ltype,
1107 const char *rvalue,
1108 void *data,
1109 void *userdata) {
1110
1111 Network *n = data;
1112 const char *p = rvalue;
1113 int r;
1114
1115 assert(filename);
1116 assert(lvalue);
1117 assert(rvalue);
1118
1119 for (;;) {
1120 _cleanup_free_ char *w = NULL;
1121 struct in_addr a, *m;
1122
1123 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1124 if (r == -ENOMEM)
1125 return log_oom();
1a04db0f 1126 if (r < 0) {
ab24039f
ZJS
1127 log_syntax(unit, LOG_ERR, filename, line, r,
1128 "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1129 return 0;
1130 }
1a04db0f 1131 if (r == 0)
fa105ce6 1132 break;
1a04db0f
LP
1133
1134 if (inet_pton(AF_INET, w, &a) <= 0) {
ab24039f
ZJS
1135 log_syntax(unit, LOG_ERR, filename, line, 0,
1136 "Failed to parse DNS server address, ignoring: %s", w);
1a04db0f
LP
1137 continue;
1138 }
1139
62d74c78 1140 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1a04db0f
LP
1141 if (!m)
1142 return log_oom();
1143
1144 m[n->n_dhcp_server_dns++] = a;
1145 n->dhcp_server_dns = m;
1146 }
fa105ce6 1147
88295a05
PF
1148 return 0;
1149}
1150
1151int config_parse_radv_dns(
1152 const char *unit,
1153 const char *filename,
1154 unsigned line,
1155 const char *section,
1156 unsigned section_line,
1157 const char *lvalue,
1158 int ltype,
1159 const char *rvalue,
1160 void *data,
1161 void *userdata) {
1162
1163 Network *n = data;
1164 const char *p = rvalue;
1165 int r;
1166
1167 assert(filename);
1168 assert(lvalue);
1169 assert(rvalue);
1170
1171 for (;;) {
1172 _cleanup_free_ char *w = NULL;
1173 union in_addr_union a;
1174
1175 r = extract_first_word(&p, &w, NULL, 0);
1176 if (r == -ENOMEM)
1177 return log_oom();
1178 if (r < 0) {
ab24039f
ZJS
1179 log_syntax(unit, LOG_ERR, filename, line, r,
1180 "Failed to extract word, ignoring: %s", rvalue);
88295a05
PF
1181 return 0;
1182 }
1183 if (r == 0)
1184 break;
1185
1186 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1187 struct in6_addr *m;
1188
62d74c78 1189 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
88295a05
PF
1190 if (!m)
1191 return log_oom();
1192
1193 m[n->n_router_dns++] = a.in6;
1194 n->router_dns = m;
1195
1196 } else
ab24039f
ZJS
1197 log_syntax(unit, LOG_ERR, filename, line, 0,
1198 "Failed to parse DNS server address, ignoring: %s", w);
88295a05
PF
1199 }
1200
700f1186
PF
1201 return 0;
1202}
1203
1204int config_parse_radv_search_domains(
1205 const char *unit,
1206 const char *filename,
1207 unsigned line,
1208 const char *section,
1209 unsigned section_line,
1210 const char *lvalue,
1211 int ltype,
1212 const char *rvalue,
1213 void *data,
1214 void *userdata) {
1215
1216 Network *n = data;
1217 const char *p = rvalue;
1218 int r;
1219
1220 assert(filename);
1221 assert(lvalue);
1222 assert(rvalue);
1223
1224 for (;;) {
7a99f98b 1225 _cleanup_free_ char *w = NULL, *idna = NULL;
700f1186
PF
1226
1227 r = extract_first_word(&p, &w, NULL, 0);
1228 if (r == -ENOMEM)
1229 return log_oom();
1230 if (r < 0) {
ab24039f
ZJS
1231 log_syntax(unit, LOG_ERR, filename, line, r,
1232 "Failed to extract word, ignoring: %s", rvalue);
700f1186
PF
1233 return 0;
1234 }
1235 if (r == 0)
1236 break;
1237
1238 r = dns_name_apply_idna(w, &idna);
7a99f98b 1239 if (r < 0) {
ab24039f
ZJS
1240 log_syntax(unit, LOG_ERR, filename, line, r,
1241 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
7a99f98b 1242 continue;
5e2a51d5
ZJS
1243 } else if (r == 0)
1244 /* transfer ownership to simplify subsequent operations */
1245 idna = TAKE_PTR(w);
1246
1247 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
1248 if (r < 0)
1249 return r;
1250
1251 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1252 if (r < 0)
1253 return r;
700f1186
PF
1254 }
1255
fa105ce6 1256 return 0;
1a04db0f
LP
1257}
1258
1259int config_parse_dhcp_server_ntp(
1260 const char *unit,
1261 const char *filename,
1262 unsigned line,
1263 const char *section,
1264 unsigned section_line,
1265 const char *lvalue,
1266 int ltype,
1267 const char *rvalue,
1268 void *data,
1269 void *userdata) {
1270
1271 Network *n = data;
1272 const char *p = rvalue;
1273 int r;
1274
1275 assert(filename);
1276 assert(lvalue);
1277 assert(rvalue);
1278
1279 for (;;) {
1280 _cleanup_free_ char *w = NULL;
1281 struct in_addr a, *m;
1282
1283 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1284 if (r == -ENOMEM)
1285 return log_oom();
1a04db0f 1286 if (r < 0) {
ab24039f
ZJS
1287 log_syntax(unit, LOG_ERR, filename, line, r,
1288 "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1289 return 0;
1290 }
1a04db0f
LP
1291 if (r == 0)
1292 return 0;
1293
1294 if (inet_pton(AF_INET, w, &a) <= 0) {
ab24039f
ZJS
1295 log_syntax(unit, LOG_ERR, filename, line, 0,
1296 "Failed to parse NTP server address, ignoring: %s", w);
1a04db0f
LP
1297 continue;
1298 }
1299
62d74c78 1300 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1a04db0f
LP
1301 if (!m)
1302 return log_oom();
1303
1304 m[n->n_dhcp_server_ntp++] = a;
1305 n->dhcp_server_ntp = m;
1306 }
1307}
8a516214 1308
53253824
SS
1309int config_parse_dns(
1310 const char *unit,
1311 const char *filename,
1312 unsigned line,
1313 const char *section,
1314 unsigned section_line,
1315 const char *lvalue,
1316 int ltype,
1317 const char *rvalue,
1318 void *data,
1319 void *userdata) {
1320
1321 Network *n = userdata;
1322 int r;
1323
1324 assert(filename);
1325 assert(lvalue);
1326 assert(rvalue);
1327
1328 for (;;) {
1329 _cleanup_free_ char *w = NULL;
1330 union in_addr_union a;
5512a963 1331 struct in_addr_data *m;
53253824
SS
1332 int family;
1333
5512a963 1334 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1335 if (r == -ENOMEM)
1336 return log_oom();
1337 if (r < 0) {
ab24039f
ZJS
1338 log_syntax(unit, LOG_ERR, filename, line, r,
1339 "Invalid syntax, ignoring: %s", rvalue);
53253824
SS
1340 break;
1341 }
5512a963
LP
1342 if (r == 0)
1343 break;
53253824
SS
1344
1345 r = in_addr_from_string_auto(w, &family, &a);
1346 if (r < 0) {
ab24039f
ZJS
1347 log_syntax(unit, LOG_ERR, filename, line, r,
1348 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1349 continue;
1350 }
1351
62d74c78 1352 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1353 if (!m)
53253824
SS
1354 return log_oom();
1355
5512a963
LP
1356 m[n->n_dns++] = (struct in_addr_data) {
1357 .family = family,
1358 .address = a,
1359 };
1360
1361 n->dns = m;
53253824
SS
1362 }
1363
1364 return 0;
1365}
1366
8a516214
LP
1367int config_parse_dnssec_negative_trust_anchors(
1368 const char *unit,
1369 const char *filename,
1370 unsigned line,
1371 const char *section,
1372 unsigned section_line,
1373 const char *lvalue,
1374 int ltype,
1375 const char *rvalue,
1376 void *data,
1377 void *userdata) {
1378
1379 const char *p = rvalue;
1380 Network *n = data;
1381 int r;
1382
3df9bec5 1383 assert(n);
8a516214
LP
1384 assert(lvalue);
1385 assert(rvalue);
1386
1387 if (isempty(rvalue)) {
1388 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1389 return 0;
1390 }
1391
1392 for (;;) {
1393 _cleanup_free_ char *w = NULL;
1394
1395 r = extract_first_word(&p, &w, NULL, 0);
1396 if (r < 0) {
ab24039f
ZJS
1397 log_syntax(unit, LOG_ERR, filename, line, r,
1398 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
8a516214
LP
1399 break;
1400 }
1401 if (r == 0)
1402 break;
1403
1404 r = dns_name_is_valid(w);
1405 if (r <= 0) {
ab24039f
ZJS
1406 log_syntax(unit, LOG_ERR, filename, line, r,
1407 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1408 continue;
1409 }
1410
cbbf38ae
LP
1411 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1412 if (r < 0)
1413 return log_oom();
1414
8a516214
LP
1415 r = set_put(n->dnssec_negative_trust_anchors, w);
1416 if (r < 0)
1417 return log_oom();
1418 if (r > 0)
1419 w = NULL;
1420 }
1421
1422 return 0;
1423}
b2a81c0b 1424
26575990
LP
1425int config_parse_ntp(
1426 const char *unit,
1427 const char *filename,
1428 unsigned line,
1429 const char *section,
1430 unsigned section_line,
1431 const char *lvalue,
1432 int ltype,
1433 const char *rvalue,
1434 void *data,
1435 void *userdata) {
1436
1437 char ***l = data;
1438 int r;
1439
1440 assert(l);
1441 assert(lvalue);
1442 assert(rvalue);
1443
1444 if (isempty(rvalue)) {
1445 *l = strv_free(*l);
1446 return 0;
1447 }
1448
1449 for (;;) {
1450 _cleanup_free_ char *w = NULL;
1451
1452 r = extract_first_word(&rvalue, &w, NULL, 0);
1453 if (r == -ENOMEM)
1454 return log_oom();
1455 if (r < 0) {
ab24039f
ZJS
1456 log_syntax(unit, LOG_ERR, filename, line, r,
1457 "Failed to extract NTP server name, ignoring: %s", rvalue);
26575990
LP
1458 break;
1459 }
1460 if (r == 0)
1461 break;
1462
1463 r = dns_name_is_valid_or_address(w);
1464 if (r <= 0) {
ab24039f
ZJS
1465 log_syntax(unit, LOG_ERR, filename, line, r,
1466 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1467 continue;
af1c0de0
SS
1468 }
1469
c448459d
ZJS
1470 if (strv_length(*l) > MAX_NTP_SERVERS) {
1471 log_syntax(unit, LOG_WARNING, filename, line, 0,
1472 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1473 MAX_NTP_SERVERS, w);
1474 break;
1475 }
1476
1477 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1478 if (r < 0)
1479 return log_oom();
af1c0de0
SS
1480 }
1481
1482 return 0;
1483}
1484
1485int config_parse_dhcp_user_class(
1486 const char *unit,
1487 const char *filename,
1488 unsigned line,
1489 const char *section,
1490 unsigned section_line,
1491 const char *lvalue,
1492 int ltype,
1493 const char *rvalue,
1494 void *data,
1495 void *userdata) {
1496
1497 char ***l = data;
1498 int r;
1499
1500 assert(l);
1501 assert(lvalue);
1502 assert(rvalue);
1503
1504 if (isempty(rvalue)) {
1505 *l = strv_free(*l);
1506 return 0;
1507 }
1508
1509 for (;;) {
1510 _cleanup_free_ char *w = NULL;
1511
1512 r = extract_first_word(&rvalue, &w, NULL, 0);
1513 if (r == -ENOMEM)
1514 return log_oom();
1515 if (r < 0) {
ab24039f
ZJS
1516 log_syntax(unit, LOG_ERR, filename, line, r,
1517 "Failed to split user classes option, ignoring: %s", rvalue);
af1c0de0
SS
1518 break;
1519 }
1520 if (r == 0)
1521 break;
1522
1523 if (strlen(w) > 255) {
80be3de3 1524 log_syntax(unit, LOG_ERR, filename, line, 0,
ab24039f 1525 "%s length is not in the range 1-255, ignoring.", w);
af1c0de0 1526 continue;
26575990
LP
1527 }
1528
1529 r = strv_push(l, w);
1530 if (r < 0)
1531 return log_oom();
1532
1533 w = NULL;
1534 }
1535
1536 return 0;
1537}
1538
d5fa3339
YW
1539int config_parse_section_route_table(
1540 const char *unit,
1541 const char *filename,
1542 unsigned line,
1543 const char *section,
1544 unsigned section_line,
1545 const char *lvalue,
1546 int ltype,
1547 const char *rvalue,
1548 void *data,
1549 void *userdata) {
1550
fc1ba79d 1551 Network *network = data;
f594276b
JK
1552 uint32_t rt;
1553 int r;
1554
1555 assert(filename);
1556 assert(lvalue);
1557 assert(rvalue);
1558 assert(data);
1559
1560 r = safe_atou32(rvalue, &rt);
1561 if (r < 0) {
1562 log_syntax(unit, LOG_ERR, filename, line, r,
d5fa3339 1563 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
f594276b
JK
1564 return 0;
1565 }
1566
d5fa3339
YW
1567 if (streq_ptr(section, "DHCP")) {
1568 network->dhcp_route_table = rt;
1569 network->dhcp_route_table_set = true;
1570 } else { /* section is IPv6AcceptRA */
1571 network->ipv6_accept_ra_route_table = rt;
1572 network->ipv6_accept_ra_route_table_set = true;
1573 }
f594276b
JK
1574
1575 return 0;
1576}
1577
ab24039f
ZJS
1578DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
1579 "Failed to parse DHCP use domains setting");
b2a81c0b
LP
1580
1581static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1582 [DHCP_USE_DOMAINS_NO] = "no",
1583 [DHCP_USE_DOMAINS_ROUTE] = "route",
1584 [DHCP_USE_DOMAINS_YES] = "yes",
1585};
1586
1587DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
34437b4f
LP
1588
1589DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1590
1591static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1592 [LLDP_MODE_NO] = "no",
1593 [LLDP_MODE_YES] = "yes",
1594 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1595};
1596
1597DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
8217ed5e
TH
1598
1599int config_parse_iaid(const char *unit,
1600 const char *filename,
1601 unsigned line,
1602 const char *section,
1603 unsigned section_line,
1604 const char *lvalue,
1605 int ltype,
1606 const char *rvalue,
1607 void *data,
1608 void *userdata) {
1609 Network *network = data;
1610 uint32_t iaid;
1611 int r;
1612
1613 assert(filename);
1614 assert(lvalue);
1615 assert(rvalue);
1616 assert(network);
1617
1618 r = safe_atou32(rvalue, &iaid);
1619 if (r < 0) {
1620 log_syntax(unit, LOG_ERR, filename, line, r,
1621 "Unable to read IAID, ignoring assignment: %s", rvalue);
1622 return 0;
1623 }
1624
1625 network->iaid = iaid;
1626 network->iaid_set = true;
1627
1628 return 0;
1629}
4ac77d63
YW
1630
1631int config_parse_required_for_online(
1632 const char *unit,
1633 const char *filename,
1634 unsigned line,
1635 const char *section,
1636 unsigned section_line,
1637 const char *lvalue,
1638 int ltype,
1639 const char *rvalue,
1640 void *data,
1641 void *userdata) {
1642
1643 Network *network = data;
1644 LinkOperationalState s;
1645 bool required = true;
1646 int r;
1647
1648 if (isempty(rvalue)) {
1649 network->required_for_online = true;
1650 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1651 return 0;
1652 }
1653
1654 s = link_operstate_from_string(rvalue);
1655 if (s < 0) {
1656 r = parse_boolean(rvalue);
1657 if (r < 0) {
1658 log_syntax(unit, LOG_ERR, filename, line, r,
1659 "Failed to parse %s= setting, ignoring assignment: %s",
1660 lvalue, rvalue);
1661 return 0;
1662 }
1663
1664 required = r;
1665 s = LINK_OPERSTATE_DEGRADED;
1666 }
1667
1668 network->required_for_online = required;
1669 network->required_operstate_for_online = s;
1670
1671 return 0;
1672}