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