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