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