]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: also check that Hostname= is a valid DNS domain name
[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
ca52812a
YW
39 if (x->line < y->line)
40 return -1;
41 if (x->line > y->line)
42 return 1;
43
44 return 0;
f4859fc7
SS
45}
46
47const struct hash_ops network_config_hash_ops = {
48 .hash = network_config_hash_func,
49 .compare = network_config_compare_func,
50};
51
52int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
53 NetworkConfigSection *cs;
54
55 cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
56 if (!cs)
57 return -ENOMEM;
58
59 strcpy(cs->filename, filename);
60 cs->line = line;
61
ae2a15bc 62 *s = TAKE_PTR(cs);
f4859fc7
SS
63
64 return 0;
65}
66
67void network_config_section_free(NetworkConfigSection *cs) {
bce67bbe 68 free(cs);
f4859fc7
SS
69}
70
add8d07d 71/* Set defaults following RFC7844 */
72void network_apply_anonymize_if_set(Network *network) {
73 if (!network->dhcp_anonymize)
74 return;
75 /* RFC7844 3.7
76 SHOULD NOT send the Host Name option */
77 network->dhcp_send_hostname = false;
78 /* RFC7844 section 3.:
79 MAY contain the Client Identifier option
80 Section 3.5:
81 clients MUST use client identifiers based solely
82 on the link-layer address */
83 /* NOTE: Using MAC, as it does not reveal extra information,
84 * and some servers might not answer if this option is not sent */
85 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
86 /* RFC 7844 3.10:
87 SHOULD NOT use the Vendor Class Identifier option */
88 /* NOTE: it was not initiallized to any value in network_load_one. */
89 network->dhcp_vendor_class_identifier = false;
90 /* RFC7844 section 3.6.:
91 The client intending to protect its privacy SHOULD only request a
92 minimal number of options in the PRL and SHOULD also randomly shuffle
93 the ordering of option codes in the PRL. If this random ordering
94 cannot be implemented, the client MAY order the option codes in the
95 PRL by option code number (lowest to highest).
96 */
97 /* NOTE: dhcp_use_mtu is false by default,
98 * though it was not initiallized to any value in network_load_one.
99 * Maybe there should be another var called *send*?
100 * (to use the MTU sent by the server but to do not send
101 * the option in the PRL). */
102 network->dhcp_use_mtu = false;
28522b0d 103 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
104 * but this is needed to use them. */
105 network->dhcp_use_routes = true;
add8d07d 106 /* RFC7844 section 3.6.
107 * same comments as previous option */
108 network->dhcp_use_timezone = false;
109}
110
f579559b 111static int network_load_one(Manager *manager, const char *filename) {
8e766630 112 _cleanup_(network_freep) Network *network = NULL;
f579559b 113 _cleanup_fclose_ FILE *file = NULL;
dbffab87 114 char *d;
047a0dac 115 const char *dropin_dirname;
b3070dc0
TG
116 Route *route;
117 Address *address;
f579559b
TG
118 int r;
119
bf1bc670
TA
120 assert(manager);
121 assert(filename);
122
f579559b
TG
123 file = fopen(filename, "re");
124 if (!file) {
125 if (errno == ENOENT)
126 return 0;
1e7a0e21
LP
127
128 return -errno;
f579559b
TG
129 }
130
ed88bcfb
ZJS
131 if (null_or_empty_fd(fileno(file))) {
132 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
133 return 0;
134 }
135
f579559b
TG
136 network = new0(Network, 1);
137 if (!network)
138 return log_oom();
139
5a3eb5a7
TG
140 network->manager = manager;
141
f048a16b
TG
142 LIST_HEAD_INIT(network->static_addresses);
143 LIST_HEAD_INIT(network->static_routes);
b98b483b 144 LIST_HEAD_INIT(network->static_fdb_entries);
a0e5c15d 145 LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
95b74ef6 146 LIST_HEAD_INIT(network->address_labels);
057abfd8 147 LIST_HEAD_INIT(network->static_prefixes);
bce67bbe 148 LIST_HEAD_INIT(network->rules);
f579559b 149
d5099efc 150 network->stacked_netdevs = hashmap_new(&string_hash_ops);
6a0a2f86 151 if (!network->stacked_netdevs)
326cb406
SS
152 return log_oom();
153
f4859fc7 154 network->addresses_by_section = hashmap_new(&network_config_hash_ops);
6ae115c1
TG
155 if (!network->addresses_by_section)
156 return log_oom();
157
f4859fc7 158 network->routes_by_section = hashmap_new(&network_config_hash_ops);
6ae115c1
TG
159 if (!network->routes_by_section)
160 return log_oom();
161
b98b483b
AR
162 network->fdb_entries_by_section = hashmap_new(NULL);
163 if (!network->fdb_entries_by_section)
164 return log_oom();
165
95b74ef6
SS
166 network->address_labels_by_section = hashmap_new(&network_config_hash_ops);
167 if (!network->address_labels_by_section)
057abfd8
PF
168 log_oom();
169
170 network->prefixes_by_section = hashmap_new(&network_config_hash_ops);
171 if (!network->prefixes_by_section)
95b74ef6
SS
172 return log_oom();
173
bce67bbe
SS
174 network->rules_by_section = hashmap_new(&network_config_hash_ops);
175 if (!network->rules_by_section)
176 return log_oom();
177
6ae115c1
TG
178 network->filename = strdup(filename);
179 if (!network->filename)
180 return log_oom();
181
dbffab87
TG
182 network->name = strdup(basename(filename));
183 if (!network->name)
184 return log_oom();
185
186 d = strrchr(network->name, '.');
187 if (!d)
188 return -EINVAL;
189
190 assert(streq(d, ".network"));
191
192 *d = '\0';
193
c1a38904 194 network->required_for_online = true;
cb9fc36a 195 network->dhcp = ADDRESS_FAMILY_NO;
27cb34f5
LP
196 network->dhcp_use_ntp = true;
197 network->dhcp_use_dns = true;
198 network->dhcp_use_hostname = true;
199 network->dhcp_use_routes = true;
add8d07d 200 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
27cb34f5 201 network->dhcp_send_hostname = true;
add8d07d 202 /* To enable/disable RFC7844 Anonymity Profiles */
203 network->dhcp_anonymize = false;
84b5b79a 204 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
add8d07d 205 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
3e43b2cd 206 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
f594276b 207 network->dhcp_route_table = RT_TABLE_MAIN;
fc1ba79d 208 network->dhcp_route_table_set = false;
add8d07d 209 /* NOTE: the following vars were not set to any default,
210 * even if they are commented in the man?
211 * These vars might be overwriten by network_apply_anonymize_if_set */
212 network->dhcp_vendor_class_identifier = false;
95ab9eff
AJ
213 /* NOTE: from man: UseMTU=... Defaults to false*/
214 network->dhcp_use_mtu = false;
add8d07d 215 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
216 network->dhcp_use_timezone = false;
fb5c8216 217 network->rapid_commit = true;
5be4d38e 218
539f2a73
LP
219 network->dhcp_server_emit_dns = true;
220 network->dhcp_server_emit_ntp = true;
77ff6022 221 network->dhcp_server_emit_router = true;
539f2a73
LP
222 network->dhcp_server_emit_timezone = true;
223
9e25315c
PF
224 network->router_emit_dns = true;
225 network->router_emit_domains = true;
226
7f9915f0
SS
227 network->use_bpdu = -1;
228 network->hairpin = -1;
229 network->fast_leave = -1;
230 network->allow_port_to_be_root = -1;
231 network->unicast_flood = -1;
b56be296 232 network->priority = LINK_BRIDGE_PORT_PRIORITY_INVALID;
84c34096 233
7cececb2
LP
234 network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
235
a7e5da6e 236 network->llmnr = RESOLVE_SUPPORT_YES;
aaa297d4 237 network->mdns = RESOLVE_SUPPORT_NO;
ad6c0475 238 network->dnssec_mode = _DNSSEC_MODE_INVALID;
c9299be2 239 network->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID;
bd8f6538 240
d0d6a4cd
TG
241 network->link_local = ADDRESS_FAMILY_IPV6;
242
1f0d9695 243 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
4f2e437a 244 network->ipv6_accept_ra = -1;
8749cbcd 245 network->ipv6_dad_transmits = -1;
b69c3180 246 network->ipv6_hop_limit = -1;
465dfe59 247 network->ipv6_proxy_ndp = -1;
8341a5c3 248 network->duid.type = _DUID_TYPE_INVALID;
23d8b221 249 network->proxy_arp = -1;
99d2baa2 250 network->arp = -1;
e6ebebbe 251 network->multicast = -1;
866e6b7a 252 network->allmulticast = -1;
1e7a0e21 253 network->ipv6_accept_ra_use_dns = true;
2ba31d29 254 network->ipv6_accept_ra_route_table = RT_TABLE_MAIN;
11102cba 255 network->ipv6_mtu = 0;
49092e22 256
23bb31aa
ZJS
257 dropin_dirname = strjoina(network->name, ".network.d");
258
259 r = config_parse_many(filename, network_dirs, dropin_dirname,
260 "Match\0"
261 "Link\0"
262 "Network\0"
263 "Address\0"
95b74ef6 264 "IPv6AddressLabel\0"
bce67bbe 265 "RoutingPolicyRule\0"
23bb31aa
ZJS
266 "Route\0"
267 "DHCP\0"
268 "DHCPv4\0" /* compat */
269 "DHCPServer\0"
270 "IPv6AcceptRA\0"
a0e5c15d 271 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
272 "Bridge\0"
273 "BridgeFDB\0"
9d5d0090 274 "BridgeVLAN\0"
7d5cac19 275 "IPv6PrefixDelegation\0"
06828bb6
HP
276 "IPv6Prefix\0"
277 "CAN\0",
23bb31aa 278 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 279 CONFIG_PARSE_WARN, network);
36f822c4 280 if (r < 0)
f579559b 281 return r;
f579559b 282
add8d07d 283 network_apply_anonymize_if_set(network);
284
5a8bcb67
LP
285 /* IPMasquerade=yes implies IPForward=yes */
286 if (network->ip_masquerade)
769d324c 287 network->ip_forward |= ADDRESS_FAMILY_IPV4;
5a8bcb67 288
f579559b 289 LIST_PREPEND(networks, manager->networks, network);
b3070dc0 290
dbffab87
TG
291 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
292 if (r < 0)
293 return r;
294
295 r = hashmap_put(manager->networks_by_name, network->name, network);
296 if (r < 0)
297 return r;
298
3d3d4255 299 LIST_FOREACH(routes, route, network->static_routes) {
b3070dc0
TG
300 if (!route->family) {
301 log_warning("Route section without Gateway field configured in %s. "
302 "Ignoring", filename);
303 return 0;
304 }
b3070dc0
TG
305 }
306
3d3d4255 307 LIST_FOREACH(addresses, address, network->static_addresses) {
b3070dc0
TG
308 if (!address->family) {
309 log_warning("Address section without Address field configured in %s. "
310 "Ignoring", filename);
311 return 0;
312 }
313 }
314
f579559b
TG
315 network = NULL;
316
317 return 0;
318}
319
320int network_load(Manager *manager) {
321 Network *network;
477e73b5
ZJS
322 _cleanup_strv_free_ char **files = NULL;
323 char **f;
f579559b
TG
324 int r;
325
326 assert(manager);
327
328 while ((network = manager->networks))
329 network_free(network);
330
b5084605 331 r = conf_files_list_strv(&files, ".network", NULL, 0, network_dirs);
f647962d
MS
332 if (r < 0)
333 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b
TG
334
335 STRV_FOREACH_BACKWARDS(f, files) {
336 r = network_load_one(manager, *f);
337 if (r < 0)
338 return r;
339 }
340
f579559b
TG
341 return 0;
342}
343
f579559b 344void network_free(Network *network) {
a0e5c15d 345 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
346 RoutingPolicyRule *rule;
347 FdbEntry *fdb_entry;
95b74ef6 348 AddressLabel *label;
057abfd8 349 Prefix *prefix;
bce67bbe
SS
350 Address *address;
351 NetDev *netdev;
352 Route *route;
06f021a8 353 Iterator i;
f579559b
TG
354
355 if (!network)
356 return;
357
358 free(network->filename);
359
e90d0374 360 set_free_free(network->match_mac);
5256e00e
TG
361 strv_free(network->match_path);
362 strv_free(network->match_driver);
363 strv_free(network->match_type);
364 strv_free(network->match_name);
f579559b
TG
365
366 free(network->description);
edb85f0d 367 free(network->dhcp_vendor_class_identifier);
af1c0de0 368 strv_free(network->dhcp_user_class);
27cb34f5 369 free(network->dhcp_hostname);
f579559b 370
c106cc36
TG
371 free(network->mac);
372
b0e39c82 373 strv_free(network->ntp);
5512a963 374 free(network->dns);
3df9bec5
LP
375 strv_free(network->search_domains);
376 strv_free(network->route_domains);
0d4ad91d 377 strv_free(network->bind_carrier);
3bef724f 378
47e2dc31 379 netdev_unref(network->bridge);
47e2dc31 380 netdev_unref(network->bond);
6cb955c6 381 netdev_unref(network->vrf);
47e2dc31 382
2c36be2f
TG
383 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
384 hashmap_remove(network->stacked_netdevs, netdev->ifname);
326cb406 385 netdev_unref(netdev);
2c36be2f 386 }
6a0a2f86 387 hashmap_free(network->stacked_netdevs);
326cb406 388
f048a16b 389 while ((route = network->static_routes))
f579559b
TG
390 route_free(route);
391
f048a16b 392 while ((address = network->static_addresses))
f579559b
TG
393 address_free(address);
394
b98b483b
AR
395 while ((fdb_entry = network->static_fdb_entries))
396 fdb_entry_free(fdb_entry);
397
a0e5c15d
FK
398 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
399 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
400
95b74ef6
SS
401 while ((label = network->address_labels))
402 address_label_free(label);
403
057abfd8
PF
404 while ((prefix = network->static_prefixes))
405 prefix_free(prefix);
406
bce67bbe
SS
407 while ((rule = network->rules))
408 routing_policy_rule_free(rule);
409
6ae115c1
TG
410 hashmap_free(network->addresses_by_section);
411 hashmap_free(network->routes_by_section);
b98b483b 412 hashmap_free(network->fdb_entries_by_section);
95b74ef6 413 hashmap_free(network->address_labels_by_section);
057abfd8 414 hashmap_free(network->prefixes_by_section);
bce67bbe 415 hashmap_free(network->rules_by_section);
6ae115c1 416
dbffab87
TG
417 if (network->manager) {
418 if (network->manager->networks)
419 LIST_REMOVE(networks, network->manager->networks, network);
420
421 if (network->manager->networks_by_name)
422 hashmap_remove(network->manager->networks_by_name, network->name);
423 }
424
425 free(network->name);
f579559b 426
79e16ce3
LP
427 condition_free_list(network->match_host);
428 condition_free_list(network->match_virt);
5022f08a
LP
429 condition_free_list(network->match_kernel_cmdline);
430 condition_free_list(network->match_kernel_version);
79e16ce3
LP
431 condition_free_list(network->match_arch);
432
8eb9058d 433 free(network->dhcp_server_timezone);
1a04db0f
LP
434 free(network->dhcp_server_dns);
435 free(network->dhcp_server_ntp);
8eb9058d 436
8a516214
LP
437 set_free_free(network->dnssec_negative_trust_anchors);
438
f579559b
TG
439 free(network);
440}
441
dbffab87
TG
442int network_get_by_name(Manager *manager, const char *name, Network **ret) {
443 Network *network;
444
445 assert(manager);
446 assert(name);
447 assert(ret);
448
449 network = hashmap_get(manager->networks_by_name, name);
450 if (!network)
451 return -ENOENT;
452
453 *ret = network;
454
455 return 0;
456}
457
505f8da7
TG
458int network_get(Manager *manager, struct udev_device *device,
459 const char *ifname, const struct ether_addr *address,
460 Network **ret) {
f579559b 461 Network *network;
af3aa302 462 struct udev_device *parent;
24c083df 463 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
f579559b
TG
464
465 assert(manager);
f579559b 466 assert(ret);
af3aa302 467
24c083df
TG
468 if (device) {
469 path = udev_device_get_property_value(device, "ID_PATH");
af3aa302 470
24c083df
TG
471 parent = udev_device_get_parent(device);
472 if (parent)
473 parent_driver = udev_device_get_driver(parent);
af3aa302 474
24c083df 475 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
af3aa302 476
24c083df
TG
477 devtype = udev_device_get_devtype(device);
478 }
f579559b 479
f579559b
TG
480 LIST_FOREACH(networks, network, manager->networks) {
481 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
482 network->match_driver, network->match_type,
483 network->match_name, network->match_host,
5022f08a
LP
484 network->match_virt, network->match_kernel_cmdline,
485 network->match_kernel_version, network->match_arch,
af3aa302
TG
486 address, path, parent_driver, driver,
487 devtype, ifname)) {
24c083df 488 if (network->match_name && device) {
ca6038b8
TG
489 const char *attr;
490 uint8_t name_assign_type = NET_NAME_UNKNOWN;
491
32bc8adc 492 attr = udev_device_get_sysattr_value(device, "name_assign_type");
285760fe 493 if (attr)
dc751688 494 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
495
496 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
497 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
498 ifname, network->filename);
32bc8adc 499 else
a2fae7bb 500 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 501 } else
a2fae7bb 502 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 503
f579559b
TG
504 *ret = network;
505 return 0;
506 }
507 }
508
509 *ret = NULL;
510
511 return -ENOENT;
512}
513
7d342c03 514int network_apply(Network *network, Link *link) {
f579559b
TG
515 int r;
516
c4a03a56
TG
517 assert(network);
518 assert(link);
519
f579559b
TG
520 link->network = network;
521
bfa695b5
TG
522 if (network->ipv4ll_route) {
523 Route *route;
524
0b180d75 525 r = route_new_static(network, NULL, 0, &route);
bfa695b5
TG
526 if (r < 0)
527 return r;
528
2ce40956 529 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
bfa695b5
TG
530 if (r == 0)
531 return -EINVAL;
532 if (r < 0)
533 return -errno;
534
535 route->family = AF_INET;
536 route->dst_prefixlen = 16;
537 route->scope = RT_SCOPE_LINK;
86655331 538 route->priority = IPV4LL_ROUTE_METRIC;
bfa695b5
TG
539 route->protocol = RTPROT_STATIC;
540 }
541
5512a963 542 if (network->n_dns > 0 ||
3df9bec5
LP
543 !strv_isempty(network->ntp) ||
544 !strv_isempty(network->search_domains) ||
2ad6b610 545 !strv_isempty(network->route_domains))
84de38c5 546 link_dirty(link);
3bef724f 547
f579559b
TG
548 return 0;
549}
02b59d57 550
439689c6
SS
551bool network_has_static_ipv6_addresses(Network *network) {
552 Address *address;
553
554 assert(network);
555
556 LIST_FOREACH(addresses, address, network->static_addresses) {
557 if (address->family == AF_INET6)
558 return true;
559 }
560
561 return false;
562}
563
69a93e7d 564int config_parse_netdev(const char *unit,
02b59d57
TG
565 const char *filename,
566 unsigned line,
567 const char *section,
568 unsigned section_line,
569 const char *lvalue,
570 int ltype,
571 const char *rvalue,
572 void *data,
573 void *userdata) {
574 Network *network = userdata;
31d0ac36
TG
575 _cleanup_free_ char *kind_string = NULL;
576 char *p;
1a436809 577 NetDev *netdev;
69a93e7d 578 NetDevKind kind;
02b59d57
TG
579 int r;
580
581 assert(filename);
582 assert(lvalue);
583 assert(rvalue);
584 assert(data);
585
69a93e7d
TG
586 kind_string = strdup(lvalue);
587 if (!kind_string)
588 return log_oom();
52433f6b 589
69a93e7d
TG
590 /* the keys are CamelCase versions of the kind */
591 for (p = kind_string; *p; p++)
592 *p = tolower(*p);
52433f6b 593
69a93e7d
TG
594 kind = netdev_kind_from_string(kind_string);
595 if (kind == _NETDEV_KIND_INVALID) {
12ca818f 596 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
597 return 0;
598 }
599
54abf461
TG
600 r = netdev_get(network->manager, rvalue, &netdev);
601 if (r < 0) {
12ca818f 602 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
603 return 0;
604 }
605
69a93e7d 606 if (netdev->kind != kind) {
12ca818f 607 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
608 return 0;
609 }
610
69a93e7d
TG
611 switch (kind) {
612 case NETDEV_KIND_BRIDGE:
613 network->bridge = netdev;
54abf461 614
69a93e7d
TG
615 break;
616 case NETDEV_KIND_BOND:
617 network->bond = netdev;
fe6b2d55 618
6cb955c6
AR
619 break;
620 case NETDEV_KIND_VRF:
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
64d6c229 1016 char **datap = data, *tz = NULL;
8eb9058d
LP
1017 int r;
1018
1019 assert(filename);
1020 assert(lvalue);
1021 assert(rvalue);
1022
1023 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1024 if (r < 0)
1025 return r;
1026
089fb865 1027 if (!timezone_is_valid(tz, LOG_ERR)) {
12ca818f 1028 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1029 free(tz);
1030 return 0;
1031 }
1032
64d6c229
TA
1033 free(*datap);
1034 *datap = tz;
8eb9058d
LP
1035
1036 return 0;
1037}
1a04db0f
LP
1038
1039int config_parse_dhcp_server_dns(
1040 const char *unit,
1041 const char *filename,
1042 unsigned line,
1043 const char *section,
1044 unsigned section_line,
1045 const char *lvalue,
1046 int ltype,
1047 const char *rvalue,
1048 void *data,
1049 void *userdata) {
1050
1051 Network *n = data;
1052 const char *p = rvalue;
1053 int r;
1054
1055 assert(filename);
1056 assert(lvalue);
1057 assert(rvalue);
1058
1059 for (;;) {
1060 _cleanup_free_ char *w = NULL;
1061 struct in_addr a, *m;
1062
1063 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1064 if (r == -ENOMEM)
1065 return log_oom();
1a04db0f
LP
1066 if (r < 0) {
1067 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1068 return 0;
1069 }
1a04db0f 1070 if (r == 0)
fa105ce6 1071 break;
1a04db0f
LP
1072
1073 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 1074 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1a04db0f
LP
1075 continue;
1076 }
1077
62d74c78 1078 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1a04db0f
LP
1079 if (!m)
1080 return log_oom();
1081
1082 m[n->n_dhcp_server_dns++] = a;
1083 n->dhcp_server_dns = m;
1084 }
fa105ce6 1085
88295a05
PF
1086 return 0;
1087}
1088
1089int config_parse_radv_dns(
1090 const char *unit,
1091 const char *filename,
1092 unsigned line,
1093 const char *section,
1094 unsigned section_line,
1095 const char *lvalue,
1096 int ltype,
1097 const char *rvalue,
1098 void *data,
1099 void *userdata) {
1100
1101 Network *n = data;
1102 const char *p = rvalue;
1103 int r;
1104
1105 assert(filename);
1106 assert(lvalue);
1107 assert(rvalue);
1108
1109 for (;;) {
1110 _cleanup_free_ char *w = NULL;
1111 union in_addr_union a;
1112
1113 r = extract_first_word(&p, &w, NULL, 0);
1114 if (r == -ENOMEM)
1115 return log_oom();
1116 if (r < 0) {
1117 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1118 return 0;
1119 }
1120 if (r == 0)
1121 break;
1122
1123 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1124 struct in6_addr *m;
1125
62d74c78 1126 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
88295a05
PF
1127 if (!m)
1128 return log_oom();
1129
1130 m[n->n_router_dns++] = a.in6;
1131 n->router_dns = m;
1132
1133 } else
1134 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1135
1136 }
1137
700f1186
PF
1138 return 0;
1139}
1140
1141int config_parse_radv_search_domains(
1142 const char *unit,
1143 const char *filename,
1144 unsigned line,
1145 const char *section,
1146 unsigned section_line,
1147 const char *lvalue,
1148 int ltype,
1149 const char *rvalue,
1150 void *data,
1151 void *userdata) {
1152
1153 Network *n = data;
1154 const char *p = rvalue;
1155 int r;
1156
1157 assert(filename);
1158 assert(lvalue);
1159 assert(rvalue);
1160
1161 for (;;) {
1162 _cleanup_free_ char *w = NULL;
1163 _cleanup_free_ char *idna = NULL;
1164
1165 r = extract_first_word(&p, &w, NULL, 0);
1166 if (r == -ENOMEM)
1167 return log_oom();
1168 if (r < 0) {
1169 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1170 return 0;
1171 }
1172 if (r == 0)
1173 break;
1174
1175 r = dns_name_apply_idna(w, &idna);
1176 if (r > 0) {
1177 r = strv_push(&n->router_search_domains, idna);
1178 if (r >= 0)
1179 idna = NULL;
1180 } else if (r == 0) {
1181 r = strv_push(&n->router_search_domains, w);
1182 if (r >= 0)
1183 w = NULL;
1184 }
1185 }
1186
fa105ce6 1187 return 0;
1a04db0f
LP
1188}
1189
1190int config_parse_dhcp_server_ntp(
1191 const char *unit,
1192 const char *filename,
1193 unsigned line,
1194 const char *section,
1195 unsigned section_line,
1196 const char *lvalue,
1197 int ltype,
1198 const char *rvalue,
1199 void *data,
1200 void *userdata) {
1201
1202 Network *n = data;
1203 const char *p = rvalue;
1204 int r;
1205
1206 assert(filename);
1207 assert(lvalue);
1208 assert(rvalue);
1209
1210 for (;;) {
1211 _cleanup_free_ char *w = NULL;
1212 struct in_addr a, *m;
1213
1214 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1215 if (r == -ENOMEM)
1216 return log_oom();
1a04db0f 1217 if (r < 0) {
12ca818f 1218 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1219 return 0;
1220 }
1a04db0f
LP
1221 if (r == 0)
1222 return 0;
1223
1224 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 1225 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1a04db0f
LP
1226 continue;
1227 }
1228
62d74c78 1229 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1a04db0f
LP
1230 if (!m)
1231 return log_oom();
1232
1233 m[n->n_dhcp_server_ntp++] = a;
1234 n->dhcp_server_ntp = m;
1235 }
1236}
8a516214 1237
53253824
SS
1238int config_parse_dns(
1239 const char *unit,
1240 const char *filename,
1241 unsigned line,
1242 const char *section,
1243 unsigned section_line,
1244 const char *lvalue,
1245 int ltype,
1246 const char *rvalue,
1247 void *data,
1248 void *userdata) {
1249
1250 Network *n = userdata;
1251 int r;
1252
1253 assert(filename);
1254 assert(lvalue);
1255 assert(rvalue);
1256
1257 for (;;) {
1258 _cleanup_free_ char *w = NULL;
1259 union in_addr_union a;
5512a963 1260 struct in_addr_data *m;
53253824
SS
1261 int family;
1262
5512a963 1263 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1264 if (r == -ENOMEM)
1265 return log_oom();
1266 if (r < 0) {
1267 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1268 break;
1269 }
5512a963
LP
1270 if (r == 0)
1271 break;
53253824
SS
1272
1273 r = in_addr_from_string_auto(w, &family, &a);
1274 if (r < 0) {
5512a963 1275 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1276 continue;
1277 }
1278
62d74c78 1279 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1280 if (!m)
53253824
SS
1281 return log_oom();
1282
5512a963
LP
1283 m[n->n_dns++] = (struct in_addr_data) {
1284 .family = family,
1285 .address = a,
1286 };
1287
1288 n->dns = m;
53253824
SS
1289 }
1290
1291 return 0;
1292}
1293
8a516214
LP
1294int config_parse_dnssec_negative_trust_anchors(
1295 const char *unit,
1296 const char *filename,
1297 unsigned line,
1298 const char *section,
1299 unsigned section_line,
1300 const char *lvalue,
1301 int ltype,
1302 const char *rvalue,
1303 void *data,
1304 void *userdata) {
1305
1306 const char *p = rvalue;
1307 Network *n = data;
1308 int r;
1309
3df9bec5 1310 assert(n);
8a516214
LP
1311 assert(lvalue);
1312 assert(rvalue);
1313
1314 if (isempty(rvalue)) {
1315 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1316 return 0;
1317 }
1318
1319 for (;;) {
1320 _cleanup_free_ char *w = NULL;
1321
1322 r = extract_first_word(&p, &w, NULL, 0);
1323 if (r < 0) {
1324 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1325 break;
1326 }
1327 if (r == 0)
1328 break;
1329
1330 r = dns_name_is_valid(w);
1331 if (r <= 0) {
1332 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1333 continue;
1334 }
1335
cbbf38ae
LP
1336 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1337 if (r < 0)
1338 return log_oom();
1339
8a516214
LP
1340 r = set_put(n->dnssec_negative_trust_anchors, w);
1341 if (r < 0)
1342 return log_oom();
1343 if (r > 0)
1344 w = NULL;
1345 }
1346
1347 return 0;
1348}
b2a81c0b 1349
26575990
LP
1350int config_parse_ntp(
1351 const char *unit,
1352 const char *filename,
1353 unsigned line,
1354 const char *section,
1355 unsigned section_line,
1356 const char *lvalue,
1357 int ltype,
1358 const char *rvalue,
1359 void *data,
1360 void *userdata) {
1361
1362 char ***l = data;
1363 int r;
1364
1365 assert(l);
1366 assert(lvalue);
1367 assert(rvalue);
1368
1369 if (isempty(rvalue)) {
1370 *l = strv_free(*l);
1371 return 0;
1372 }
1373
1374 for (;;) {
1375 _cleanup_free_ char *w = NULL;
1376
1377 r = extract_first_word(&rvalue, &w, NULL, 0);
1378 if (r == -ENOMEM)
1379 return log_oom();
1380 if (r < 0) {
1381 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1382 break;
1383 }
1384 if (r == 0)
1385 break;
1386
1387 r = dns_name_is_valid_or_address(w);
1388 if (r <= 0) {
1389 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1390 continue;
af1c0de0
SS
1391 }
1392
1393 r = strv_push(l, w);
1394 if (r < 0)
1395 return log_oom();
1396
1397 w = NULL;
1398 }
1399
1400 return 0;
1401}
1402
1403int config_parse_dhcp_user_class(
1404 const char *unit,
1405 const char *filename,
1406 unsigned line,
1407 const char *section,
1408 unsigned section_line,
1409 const char *lvalue,
1410 int ltype,
1411 const char *rvalue,
1412 void *data,
1413 void *userdata) {
1414
1415 char ***l = data;
1416 int r;
1417
1418 assert(l);
1419 assert(lvalue);
1420 assert(rvalue);
1421
1422 if (isempty(rvalue)) {
1423 *l = strv_free(*l);
1424 return 0;
1425 }
1426
1427 for (;;) {
1428 _cleanup_free_ char *w = NULL;
1429
1430 r = extract_first_word(&rvalue, &w, NULL, 0);
1431 if (r == -ENOMEM)
1432 return log_oom();
1433 if (r < 0) {
1434 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split user classes option, ignoring: %s", rvalue);
1435 break;
1436 }
1437 if (r == 0)
1438 break;
1439
1440 if (strlen(w) > 255) {
1441 log_syntax(unit, LOG_ERR, filename, line, r, "%s length is not in the range 1-255, ignoring.", w);
1442 continue;
26575990
LP
1443 }
1444
1445 r = strv_push(l, w);
1446 if (r < 0)
1447 return log_oom();
1448
1449 w = NULL;
1450 }
1451
1452 return 0;
1453}
1454
f594276b
JK
1455int config_parse_dhcp_route_table(const char *unit,
1456 const char *filename,
1457 unsigned line,
1458 const char *section,
1459 unsigned section_line,
1460 const char *lvalue,
1461 int ltype,
1462 const char *rvalue,
1463 void *data,
1464 void *userdata) {
fc1ba79d 1465 Network *network = data;
f594276b
JK
1466 uint32_t rt;
1467 int r;
1468
1469 assert(filename);
1470 assert(lvalue);
1471 assert(rvalue);
1472 assert(data);
1473
1474 r = safe_atou32(rvalue, &rt);
1475 if (r < 0) {
1476 log_syntax(unit, LOG_ERR, filename, line, r,
1477 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1478 return 0;
1479 }
1480
fc1ba79d
AR
1481 network->dhcp_route_table = rt;
1482 network->dhcp_route_table_set = true;
f594276b
JK
1483
1484 return 0;
1485}
1486
b2a81c0b
LP
1487DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1488
1489static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1490 [DHCP_USE_DOMAINS_NO] = "no",
1491 [DHCP_USE_DOMAINS_ROUTE] = "route",
1492 [DHCP_USE_DOMAINS_YES] = "yes",
1493};
1494
1495DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
34437b4f
LP
1496
1497DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1498
1499static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1500 [LLDP_MODE_NO] = "no",
1501 [LLDP_MODE_YES] = "yes",
1502 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1503};
1504
1505DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);