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