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