]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
Merge pull request #10152 from yuwata/udev-use-extract
[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:
610 network->bridge = netdev;
54abf461 611
69a93e7d
TG
612 break;
613 case NETDEV_KIND_BOND:
614 network->bond = netdev;
fe6b2d55 615
6cb955c6
AR
616 break;
617 case NETDEV_KIND_VRF:
618 network->vrf = netdev;
619
69a93e7d
TG
620 break;
621 case NETDEV_KIND_VLAN:
69a93e7d 622 case NETDEV_KIND_MACVLAN:
f33ff02b 623 case NETDEV_KIND_MACVTAP:
c4a5ddc9 624 case NETDEV_KIND_IPVLAN:
326cb406 625 case NETDEV_KIND_VXLAN:
92c918b0 626 case NETDEV_KIND_VCAN:
6a0a2f86 627 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
326cb406 628 if (r < 0) {
87ac8d99 629 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
326cb406
SS
630 return 0;
631 }
632
69a93e7d
TG
633 break;
634 default:
87ac8d99 635 assert_not_reached("Cannot parse NetDev");
fe6b2d55
TG
636 }
637
47e2dc31
TG
638 netdev_ref(netdev);
639
fe6b2d55
TG
640 return 0;
641}
7951dea2 642
3df9bec5
LP
643int config_parse_domains(
644 const char *unit,
645 const char *filename,
646 unsigned line,
647 const char *section,
648 unsigned section_line,
649 const char *lvalue,
650 int ltype,
651 const char *rvalue,
652 void *data,
653 void *userdata) {
654
655 const char *p;
656 Network *n = data;
6192b846
TG
657 int r;
658
3df9bec5
LP
659 assert(n);
660 assert(lvalue);
661 assert(rvalue);
6192b846 662
3df9bec5
LP
663 if (isempty(rvalue)) {
664 n->search_domains = strv_free(n->search_domains);
665 n->route_domains = strv_free(n->route_domains);
666 return 0;
667 }
67272d15 668
3df9bec5
LP
669 p = rvalue;
670 for (;;) {
671 _cleanup_free_ char *w = NULL, *normalized = NULL;
672 const char *domain;
673 bool is_route;
674
675 r = extract_first_word(&p, &w, NULL, 0);
676 if (r < 0) {
677 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
678 break;
679 }
680 if (r == 0)
681 break;
682
683 is_route = w[0] == '~';
684 domain = is_route ? w + 1 : w;
685
686 if (dns_name_is_root(domain) || streq(domain, "*")) {
687 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
688 * routing domain, unconditionally. */
689 is_route = true;
690 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
691
692 } else {
693 r = dns_name_normalize(domain, &normalized);
694 if (r < 0) {
695 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
696 continue;
697 }
698
699 domain = normalized;
700
701 if (is_localhost(domain)) {
702 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 703 continue;
3df9bec5 704 }
37de2509 705 }
40274ed6 706
3df9bec5
LP
707 if (is_route) {
708 r = strv_extend(&n->route_domains, domain);
709 if (r < 0)
710 return log_oom();
40274ed6 711
3df9bec5
LP
712 } else {
713 r = strv_extend(&n->search_domains, domain);
714 if (r < 0)
715 return log_oom();
716 }
40274ed6 717 }
f15b6e5a 718
3df9bec5
LP
719 strv_uniq(n->route_domains);
720 strv_uniq(n->search_domains);
721
6192b846
TG
722 return 0;
723}
724
7951dea2
SS
725int config_parse_tunnel(const char *unit,
726 const char *filename,
727 unsigned line,
728 const char *section,
729 unsigned section_line,
730 const char *lvalue,
731 int ltype,
732 const char *rvalue,
733 void *data,
734 void *userdata) {
735 Network *network = userdata;
736 NetDev *netdev;
737 int r;
738
739 assert(filename);
740 assert(lvalue);
741 assert(rvalue);
742 assert(data);
743
744 r = netdev_get(network->manager, rvalue, &netdev);
745 if (r < 0) {
6a7a4e4d 746 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
7951dea2
SS
747 return 0;
748 }
749
d29ad81e
ZJS
750 if (!IN_SET(netdev->kind,
751 NETDEV_KIND_IPIP,
752 NETDEV_KIND_SIT,
753 NETDEV_KIND_GRE,
754 NETDEV_KIND_GRETAP,
755 NETDEV_KIND_IP6GRE,
756 NETDEV_KIND_IP6GRETAP,
757 NETDEV_KIND_VTI,
758 NETDEV_KIND_VTI6,
759 NETDEV_KIND_IP6TNL)) {
12ca818f 760 log_syntax(unit, LOG_ERR, filename, line, 0,
7951dea2
SS
761 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
762 return 0;
763 }
764
6a0a2f86
TG
765 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
766 if (r < 0) {
6a7a4e4d 767 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
6a0a2f86
TG
768 return 0;
769 }
770
771 netdev_ref(netdev);
7951dea2
SS
772
773 return 0;
774}
bd8f6538 775
d0d6a4cd
TG
776int config_parse_ipv4ll(
777 const char* unit,
778 const char *filename,
779 unsigned line,
780 const char *section,
781 unsigned section_line,
782 const char *lvalue,
783 int ltype,
784 const char *rvalue,
785 void *data,
786 void *userdata) {
787
788 AddressFamilyBoolean *link_local = data;
789
790 assert(filename);
791 assert(lvalue);
792 assert(rvalue);
793 assert(data);
794
795 /* Note that this is mostly like
796 * config_parse_address_family_boolean(), except that it
797 * applies only to IPv4 */
798
5883ff60 799 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
d0d6a4cd
TG
800
801 return 0;
802}
803
bd8f6538
TG
804int config_parse_dhcp(
805 const char* unit,
806 const char *filename,
807 unsigned line,
808 const char *section,
809 unsigned section_line,
810 const char *lvalue,
811 int ltype,
812 const char *rvalue,
813 void *data,
814 void *userdata) {
815
cb9fc36a 816 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
817
818 assert(filename);
819 assert(lvalue);
820 assert(rvalue);
821 assert(data);
822
769d324c
LP
823 /* Note that this is mostly like
824 * config_parse_address_family_boolean(), except that it
825 * understands some old names for the enum values */
826
cb9fc36a
LP
827 s = address_family_boolean_from_string(rvalue);
828 if (s < 0) {
829
830 /* Previously, we had a slightly different enum here,
831 * support its values for compatbility. */
832
833 if (streq(rvalue, "none"))
834 s = ADDRESS_FAMILY_NO;
835 else if (streq(rvalue, "v4"))
836 s = ADDRESS_FAMILY_IPV4;
837 else if (streq(rvalue, "v6"))
838 s = ADDRESS_FAMILY_IPV6;
839 else if (streq(rvalue, "both"))
840 s = ADDRESS_FAMILY_YES;
841 else {
12ca818f 842 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
843 return 0;
844 }
bd8f6538
TG
845 }
846
cb9fc36a 847 *dhcp = s;
bd8f6538
TG
848 return 0;
849}
850
3e43b2cd
JJ
851static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
852 [DHCP_CLIENT_ID_MAC] = "mac",
dace710c
YW
853 [DHCP_CLIENT_ID_DUID] = "duid",
854 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
3e43b2cd
JJ
855};
856
499d555a
SS
857DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
858DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
3e43b2cd 859
60c35566 860int config_parse_ipv6token(
7f77697a
TG
861 const char* unit,
862 const char *filename,
863 unsigned line,
864 const char *section,
865 unsigned section_line,
866 const char *lvalue,
867 int ltype,
868 const char *rvalue,
869 void *data,
870 void *userdata) {
871
872 union in_addr_union buffer;
873 struct in6_addr *token = data;
874 int r;
875
876 assert(filename);
877 assert(lvalue);
878 assert(rvalue);
879 assert(token);
880
881 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
882 if (r < 0) {
6a7a4e4d 883 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
884 return 0;
885 }
886
887 r = in_addr_is_null(AF_INET6, &buffer);
12ca818f 888 if (r != 0) {
87ac8d99 889 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
890 return 0;
891 }
892
893 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
87ac8d99 894 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
895 return 0;
896 }
897
898 *token = buffer.in6;
899
900 return 0;
901}
8add5f79 902
49092e22 903static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
904 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
905 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
906 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
907};
908
909DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
910
911int config_parse_ipv6_privacy_extensions(
912 const char* unit,
913 const char *filename,
914 unsigned line,
915 const char *section,
916 unsigned section_line,
917 const char *lvalue,
918 int ltype,
919 const char *rvalue,
920 void *data,
921 void *userdata) {
922
923 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
924 int k;
925
926 assert(filename);
927 assert(lvalue);
928 assert(rvalue);
929 assert(ipv6_privacy_extensions);
930
931 /* Our enum shall be a superset of booleans, hence first try
932 * to parse as boolean, and then as enum */
933
934 k = parse_boolean(rvalue);
935 if (k > 0)
1f0d9695 936 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 937 else if (k == 0)
1f0d9695 938 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 939 else {
1f0d9695 940 IPv6PrivacyExtensions s;
49092e22
SS
941
942 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
943 if (s < 0) {
944
945 if (streq(rvalue, "kernel"))
946 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
947 else {
12ca818f 948 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1f0d9695
LP
949 return 0;
950 }
49092e22
SS
951 }
952
953 *ipv6_privacy_extensions = s;
954 }
955
956 return 0;
957}
a7d0ef44 958
1ac608c9
LP
959int config_parse_hostname(
960 const char *unit,
961 const char *filename,
962 unsigned line,
963 const char *section,
964 unsigned section_line,
965 const char *lvalue,
966 int ltype,
967 const char *rvalue,
968 void *data,
969 void *userdata) {
970
6528693a
YW
971 _cleanup_free_ char *hn = NULL;
972 char **hostname = data;
a7d0ef44
SS
973 int r;
974
975 assert(filename);
976 assert(lvalue);
977 assert(rvalue);
978
1ac608c9 979 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
980 if (r < 0)
981 return r;
982
1ac608c9 983 if (!hostname_is_valid(hn, false)) {
12ca818f 984 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
985 return 0;
986 }
987
6528693a
YW
988 r = dns_name_is_valid(hn);
989 if (r < 0) {
990 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
991 return 0;
992 }
993 if (r == 0) {
994 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
995 return 0;
996 }
997
998 return free_and_replace(*hostname, hn);
a7d0ef44 999}
8eb9058d
LP
1000
1001int config_parse_timezone(
1002 const char *unit,
1003 const char *filename,
1004 unsigned line,
1005 const char *section,
1006 unsigned section_line,
1007 const char *lvalue,
1008 int ltype,
1009 const char *rvalue,
1010 void *data,
1011 void *userdata) {
1012
19f9e4e2
YW
1013 _cleanup_free_ char *tz = NULL;
1014 char **datap = data;
8eb9058d
LP
1015 int r;
1016
1017 assert(filename);
1018 assert(lvalue);
1019 assert(rvalue);
1020
1021 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1022 if (r < 0)
1023 return r;
1024
089fb865 1025 if (!timezone_is_valid(tz, LOG_ERR)) {
12ca818f 1026 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1027 return 0;
1028 }
1029
19f9e4e2 1030 return free_and_replace(*datap, tz);
8eb9058d 1031}
1a04db0f
LP
1032
1033int config_parse_dhcp_server_dns(
1034 const char *unit,
1035 const char *filename,
1036 unsigned line,
1037 const char *section,
1038 unsigned section_line,
1039 const char *lvalue,
1040 int ltype,
1041 const char *rvalue,
1042 void *data,
1043 void *userdata) {
1044
1045 Network *n = data;
1046 const char *p = rvalue;
1047 int r;
1048
1049 assert(filename);
1050 assert(lvalue);
1051 assert(rvalue);
1052
1053 for (;;) {
1054 _cleanup_free_ char *w = NULL;
1055 struct in_addr a, *m;
1056
1057 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1058 if (r == -ENOMEM)
1059 return log_oom();
1a04db0f
LP
1060 if (r < 0) {
1061 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1062 return 0;
1063 }
1a04db0f 1064 if (r == 0)
fa105ce6 1065 break;
1a04db0f
LP
1066
1067 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 1068 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1a04db0f
LP
1069 continue;
1070 }
1071
62d74c78 1072 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1a04db0f
LP
1073 if (!m)
1074 return log_oom();
1075
1076 m[n->n_dhcp_server_dns++] = a;
1077 n->dhcp_server_dns = m;
1078 }
fa105ce6 1079
88295a05
PF
1080 return 0;
1081}
1082
1083int config_parse_radv_dns(
1084 const char *unit,
1085 const char *filename,
1086 unsigned line,
1087 const char *section,
1088 unsigned section_line,
1089 const char *lvalue,
1090 int ltype,
1091 const char *rvalue,
1092 void *data,
1093 void *userdata) {
1094
1095 Network *n = data;
1096 const char *p = rvalue;
1097 int r;
1098
1099 assert(filename);
1100 assert(lvalue);
1101 assert(rvalue);
1102
1103 for (;;) {
1104 _cleanup_free_ char *w = NULL;
1105 union in_addr_union a;
1106
1107 r = extract_first_word(&p, &w, NULL, 0);
1108 if (r == -ENOMEM)
1109 return log_oom();
1110 if (r < 0) {
1111 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1112 return 0;
1113 }
1114 if (r == 0)
1115 break;
1116
1117 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1118 struct in6_addr *m;
1119
62d74c78 1120 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
88295a05
PF
1121 if (!m)
1122 return log_oom();
1123
1124 m[n->n_router_dns++] = a.in6;
1125 n->router_dns = m;
1126
1127 } else
1128 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1129
1130 }
1131
700f1186
PF
1132 return 0;
1133}
1134
1135int config_parse_radv_search_domains(
1136 const char *unit,
1137 const char *filename,
1138 unsigned line,
1139 const char *section,
1140 unsigned section_line,
1141 const char *lvalue,
1142 int ltype,
1143 const char *rvalue,
1144 void *data,
1145 void *userdata) {
1146
1147 Network *n = data;
1148 const char *p = rvalue;
1149 int r;
1150
1151 assert(filename);
1152 assert(lvalue);
1153 assert(rvalue);
1154
1155 for (;;) {
1156 _cleanup_free_ char *w = NULL;
1157 _cleanup_free_ char *idna = NULL;
1158
1159 r = extract_first_word(&p, &w, NULL, 0);
1160 if (r == -ENOMEM)
1161 return log_oom();
1162 if (r < 0) {
1163 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1164 return 0;
1165 }
1166 if (r == 0)
1167 break;
1168
1169 r = dns_name_apply_idna(w, &idna);
1170 if (r > 0) {
1171 r = strv_push(&n->router_search_domains, idna);
1172 if (r >= 0)
1173 idna = NULL;
1174 } else if (r == 0) {
1175 r = strv_push(&n->router_search_domains, w);
1176 if (r >= 0)
1177 w = NULL;
1178 }
1179 }
1180
fa105ce6 1181 return 0;
1a04db0f
LP
1182}
1183
1184int config_parse_dhcp_server_ntp(
1185 const char *unit,
1186 const char *filename,
1187 unsigned line,
1188 const char *section,
1189 unsigned section_line,
1190 const char *lvalue,
1191 int ltype,
1192 const char *rvalue,
1193 void *data,
1194 void *userdata) {
1195
1196 Network *n = data;
1197 const char *p = rvalue;
1198 int r;
1199
1200 assert(filename);
1201 assert(lvalue);
1202 assert(rvalue);
1203
1204 for (;;) {
1205 _cleanup_free_ char *w = NULL;
1206 struct in_addr a, *m;
1207
1208 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1209 if (r == -ENOMEM)
1210 return log_oom();
1a04db0f 1211 if (r < 0) {
12ca818f 1212 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1213 return 0;
1214 }
1a04db0f
LP
1215 if (r == 0)
1216 return 0;
1217
1218 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 1219 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1a04db0f
LP
1220 continue;
1221 }
1222
62d74c78 1223 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1a04db0f
LP
1224 if (!m)
1225 return log_oom();
1226
1227 m[n->n_dhcp_server_ntp++] = a;
1228 n->dhcp_server_ntp = m;
1229 }
1230}
8a516214 1231
53253824
SS
1232int config_parse_dns(
1233 const char *unit,
1234 const char *filename,
1235 unsigned line,
1236 const char *section,
1237 unsigned section_line,
1238 const char *lvalue,
1239 int ltype,
1240 const char *rvalue,
1241 void *data,
1242 void *userdata) {
1243
1244 Network *n = userdata;
1245 int r;
1246
1247 assert(filename);
1248 assert(lvalue);
1249 assert(rvalue);
1250
1251 for (;;) {
1252 _cleanup_free_ char *w = NULL;
1253 union in_addr_union a;
5512a963 1254 struct in_addr_data *m;
53253824
SS
1255 int family;
1256
5512a963 1257 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1258 if (r == -ENOMEM)
1259 return log_oom();
1260 if (r < 0) {
1261 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1262 break;
1263 }
5512a963
LP
1264 if (r == 0)
1265 break;
53253824
SS
1266
1267 r = in_addr_from_string_auto(w, &family, &a);
1268 if (r < 0) {
5512a963 1269 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1270 continue;
1271 }
1272
62d74c78 1273 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1274 if (!m)
53253824
SS
1275 return log_oom();
1276
5512a963
LP
1277 m[n->n_dns++] = (struct in_addr_data) {
1278 .family = family,
1279 .address = a,
1280 };
1281
1282 n->dns = m;
53253824
SS
1283 }
1284
1285 return 0;
1286}
1287
8a516214
LP
1288int config_parse_dnssec_negative_trust_anchors(
1289 const char *unit,
1290 const char *filename,
1291 unsigned line,
1292 const char *section,
1293 unsigned section_line,
1294 const char *lvalue,
1295 int ltype,
1296 const char *rvalue,
1297 void *data,
1298 void *userdata) {
1299
1300 const char *p = rvalue;
1301 Network *n = data;
1302 int r;
1303
3df9bec5 1304 assert(n);
8a516214
LP
1305 assert(lvalue);
1306 assert(rvalue);
1307
1308 if (isempty(rvalue)) {
1309 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1310 return 0;
1311 }
1312
1313 for (;;) {
1314 _cleanup_free_ char *w = NULL;
1315
1316 r = extract_first_word(&p, &w, NULL, 0);
1317 if (r < 0) {
1318 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1319 break;
1320 }
1321 if (r == 0)
1322 break;
1323
1324 r = dns_name_is_valid(w);
1325 if (r <= 0) {
1326 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1327 continue;
1328 }
1329
cbbf38ae
LP
1330 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1331 if (r < 0)
1332 return log_oom();
1333
8a516214
LP
1334 r = set_put(n->dnssec_negative_trust_anchors, w);
1335 if (r < 0)
1336 return log_oom();
1337 if (r > 0)
1338 w = NULL;
1339 }
1340
1341 return 0;
1342}
b2a81c0b 1343
26575990
LP
1344int config_parse_ntp(
1345 const char *unit,
1346 const char *filename,
1347 unsigned line,
1348 const char *section,
1349 unsigned section_line,
1350 const char *lvalue,
1351 int ltype,
1352 const char *rvalue,
1353 void *data,
1354 void *userdata) {
1355
1356 char ***l = data;
1357 int r;
1358
1359 assert(l);
1360 assert(lvalue);
1361 assert(rvalue);
1362
1363 if (isempty(rvalue)) {
1364 *l = strv_free(*l);
1365 return 0;
1366 }
1367
1368 for (;;) {
1369 _cleanup_free_ char *w = NULL;
1370
1371 r = extract_first_word(&rvalue, &w, NULL, 0);
1372 if (r == -ENOMEM)
1373 return log_oom();
1374 if (r < 0) {
1375 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1376 break;
1377 }
1378 if (r == 0)
1379 break;
1380
1381 r = dns_name_is_valid_or_address(w);
1382 if (r <= 0) {
1383 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1384 continue;
af1c0de0
SS
1385 }
1386
1387 r = strv_push(l, w);
1388 if (r < 0)
1389 return log_oom();
1390
1391 w = NULL;
1392 }
1393
1394 return 0;
1395}
1396
1397int config_parse_dhcp_user_class(
1398 const char *unit,
1399 const char *filename,
1400 unsigned line,
1401 const char *section,
1402 unsigned section_line,
1403 const char *lvalue,
1404 int ltype,
1405 const char *rvalue,
1406 void *data,
1407 void *userdata) {
1408
1409 char ***l = data;
1410 int r;
1411
1412 assert(l);
1413 assert(lvalue);
1414 assert(rvalue);
1415
1416 if (isempty(rvalue)) {
1417 *l = strv_free(*l);
1418 return 0;
1419 }
1420
1421 for (;;) {
1422 _cleanup_free_ char *w = NULL;
1423
1424 r = extract_first_word(&rvalue, &w, NULL, 0);
1425 if (r == -ENOMEM)
1426 return log_oom();
1427 if (r < 0) {
1428 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split user classes option, ignoring: %s", rvalue);
1429 break;
1430 }
1431 if (r == 0)
1432 break;
1433
1434 if (strlen(w) > 255) {
1435 log_syntax(unit, LOG_ERR, filename, line, r, "%s length is not in the range 1-255, ignoring.", w);
1436 continue;
26575990
LP
1437 }
1438
1439 r = strv_push(l, w);
1440 if (r < 0)
1441 return log_oom();
1442
1443 w = NULL;
1444 }
1445
1446 return 0;
1447}
1448
f594276b
JK
1449int config_parse_dhcp_route_table(const char *unit,
1450 const char *filename,
1451 unsigned line,
1452 const char *section,
1453 unsigned section_line,
1454 const char *lvalue,
1455 int ltype,
1456 const char *rvalue,
1457 void *data,
1458 void *userdata) {
fc1ba79d 1459 Network *network = data;
f594276b
JK
1460 uint32_t rt;
1461 int r;
1462
1463 assert(filename);
1464 assert(lvalue);
1465 assert(rvalue);
1466 assert(data);
1467
1468 r = safe_atou32(rvalue, &rt);
1469 if (r < 0) {
1470 log_syntax(unit, LOG_ERR, filename, line, r,
1471 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1472 return 0;
1473 }
1474
fc1ba79d
AR
1475 network->dhcp_route_table = rt;
1476 network->dhcp_route_table_set = true;
f594276b
JK
1477
1478 return 0;
1479}
1480
b2a81c0b
LP
1481DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1482
1483static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1484 [DHCP_USE_DOMAINS_NO] = "no",
1485 [DHCP_USE_DOMAINS_ROUTE] = "route",
1486 [DHCP_USE_DOMAINS_YES] = "yes",
1487};
1488
1489DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
34437b4f
LP
1490
1491DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1492
1493static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1494 [LLDP_MODE_NO] = "no",
1495 [LLDP_MODE_YES] = "yes",
1496 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1497};
1498
1499DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);