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