]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: request product UUID when DUIDType=uuid but DUIDRawData= is not set
[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 */
83 /* NOTE: it was not initiallized to any value in network_load_one. */
84 network->dhcp_vendor_class_identifier = false;
85 /* RFC7844 section 3.6.:
86 The client intending to protect its privacy SHOULD only request a
87 minimal number of options in the PRL and SHOULD also randomly shuffle
88 the ordering of option codes in the PRL. If this random ordering
89 cannot be implemented, the client MAY order the option codes in the
90 PRL by option code number (lowest to highest).
91 */
92 /* NOTE: dhcp_use_mtu is false by default,
93 * though it was not initiallized to any value in network_load_one.
94 * Maybe there should be another var called *send*?
95 * (to use the MTU sent by the server but to do not send
96 * the option in the PRL). */
97 network->dhcp_use_mtu = false;
28522b0d 98 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
99 * but this is needed to use them. */
100 network->dhcp_use_routes = true;
add8d07d 101 /* RFC7844 section 3.6.
102 * same comments as previous option */
103 network->dhcp_use_timezone = false;
104}
105
f579559b 106static int network_load_one(Manager *manager, const char *filename) {
8e766630 107 _cleanup_(network_freep) Network *network = NULL;
f579559b 108 _cleanup_fclose_ FILE *file = NULL;
dbffab87 109 char *d;
047a0dac 110 const char *dropin_dirname;
b3070dc0
TG
111 Route *route;
112 Address *address;
f579559b
TG
113 int r;
114
bf1bc670
TA
115 assert(manager);
116 assert(filename);
117
f579559b
TG
118 file = fopen(filename, "re");
119 if (!file) {
120 if (errno == ENOENT)
121 return 0;
1e7a0e21
LP
122
123 return -errno;
f579559b
TG
124 }
125
ed88bcfb
ZJS
126 if (null_or_empty_fd(fileno(file))) {
127 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
128 return 0;
129 }
130
f579559b
TG
131 network = new0(Network, 1);
132 if (!network)
133 return log_oom();
134
5a3eb5a7
TG
135 network->manager = manager;
136
f048a16b
TG
137 LIST_HEAD_INIT(network->static_addresses);
138 LIST_HEAD_INIT(network->static_routes);
b98b483b 139 LIST_HEAD_INIT(network->static_fdb_entries);
a0e5c15d 140 LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
95b74ef6 141 LIST_HEAD_INIT(network->address_labels);
057abfd8 142 LIST_HEAD_INIT(network->static_prefixes);
bce67bbe 143 LIST_HEAD_INIT(network->rules);
f579559b 144
d5099efc 145 network->stacked_netdevs = hashmap_new(&string_hash_ops);
6a0a2f86 146 if (!network->stacked_netdevs)
326cb406
SS
147 return log_oom();
148
f4859fc7 149 network->addresses_by_section = hashmap_new(&network_config_hash_ops);
6ae115c1
TG
150 if (!network->addresses_by_section)
151 return log_oom();
152
f4859fc7 153 network->routes_by_section = hashmap_new(&network_config_hash_ops);
6ae115c1
TG
154 if (!network->routes_by_section)
155 return log_oom();
156
b98b483b
AR
157 network->fdb_entries_by_section = hashmap_new(NULL);
158 if (!network->fdb_entries_by_section)
159 return log_oom();
160
95b74ef6
SS
161 network->address_labels_by_section = hashmap_new(&network_config_hash_ops);
162 if (!network->address_labels_by_section)
057abfd8
PF
163 log_oom();
164
165 network->prefixes_by_section = hashmap_new(&network_config_hash_ops);
166 if (!network->prefixes_by_section)
95b74ef6
SS
167 return log_oom();
168
bce67bbe
SS
169 network->rules_by_section = hashmap_new(&network_config_hash_ops);
170 if (!network->rules_by_section)
171 return log_oom();
172
6ae115c1
TG
173 network->filename = strdup(filename);
174 if (!network->filename)
175 return log_oom();
176
dbffab87
TG
177 network->name = strdup(basename(filename));
178 if (!network->name)
179 return log_oom();
180
181 d = strrchr(network->name, '.');
182 if (!d)
183 return -EINVAL;
184
185 assert(streq(d, ".network"));
186
187 *d = '\0';
188
c1a38904 189 network->required_for_online = true;
cb9fc36a 190 network->dhcp = ADDRESS_FAMILY_NO;
27cb34f5
LP
191 network->dhcp_use_ntp = true;
192 network->dhcp_use_dns = true;
193 network->dhcp_use_hostname = true;
194 network->dhcp_use_routes = true;
add8d07d 195 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
27cb34f5 196 network->dhcp_send_hostname = true;
add8d07d 197 /* To enable/disable RFC7844 Anonymity Profiles */
198 network->dhcp_anonymize = false;
84b5b79a 199 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
add8d07d 200 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
3e43b2cd 201 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
f594276b 202 network->dhcp_route_table = RT_TABLE_MAIN;
fc1ba79d 203 network->dhcp_route_table_set = false;
add8d07d 204 /* NOTE: the following vars were not set to any default,
205 * even if they are commented in the man?
206 * These vars might be overwriten by network_apply_anonymize_if_set */
207 network->dhcp_vendor_class_identifier = false;
95ab9eff
AJ
208 /* NOTE: from man: UseMTU=... Defaults to false*/
209 network->dhcp_use_mtu = false;
add8d07d 210 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
211 network->dhcp_use_timezone = false;
fb5c8216 212 network->rapid_commit = true;
5be4d38e 213
539f2a73
LP
214 network->dhcp_server_emit_dns = true;
215 network->dhcp_server_emit_ntp = true;
77ff6022 216 network->dhcp_server_emit_router = true;
539f2a73
LP
217 network->dhcp_server_emit_timezone = true;
218
9e25315c
PF
219 network->router_emit_dns = true;
220 network->router_emit_domains = true;
221
7f9915f0
SS
222 network->use_bpdu = -1;
223 network->hairpin = -1;
224 network->fast_leave = -1;
225 network->allow_port_to_be_root = -1;
226 network->unicast_flood = -1;
b56be296 227 network->priority = LINK_BRIDGE_PORT_PRIORITY_INVALID;
84c34096 228
7cececb2
LP
229 network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
230
a7e5da6e 231 network->llmnr = RESOLVE_SUPPORT_YES;
aaa297d4 232 network->mdns = RESOLVE_SUPPORT_NO;
ad6c0475 233 network->dnssec_mode = _DNSSEC_MODE_INVALID;
c9299be2 234 network->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID;
bd8f6538 235
d0d6a4cd
TG
236 network->link_local = ADDRESS_FAMILY_IPV6;
237
1f0d9695 238 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
4f2e437a 239 network->ipv6_accept_ra = -1;
8749cbcd 240 network->ipv6_dad_transmits = -1;
b69c3180 241 network->ipv6_hop_limit = -1;
465dfe59 242 network->ipv6_proxy_ndp = -1;
8341a5c3 243 network->duid.type = _DUID_TYPE_INVALID;
23d8b221 244 network->proxy_arp = -1;
99d2baa2 245 network->arp = -1;
e6ebebbe 246 network->multicast = -1;
866e6b7a 247 network->allmulticast = -1;
1e7a0e21 248 network->ipv6_accept_ra_use_dns = true;
2ba31d29 249 network->ipv6_accept_ra_route_table = RT_TABLE_MAIN;
11102cba 250 network->ipv6_mtu = 0;
49092e22 251
23bb31aa
ZJS
252 dropin_dirname = strjoina(network->name, ".network.d");
253
254 r = config_parse_many(filename, network_dirs, dropin_dirname,
255 "Match\0"
256 "Link\0"
257 "Network\0"
258 "Address\0"
95b74ef6 259 "IPv6AddressLabel\0"
bce67bbe 260 "RoutingPolicyRule\0"
23bb31aa
ZJS
261 "Route\0"
262 "DHCP\0"
263 "DHCPv4\0" /* compat */
264 "DHCPServer\0"
265 "IPv6AcceptRA\0"
a0e5c15d 266 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
267 "Bridge\0"
268 "BridgeFDB\0"
9d5d0090 269 "BridgeVLAN\0"
7d5cac19 270 "IPv6PrefixDelegation\0"
06828bb6
HP
271 "IPv6Prefix\0"
272 "CAN\0",
23bb31aa 273 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 274 CONFIG_PARSE_WARN, network);
36f822c4 275 if (r < 0)
f579559b 276 return r;
f579559b 277
add8d07d 278 network_apply_anonymize_if_set(network);
279
5a8bcb67
LP
280 /* IPMasquerade=yes implies IPForward=yes */
281 if (network->ip_masquerade)
769d324c 282 network->ip_forward |= ADDRESS_FAMILY_IPV4;
5a8bcb67 283
f579559b 284 LIST_PREPEND(networks, manager->networks, network);
b3070dc0 285
dbffab87
TG
286 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
287 if (r < 0)
288 return r;
289
290 r = hashmap_put(manager->networks_by_name, network->name, network);
291 if (r < 0)
292 return r;
293
3d3d4255 294 LIST_FOREACH(routes, route, network->static_routes) {
b3070dc0
TG
295 if (!route->family) {
296 log_warning("Route section without Gateway field configured in %s. "
297 "Ignoring", filename);
298 return 0;
299 }
b3070dc0
TG
300 }
301
3d3d4255 302 LIST_FOREACH(addresses, address, network->static_addresses) {
b3070dc0
TG
303 if (!address->family) {
304 log_warning("Address section without Address field configured in %s. "
305 "Ignoring", filename);
306 return 0;
307 }
308 }
309
f579559b
TG
310 network = NULL;
311
312 return 0;
313}
314
315int network_load(Manager *manager) {
316 Network *network;
477e73b5
ZJS
317 _cleanup_strv_free_ char **files = NULL;
318 char **f;
f579559b
TG
319 int r;
320
321 assert(manager);
322
323 while ((network = manager->networks))
324 network_free(network);
325
b5084605 326 r = conf_files_list_strv(&files, ".network", NULL, 0, network_dirs);
f647962d
MS
327 if (r < 0)
328 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b
TG
329
330 STRV_FOREACH_BACKWARDS(f, files) {
331 r = network_load_one(manager, *f);
332 if (r < 0)
333 return r;
334 }
335
f579559b
TG
336 return 0;
337}
338
f579559b 339void network_free(Network *network) {
a0e5c15d 340 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
341 RoutingPolicyRule *rule;
342 FdbEntry *fdb_entry;
95b74ef6 343 AddressLabel *label;
057abfd8 344 Prefix *prefix;
bce67bbe
SS
345 Address *address;
346 NetDev *netdev;
347 Route *route;
06f021a8 348 Iterator i;
f579559b
TG
349
350 if (!network)
351 return;
352
353 free(network->filename);
354
e90d0374 355 set_free_free(network->match_mac);
5256e00e
TG
356 strv_free(network->match_path);
357 strv_free(network->match_driver);
358 strv_free(network->match_type);
359 strv_free(network->match_name);
f579559b
TG
360
361 free(network->description);
edb85f0d 362 free(network->dhcp_vendor_class_identifier);
af1c0de0 363 strv_free(network->dhcp_user_class);
27cb34f5 364 free(network->dhcp_hostname);
f579559b 365
c106cc36
TG
366 free(network->mac);
367
b0e39c82 368 strv_free(network->ntp);
5512a963 369 free(network->dns);
3df9bec5
LP
370 strv_free(network->search_domains);
371 strv_free(network->route_domains);
0d4ad91d 372 strv_free(network->bind_carrier);
3bef724f 373
47e2dc31 374 netdev_unref(network->bridge);
47e2dc31 375 netdev_unref(network->bond);
6cb955c6 376 netdev_unref(network->vrf);
47e2dc31 377
2c36be2f
TG
378 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
379 hashmap_remove(network->stacked_netdevs, netdev->ifname);
326cb406 380 netdev_unref(netdev);
2c36be2f 381 }
6a0a2f86 382 hashmap_free(network->stacked_netdevs);
326cb406 383
f048a16b 384 while ((route = network->static_routes))
f579559b
TG
385 route_free(route);
386
f048a16b 387 while ((address = network->static_addresses))
f579559b
TG
388 address_free(address);
389
b98b483b
AR
390 while ((fdb_entry = network->static_fdb_entries))
391 fdb_entry_free(fdb_entry);
392
a0e5c15d
FK
393 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
394 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
395
95b74ef6
SS
396 while ((label = network->address_labels))
397 address_label_free(label);
398
057abfd8
PF
399 while ((prefix = network->static_prefixes))
400 prefix_free(prefix);
401
bce67bbe
SS
402 while ((rule = network->rules))
403 routing_policy_rule_free(rule);
404
6ae115c1
TG
405 hashmap_free(network->addresses_by_section);
406 hashmap_free(network->routes_by_section);
b98b483b 407 hashmap_free(network->fdb_entries_by_section);
95b74ef6 408 hashmap_free(network->address_labels_by_section);
057abfd8 409 hashmap_free(network->prefixes_by_section);
bce67bbe 410 hashmap_free(network->rules_by_section);
6ae115c1 411
dbffab87
TG
412 if (network->manager) {
413 if (network->manager->networks)
414 LIST_REMOVE(networks, network->manager->networks, network);
415
416 if (network->manager->networks_by_name)
417 hashmap_remove(network->manager->networks_by_name, network->name);
27dfc982
YW
418
419 if (network->manager->duids_requesting_uuid)
420 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
421 }
422
423 free(network->name);
f579559b 424
79e16ce3
LP
425 condition_free_list(network->match_host);
426 condition_free_list(network->match_virt);
5022f08a
LP
427 condition_free_list(network->match_kernel_cmdline);
428 condition_free_list(network->match_kernel_version);
79e16ce3
LP
429 condition_free_list(network->match_arch);
430
8eb9058d 431 free(network->dhcp_server_timezone);
1a04db0f
LP
432 free(network->dhcp_server_dns);
433 free(network->dhcp_server_ntp);
8eb9058d 434
8a516214
LP
435 set_free_free(network->dnssec_negative_trust_anchors);
436
f579559b
TG
437 free(network);
438}
439
dbffab87
TG
440int network_get_by_name(Manager *manager, const char *name, Network **ret) {
441 Network *network;
442
443 assert(manager);
444 assert(name);
445 assert(ret);
446
447 network = hashmap_get(manager->networks_by_name, name);
448 if (!network)
449 return -ENOENT;
450
451 *ret = network;
452
453 return 0;
454}
455
505f8da7
TG
456int network_get(Manager *manager, struct udev_device *device,
457 const char *ifname, const struct ether_addr *address,
458 Network **ret) {
f579559b 459 Network *network;
af3aa302 460 struct udev_device *parent;
24c083df 461 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
f579559b
TG
462
463 assert(manager);
f579559b 464 assert(ret);
af3aa302 465
24c083df
TG
466 if (device) {
467 path = udev_device_get_property_value(device, "ID_PATH");
af3aa302 468
24c083df
TG
469 parent = udev_device_get_parent(device);
470 if (parent)
471 parent_driver = udev_device_get_driver(parent);
af3aa302 472
24c083df 473 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
af3aa302 474
24c083df
TG
475 devtype = udev_device_get_devtype(device);
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
32bc8adc 490 attr = udev_device_get_sysattr_value(device, "name_assign_type");
285760fe 491 if (attr)
dc751688 492 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
493
494 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
495 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
496 ifname, network->filename);
32bc8adc 497 else
a2fae7bb 498 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 499 } else
a2fae7bb 500 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 501
f579559b
TG
502 *ret = network;
503 return 0;
504 }
505 }
506
507 *ret = NULL;
508
509 return -ENOENT;
510}
511
7d342c03 512int network_apply(Network *network, Link *link) {
f579559b
TG
513 int r;
514
c4a03a56
TG
515 assert(network);
516 assert(link);
517
f579559b
TG
518 link->network = network;
519
bfa695b5
TG
520 if (network->ipv4ll_route) {
521 Route *route;
522
0b180d75 523 r = route_new_static(network, NULL, 0, &route);
bfa695b5
TG
524 if (r < 0)
525 return r;
526
2ce40956 527 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
bfa695b5
TG
528 if (r == 0)
529 return -EINVAL;
530 if (r < 0)
531 return -errno;
532
533 route->family = AF_INET;
534 route->dst_prefixlen = 16;
535 route->scope = RT_SCOPE_LINK;
86655331 536 route->priority = IPV4LL_ROUTE_METRIC;
bfa695b5
TG
537 route->protocol = RTPROT_STATIC;
538 }
539
5512a963 540 if (network->n_dns > 0 ||
3df9bec5
LP
541 !strv_isempty(network->ntp) ||
542 !strv_isempty(network->search_domains) ||
2ad6b610 543 !strv_isempty(network->route_domains))
84de38c5 544 link_dirty(link);
3bef724f 545
f579559b
TG
546 return 0;
547}
02b59d57 548
439689c6
SS
549bool network_has_static_ipv6_addresses(Network *network) {
550 Address *address;
551
552 assert(network);
553
554 LIST_FOREACH(addresses, address, network->static_addresses) {
555 if (address->family == AF_INET6)
556 return true;
557 }
558
559 return false;
560}
561
69a93e7d 562int config_parse_netdev(const char *unit,
02b59d57
TG
563 const char *filename,
564 unsigned line,
565 const char *section,
566 unsigned section_line,
567 const char *lvalue,
568 int ltype,
569 const char *rvalue,
570 void *data,
571 void *userdata) {
572 Network *network = userdata;
31d0ac36
TG
573 _cleanup_free_ char *kind_string = NULL;
574 char *p;
1a436809 575 NetDev *netdev;
69a93e7d 576 NetDevKind kind;
02b59d57
TG
577 int r;
578
579 assert(filename);
580 assert(lvalue);
581 assert(rvalue);
582 assert(data);
583
69a93e7d
TG
584 kind_string = strdup(lvalue);
585 if (!kind_string)
586 return log_oom();
52433f6b 587
69a93e7d
TG
588 /* the keys are CamelCase versions of the kind */
589 for (p = kind_string; *p; p++)
590 *p = tolower(*p);
52433f6b 591
69a93e7d
TG
592 kind = netdev_kind_from_string(kind_string);
593 if (kind == _NETDEV_KIND_INVALID) {
12ca818f 594 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
595 return 0;
596 }
597
54abf461
TG
598 r = netdev_get(network->manager, rvalue, &netdev);
599 if (r < 0) {
12ca818f 600 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
601 return 0;
602 }
603
69a93e7d 604 if (netdev->kind != kind) {
12ca818f 605 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
606 return 0;
607 }
608
69a93e7d
TG
609 switch (kind) {
610 case NETDEV_KIND_BRIDGE:
611 network->bridge = netdev;
54abf461 612
69a93e7d
TG
613 break;
614 case NETDEV_KIND_BOND:
615 network->bond = netdev;
fe6b2d55 616
6cb955c6
AR
617 break;
618 case NETDEV_KIND_VRF:
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);