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