]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
networkd: add support to keep configuration
[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
7da377ef
SS
242 if (network->dhcp_critical >= 0) {
243 if (network->keep_configuration >= 0)
244 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
245 "Ignoring CriticalConnection=.", network->filename);
246 else if (network->dhcp_critical)
247 /* CriticalConnection=yes also preserve foreign static configurations. */
248 network->keep_configuration = KEEP_CONFIGURATION_YES;
249 else
250 network->keep_configuration = KEEP_CONFIGURATION_NO;
251 }
252
253 if (network->keep_configuration < 0)
254 network->keep_configuration = KEEP_CONFIGURATION_NO;
255
4bec2f23 256 LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
fcbf4cb7 257 if (address_section_verify(address) < 0)
4bec2f23 258 address_free(address);
4bec2f23 259
fcbf4cb7
YW
260 LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
261 if (route_section_verify(route, network) < 0)
4bec2f23 262 route_free(route);
0321cea7 263
fcbf4cb7
YW
264 LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
265 if (section_is_invalid(fdb->section))
266 fdb_entry_free(fdb);
267
268 LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
269 if (section_is_invalid(neighbor->section))
270 neighbor_free(neighbor);
271
272 LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
273 if (section_is_invalid(label->section))
274 address_label_free(label);
275
276 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
277 if (section_is_invalid(prefix->section))
278 prefix_free(prefix);
279
280 LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
281 if (section_is_invalid(rule->section))
282 routing_policy_rule_free(rule);
4912ab77 283
0321cea7
YW
284 return 0;
285}
286
212bd73c 287int network_load_one(Manager *manager, const char *filename) {
838b2f7a 288 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 289 _cleanup_(network_unrefp) Network *network = NULL;
f579559b 290 _cleanup_fclose_ FILE *file = NULL;
047a0dac 291 const char *dropin_dirname;
838b2f7a 292 char *d;
f579559b
TG
293 int r;
294
bf1bc670
TA
295 assert(manager);
296 assert(filename);
297
f579559b
TG
298 file = fopen(filename, "re");
299 if (!file) {
300 if (errno == ENOENT)
301 return 0;
1e7a0e21
LP
302
303 return -errno;
f579559b
TG
304 }
305
ed88bcfb
ZJS
306 if (null_or_empty_fd(fileno(file))) {
307 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
308 return 0;
309 }
310
838b2f7a
YW
311 fname = strdup(filename);
312 if (!fname)
313 return log_oom();
314
315 name = strdup(basename(filename));
316 if (!name)
317 return log_oom();
318
319 d = strrchr(name, '.');
320 if (!d)
321 return -EINVAL;
322
323 *d = '\0';
324
325 dropin_dirname = strjoina(name, ".network.d");
326
17f9c355 327 network = new(Network, 1);
f579559b
TG
328 if (!network)
329 return log_oom();
330
17f9c355 331 *network = (Network) {
838b2f7a
YW
332 .filename = TAKE_PTR(fname),
333 .name = TAKE_PTR(name),
17f9c355 334
715d398e 335 .manager = manager,
35ac3b76
YW
336 .n_ref = 1,
337
17f9c355 338 .required_for_online = true,
4ac77d63 339 .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
17f9c355 340 .dhcp = ADDRESS_FAMILY_NO,
7da377ef 341 .dhcp_critical = -1,
17f9c355
YW
342 .dhcp_use_ntp = true,
343 .dhcp_use_dns = true,
344 .dhcp_use_hostname = true,
345 .dhcp_use_routes = true,
5238e957 346 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
347 .dhcp_send_hostname = true,
348 /* To enable/disable RFC7844 Anonymity Profiles */
349 .dhcp_anonymize = false,
350 .dhcp_route_metric = DHCP_ROUTE_METRIC,
c9c908a6 351 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
352 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
353 .dhcp_route_table = RT_TABLE_MAIN,
354 .dhcp_route_table_set = false,
355 /* NOTE: from man: UseMTU=... Defaults to false*/
356 .dhcp_use_mtu = false,
357 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
358 .dhcp_use_timezone = false,
359 .rapid_commit = true,
360
361 .dhcp_server_emit_dns = true,
362 .dhcp_server_emit_ntp = true,
363 .dhcp_server_emit_router = true,
364 .dhcp_server_emit_timezone = true,
365
366 .router_emit_dns = true,
367 .router_emit_domains = true,
368
369 .use_bpdu = -1,
370 .hairpin = -1,
371 .fast_leave = -1,
372 .allow_port_to_be_root = -1,
373 .unicast_flood = -1,
7f15b714 374 .multicast_flood = -1,
d3aa8b49 375 .multicast_to_unicast = -1,
7f15b714
TJ
376 .neighbor_suppression = -1,
377 .learning = -1,
1087623b
SS
378 .bridge_proxy_arp = -1,
379 .bridge_proxy_arp_wifi = -1,
17f9c355 380 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 381 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355
YW
382
383 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
384
7ece6f58 385 .dns_default_route = -1,
17f9c355
YW
386 .llmnr = RESOLVE_SUPPORT_YES,
387 .mdns = RESOLVE_SUPPORT_NO,
388 .dnssec_mode = _DNSSEC_MODE_INVALID,
389 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
390
0321cea7
YW
391 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
392 .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID,
17f9c355
YW
393
394 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
395 .ipv6_accept_ra = -1,
396 .ipv6_dad_transmits = -1,
397 .ipv6_hop_limit = -1,
398 .ipv6_proxy_ndp = -1,
399 .duid.type = _DUID_TYPE_INVALID,
400 .proxy_arp = -1,
401 .arp = -1,
402 .multicast = -1,
403 .allmulticast = -1,
404 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
405 .ipv6_accept_ra_use_autonomous_prefix = true,
406 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 407 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 408 .ipv6_accept_ra_route_table_set = false,
c423be28 409
7da377ef
SS
410 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
411
c423be28 412 .can_triple_sampling = -1,
17f9c355 413 };
f579559b 414
dc0d4078 415 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
23bb31aa
ZJS
416 "Match\0"
417 "Link\0"
418 "Network\0"
419 "Address\0"
e4a71bf3 420 "Neighbor\0"
95b74ef6 421 "IPv6AddressLabel\0"
bce67bbe 422 "RoutingPolicyRule\0"
23bb31aa
ZJS
423 "Route\0"
424 "DHCP\0"
425 "DHCPv4\0" /* compat */
426 "DHCPServer\0"
427 "IPv6AcceptRA\0"
a0e5c15d 428 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
429 "Bridge\0"
430 "BridgeFDB\0"
9d5d0090 431 "BridgeVLAN\0"
7d5cac19 432 "IPv6PrefixDelegation\0"
06828bb6
HP
433 "IPv6Prefix\0"
434 "CAN\0",
23bb31aa 435 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 436 CONFIG_PARSE_WARN, network);
102bc043 437 if (r < 0)
f579559b 438 return r;
f579559b 439
add8d07d 440 network_apply_anonymize_if_set(network);
441
fa7cd711
YW
442 r = network_add_ipv4ll_route(network);
443 if (r < 0)
444 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
445
5d5003ab
YW
446 r = network_add_default_route_on_device(network);
447 if (r < 0)
448 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
449 network->filename);
450
715d398e 451 r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
dbffab87
TG
452 if (r < 0)
453 return r;
454
715d398e 455 r = ordered_hashmap_put(manager->networks, network->name, network);
dbffab87
TG
456 if (r < 0)
457 return r;
458
0321cea7
YW
459 if (network_verify(network) < 0)
460 return 0;
b3070dc0 461
f579559b 462 network = NULL;
f579559b
TG
463 return 0;
464}
465
466int network_load(Manager *manager) {
477e73b5
ZJS
467 _cleanup_strv_free_ char **files = NULL;
468 char **f;
f579559b
TG
469 int r;
470
471 assert(manager);
472
715d398e 473 ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
f579559b 474
dc0d4078 475 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
476 if (r < 0)
477 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 478
715d398e 479 STRV_FOREACH(f, files) {
f579559b
TG
480 r = network_load_one(manager, *f);
481 if (r < 0)
482 return r;
483 }
484
f579559b
TG
485 return 0;
486}
487
35ac3b76 488static Network *network_free(Network *network) {
a0e5c15d 489 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
490 RoutingPolicyRule *rule;
491 FdbEntry *fdb_entry;
e4a71bf3 492 Neighbor *neighbor;
95b74ef6 493 AddressLabel *label;
057abfd8 494 Prefix *prefix;
bce67bbe 495 Address *address;
bce67bbe 496 Route *route;
f579559b
TG
497
498 if (!network)
35ac3b76 499 return NULL;
f579559b
TG
500
501 free(network->filename);
502
e90d0374 503 set_free_free(network->match_mac);
5256e00e
TG
504 strv_free(network->match_path);
505 strv_free(network->match_driver);
506 strv_free(network->match_type);
507 strv_free(network->match_name);
c4f58dea 508 condition_free_list(network->conditions);
f579559b
TG
509
510 free(network->description);
edb85f0d 511 free(network->dhcp_vendor_class_identifier);
af1c0de0 512 strv_free(network->dhcp_user_class);
27cb34f5 513 free(network->dhcp_hostname);
727b5734 514 set_free(network->dhcp_black_listed_ip);
c106cc36
TG
515 free(network->mac);
516
b0e39c82 517 strv_free(network->ntp);
5512a963 518 free(network->dns);
5e2a51d5
ZJS
519 ordered_set_free_free(network->search_domains);
520 ordered_set_free_free(network->route_domains);
0d4ad91d 521 strv_free(network->bind_carrier);
cdd7812b 522
5e2a51d5 523 ordered_set_free_free(network->router_search_domains);
cdd7812b 524 free(network->router_dns);
e520ce64 525 set_free_free(network->ndisc_black_listed_prefix);
3bef724f 526
cebe1257
YW
527 free(network->bridge_name);
528 free(network->bond_name);
529 free(network->vrf_name);
530 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 531 netdev_unref(network->bridge);
47e2dc31 532 netdev_unref(network->bond);
6cb955c6 533 netdev_unref(network->vrf);
fa6f1e54 534 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 535
f048a16b 536 while ((route = network->static_routes))
f579559b
TG
537 route_free(route);
538
f048a16b 539 while ((address = network->static_addresses))
f579559b
TG
540 address_free(address);
541
b98b483b
AR
542 while ((fdb_entry = network->static_fdb_entries))
543 fdb_entry_free(fdb_entry);
544
a0e5c15d
FK
545 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
546 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
547
e4a71bf3
WKI
548 while ((neighbor = network->neighbors))
549 neighbor_free(neighbor);
550
95b74ef6
SS
551 while ((label = network->address_labels))
552 address_label_free(label);
553
057abfd8
PF
554 while ((prefix = network->static_prefixes))
555 prefix_free(prefix);
556
bce67bbe
SS
557 while ((rule = network->rules))
558 routing_policy_rule_free(rule);
559
6ae115c1
TG
560 hashmap_free(network->addresses_by_section);
561 hashmap_free(network->routes_by_section);
b98b483b 562 hashmap_free(network->fdb_entries_by_section);
e4a71bf3 563 hashmap_free(network->neighbors_by_section);
95b74ef6 564 hashmap_free(network->address_labels_by_section);
057abfd8 565 hashmap_free(network->prefixes_by_section);
bce67bbe 566 hashmap_free(network->rules_by_section);
6ae115c1 567
dbffab87 568 if (network->manager) {
715d398e
YW
569 if (network->manager->networks && network->name)
570 ordered_hashmap_remove(network->manager->networks, network->name);
27dfc982
YW
571
572 if (network->manager->duids_requesting_uuid)
573 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
574 }
575
576 free(network->name);
f579559b 577
8eb9058d 578 free(network->dhcp_server_timezone);
1a04db0f
LP
579 free(network->dhcp_server_dns);
580 free(network->dhcp_server_ntp);
8eb9058d 581
8a516214
LP
582 set_free_free(network->dnssec_negative_trust_anchors);
583
35ac3b76 584 return mfree(network);
f579559b
TG
585}
586
35ac3b76
YW
587DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
588
dbffab87
TG
589int network_get_by_name(Manager *manager, const char *name, Network **ret) {
590 Network *network;
591
592 assert(manager);
593 assert(name);
594 assert(ret);
595
715d398e 596 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
597 if (!network)
598 return -ENOENT;
599
600 *ret = network;
601
602 return 0;
603}
604
51517f9e 605int network_get(Manager *manager, sd_device *device,
505f8da7
TG
606 const char *ifname, const struct ether_addr *address,
607 Network **ret) {
4f4daf41 608 const char *path = NULL, *driver = NULL, *devtype = NULL;
51517f9e 609 Network *network;
715d398e 610 Iterator i;
f579559b
TG
611
612 assert(manager);
f579559b 613 assert(ret);
af3aa302 614
24c083df 615 if (device) {
51517f9e 616 (void) sd_device_get_property_value(device, "ID_PATH", &path);
af3aa302 617
51517f9e 618 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
af3aa302 619
51517f9e 620 (void) sd_device_get_devtype(device, &devtype);
24c083df 621 }
f579559b 622
715d398e 623 ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
f579559b 624 if (net_match_config(network->match_mac, network->match_path,
505f8da7 625 network->match_driver, network->match_type,
c4f58dea 626 network->match_name,
4f4daf41 627 address, path, driver, devtype, ifname)) {
24c083df 628 if (network->match_name && device) {
ca6038b8
TG
629 const char *attr;
630 uint8_t name_assign_type = NET_NAME_UNKNOWN;
631
51517f9e 632 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 633 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
634
635 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
636 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
637 ifname, network->filename);
32bc8adc 638 else
a2fae7bb 639 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 640 } else
a2fae7bb 641 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 642
f579559b
TG
643 *ret = network;
644 return 0;
645 }
f579559b
TG
646
647 *ret = NULL;
648
649 return -ENOENT;
650}
651
7d342c03 652int network_apply(Network *network, Link *link) {
c4a03a56
TG
653 assert(network);
654 assert(link);
655
c9c908a6 656 link->network = network_ref(network);
f579559b 657
5512a963 658 if (network->n_dns > 0 ||
3df9bec5 659 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
660 !ordered_set_isempty(network->search_domains) ||
661 !ordered_set_isempty(network->route_domains))
84de38c5 662 link_dirty(link);
3bef724f 663
f579559b
TG
664 return 0;
665}
02b59d57 666
439689c6
SS
667bool network_has_static_ipv6_addresses(Network *network) {
668 Address *address;
669
670 assert(network);
671
672 LIST_FOREACH(addresses, address, network->static_addresses) {
673 if (address->family == AF_INET6)
674 return true;
675 }
676
677 return false;
678}
679
cebe1257 680int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
681 const char *filename,
682 unsigned line,
683 const char *section,
684 unsigned section_line,
685 const char *lvalue,
686 int ltype,
687 const char *rvalue,
688 void *data,
689 void *userdata) {
95dba435
YW
690 _cleanup_free_ char *name = NULL;
691 NetDevKind kind = ltype;
cebe1257 692 Hashmap **h = data;
02b59d57
TG
693 int r;
694
695 assert(filename);
696 assert(lvalue);
697 assert(rvalue);
698 assert(data);
95dba435
YW
699 assert(IN_SET(kind,
700 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0
SS
701 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
702 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL));
54abf461 703
cebe1257 704 if (!ifname_valid(rvalue)) {
3772cfde
ZJS
705 log_syntax(unit, LOG_ERR, filename, line, 0,
706 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
707 return 0;
708 }
709
cebe1257
YW
710 name = strdup(rvalue);
711 if (!name)
712 return log_oom();
3e570042 713
cebe1257
YW
714 r = hashmap_ensure_allocated(h, &string_hash_ops);
715 if (r < 0)
716 return log_oom();
326cb406 717
cebe1257 718 r = hashmap_put(*h, name, INT_TO_PTR(kind));
83ec4592 719 if (r < 0)
3772cfde 720 log_syntax(unit, LOG_ERR, filename, line, r,
83ec4592
ZJS
721 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
722 else if (r == 0)
723 log_syntax(unit, LOG_DEBUG, filename, line, r,
724 "NetDev '%s' specified twice, ignoring.", name);
725 else
726 name = NULL;
47e2dc31 727
fe6b2d55
TG
728 return 0;
729}
7951dea2 730
3df9bec5
LP
731int config_parse_domains(
732 const char *unit,
733 const char *filename,
734 unsigned line,
735 const char *section,
736 unsigned section_line,
737 const char *lvalue,
738 int ltype,
739 const char *rvalue,
740 void *data,
741 void *userdata) {
742
743 const char *p;
744 Network *n = data;
6192b846
TG
745 int r;
746
3df9bec5
LP
747 assert(n);
748 assert(lvalue);
749 assert(rvalue);
6192b846 750
3df9bec5 751 if (isempty(rvalue)) {
5e2a51d5
ZJS
752 n->search_domains = ordered_set_free_free(n->search_domains);
753 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
754 return 0;
755 }
67272d15 756
3df9bec5
LP
757 p = rvalue;
758 for (;;) {
759 _cleanup_free_ char *w = NULL, *normalized = NULL;
760 const char *domain;
761 bool is_route;
762
763 r = extract_first_word(&p, &w, NULL, 0);
764 if (r < 0) {
ab24039f
ZJS
765 log_syntax(unit, LOG_ERR, filename, line, r,
766 "Failed to extract search or route domain, ignoring: %s", rvalue);
3df9bec5
LP
767 break;
768 }
769 if (r == 0)
770 break;
771
772 is_route = w[0] == '~';
773 domain = is_route ? w + 1 : w;
774
775 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
776 /* If the root domain appears as is, or the special token "*" is found, we'll
777 * consider this as routing domain, unconditionally. */
3df9bec5 778 is_route = true;
ab24039f
ZJS
779 domain = "."; /* make sure we don't allow empty strings, thus write the root
780 * domain as "." */
3df9bec5 781 } else {
7470cc4c 782 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 783 if (r < 0) {
ab24039f
ZJS
784 log_syntax(unit, LOG_ERR, filename, line, r,
785 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
786 continue;
787 }
788
789 domain = normalized;
790
791 if (is_localhost(domain)) {
ab24039f
ZJS
792 log_syntax(unit, LOG_ERR, filename, line, 0,
793 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
794 domain);
37de2509 795 continue;
3df9bec5 796 }
37de2509 797 }
40274ed6 798
5e2a51d5
ZJS
799 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
800 r = ordered_set_ensure_allocated(set, &string_hash_ops);
801 if (r < 0)
802 return r;
803
804 r = ordered_set_put_strdup(*set, domain);
09451975
LP
805 if (r < 0)
806 return log_oom();
40274ed6 807 }
f15b6e5a 808
6192b846
TG
809 return 0;
810}
811
d0d6a4cd
TG
812int config_parse_ipv4ll(
813 const char* unit,
814 const char *filename,
815 unsigned line,
816 const char *section,
817 unsigned section_line,
818 const char *lvalue,
819 int ltype,
820 const char *rvalue,
821 void *data,
822 void *userdata) {
823
824 AddressFamilyBoolean *link_local = data;
810ae0dc 825 int r;
d0d6a4cd
TG
826
827 assert(filename);
828 assert(lvalue);
829 assert(rvalue);
830 assert(data);
831
832 /* Note that this is mostly like
833 * config_parse_address_family_boolean(), except that it
834 * applies only to IPv4 */
835
810ae0dc
YW
836 r = parse_boolean(rvalue);
837 if (r < 0) {
838 log_syntax(unit, LOG_ERR, filename, line, r,
839 "Failed to parse %s=%s, ignoring assignment. "
840 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
841 lvalue, rvalue, lvalue);
842 return 0;
843 }
844
845 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
846
847 log_syntax(unit, LOG_WARNING, filename, line, 0,
848 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
849 lvalue, rvalue, address_family_boolean_to_string(*link_local));
d0d6a4cd
TG
850
851 return 0;
852}
853
bd8f6538
TG
854int config_parse_dhcp(
855 const char* unit,
856 const char *filename,
857 unsigned line,
858 const char *section,
859 unsigned section_line,
860 const char *lvalue,
861 int ltype,
862 const char *rvalue,
863 void *data,
864 void *userdata) {
865
cb9fc36a 866 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
867
868 assert(filename);
869 assert(lvalue);
870 assert(rvalue);
871 assert(data);
872
769d324c
LP
873 /* Note that this is mostly like
874 * config_parse_address_family_boolean(), except that it
875 * understands some old names for the enum values */
876
cb9fc36a
LP
877 s = address_family_boolean_from_string(rvalue);
878 if (s < 0) {
879
880 /* Previously, we had a slightly different enum here,
5238e957 881 * support its values for compatibility. */
cb9fc36a
LP
882
883 if (streq(rvalue, "none"))
884 s = ADDRESS_FAMILY_NO;
885 else if (streq(rvalue, "v4"))
886 s = ADDRESS_FAMILY_IPV4;
887 else if (streq(rvalue, "v6"))
888 s = ADDRESS_FAMILY_IPV6;
889 else if (streq(rvalue, "both"))
890 s = ADDRESS_FAMILY_YES;
891 else {
ab24039f
ZJS
892 log_syntax(unit, LOG_ERR, filename, line, 0,
893 "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
894 return 0;
895 }
41f62acc
YW
896
897 log_syntax(unit, LOG_WARNING, filename, line, 0,
898 "DHCP=%s is deprecated, please use DHCP=%s instead.",
899 rvalue, address_family_boolean_to_string(s));
bd8f6538
TG
900 }
901
cb9fc36a 902 *dhcp = s;
bd8f6538
TG
903 return 0;
904}
905
3e43b2cd
JJ
906static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
907 [DHCP_CLIENT_ID_MAC] = "mac",
dace710c
YW
908 [DHCP_CLIENT_ID_DUID] = "duid",
909 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
3e43b2cd
JJ
910};
911
499d555a 912DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
ab24039f
ZJS
913DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
914 "Failed to parse client identifier type");
3e43b2cd 915
60c35566 916int config_parse_ipv6token(
7f77697a
TG
917 const char* unit,
918 const char *filename,
919 unsigned line,
920 const char *section,
921 unsigned section_line,
922 const char *lvalue,
923 int ltype,
924 const char *rvalue,
925 void *data,
926 void *userdata) {
927
928 union in_addr_union buffer;
929 struct in6_addr *token = data;
930 int r;
931
932 assert(filename);
933 assert(lvalue);
934 assert(rvalue);
935 assert(token);
936
937 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
938 if (r < 0) {
ab24039f
ZJS
939 log_syntax(unit, LOG_ERR, filename, line, r,
940 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
941 return 0;
942 }
943
c606db69 944 if (in_addr_is_null(AF_INET6, &buffer)) {
ab24039f
ZJS
945 log_syntax(unit, LOG_ERR, filename, line, 0,
946 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
947 return 0;
948 }
949
950 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
ab24039f
ZJS
951 log_syntax(unit, LOG_ERR, filename, line, 0,
952 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
953 return 0;
954 }
955
956 *token = buffer.in6;
957
958 return 0;
959}
8add5f79 960
49092e22 961static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
962 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
963 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
964 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
965};
966
967DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
968
969int config_parse_ipv6_privacy_extensions(
970 const char* unit,
971 const char *filename,
972 unsigned line,
973 const char *section,
974 unsigned section_line,
975 const char *lvalue,
976 int ltype,
977 const char *rvalue,
978 void *data,
979 void *userdata) {
980
981 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
982 int k;
983
984 assert(filename);
985 assert(lvalue);
986 assert(rvalue);
987 assert(ipv6_privacy_extensions);
988
989 /* Our enum shall be a superset of booleans, hence first try
990 * to parse as boolean, and then as enum */
991
992 k = parse_boolean(rvalue);
993 if (k > 0)
1f0d9695 994 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 995 else if (k == 0)
1f0d9695 996 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 997 else {
1f0d9695 998 IPv6PrivacyExtensions s;
49092e22
SS
999
1000 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
1001 if (s < 0) {
1002
1003 if (streq(rvalue, "kernel"))
1004 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
1005 else {
ab24039f
ZJS
1006 log_syntax(unit, LOG_ERR, filename, line, 0,
1007 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1f0d9695
LP
1008 return 0;
1009 }
49092e22
SS
1010 }
1011
1012 *ipv6_privacy_extensions = s;
1013 }
1014
1015 return 0;
1016}
a7d0ef44 1017
1ac608c9
LP
1018int config_parse_hostname(
1019 const char *unit,
1020 const char *filename,
1021 unsigned line,
1022 const char *section,
1023 unsigned section_line,
1024 const char *lvalue,
1025 int ltype,
1026 const char *rvalue,
1027 void *data,
1028 void *userdata) {
1029
6528693a
YW
1030 _cleanup_free_ char *hn = NULL;
1031 char **hostname = data;
a7d0ef44
SS
1032 int r;
1033
1034 assert(filename);
1035 assert(lvalue);
1036 assert(rvalue);
1037
1ac608c9 1038 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
1039 if (r < 0)
1040 return r;
1041
1ac608c9 1042 if (!hostname_is_valid(hn, false)) {
ab24039f
ZJS
1043 log_syntax(unit, LOG_ERR, filename, line, 0,
1044 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
1045 return 0;
1046 }
1047
6528693a
YW
1048 r = dns_name_is_valid(hn);
1049 if (r < 0) {
ab24039f
ZJS
1050 log_syntax(unit, LOG_ERR, filename, line, r,
1051 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
1052 return 0;
1053 }
1054 if (r == 0) {
ab24039f
ZJS
1055 log_syntax(unit, LOG_ERR, filename, line, 0,
1056 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
1057 return 0;
1058 }
1059
1060 return free_and_replace(*hostname, hn);
a7d0ef44 1061}
8eb9058d
LP
1062
1063int config_parse_timezone(
1064 const char *unit,
1065 const char *filename,
1066 unsigned line,
1067 const char *section,
1068 unsigned section_line,
1069 const char *lvalue,
1070 int ltype,
1071 const char *rvalue,
1072 void *data,
1073 void *userdata) {
1074
19f9e4e2
YW
1075 _cleanup_free_ char *tz = NULL;
1076 char **datap = data;
8eb9058d
LP
1077 int r;
1078
1079 assert(filename);
1080 assert(lvalue);
1081 assert(rvalue);
1082
1083 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1084 if (r < 0)
1085 return r;
1086
089fb865 1087 if (!timezone_is_valid(tz, LOG_ERR)) {
ab24039f
ZJS
1088 log_syntax(unit, LOG_ERR, filename, line, 0,
1089 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1090 return 0;
1091 }
1092
19f9e4e2 1093 return free_and_replace(*datap, tz);
8eb9058d 1094}
1a04db0f
LP
1095
1096int config_parse_dhcp_server_dns(
1097 const char *unit,
1098 const char *filename,
1099 unsigned line,
1100 const char *section,
1101 unsigned section_line,
1102 const char *lvalue,
1103 int ltype,
1104 const char *rvalue,
1105 void *data,
1106 void *userdata) {
1107
1108 Network *n = data;
1109 const char *p = rvalue;
1110 int r;
1111
1112 assert(filename);
1113 assert(lvalue);
1114 assert(rvalue);
1115
1116 for (;;) {
1117 _cleanup_free_ char *w = NULL;
004aadca
YW
1118 union in_addr_union a;
1119 struct in_addr *m;
1a04db0f
LP
1120
1121 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1122 if (r == -ENOMEM)
1123 return log_oom();
1a04db0f 1124 if (r < 0) {
ab24039f
ZJS
1125 log_syntax(unit, LOG_ERR, filename, line, r,
1126 "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1127 return 0;
1128 }
1a04db0f 1129 if (r == 0)
fa105ce6 1130 break;
1a04db0f 1131
004aadca
YW
1132 r = in_addr_from_string(AF_INET, w, &a);
1133 if (r < 0) {
1134 log_syntax(unit, LOG_ERR, filename, line, r,
1135 "Failed to parse DNS server address '%s', ignoring assignment: %m", w);
1a04db0f
LP
1136 continue;
1137 }
1138
62d74c78 1139 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1a04db0f
LP
1140 if (!m)
1141 return log_oom();
1142
004aadca 1143 m[n->n_dhcp_server_dns++] = a.in;
1a04db0f
LP
1144 n->dhcp_server_dns = m;
1145 }
fa105ce6 1146
88295a05
PF
1147 return 0;
1148}
1149
1150int config_parse_radv_dns(
1151 const char *unit,
1152 const char *filename,
1153 unsigned line,
1154 const char *section,
1155 unsigned section_line,
1156 const char *lvalue,
1157 int ltype,
1158 const char *rvalue,
1159 void *data,
1160 void *userdata) {
1161
1162 Network *n = data;
1163 const char *p = rvalue;
1164 int r;
1165
1166 assert(filename);
1167 assert(lvalue);
1168 assert(rvalue);
1169
1170 for (;;) {
1171 _cleanup_free_ char *w = NULL;
1172 union in_addr_union a;
1173
1174 r = extract_first_word(&p, &w, NULL, 0);
1175 if (r == -ENOMEM)
1176 return log_oom();
1177 if (r < 0) {
ab24039f
ZJS
1178 log_syntax(unit, LOG_ERR, filename, line, r,
1179 "Failed to extract word, ignoring: %s", rvalue);
88295a05
PF
1180 return 0;
1181 }
1182 if (r == 0)
1183 break;
1184
1185 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1186 struct in6_addr *m;
1187
62d74c78 1188 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
88295a05
PF
1189 if (!m)
1190 return log_oom();
1191
1192 m[n->n_router_dns++] = a.in6;
1193 n->router_dns = m;
1194
1195 } else
ab24039f
ZJS
1196 log_syntax(unit, LOG_ERR, filename, line, 0,
1197 "Failed to parse DNS server address, ignoring: %s", w);
88295a05
PF
1198 }
1199
700f1186
PF
1200 return 0;
1201}
1202
1203int config_parse_radv_search_domains(
1204 const char *unit,
1205 const char *filename,
1206 unsigned line,
1207 const char *section,
1208 unsigned section_line,
1209 const char *lvalue,
1210 int ltype,
1211 const char *rvalue,
1212 void *data,
1213 void *userdata) {
1214
1215 Network *n = data;
1216 const char *p = rvalue;
1217 int r;
1218
1219 assert(filename);
1220 assert(lvalue);
1221 assert(rvalue);
1222
1223 for (;;) {
7a99f98b 1224 _cleanup_free_ char *w = NULL, *idna = NULL;
700f1186
PF
1225
1226 r = extract_first_word(&p, &w, NULL, 0);
1227 if (r == -ENOMEM)
1228 return log_oom();
1229 if (r < 0) {
ab24039f
ZJS
1230 log_syntax(unit, LOG_ERR, filename, line, r,
1231 "Failed to extract word, ignoring: %s", rvalue);
700f1186
PF
1232 return 0;
1233 }
1234 if (r == 0)
1235 break;
1236
1237 r = dns_name_apply_idna(w, &idna);
7a99f98b 1238 if (r < 0) {
ab24039f
ZJS
1239 log_syntax(unit, LOG_ERR, filename, line, r,
1240 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
7a99f98b 1241 continue;
5e2a51d5
ZJS
1242 } else if (r == 0)
1243 /* transfer ownership to simplify subsequent operations */
1244 idna = TAKE_PTR(w);
1245
1246 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
1247 if (r < 0)
1248 return r;
1249
1250 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1251 if (r < 0)
1252 return r;
700f1186
PF
1253 }
1254
fa105ce6 1255 return 0;
1a04db0f
LP
1256}
1257
1258int config_parse_dhcp_server_ntp(
1259 const char *unit,
1260 const char *filename,
1261 unsigned line,
1262 const char *section,
1263 unsigned section_line,
1264 const char *lvalue,
1265 int ltype,
1266 const char *rvalue,
1267 void *data,
1268 void *userdata) {
1269
1270 Network *n = data;
1271 const char *p = rvalue;
1272 int r;
1273
1274 assert(filename);
1275 assert(lvalue);
1276 assert(rvalue);
1277
1278 for (;;) {
1279 _cleanup_free_ char *w = NULL;
004aadca
YW
1280 union in_addr_union a;
1281 struct in_addr *m;
1a04db0f
LP
1282
1283 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1284 if (r == -ENOMEM)
1285 return log_oom();
1a04db0f 1286 if (r < 0) {
ab24039f
ZJS
1287 log_syntax(unit, LOG_ERR, filename, line, r,
1288 "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1289 return 0;
1290 }
1a04db0f
LP
1291 if (r == 0)
1292 return 0;
1293
004aadca
YW
1294 r = in_addr_from_string(AF_INET, w, &a);
1295 if (r < 0) {
1296 log_syntax(unit, LOG_ERR, filename, line, r,
1297 "Failed to parse NTP server address '%s', ignoring: %m", w);
1a04db0f
LP
1298 continue;
1299 }
1300
62d74c78 1301 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1a04db0f
LP
1302 if (!m)
1303 return log_oom();
1304
004aadca 1305 m[n->n_dhcp_server_ntp++] = a.in;
1a04db0f
LP
1306 n->dhcp_server_ntp = m;
1307 }
1308}
8a516214 1309
53253824
SS
1310int config_parse_dns(
1311 const char *unit,
1312 const char *filename,
1313 unsigned line,
1314 const char *section,
1315 unsigned section_line,
1316 const char *lvalue,
1317 int ltype,
1318 const char *rvalue,
1319 void *data,
1320 void *userdata) {
1321
1322 Network *n = userdata;
1323 int r;
1324
1325 assert(filename);
1326 assert(lvalue);
1327 assert(rvalue);
1328
1329 for (;;) {
1330 _cleanup_free_ char *w = NULL;
1331 union in_addr_union a;
5512a963 1332 struct in_addr_data *m;
53253824
SS
1333 int family;
1334
5512a963 1335 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1336 if (r == -ENOMEM)
1337 return log_oom();
1338 if (r < 0) {
ab24039f
ZJS
1339 log_syntax(unit, LOG_ERR, filename, line, r,
1340 "Invalid syntax, ignoring: %s", rvalue);
53253824
SS
1341 break;
1342 }
5512a963
LP
1343 if (r == 0)
1344 break;
53253824
SS
1345
1346 r = in_addr_from_string_auto(w, &family, &a);
1347 if (r < 0) {
ab24039f
ZJS
1348 log_syntax(unit, LOG_ERR, filename, line, r,
1349 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1350 continue;
1351 }
1352
62d74c78 1353 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1354 if (!m)
53253824
SS
1355 return log_oom();
1356
5512a963
LP
1357 m[n->n_dns++] = (struct in_addr_data) {
1358 .family = family,
1359 .address = a,
1360 };
1361
1362 n->dns = m;
53253824
SS
1363 }
1364
1365 return 0;
1366}
1367
8a516214
LP
1368int config_parse_dnssec_negative_trust_anchors(
1369 const char *unit,
1370 const char *filename,
1371 unsigned line,
1372 const char *section,
1373 unsigned section_line,
1374 const char *lvalue,
1375 int ltype,
1376 const char *rvalue,
1377 void *data,
1378 void *userdata) {
1379
1380 const char *p = rvalue;
1381 Network *n = data;
1382 int r;
1383
3df9bec5 1384 assert(n);
8a516214
LP
1385 assert(lvalue);
1386 assert(rvalue);
1387
1388 if (isempty(rvalue)) {
1389 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1390 return 0;
1391 }
1392
1393 for (;;) {
1394 _cleanup_free_ char *w = NULL;
1395
1396 r = extract_first_word(&p, &w, NULL, 0);
1397 if (r < 0) {
ab24039f
ZJS
1398 log_syntax(unit, LOG_ERR, filename, line, r,
1399 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
8a516214
LP
1400 break;
1401 }
1402 if (r == 0)
1403 break;
1404
1405 r = dns_name_is_valid(w);
1406 if (r <= 0) {
ab24039f
ZJS
1407 log_syntax(unit, LOG_ERR, filename, line, r,
1408 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1409 continue;
1410 }
1411
cbbf38ae
LP
1412 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1413 if (r < 0)
1414 return log_oom();
1415
8a516214
LP
1416 r = set_put(n->dnssec_negative_trust_anchors, w);
1417 if (r < 0)
1418 return log_oom();
1419 if (r > 0)
1420 w = NULL;
1421 }
1422
1423 return 0;
1424}
b2a81c0b 1425
26575990
LP
1426int config_parse_ntp(
1427 const char *unit,
1428 const char *filename,
1429 unsigned line,
1430 const char *section,
1431 unsigned section_line,
1432 const char *lvalue,
1433 int ltype,
1434 const char *rvalue,
1435 void *data,
1436 void *userdata) {
1437
1438 char ***l = data;
1439 int r;
1440
1441 assert(l);
1442 assert(lvalue);
1443 assert(rvalue);
1444
1445 if (isempty(rvalue)) {
1446 *l = strv_free(*l);
1447 return 0;
1448 }
1449
1450 for (;;) {
1451 _cleanup_free_ char *w = NULL;
1452
1453 r = extract_first_word(&rvalue, &w, NULL, 0);
1454 if (r == -ENOMEM)
1455 return log_oom();
1456 if (r < 0) {
ab24039f
ZJS
1457 log_syntax(unit, LOG_ERR, filename, line, r,
1458 "Failed to extract NTP server name, ignoring: %s", rvalue);
26575990
LP
1459 break;
1460 }
1461 if (r == 0)
1462 break;
1463
1464 r = dns_name_is_valid_or_address(w);
1465 if (r <= 0) {
ab24039f
ZJS
1466 log_syntax(unit, LOG_ERR, filename, line, r,
1467 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1468 continue;
af1c0de0
SS
1469 }
1470
c448459d
ZJS
1471 if (strv_length(*l) > MAX_NTP_SERVERS) {
1472 log_syntax(unit, LOG_WARNING, filename, line, 0,
1473 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1474 MAX_NTP_SERVERS, w);
1475 break;
1476 }
1477
1478 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1479 if (r < 0)
1480 return log_oom();
af1c0de0
SS
1481 }
1482
1483 return 0;
1484}
1485
1486int config_parse_dhcp_user_class(
1487 const char *unit,
1488 const char *filename,
1489 unsigned line,
1490 const char *section,
1491 unsigned section_line,
1492 const char *lvalue,
1493 int ltype,
1494 const char *rvalue,
1495 void *data,
1496 void *userdata) {
1497
1498 char ***l = data;
1499 int r;
1500
1501 assert(l);
1502 assert(lvalue);
1503 assert(rvalue);
1504
1505 if (isempty(rvalue)) {
1506 *l = strv_free(*l);
1507 return 0;
1508 }
1509
1510 for (;;) {
1511 _cleanup_free_ char *w = NULL;
1512
1513 r = extract_first_word(&rvalue, &w, NULL, 0);
1514 if (r == -ENOMEM)
1515 return log_oom();
1516 if (r < 0) {
ab24039f
ZJS
1517 log_syntax(unit, LOG_ERR, filename, line, r,
1518 "Failed to split user classes option, ignoring: %s", rvalue);
af1c0de0
SS
1519 break;
1520 }
1521 if (r == 0)
1522 break;
1523
1524 if (strlen(w) > 255) {
80be3de3 1525 log_syntax(unit, LOG_ERR, filename, line, 0,
ab24039f 1526 "%s length is not in the range 1-255, ignoring.", w);
af1c0de0 1527 continue;
26575990
LP
1528 }
1529
1530 r = strv_push(l, w);
1531 if (r < 0)
1532 return log_oom();
1533
1534 w = NULL;
1535 }
1536
1537 return 0;
1538}
1539
d5fa3339
YW
1540int config_parse_section_route_table(
1541 const char *unit,
1542 const char *filename,
1543 unsigned line,
1544 const char *section,
1545 unsigned section_line,
1546 const char *lvalue,
1547 int ltype,
1548 const char *rvalue,
1549 void *data,
1550 void *userdata) {
1551
fc1ba79d 1552 Network *network = data;
f594276b
JK
1553 uint32_t rt;
1554 int r;
1555
1556 assert(filename);
1557 assert(lvalue);
1558 assert(rvalue);
1559 assert(data);
1560
1561 r = safe_atou32(rvalue, &rt);
1562 if (r < 0) {
1563 log_syntax(unit, LOG_ERR, filename, line, r,
d5fa3339 1564 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
f594276b
JK
1565 return 0;
1566 }
1567
d5fa3339
YW
1568 if (streq_ptr(section, "DHCP")) {
1569 network->dhcp_route_table = rt;
1570 network->dhcp_route_table_set = true;
1571 } else { /* section is IPv6AcceptRA */
1572 network->ipv6_accept_ra_route_table = rt;
1573 network->ipv6_accept_ra_route_table_set = true;
1574 }
f594276b
JK
1575
1576 return 0;
1577}
1578
715cedfb
SS
1579int config_parse_dhcp_max_attempts(
1580 const char *unit,
1581 const char *filename,
1582 unsigned line,
1583 const char *section,
1584 unsigned section_line,
1585 const char *lvalue,
1586 int ltype,
1587 const char *rvalue,
1588 void *data,
1589 void *userdata) {
1590
1591 Network *network = data;
1592 uint64_t a;
1593 int r;
1594
1595 assert(network);
1596 assert(lvalue);
1597 assert(rvalue);
1598
1599 if (isempty(rvalue)) {
1600 network->dhcp_max_attempts = 0;
1601 return 0;
1602 }
1603
1604 if (streq(rvalue, "infinity")) {
1605 network->dhcp_max_attempts = (uint64_t) -1;
1606 return 0;
1607 }
1608
1609 r = safe_atou64(rvalue, &a);
1610 if (r < 0) {
1611 log_syntax(unit, LOG_ERR, filename, line, r,
1612 "Failed to parse DHCP maximum attempts, ignoring: %s", rvalue);
1613 return 0;
1614 }
1615
1616 if (a == 0) {
1617 log_syntax(unit, LOG_ERR, filename, line, 0,
1618 "%s= must be positive integer or 'infinity', ignoring: %s", lvalue, rvalue);
1619 return 0;
1620 }
1621
1622 network->dhcp_max_attempts = a;
1623
1624 return 0;
1625}
1626
727b5734
SS
1627int config_parse_dhcp_black_listed_ip_address(
1628 const char *unit,
1629 const char *filename,
1630 unsigned line,
1631 const char *section,
1632 unsigned section_line,
1633 const char *lvalue,
1634 int ltype,
1635 const char *rvalue,
1636 void *data,
1637 void *userdata) {
1638
1639 Network *network = data;
1640 const char *p;
1641 int r;
1642
1643 assert(filename);
1644 assert(lvalue);
1645 assert(rvalue);
1646 assert(data);
1647
1648 if (isempty(rvalue)) {
1649 network->dhcp_black_listed_ip = set_free(network->dhcp_black_listed_ip);
1650 return 0;
1651 }
1652
1653 for (p = rvalue;;) {
1654 _cleanup_free_ char *n = NULL;
1655 union in_addr_union ip;
1656
1657 r = extract_first_word(&p, &n, NULL, 0);
1658 if (r < 0) {
1659 log_syntax(unit, LOG_ERR, filename, line, r,
1660 "Failed to parse DHCP black listed ip address, ignoring assignment: %s",
1661 rvalue);
1662 return 0;
1663 }
1664 if (r == 0)
1665 return 0;
1666
1667 r = in_addr_from_string(AF_INET, n, &ip);
1668 if (r < 0) {
1669 log_syntax(unit, LOG_ERR, filename, line, r,
1670 "DHCP black listed ip address is invalid, ignoring assignment: %s", n);
1671 continue;
1672 }
1673
1674 r = set_ensure_allocated(&network->dhcp_black_listed_ip, NULL);
1675 if (r < 0)
1676 return log_oom();
1677
1678 r = set_put(network->dhcp_black_listed_ip, UINT32_TO_PTR(ip.in.s_addr));
727b5734
SS
1679 if (r < 0)
1680 log_syntax(unit, LOG_ERR, filename, line, r,
1681 "Failed to store DHCP black listed ip address '%s', ignoring assignment: %m", n);
1682 }
1683
1684 return 0;
1685}
1686
ab24039f
ZJS
1687DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
1688 "Failed to parse DHCP use domains setting");
b2a81c0b
LP
1689
1690static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1691 [DHCP_USE_DOMAINS_NO] = "no",
1692 [DHCP_USE_DOMAINS_ROUTE] = "route",
1693 [DHCP_USE_DOMAINS_YES] = "yes",
1694};
1695
1696DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
34437b4f 1697
8217ed5e
TH
1698int config_parse_iaid(const char *unit,
1699 const char *filename,
1700 unsigned line,
1701 const char *section,
1702 unsigned section_line,
1703 const char *lvalue,
1704 int ltype,
1705 const char *rvalue,
1706 void *data,
1707 void *userdata) {
1708 Network *network = data;
1709 uint32_t iaid;
1710 int r;
1711
1712 assert(filename);
1713 assert(lvalue);
1714 assert(rvalue);
1715 assert(network);
1716
1717 r = safe_atou32(rvalue, &iaid);
1718 if (r < 0) {
1719 log_syntax(unit, LOG_ERR, filename, line, r,
1720 "Unable to read IAID, ignoring assignment: %s", rvalue);
1721 return 0;
1722 }
1723
1724 network->iaid = iaid;
1725 network->iaid_set = true;
1726
1727 return 0;
1728}
4ac77d63
YW
1729
1730int config_parse_required_for_online(
1731 const char *unit,
1732 const char *filename,
1733 unsigned line,
1734 const char *section,
1735 unsigned section_line,
1736 const char *lvalue,
1737 int ltype,
1738 const char *rvalue,
1739 void *data,
1740 void *userdata) {
1741
1742 Network *network = data;
1743 LinkOperationalState s;
1744 bool required = true;
1745 int r;
1746
1747 if (isempty(rvalue)) {
1748 network->required_for_online = true;
1749 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1750 return 0;
1751 }
1752
1753 s = link_operstate_from_string(rvalue);
1754 if (s < 0) {
1755 r = parse_boolean(rvalue);
1756 if (r < 0) {
1757 log_syntax(unit, LOG_ERR, filename, line, r,
1758 "Failed to parse %s= setting, ignoring assignment: %s",
1759 lvalue, rvalue);
1760 return 0;
1761 }
1762
1763 required = r;
1764 s = LINK_OPERSTATE_DEGRADED;
1765 }
1766
1767 network->required_for_online = required;
1768 network->required_operstate_for_online = s;
1769
1770 return 0;
1771}
7da377ef
SS
1772
1773DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1774 "Failed to parse KeepConfiguration= setting");
1775
1776static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1777 [KEEP_CONFIGURATION_NO] = "no",
1778 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1779 [KEEP_CONFIGURATION_STATIC] = "static",
1780 [KEEP_CONFIGURATION_YES] = "yes",
1781};
1782
1783DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);