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