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