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