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