]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
networkd: Fix SIP double-free
[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) &&
44005bfb
YW
160 strv_isempty(network->match_name) && strv_isempty(network->match_property) &&
161 !network->conditions)
84ea567e
YW
162 log_warning("%s: No valid settings found in the [Match] section. "
163 "The file will match all interfaces. "
164 "If that is intended, please add Name=* in the [Match] section.",
165 network->filename);
166
cebe1257 167 /* skip out early if configuration does not match the environment */
c4f58dea 168 if (!condition_test_list(network->conditions, NULL, NULL, NULL))
cebe1257 169 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
3772cfde
ZJS
170 "%s: Conditions in the file do not match the system environment, skipping.",
171 network->filename);
cebe1257
YW
172
173 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
174 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
175 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
176 (void) network_resolve_stacked_netdevs(network);
177
178 /* Free unnecessary entries. */
179 network->bond_name = mfree(network->bond_name);
180 network->bridge_name = mfree(network->bridge_name);
181 network->vrf_name = mfree(network->vrf_name);
182 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
183
0321cea7
YW
184 if (network->bond) {
185 /* Bonding slave does not support addressing. */
186 if (network->ipv6_accept_ra > 0) {
ab24039f
ZJS
187 log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
188 network->filename);
0321cea7
YW
189 network->ipv6_accept_ra = 0;
190 }
191 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
192 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
193 network->filename);
0321cea7
YW
194 network->link_local = ADDRESS_FAMILY_NO;
195 }
196 if (network->dhcp != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
197 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
198 network->filename);
0321cea7
YW
199 network->dhcp = ADDRESS_FAMILY_NO;
200 }
201 if (network->dhcp_server) {
ab24039f
ZJS
202 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
203 network->filename);
0321cea7
YW
204 network->dhcp_server = false;
205 }
206 if (network->n_static_addresses > 0) {
ab24039f
ZJS
207 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
208 network->filename);
0321cea7
YW
209 while ((address = network->static_addresses))
210 address_free(address);
211 }
212 if (network->n_static_routes > 0) {
ab24039f
ZJS
213 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
214 network->filename);
0321cea7
YW
215 while ((route = network->static_routes))
216 route_free(route);
217 }
218 }
219
220 if (network->link_local < 0)
8f191801
YW
221 network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
222
44013aa4
YW
223 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
224 if (network->ipv6_accept_ra > 0) {
225 log_warning("%s: IPv6AcceptRA= is enabled by the .network file but IPv6 link local addressing is disabled. "
226 "Disabling IPv6AcceptRA=.", network->filename);
227 network->ipv6_accept_ra = false;
228 }
229
230 if (FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV6)) {
231 log_warning("%s: DHCPv6 client is enabled by the .network file but IPv6 link local addressing is disabled. "
232 "Disabling DHCPv6 client.", network->filename);
233 SET_FLAG(network->dhcp, ADDRESS_FAMILY_IPV6, false);
234 }
235
236 if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) {
237 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
238 "Disabling IPv6PrefixDelegation=.", network->filename);
239 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
240 }
241 }
242
29e81083
YW
243 if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
244 !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
245 log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
246 "Disabling the fallback assignment.", network->filename);
247 SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
248 }
249
8f191801
YW
250 if (network->ipv6_accept_ra < 0 && network->bridge)
251 network->ipv6_accept_ra = false;
0321cea7
YW
252
253 /* IPMasquerade=yes implies IPForward=yes */
254 if (network->ip_masquerade)
255 network->ip_forward |= ADDRESS_FAMILY_IPV4;
256
933c70a0 257 if (network->mtu > 0 && network->dhcp_use_mtu) {
0321cea7
YW
258 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
259 "Disabling UseMTU=.", network->filename);
260 network->dhcp_use_mtu = false;
261 }
262
7da377ef
SS
263 if (network->dhcp_critical >= 0) {
264 if (network->keep_configuration >= 0)
265 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
266 "Ignoring CriticalConnection=.", network->filename);
267 else if (network->dhcp_critical)
268 /* CriticalConnection=yes also preserve foreign static configurations. */
269 network->keep_configuration = KEEP_CONFIGURATION_YES;
270 else
95355a28
YW
271 /* For backward compatibility, we do not release DHCP addresses on manager stop. */
272 network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
7da377ef
SS
273 }
274
275 if (network->keep_configuration < 0)
95355a28
YW
276 /* For backward compatibility, we do not release DHCP addresses on manager stop. */
277 network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
7da377ef 278
4bec2f23 279 LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
fcbf4cb7 280 if (address_section_verify(address) < 0)
4bec2f23 281 address_free(address);
4bec2f23 282
fcbf4cb7
YW
283 LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
284 if (route_section_verify(route, network) < 0)
4bec2f23 285 route_free(route);
0321cea7 286
fcbf4cb7
YW
287 LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
288 if (section_is_invalid(fdb->section))
289 fdb_entry_free(fdb);
290
291 LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
044d4b40 292 if (neighbor_section_verify(neighbor) < 0)
fcbf4cb7
YW
293 neighbor_free(neighbor);
294
295 LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
296 if (section_is_invalid(label->section))
297 address_label_free(label);
298
299 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
300 if (section_is_invalid(prefix->section))
301 prefix_free(prefix);
302
303 LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
0aabccc8 304 if (routing_policy_rule_section_verify(rule) < 0)
fcbf4cb7 305 routing_policy_rule_free(rule);
4912ab77 306
0321cea7
YW
307 return 0;
308}
309
212bd73c 310int network_load_one(Manager *manager, const char *filename) {
838b2f7a 311 _cleanup_free_ char *fname = NULL, *name = NULL;
35ac3b76 312 _cleanup_(network_unrefp) Network *network = NULL;
f579559b 313 _cleanup_fclose_ FILE *file = NULL;
047a0dac 314 const char *dropin_dirname;
838b2f7a 315 char *d;
f579559b
TG
316 int r;
317
bf1bc670
TA
318 assert(manager);
319 assert(filename);
320
f579559b
TG
321 file = fopen(filename, "re");
322 if (!file) {
323 if (errno == ENOENT)
324 return 0;
1e7a0e21
LP
325
326 return -errno;
f579559b
TG
327 }
328
ed88bcfb
ZJS
329 if (null_or_empty_fd(fileno(file))) {
330 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
331 return 0;
332 }
333
838b2f7a
YW
334 fname = strdup(filename);
335 if (!fname)
336 return log_oom();
337
338 name = strdup(basename(filename));
339 if (!name)
340 return log_oom();
341
342 d = strrchr(name, '.');
343 if (!d)
344 return -EINVAL;
345
346 *d = '\0';
347
348 dropin_dirname = strjoina(name, ".network.d");
349
17f9c355 350 network = new(Network, 1);
f579559b
TG
351 if (!network)
352 return log_oom();
353
17f9c355 354 *network = (Network) {
838b2f7a
YW
355 .filename = TAKE_PTR(fname),
356 .name = TAKE_PTR(name),
17f9c355 357
715d398e 358 .manager = manager,
35ac3b76
YW
359 .n_ref = 1,
360
17f9c355 361 .required_for_online = true,
4ac77d63 362 .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
17f9c355 363 .dhcp = ADDRESS_FAMILY_NO,
7da377ef 364 .dhcp_critical = -1,
17f9c355 365 .dhcp_use_ntp = true,
299d578f 366 .dhcp_use_sip = true,
17f9c355
YW
367 .dhcp_use_dns = true,
368 .dhcp_use_hostname = true,
369 .dhcp_use_routes = true,
5238e957 370 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
371 .dhcp_send_hostname = true,
372 /* To enable/disable RFC7844 Anonymity Profiles */
373 .dhcp_anonymize = false,
374 .dhcp_route_metric = DHCP_ROUTE_METRIC,
c9c908a6 375 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
17f9c355
YW
376 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
377 .dhcp_route_table = RT_TABLE_MAIN,
378 .dhcp_route_table_set = false,
379 /* NOTE: from man: UseMTU=... Defaults to false*/
380 .dhcp_use_mtu = false,
381 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
382 .dhcp_use_timezone = false,
383 .rapid_commit = true,
384
caa8ca42
SS
385 .dhcp6_use_ntp = true,
386 .dhcp6_use_dns = true,
387
17f9c355
YW
388 .dhcp_server_emit_dns = true,
389 .dhcp_server_emit_ntp = true,
299d578f 390 .dhcp_server_emit_sip = true,
17f9c355
YW
391 .dhcp_server_emit_router = true,
392 .dhcp_server_emit_timezone = true,
393
394 .router_emit_dns = true,
395 .router_emit_domains = true,
396
397 .use_bpdu = -1,
398 .hairpin = -1,
399 .fast_leave = -1,
400 .allow_port_to_be_root = -1,
401 .unicast_flood = -1,
7f15b714 402 .multicast_flood = -1,
d3aa8b49 403 .multicast_to_unicast = -1,
7f15b714
TJ
404 .neighbor_suppression = -1,
405 .learning = -1,
1087623b
SS
406 .bridge_proxy_arp = -1,
407 .bridge_proxy_arp_wifi = -1,
17f9c355 408 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
0fadb2a4 409 .multicast_router = _MULTICAST_ROUTER_INVALID,
17f9c355
YW
410
411 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
412
7ece6f58 413 .dns_default_route = -1,
17f9c355
YW
414 .llmnr = RESOLVE_SUPPORT_YES,
415 .mdns = RESOLVE_SUPPORT_NO,
416 .dnssec_mode = _DNSSEC_MODE_INVALID,
417 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
418
0321cea7 419 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
2d792895 420 .link_local = _ADDRESS_FAMILY_INVALID,
17f9c355
YW
421
422 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
423 .ipv6_accept_ra = -1,
424 .ipv6_dad_transmits = -1,
425 .ipv6_hop_limit = -1,
426 .ipv6_proxy_ndp = -1,
427 .duid.type = _DUID_TYPE_INVALID,
428 .proxy_arp = -1,
429 .arp = -1,
430 .multicast = -1,
431 .allmulticast = -1,
432 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
433 .ipv6_accept_ra_use_autonomous_prefix = true,
434 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 435 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 436 .ipv6_accept_ra_route_table_set = false,
c423be28 437
7da377ef
SS
438 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
439
c423be28 440 .can_triple_sampling = -1,
17f9c355 441 };
f579559b 442
dc0d4078 443 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
23bb31aa
ZJS
444 "Match\0"
445 "Link\0"
446 "Network\0"
447 "Address\0"
e4a71bf3 448 "Neighbor\0"
95b74ef6 449 "IPv6AddressLabel\0"
bce67bbe 450 "RoutingPolicyRule\0"
23bb31aa
ZJS
451 "Route\0"
452 "DHCP\0"
453 "DHCPv4\0" /* compat */
caa8ca42 454 "DHCPv6\0"
23bb31aa
ZJS
455 "DHCPServer\0"
456 "IPv6AcceptRA\0"
a0e5c15d 457 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
458 "Bridge\0"
459 "BridgeFDB\0"
9d5d0090 460 "BridgeVLAN\0"
7d5cac19 461 "IPv6PrefixDelegation\0"
06828bb6 462 "IPv6Prefix\0"
203d4df5 463 "IPv6RoutePrefix\0"
06828bb6 464 "CAN\0",
23bb31aa 465 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 466 CONFIG_PARSE_WARN, network);
102bc043 467 if (r < 0)
f579559b 468 return r;
f579559b 469
add8d07d 470 network_apply_anonymize_if_set(network);
471
fa7cd711
YW
472 r = network_add_ipv4ll_route(network);
473 if (r < 0)
474 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
475
5d5003ab
YW
476 r = network_add_default_route_on_device(network);
477 if (r < 0)
478 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
479 network->filename);
480
715d398e 481 r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
dbffab87
TG
482 if (r < 0)
483 return r;
484
715d398e 485 r = ordered_hashmap_put(manager->networks, network->name, network);
dbffab87
TG
486 if (r < 0)
487 return r;
488
0321cea7
YW
489 if (network_verify(network) < 0)
490 return 0;
b3070dc0 491
f579559b 492 network = NULL;
f579559b
TG
493 return 0;
494}
495
496int network_load(Manager *manager) {
477e73b5
ZJS
497 _cleanup_strv_free_ char **files = NULL;
498 char **f;
f579559b
TG
499 int r;
500
501 assert(manager);
502
715d398e 503 ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
f579559b 504
dc0d4078 505 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
506 if (r < 0)
507 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b 508
715d398e 509 STRV_FOREACH(f, files) {
f579559b
TG
510 r = network_load_one(manager, *f);
511 if (r < 0)
be711082 512 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
f579559b
TG
513 }
514
f579559b
TG
515 return 0;
516}
517
35ac3b76 518static Network *network_free(Network *network) {
a0e5c15d 519 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
520 RoutingPolicyRule *rule;
521 FdbEntry *fdb_entry;
e4a71bf3 522 Neighbor *neighbor;
95b74ef6 523 AddressLabel *label;
057abfd8 524 Prefix *prefix;
bce67bbe 525 Address *address;
bce67bbe 526 Route *route;
f579559b
TG
527
528 if (!network)
35ac3b76 529 return NULL;
f579559b
TG
530
531 free(network->filename);
532
e90d0374 533 set_free_free(network->match_mac);
5256e00e
TG
534 strv_free(network->match_path);
535 strv_free(network->match_driver);
536 strv_free(network->match_type);
537 strv_free(network->match_name);
44005bfb 538 strv_free(network->match_property);
c4f58dea 539 condition_free_list(network->conditions);
f579559b
TG
540
541 free(network->description);
edb85f0d 542 free(network->dhcp_vendor_class_identifier);
af1c0de0 543 strv_free(network->dhcp_user_class);
27cb34f5 544 free(network->dhcp_hostname);
727b5734 545 set_free(network->dhcp_black_listed_ip);
5bc945be 546 set_free(network->dhcp_request_options);
c106cc36
TG
547 free(network->mac);
548
b0e39c82 549 strv_free(network->ntp);
5512a963 550 free(network->dns);
299d578f 551 strv_free(network->sip);
5e2a51d5
ZJS
552 ordered_set_free_free(network->search_domains);
553 ordered_set_free_free(network->route_domains);
0d4ad91d 554 strv_free(network->bind_carrier);
cdd7812b 555
5e2a51d5 556 ordered_set_free_free(network->router_search_domains);
cdd7812b 557 free(network->router_dns);
e520ce64 558 set_free_free(network->ndisc_black_listed_prefix);
3bef724f 559
cebe1257
YW
560 free(network->bridge_name);
561 free(network->bond_name);
562 free(network->vrf_name);
563 hashmap_free_free_key(network->stacked_netdev_names);
47e2dc31 564 netdev_unref(network->bridge);
47e2dc31 565 netdev_unref(network->bond);
6cb955c6 566 netdev_unref(network->vrf);
fa6f1e54 567 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 568
f048a16b 569 while ((route = network->static_routes))
f579559b
TG
570 route_free(route);
571
f048a16b 572 while ((address = network->static_addresses))
f579559b
TG
573 address_free(address);
574
b98b483b
AR
575 while ((fdb_entry = network->static_fdb_entries))
576 fdb_entry_free(fdb_entry);
577
a0e5c15d
FK
578 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
579 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
580
e4a71bf3
WKI
581 while ((neighbor = network->neighbors))
582 neighbor_free(neighbor);
583
95b74ef6
SS
584 while ((label = network->address_labels))
585 address_label_free(label);
586
057abfd8
PF
587 while ((prefix = network->static_prefixes))
588 prefix_free(prefix);
589
bce67bbe
SS
590 while ((rule = network->rules))
591 routing_policy_rule_free(rule);
592
6ae115c1
TG
593 hashmap_free(network->addresses_by_section);
594 hashmap_free(network->routes_by_section);
b98b483b 595 hashmap_free(network->fdb_entries_by_section);
e4a71bf3 596 hashmap_free(network->neighbors_by_section);
95b74ef6 597 hashmap_free(network->address_labels_by_section);
057abfd8 598 hashmap_free(network->prefixes_by_section);
bce67bbe 599 hashmap_free(network->rules_by_section);
6ae115c1 600
dbffab87 601 if (network->manager) {
715d398e
YW
602 if (network->manager->networks && network->name)
603 ordered_hashmap_remove(network->manager->networks, network->name);
27dfc982
YW
604
605 if (network->manager->duids_requesting_uuid)
606 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
607 }
608
609 free(network->name);
f579559b 610
8eb9058d 611 free(network->dhcp_server_timezone);
1a04db0f
LP
612 free(network->dhcp_server_dns);
613 free(network->dhcp_server_ntp);
299d578f 614 free(network->dhcp_server_sip);
8eb9058d 615
8a516214
LP
616 set_free_free(network->dnssec_negative_trust_anchors);
617
35ac3b76 618 return mfree(network);
f579559b
TG
619}
620
35ac3b76
YW
621DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
622
dbffab87
TG
623int network_get_by_name(Manager *manager, const char *name, Network **ret) {
624 Network *network;
625
626 assert(manager);
627 assert(name);
628 assert(ret);
629
715d398e 630 network = ordered_hashmap_get(manager->networks, name);
dbffab87
TG
631 if (!network)
632 return -ENOENT;
633
634 *ret = network;
635
636 return 0;
637}
638
51517f9e 639int network_get(Manager *manager, sd_device *device,
505f8da7
TG
640 const char *ifname, const struct ether_addr *address,
641 Network **ret) {
51517f9e 642 Network *network;
715d398e 643 Iterator i;
f579559b
TG
644
645 assert(manager);
f579559b 646 assert(ret);
af3aa302 647
715d398e 648 ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
44005bfb
YW
649 if (net_match_config(network->match_mac, network->match_path, network->match_driver,
650 network->match_type, network->match_name, network->match_property,
b38de0e9 651 device, address, ifname)) {
24c083df 652 if (network->match_name && device) {
ca6038b8
TG
653 const char *attr;
654 uint8_t name_assign_type = NET_NAME_UNKNOWN;
655
51517f9e 656 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 657 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
658
659 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
660 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
661 ifname, network->filename);
32bc8adc 662 else
a2fae7bb 663 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 664 } else
a2fae7bb 665 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 666
f579559b
TG
667 *ret = network;
668 return 0;
669 }
f579559b
TG
670
671 *ret = NULL;
672
673 return -ENOENT;
674}
675
7d342c03 676int network_apply(Network *network, Link *link) {
c4a03a56
TG
677 assert(network);
678 assert(link);
679
c9c908a6 680 link->network = network_ref(network);
f579559b 681
5512a963 682 if (network->n_dns > 0 ||
3df9bec5 683 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
684 !ordered_set_isempty(network->search_domains) ||
685 !ordered_set_isempty(network->route_domains))
84de38c5 686 link_dirty(link);
3bef724f 687
f579559b
TG
688 return 0;
689}
02b59d57 690
adfeee49 691bool network_has_static_ipv6_configurations(Network *network) {
439689c6 692 Address *address;
adfeee49
YW
693 Route *route;
694 FdbEntry *fdb;
695 Neighbor *neighbor;
439689c6
SS
696
697 assert(network);
698
adfeee49 699 LIST_FOREACH(addresses, address, network->static_addresses)
439689c6
SS
700 if (address->family == AF_INET6)
701 return true;
adfeee49
YW
702
703 LIST_FOREACH(routes, route, network->static_routes)
704 if (route->family == AF_INET6)
705 return true;
706
707 LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
708 if (fdb->family == AF_INET6)
709 return true;
710
711 LIST_FOREACH(neighbors, neighbor, network->neighbors)
712 if (neighbor->family == AF_INET6)
713 return true;
714
715 if (!LIST_IS_EMPTY(network->address_labels))
716 return true;
717
718 if (!LIST_IS_EMPTY(network->static_prefixes))
719 return true;
439689c6
SS
720
721 return false;
722}
723
cebe1257 724int config_parse_stacked_netdev(const char *unit,
02b59d57
TG
725 const char *filename,
726 unsigned line,
727 const char *section,
728 unsigned section_line,
729 const char *lvalue,
730 int ltype,
731 const char *rvalue,
732 void *data,
733 void *userdata) {
95dba435
YW
734 _cleanup_free_ char *name = NULL;
735 NetDevKind kind = ltype;
cebe1257 736 Hashmap **h = data;
02b59d57
TG
737 int r;
738
739 assert(filename);
740 assert(lvalue);
741 assert(rvalue);
742 assert(data);
95dba435
YW
743 assert(IN_SET(kind,
744 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
69c317a0 745 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
98d20a17 746 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
747 NETDEV_KIND_XFRM));
54abf461 748
cebe1257 749 if (!ifname_valid(rvalue)) {
3772cfde
ZJS
750 log_syntax(unit, LOG_ERR, filename, line, 0,
751 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
752 return 0;
753 }
754
cebe1257
YW
755 name = strdup(rvalue);
756 if (!name)
757 return log_oom();
3e570042 758
cebe1257
YW
759 r = hashmap_ensure_allocated(h, &string_hash_ops);
760 if (r < 0)
761 return log_oom();
326cb406 762
cebe1257 763 r = hashmap_put(*h, name, INT_TO_PTR(kind));
83ec4592 764 if (r < 0)
3772cfde 765 log_syntax(unit, LOG_ERR, filename, line, r,
83ec4592
ZJS
766 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
767 else if (r == 0)
768 log_syntax(unit, LOG_DEBUG, filename, line, r,
769 "NetDev '%s' specified twice, ignoring.", name);
770 else
771 name = NULL;
47e2dc31 772
fe6b2d55
TG
773 return 0;
774}
7951dea2 775
3df9bec5
LP
776int config_parse_domains(
777 const char *unit,
778 const char *filename,
779 unsigned line,
780 const char *section,
781 unsigned section_line,
782 const char *lvalue,
783 int ltype,
784 const char *rvalue,
785 void *data,
786 void *userdata) {
787
788 const char *p;
789 Network *n = data;
6192b846
TG
790 int r;
791
3df9bec5
LP
792 assert(n);
793 assert(lvalue);
794 assert(rvalue);
6192b846 795
3df9bec5 796 if (isempty(rvalue)) {
5e2a51d5
ZJS
797 n->search_domains = ordered_set_free_free(n->search_domains);
798 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
799 return 0;
800 }
67272d15 801
3df9bec5
LP
802 p = rvalue;
803 for (;;) {
804 _cleanup_free_ char *w = NULL, *normalized = NULL;
805 const char *domain;
806 bool is_route;
807
808 r = extract_first_word(&p, &w, NULL, 0);
809 if (r < 0) {
ab24039f
ZJS
810 log_syntax(unit, LOG_ERR, filename, line, r,
811 "Failed to extract search or route domain, ignoring: %s", rvalue);
3df9bec5
LP
812 break;
813 }
814 if (r == 0)
815 break;
816
817 is_route = w[0] == '~';
818 domain = is_route ? w + 1 : w;
819
820 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
821 /* If the root domain appears as is, or the special token "*" is found, we'll
822 * consider this as routing domain, unconditionally. */
3df9bec5 823 is_route = true;
ab24039f
ZJS
824 domain = "."; /* make sure we don't allow empty strings, thus write the root
825 * domain as "." */
3df9bec5 826 } else {
7470cc4c 827 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 828 if (r < 0) {
ab24039f
ZJS
829 log_syntax(unit, LOG_ERR, filename, line, r,
830 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
831 continue;
832 }
833
834 domain = normalized;
835
836 if (is_localhost(domain)) {
ab24039f
ZJS
837 log_syntax(unit, LOG_ERR, filename, line, 0,
838 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
839 domain);
37de2509 840 continue;
3df9bec5 841 }
37de2509 842 }
40274ed6 843
5e2a51d5
ZJS
844 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
845 r = ordered_set_ensure_allocated(set, &string_hash_ops);
846 if (r < 0)
847 return r;
848
849 r = ordered_set_put_strdup(*set, domain);
09451975
LP
850 if (r < 0)
851 return log_oom();
40274ed6 852 }
f15b6e5a 853
6192b846
TG
854 return 0;
855}
856
60c35566 857int config_parse_ipv6token(
7f77697a
TG
858 const char* unit,
859 const char *filename,
860 unsigned line,
861 const char *section,
862 unsigned section_line,
863 const char *lvalue,
864 int ltype,
865 const char *rvalue,
866 void *data,
867 void *userdata) {
868
869 union in_addr_union buffer;
870 struct in6_addr *token = data;
871 int r;
872
873 assert(filename);
874 assert(lvalue);
875 assert(rvalue);
876 assert(token);
877
878 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
879 if (r < 0) {
ab24039f
ZJS
880 log_syntax(unit, LOG_ERR, filename, line, r,
881 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
882 return 0;
883 }
884
c606db69 885 if (in_addr_is_null(AF_INET6, &buffer)) {
ab24039f
ZJS
886 log_syntax(unit, LOG_ERR, filename, line, 0,
887 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
888 return 0;
889 }
890
891 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
ab24039f
ZJS
892 log_syntax(unit, LOG_ERR, filename, line, 0,
893 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
894 return 0;
895 }
896
897 *token = buffer.in6;
898
899 return 0;
900}
8add5f79 901
49092e22 902static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
903 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
904 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
905 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
906};
907
b146ad71
YW
908DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
909 IPV6_PRIVACY_EXTENSIONS_YES);
49092e22
SS
910
911int config_parse_ipv6_privacy_extensions(
912 const char* unit,
913 const char *filename,
914 unsigned line,
915 const char *section,
916 unsigned section_line,
917 const char *lvalue,
918 int ltype,
919 const char *rvalue,
920 void *data,
921 void *userdata) {
922
b146ad71 923 IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
49092e22
SS
924
925 assert(filename);
926 assert(lvalue);
927 assert(rvalue);
928 assert(ipv6_privacy_extensions);
929
b146ad71
YW
930 s = ipv6_privacy_extensions_from_string(rvalue);
931 if (s < 0) {
932 if (streq(rvalue, "kernel"))
933 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
934 else {
935 log_syntax(unit, LOG_ERR, filename, line, 0,
936 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
937 return 0;
49092e22 938 }
49092e22
SS
939 }
940
b146ad71
YW
941 *ipv6_privacy_extensions = s;
942
49092e22
SS
943 return 0;
944}
a7d0ef44 945
1ac608c9
LP
946int config_parse_hostname(
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
6528693a
YW
958 _cleanup_free_ char *hn = NULL;
959 char **hostname = data;
a7d0ef44
SS
960 int r;
961
962 assert(filename);
963 assert(lvalue);
964 assert(rvalue);
965
1ac608c9 966 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
967 if (r < 0)
968 return r;
969
1ac608c9 970 if (!hostname_is_valid(hn, false)) {
ab24039f
ZJS
971 log_syntax(unit, LOG_ERR, filename, line, 0,
972 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
973 return 0;
974 }
975
6528693a
YW
976 r = dns_name_is_valid(hn);
977 if (r < 0) {
ab24039f
ZJS
978 log_syntax(unit, LOG_ERR, filename, line, r,
979 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
980 return 0;
981 }
982 if (r == 0) {
ab24039f
ZJS
983 log_syntax(unit, LOG_ERR, filename, line, 0,
984 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
985 return 0;
986 }
987
988 return free_and_replace(*hostname, hn);
a7d0ef44 989}
8eb9058d
LP
990
991int config_parse_timezone(
992 const char *unit,
993 const char *filename,
994 unsigned line,
995 const char *section,
996 unsigned section_line,
997 const char *lvalue,
998 int ltype,
999 const char *rvalue,
1000 void *data,
1001 void *userdata) {
1002
19f9e4e2
YW
1003 _cleanup_free_ char *tz = NULL;
1004 char **datap = data;
8eb9058d
LP
1005 int r;
1006
1007 assert(filename);
1008 assert(lvalue);
1009 assert(rvalue);
1010
1011 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1012 if (r < 0)
1013 return r;
1014
089fb865 1015 if (!timezone_is_valid(tz, LOG_ERR)) {
ab24039f
ZJS
1016 log_syntax(unit, LOG_ERR, filename, line, 0,
1017 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1018 return 0;
1019 }
1020
19f9e4e2 1021 return free_and_replace(*datap, tz);
8eb9058d 1022}
1a04db0f 1023
53253824
SS
1024int config_parse_dns(
1025 const char *unit,
1026 const char *filename,
1027 unsigned line,
1028 const char *section,
1029 unsigned section_line,
1030 const char *lvalue,
1031 int ltype,
1032 const char *rvalue,
1033 void *data,
1034 void *userdata) {
1035
1036 Network *n = userdata;
1037 int r;
1038
1039 assert(filename);
1040 assert(lvalue);
1041 assert(rvalue);
1042
1043 for (;;) {
1044 _cleanup_free_ char *w = NULL;
1045 union in_addr_union a;
5512a963 1046 struct in_addr_data *m;
53253824
SS
1047 int family;
1048
5512a963 1049 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1050 if (r == -ENOMEM)
1051 return log_oom();
1052 if (r < 0) {
ab24039f
ZJS
1053 log_syntax(unit, LOG_ERR, filename, line, r,
1054 "Invalid syntax, ignoring: %s", rvalue);
53253824
SS
1055 break;
1056 }
5512a963
LP
1057 if (r == 0)
1058 break;
53253824
SS
1059
1060 r = in_addr_from_string_auto(w, &family, &a);
1061 if (r < 0) {
ab24039f
ZJS
1062 log_syntax(unit, LOG_ERR, filename, line, r,
1063 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1064 continue;
1065 }
1066
62d74c78 1067 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1068 if (!m)
53253824
SS
1069 return log_oom();
1070
5512a963
LP
1071 m[n->n_dns++] = (struct in_addr_data) {
1072 .family = family,
1073 .address = a,
1074 };
1075
1076 n->dns = m;
53253824
SS
1077 }
1078
1079 return 0;
1080}
1081
8a516214
LP
1082int config_parse_dnssec_negative_trust_anchors(
1083 const char *unit,
1084 const char *filename,
1085 unsigned line,
1086 const char *section,
1087 unsigned section_line,
1088 const char *lvalue,
1089 int ltype,
1090 const char *rvalue,
1091 void *data,
1092 void *userdata) {
1093
1094 const char *p = rvalue;
1095 Network *n = data;
1096 int r;
1097
3df9bec5 1098 assert(n);
8a516214
LP
1099 assert(lvalue);
1100 assert(rvalue);
1101
1102 if (isempty(rvalue)) {
1103 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1104 return 0;
1105 }
1106
1107 for (;;) {
1108 _cleanup_free_ char *w = NULL;
1109
1110 r = extract_first_word(&p, &w, NULL, 0);
1111 if (r < 0) {
ab24039f
ZJS
1112 log_syntax(unit, LOG_ERR, filename, line, r,
1113 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
8a516214
LP
1114 break;
1115 }
1116 if (r == 0)
1117 break;
1118
1119 r = dns_name_is_valid(w);
1120 if (r <= 0) {
ab24039f
ZJS
1121 log_syntax(unit, LOG_ERR, filename, line, r,
1122 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1123 continue;
1124 }
1125
cbbf38ae
LP
1126 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1127 if (r < 0)
1128 return log_oom();
1129
8a516214
LP
1130 r = set_put(n->dnssec_negative_trust_anchors, w);
1131 if (r < 0)
1132 return log_oom();
1133 if (r > 0)
1134 w = NULL;
1135 }
1136
1137 return 0;
1138}
b2a81c0b 1139
26575990
LP
1140int config_parse_ntp(
1141 const char *unit,
1142 const char *filename,
1143 unsigned line,
1144 const char *section,
1145 unsigned section_line,
1146 const char *lvalue,
1147 int ltype,
1148 const char *rvalue,
1149 void *data,
1150 void *userdata) {
1151
1152 char ***l = data;
1153 int r;
1154
1155 assert(l);
1156 assert(lvalue);
1157 assert(rvalue);
1158
1159 if (isempty(rvalue)) {
1160 *l = strv_free(*l);
1161 return 0;
1162 }
1163
1164 for (;;) {
1165 _cleanup_free_ char *w = NULL;
1166
1167 r = extract_first_word(&rvalue, &w, NULL, 0);
1168 if (r == -ENOMEM)
1169 return log_oom();
1170 if (r < 0) {
ab24039f
ZJS
1171 log_syntax(unit, LOG_ERR, filename, line, r,
1172 "Failed to extract NTP server name, ignoring: %s", rvalue);
26575990
LP
1173 break;
1174 }
1175 if (r == 0)
1176 break;
1177
1178 r = dns_name_is_valid_or_address(w);
1179 if (r <= 0) {
ab24039f
ZJS
1180 log_syntax(unit, LOG_ERR, filename, line, r,
1181 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1182 continue;
af1c0de0
SS
1183 }
1184
c448459d
ZJS
1185 if (strv_length(*l) > MAX_NTP_SERVERS) {
1186 log_syntax(unit, LOG_WARNING, filename, line, 0,
1187 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1188 MAX_NTP_SERVERS, w);
1189 break;
1190 }
1191
1192 r = strv_consume(l, TAKE_PTR(w));
af1c0de0
SS
1193 if (r < 0)
1194 return log_oom();
af1c0de0
SS
1195 }
1196
1197 return 0;
1198}
1199
4ac77d63
YW
1200int config_parse_required_for_online(
1201 const char *unit,
1202 const char *filename,
1203 unsigned line,
1204 const char *section,
1205 unsigned section_line,
1206 const char *lvalue,
1207 int ltype,
1208 const char *rvalue,
1209 void *data,
1210 void *userdata) {
1211
1212 Network *network = data;
1213 LinkOperationalState s;
1214 bool required = true;
1215 int r;
1216
1217 if (isempty(rvalue)) {
1218 network->required_for_online = true;
1219 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1220 return 0;
1221 }
1222
1223 s = link_operstate_from_string(rvalue);
1224 if (s < 0) {
1225 r = parse_boolean(rvalue);
1226 if (r < 0) {
1227 log_syntax(unit, LOG_ERR, filename, line, r,
1228 "Failed to parse %s= setting, ignoring assignment: %s",
1229 lvalue, rvalue);
1230 return 0;
1231 }
1232
1233 required = r;
1234 s = LINK_OPERSTATE_DEGRADED;
1235 }
1236
1237 network->required_for_online = required;
1238 network->required_operstate_for_online = s;
1239
1240 return 0;
1241}
7da377ef
SS
1242
1243DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1244 "Failed to parse KeepConfiguration= setting");
1245
1246static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
95355a28
YW
1247 [KEEP_CONFIGURATION_NO] = "no",
1248 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1249 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1250 [KEEP_CONFIGURATION_STATIC] = "static",
1251 [KEEP_CONFIGURATION_YES] = "yes",
7da377ef
SS
1252};
1253
1254DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);