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