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