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