]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: Use CMP() macro for comparison.
[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);
418 }
419
420 free(network->name);
f579559b 421
79e16ce3
LP
422 condition_free_list(network->match_host);
423 condition_free_list(network->match_virt);
5022f08a
LP
424 condition_free_list(network->match_kernel_cmdline);
425 condition_free_list(network->match_kernel_version);
79e16ce3
LP
426 condition_free_list(network->match_arch);
427
8eb9058d 428 free(network->dhcp_server_timezone);
1a04db0f
LP
429 free(network->dhcp_server_dns);
430 free(network->dhcp_server_ntp);
8eb9058d 431
8a516214
LP
432 set_free_free(network->dnssec_negative_trust_anchors);
433
f579559b
TG
434 free(network);
435}
436
dbffab87
TG
437int network_get_by_name(Manager *manager, const char *name, Network **ret) {
438 Network *network;
439
440 assert(manager);
441 assert(name);
442 assert(ret);
443
444 network = hashmap_get(manager->networks_by_name, name);
445 if (!network)
446 return -ENOENT;
447
448 *ret = network;
449
450 return 0;
451}
452
505f8da7
TG
453int network_get(Manager *manager, struct udev_device *device,
454 const char *ifname, const struct ether_addr *address,
455 Network **ret) {
f579559b 456 Network *network;
af3aa302 457 struct udev_device *parent;
24c083df 458 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
f579559b
TG
459
460 assert(manager);
f579559b 461 assert(ret);
af3aa302 462
24c083df
TG
463 if (device) {
464 path = udev_device_get_property_value(device, "ID_PATH");
af3aa302 465
24c083df
TG
466 parent = udev_device_get_parent(device);
467 if (parent)
468 parent_driver = udev_device_get_driver(parent);
af3aa302 469
24c083df 470 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
af3aa302 471
24c083df
TG
472 devtype = udev_device_get_devtype(device);
473 }
f579559b 474
f579559b
TG
475 LIST_FOREACH(networks, network, manager->networks) {
476 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
477 network->match_driver, network->match_type,
478 network->match_name, network->match_host,
5022f08a
LP
479 network->match_virt, network->match_kernel_cmdline,
480 network->match_kernel_version, network->match_arch,
af3aa302
TG
481 address, path, parent_driver, driver,
482 devtype, ifname)) {
24c083df 483 if (network->match_name && device) {
ca6038b8
TG
484 const char *attr;
485 uint8_t name_assign_type = NET_NAME_UNKNOWN;
486
32bc8adc 487 attr = udev_device_get_sysattr_value(device, "name_assign_type");
285760fe 488 if (attr)
dc751688 489 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
490
491 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
492 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
493 ifname, network->filename);
32bc8adc 494 else
a2fae7bb 495 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 496 } else
a2fae7bb 497 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 498
f579559b
TG
499 *ret = network;
500 return 0;
501 }
502 }
503
504 *ret = NULL;
505
506 return -ENOENT;
507}
508
7d342c03 509int network_apply(Network *network, Link *link) {
f579559b
TG
510 int r;
511
c4a03a56
TG
512 assert(network);
513 assert(link);
514
f579559b
TG
515 link->network = network;
516
bfa695b5
TG
517 if (network->ipv4ll_route) {
518 Route *route;
519
0b180d75 520 r = route_new_static(network, NULL, 0, &route);
bfa695b5
TG
521 if (r < 0)
522 return r;
523
2ce40956 524 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
bfa695b5
TG
525 if (r == 0)
526 return -EINVAL;
527 if (r < 0)
528 return -errno;
529
530 route->family = AF_INET;
531 route->dst_prefixlen = 16;
532 route->scope = RT_SCOPE_LINK;
86655331 533 route->priority = IPV4LL_ROUTE_METRIC;
bfa695b5
TG
534 route->protocol = RTPROT_STATIC;
535 }
536
5512a963 537 if (network->n_dns > 0 ||
3df9bec5
LP
538 !strv_isempty(network->ntp) ||
539 !strv_isempty(network->search_domains) ||
2ad6b610 540 !strv_isempty(network->route_domains))
84de38c5 541 link_dirty(link);
3bef724f 542
f579559b
TG
543 return 0;
544}
02b59d57 545
439689c6
SS
546bool network_has_static_ipv6_addresses(Network *network) {
547 Address *address;
548
549 assert(network);
550
551 LIST_FOREACH(addresses, address, network->static_addresses) {
552 if (address->family == AF_INET6)
553 return true;
554 }
555
556 return false;
557}
558
69a93e7d 559int config_parse_netdev(const char *unit,
02b59d57
TG
560 const char *filename,
561 unsigned line,
562 const char *section,
563 unsigned section_line,
564 const char *lvalue,
565 int ltype,
566 const char *rvalue,
567 void *data,
568 void *userdata) {
569 Network *network = userdata;
31d0ac36
TG
570 _cleanup_free_ char *kind_string = NULL;
571 char *p;
1a436809 572 NetDev *netdev;
69a93e7d 573 NetDevKind kind;
02b59d57
TG
574 int r;
575
576 assert(filename);
577 assert(lvalue);
578 assert(rvalue);
579 assert(data);
580
69a93e7d
TG
581 kind_string = strdup(lvalue);
582 if (!kind_string)
583 return log_oom();
52433f6b 584
69a93e7d
TG
585 /* the keys are CamelCase versions of the kind */
586 for (p = kind_string; *p; p++)
587 *p = tolower(*p);
52433f6b 588
69a93e7d
TG
589 kind = netdev_kind_from_string(kind_string);
590 if (kind == _NETDEV_KIND_INVALID) {
12ca818f 591 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
592 return 0;
593 }
594
54abf461
TG
595 r = netdev_get(network->manager, rvalue, &netdev);
596 if (r < 0) {
12ca818f 597 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
598 return 0;
599 }
600
69a93e7d 601 if (netdev->kind != kind) {
12ca818f 602 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
603 return 0;
604 }
605
69a93e7d
TG
606 switch (kind) {
607 case NETDEV_KIND_BRIDGE:
608 network->bridge = netdev;
54abf461 609
69a93e7d
TG
610 break;
611 case NETDEV_KIND_BOND:
612 network->bond = netdev;
fe6b2d55 613
6cb955c6
AR
614 break;
615 case NETDEV_KIND_VRF:
616 network->vrf = netdev;
617
69a93e7d
TG
618 break;
619 case NETDEV_KIND_VLAN:
69a93e7d 620 case NETDEV_KIND_MACVLAN:
f33ff02b 621 case NETDEV_KIND_MACVTAP:
c4a5ddc9 622 case NETDEV_KIND_IPVLAN:
326cb406 623 case NETDEV_KIND_VXLAN:
92c918b0 624 case NETDEV_KIND_VCAN:
6a0a2f86 625 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
326cb406 626 if (r < 0) {
87ac8d99 627 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
326cb406
SS
628 return 0;
629 }
630
69a93e7d
TG
631 break;
632 default:
87ac8d99 633 assert_not_reached("Cannot parse NetDev");
fe6b2d55
TG
634 }
635
47e2dc31
TG
636 netdev_ref(netdev);
637
fe6b2d55
TG
638 return 0;
639}
7951dea2 640
3df9bec5
LP
641int config_parse_domains(
642 const char *unit,
643 const char *filename,
644 unsigned line,
645 const char *section,
646 unsigned section_line,
647 const char *lvalue,
648 int ltype,
649 const char *rvalue,
650 void *data,
651 void *userdata) {
652
653 const char *p;
654 Network *n = data;
6192b846
TG
655 int r;
656
3df9bec5
LP
657 assert(n);
658 assert(lvalue);
659 assert(rvalue);
6192b846 660
3df9bec5
LP
661 if (isempty(rvalue)) {
662 n->search_domains = strv_free(n->search_domains);
663 n->route_domains = strv_free(n->route_domains);
664 return 0;
665 }
67272d15 666
3df9bec5
LP
667 p = rvalue;
668 for (;;) {
669 _cleanup_free_ char *w = NULL, *normalized = NULL;
670 const char *domain;
671 bool is_route;
672
673 r = extract_first_word(&p, &w, NULL, 0);
674 if (r < 0) {
675 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
676 break;
677 }
678 if (r == 0)
679 break;
680
681 is_route = w[0] == '~';
682 domain = is_route ? w + 1 : w;
683
684 if (dns_name_is_root(domain) || streq(domain, "*")) {
685 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
686 * routing domain, unconditionally. */
687 is_route = true;
688 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
689
690 } else {
691 r = dns_name_normalize(domain, &normalized);
692 if (r < 0) {
693 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
694 continue;
695 }
696
697 domain = normalized;
698
699 if (is_localhost(domain)) {
700 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 701 continue;
3df9bec5 702 }
37de2509 703 }
40274ed6 704
3df9bec5
LP
705 if (is_route) {
706 r = strv_extend(&n->route_domains, domain);
707 if (r < 0)
708 return log_oom();
40274ed6 709
3df9bec5
LP
710 } else {
711 r = strv_extend(&n->search_domains, domain);
712 if (r < 0)
713 return log_oom();
714 }
40274ed6 715 }
f15b6e5a 716
3df9bec5
LP
717 strv_uniq(n->route_domains);
718 strv_uniq(n->search_domains);
719
6192b846
TG
720 return 0;
721}
722
7951dea2
SS
723int config_parse_tunnel(const char *unit,
724 const char *filename,
725 unsigned line,
726 const char *section,
727 unsigned section_line,
728 const char *lvalue,
729 int ltype,
730 const char *rvalue,
731 void *data,
732 void *userdata) {
733 Network *network = userdata;
734 NetDev *netdev;
735 int r;
736
737 assert(filename);
738 assert(lvalue);
739 assert(rvalue);
740 assert(data);
741
742 r = netdev_get(network->manager, rvalue, &netdev);
743 if (r < 0) {
6a7a4e4d 744 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
7951dea2
SS
745 return 0;
746 }
747
d29ad81e
ZJS
748 if (!IN_SET(netdev->kind,
749 NETDEV_KIND_IPIP,
750 NETDEV_KIND_SIT,
751 NETDEV_KIND_GRE,
752 NETDEV_KIND_GRETAP,
753 NETDEV_KIND_IP6GRE,
754 NETDEV_KIND_IP6GRETAP,
755 NETDEV_KIND_VTI,
756 NETDEV_KIND_VTI6,
757 NETDEV_KIND_IP6TNL)) {
12ca818f 758 log_syntax(unit, LOG_ERR, filename, line, 0,
7951dea2
SS
759 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
760 return 0;
761 }
762
6a0a2f86
TG
763 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
764 if (r < 0) {
6a7a4e4d 765 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
6a0a2f86
TG
766 return 0;
767 }
768
769 netdev_ref(netdev);
7951dea2
SS
770
771 return 0;
772}
bd8f6538 773
d0d6a4cd
TG
774int config_parse_ipv4ll(
775 const char* unit,
776 const char *filename,
777 unsigned line,
778 const char *section,
779 unsigned section_line,
780 const char *lvalue,
781 int ltype,
782 const char *rvalue,
783 void *data,
784 void *userdata) {
785
786 AddressFamilyBoolean *link_local = data;
787
788 assert(filename);
789 assert(lvalue);
790 assert(rvalue);
791 assert(data);
792
793 /* Note that this is mostly like
794 * config_parse_address_family_boolean(), except that it
795 * applies only to IPv4 */
796
5883ff60 797 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
d0d6a4cd
TG
798
799 return 0;
800}
801
bd8f6538
TG
802int config_parse_dhcp(
803 const char* unit,
804 const char *filename,
805 unsigned line,
806 const char *section,
807 unsigned section_line,
808 const char *lvalue,
809 int ltype,
810 const char *rvalue,
811 void *data,
812 void *userdata) {
813
cb9fc36a 814 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
815
816 assert(filename);
817 assert(lvalue);
818 assert(rvalue);
819 assert(data);
820
769d324c
LP
821 /* Note that this is mostly like
822 * config_parse_address_family_boolean(), except that it
823 * understands some old names for the enum values */
824
cb9fc36a
LP
825 s = address_family_boolean_from_string(rvalue);
826 if (s < 0) {
827
828 /* Previously, we had a slightly different enum here,
829 * support its values for compatbility. */
830
831 if (streq(rvalue, "none"))
832 s = ADDRESS_FAMILY_NO;
833 else if (streq(rvalue, "v4"))
834 s = ADDRESS_FAMILY_IPV4;
835 else if (streq(rvalue, "v6"))
836 s = ADDRESS_FAMILY_IPV6;
837 else if (streq(rvalue, "both"))
838 s = ADDRESS_FAMILY_YES;
839 else {
12ca818f 840 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
841 return 0;
842 }
bd8f6538
TG
843 }
844
cb9fc36a 845 *dhcp = s;
bd8f6538
TG
846 return 0;
847}
848
3e43b2cd
JJ
849static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
850 [DHCP_CLIENT_ID_MAC] = "mac",
dace710c
YW
851 [DHCP_CLIENT_ID_DUID] = "duid",
852 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
3e43b2cd
JJ
853};
854
499d555a
SS
855DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
856DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
3e43b2cd 857
60c35566 858int config_parse_ipv6token(
7f77697a
TG
859 const char* unit,
860 const char *filename,
861 unsigned line,
862 const char *section,
863 unsigned section_line,
864 const char *lvalue,
865 int ltype,
866 const char *rvalue,
867 void *data,
868 void *userdata) {
869
870 union in_addr_union buffer;
871 struct in6_addr *token = data;
872 int r;
873
874 assert(filename);
875 assert(lvalue);
876 assert(rvalue);
877 assert(token);
878
879 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
880 if (r < 0) {
6a7a4e4d 881 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
882 return 0;
883 }
884
885 r = in_addr_is_null(AF_INET6, &buffer);
12ca818f 886 if (r != 0) {
87ac8d99 887 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
888 return 0;
889 }
890
891 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
87ac8d99 892 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
893 return 0;
894 }
895
896 *token = buffer.in6;
897
898 return 0;
899}
8add5f79 900
49092e22 901static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
902 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
903 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
904 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
905};
906
907DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
908
909int config_parse_ipv6_privacy_extensions(
910 const char* unit,
911 const char *filename,
912 unsigned line,
913 const char *section,
914 unsigned section_line,
915 const char *lvalue,
916 int ltype,
917 const char *rvalue,
918 void *data,
919 void *userdata) {
920
921 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
922 int k;
923
924 assert(filename);
925 assert(lvalue);
926 assert(rvalue);
927 assert(ipv6_privacy_extensions);
928
929 /* Our enum shall be a superset of booleans, hence first try
930 * to parse as boolean, and then as enum */
931
932 k = parse_boolean(rvalue);
933 if (k > 0)
1f0d9695 934 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 935 else if (k == 0)
1f0d9695 936 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 937 else {
1f0d9695 938 IPv6PrivacyExtensions s;
49092e22
SS
939
940 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
941 if (s < 0) {
942
943 if (streq(rvalue, "kernel"))
944 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
945 else {
12ca818f 946 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1f0d9695
LP
947 return 0;
948 }
49092e22
SS
949 }
950
951 *ipv6_privacy_extensions = s;
952 }
953
954 return 0;
955}
a7d0ef44 956
1ac608c9
LP
957int config_parse_hostname(
958 const char *unit,
959 const char *filename,
960 unsigned line,
961 const char *section,
962 unsigned section_line,
963 const char *lvalue,
964 int ltype,
965 const char *rvalue,
966 void *data,
967 void *userdata) {
968
6528693a
YW
969 _cleanup_free_ char *hn = NULL;
970 char **hostname = data;
a7d0ef44
SS
971 int r;
972
973 assert(filename);
974 assert(lvalue);
975 assert(rvalue);
976
1ac608c9 977 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
978 if (r < 0)
979 return r;
980
1ac608c9 981 if (!hostname_is_valid(hn, false)) {
12ca818f 982 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
983 return 0;
984 }
985
6528693a
YW
986 r = dns_name_is_valid(hn);
987 if (r < 0) {
988 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
989 return 0;
990 }
991 if (r == 0) {
992 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
993 return 0;
994 }
995
996 return free_and_replace(*hostname, hn);
a7d0ef44 997}
8eb9058d
LP
998
999int config_parse_timezone(
1000 const char *unit,
1001 const char *filename,
1002 unsigned line,
1003 const char *section,
1004 unsigned section_line,
1005 const char *lvalue,
1006 int ltype,
1007 const char *rvalue,
1008 void *data,
1009 void *userdata) {
1010
19f9e4e2
YW
1011 _cleanup_free_ char *tz = NULL;
1012 char **datap = data;
8eb9058d
LP
1013 int r;
1014
1015 assert(filename);
1016 assert(lvalue);
1017 assert(rvalue);
1018
1019 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1020 if (r < 0)
1021 return r;
1022
089fb865 1023 if (!timezone_is_valid(tz, LOG_ERR)) {
12ca818f 1024 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1025 return 0;
1026 }
1027
19f9e4e2 1028 return free_and_replace(*datap, tz);
8eb9058d 1029}
1a04db0f
LP
1030
1031int config_parse_dhcp_server_dns(
1032 const char *unit,
1033 const char *filename,
1034 unsigned line,
1035 const char *section,
1036 unsigned section_line,
1037 const char *lvalue,
1038 int ltype,
1039 const char *rvalue,
1040 void *data,
1041 void *userdata) {
1042
1043 Network *n = data;
1044 const char *p = rvalue;
1045 int r;
1046
1047 assert(filename);
1048 assert(lvalue);
1049 assert(rvalue);
1050
1051 for (;;) {
1052 _cleanup_free_ char *w = NULL;
1053 struct in_addr a, *m;
1054
1055 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1056 if (r == -ENOMEM)
1057 return log_oom();
1a04db0f
LP
1058 if (r < 0) {
1059 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1060 return 0;
1061 }
1a04db0f 1062 if (r == 0)
fa105ce6 1063 break;
1a04db0f
LP
1064
1065 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 1066 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1a04db0f
LP
1067 continue;
1068 }
1069
62d74c78 1070 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1a04db0f
LP
1071 if (!m)
1072 return log_oom();
1073
1074 m[n->n_dhcp_server_dns++] = a;
1075 n->dhcp_server_dns = m;
1076 }
fa105ce6 1077
88295a05
PF
1078 return 0;
1079}
1080
1081int config_parse_radv_dns(
1082 const char *unit,
1083 const char *filename,
1084 unsigned line,
1085 const char *section,
1086 unsigned section_line,
1087 const char *lvalue,
1088 int ltype,
1089 const char *rvalue,
1090 void *data,
1091 void *userdata) {
1092
1093 Network *n = data;
1094 const char *p = rvalue;
1095 int r;
1096
1097 assert(filename);
1098 assert(lvalue);
1099 assert(rvalue);
1100
1101 for (;;) {
1102 _cleanup_free_ char *w = NULL;
1103 union in_addr_union a;
1104
1105 r = extract_first_word(&p, &w, NULL, 0);
1106 if (r == -ENOMEM)
1107 return log_oom();
1108 if (r < 0) {
1109 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1110 return 0;
1111 }
1112 if (r == 0)
1113 break;
1114
1115 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1116 struct in6_addr *m;
1117
62d74c78 1118 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
88295a05
PF
1119 if (!m)
1120 return log_oom();
1121
1122 m[n->n_router_dns++] = a.in6;
1123 n->router_dns = m;
1124
1125 } else
1126 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1127
1128 }
1129
700f1186
PF
1130 return 0;
1131}
1132
1133int config_parse_radv_search_domains(
1134 const char *unit,
1135 const char *filename,
1136 unsigned line,
1137 const char *section,
1138 unsigned section_line,
1139 const char *lvalue,
1140 int ltype,
1141 const char *rvalue,
1142 void *data,
1143 void *userdata) {
1144
1145 Network *n = data;
1146 const char *p = rvalue;
1147 int r;
1148
1149 assert(filename);
1150 assert(lvalue);
1151 assert(rvalue);
1152
1153 for (;;) {
1154 _cleanup_free_ char *w = NULL;
1155 _cleanup_free_ char *idna = NULL;
1156
1157 r = extract_first_word(&p, &w, NULL, 0);
1158 if (r == -ENOMEM)
1159 return log_oom();
1160 if (r < 0) {
1161 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1162 return 0;
1163 }
1164 if (r == 0)
1165 break;
1166
1167 r = dns_name_apply_idna(w, &idna);
1168 if (r > 0) {
1169 r = strv_push(&n->router_search_domains, idna);
1170 if (r >= 0)
1171 idna = NULL;
1172 } else if (r == 0) {
1173 r = strv_push(&n->router_search_domains, w);
1174 if (r >= 0)
1175 w = NULL;
1176 }
1177 }
1178
fa105ce6 1179 return 0;
1a04db0f
LP
1180}
1181
1182int config_parse_dhcp_server_ntp(
1183 const char *unit,
1184 const char *filename,
1185 unsigned line,
1186 const char *section,
1187 unsigned section_line,
1188 const char *lvalue,
1189 int ltype,
1190 const char *rvalue,
1191 void *data,
1192 void *userdata) {
1193
1194 Network *n = data;
1195 const char *p = rvalue;
1196 int r;
1197
1198 assert(filename);
1199 assert(lvalue);
1200 assert(rvalue);
1201
1202 for (;;) {
1203 _cleanup_free_ char *w = NULL;
1204 struct in_addr a, *m;
1205
1206 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1207 if (r == -ENOMEM)
1208 return log_oom();
1a04db0f 1209 if (r < 0) {
12ca818f 1210 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1211 return 0;
1212 }
1a04db0f
LP
1213 if (r == 0)
1214 return 0;
1215
1216 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 1217 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1a04db0f
LP
1218 continue;
1219 }
1220
62d74c78 1221 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1a04db0f
LP
1222 if (!m)
1223 return log_oom();
1224
1225 m[n->n_dhcp_server_ntp++] = a;
1226 n->dhcp_server_ntp = m;
1227 }
1228}
8a516214 1229
53253824
SS
1230int config_parse_dns(
1231 const char *unit,
1232 const char *filename,
1233 unsigned line,
1234 const char *section,
1235 unsigned section_line,
1236 const char *lvalue,
1237 int ltype,
1238 const char *rvalue,
1239 void *data,
1240 void *userdata) {
1241
1242 Network *n = userdata;
1243 int r;
1244
1245 assert(filename);
1246 assert(lvalue);
1247 assert(rvalue);
1248
1249 for (;;) {
1250 _cleanup_free_ char *w = NULL;
1251 union in_addr_union a;
5512a963 1252 struct in_addr_data *m;
53253824
SS
1253 int family;
1254
5512a963 1255 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1256 if (r == -ENOMEM)
1257 return log_oom();
1258 if (r < 0) {
1259 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1260 break;
1261 }
5512a963
LP
1262 if (r == 0)
1263 break;
53253824
SS
1264
1265 r = in_addr_from_string_auto(w, &family, &a);
1266 if (r < 0) {
5512a963 1267 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1268 continue;
1269 }
1270
62d74c78 1271 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1272 if (!m)
53253824
SS
1273 return log_oom();
1274
5512a963
LP
1275 m[n->n_dns++] = (struct in_addr_data) {
1276 .family = family,
1277 .address = a,
1278 };
1279
1280 n->dns = m;
53253824
SS
1281 }
1282
1283 return 0;
1284}
1285
8a516214
LP
1286int config_parse_dnssec_negative_trust_anchors(
1287 const char *unit,
1288 const char *filename,
1289 unsigned line,
1290 const char *section,
1291 unsigned section_line,
1292 const char *lvalue,
1293 int ltype,
1294 const char *rvalue,
1295 void *data,
1296 void *userdata) {
1297
1298 const char *p = rvalue;
1299 Network *n = data;
1300 int r;
1301
3df9bec5 1302 assert(n);
8a516214
LP
1303 assert(lvalue);
1304 assert(rvalue);
1305
1306 if (isempty(rvalue)) {
1307 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1308 return 0;
1309 }
1310
1311 for (;;) {
1312 _cleanup_free_ char *w = NULL;
1313
1314 r = extract_first_word(&p, &w, NULL, 0);
1315 if (r < 0) {
1316 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1317 break;
1318 }
1319 if (r == 0)
1320 break;
1321
1322 r = dns_name_is_valid(w);
1323 if (r <= 0) {
1324 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1325 continue;
1326 }
1327
cbbf38ae
LP
1328 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1329 if (r < 0)
1330 return log_oom();
1331
8a516214
LP
1332 r = set_put(n->dnssec_negative_trust_anchors, w);
1333 if (r < 0)
1334 return log_oom();
1335 if (r > 0)
1336 w = NULL;
1337 }
1338
1339 return 0;
1340}
b2a81c0b 1341
26575990
LP
1342int config_parse_ntp(
1343 const char *unit,
1344 const char *filename,
1345 unsigned line,
1346 const char *section,
1347 unsigned section_line,
1348 const char *lvalue,
1349 int ltype,
1350 const char *rvalue,
1351 void *data,
1352 void *userdata) {
1353
1354 char ***l = data;
1355 int r;
1356
1357 assert(l);
1358 assert(lvalue);
1359 assert(rvalue);
1360
1361 if (isempty(rvalue)) {
1362 *l = strv_free(*l);
1363 return 0;
1364 }
1365
1366 for (;;) {
1367 _cleanup_free_ char *w = NULL;
1368
1369 r = extract_first_word(&rvalue, &w, NULL, 0);
1370 if (r == -ENOMEM)
1371 return log_oom();
1372 if (r < 0) {
1373 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1374 break;
1375 }
1376 if (r == 0)
1377 break;
1378
1379 r = dns_name_is_valid_or_address(w);
1380 if (r <= 0) {
1381 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1382 continue;
af1c0de0
SS
1383 }
1384
1385 r = strv_push(l, w);
1386 if (r < 0)
1387 return log_oom();
1388
1389 w = NULL;
1390 }
1391
1392 return 0;
1393}
1394
1395int config_parse_dhcp_user_class(
1396 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) {
1406
1407 char ***l = data;
1408 int r;
1409
1410 assert(l);
1411 assert(lvalue);
1412 assert(rvalue);
1413
1414 if (isempty(rvalue)) {
1415 *l = strv_free(*l);
1416 return 0;
1417 }
1418
1419 for (;;) {
1420 _cleanup_free_ char *w = NULL;
1421
1422 r = extract_first_word(&rvalue, &w, NULL, 0);
1423 if (r == -ENOMEM)
1424 return log_oom();
1425 if (r < 0) {
1426 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split user classes option, ignoring: %s", rvalue);
1427 break;
1428 }
1429 if (r == 0)
1430 break;
1431
1432 if (strlen(w) > 255) {
1433 log_syntax(unit, LOG_ERR, filename, line, r, "%s length is not in the range 1-255, ignoring.", w);
1434 continue;
26575990
LP
1435 }
1436
1437 r = strv_push(l, w);
1438 if (r < 0)
1439 return log_oom();
1440
1441 w = NULL;
1442 }
1443
1444 return 0;
1445}
1446
f594276b
JK
1447int config_parse_dhcp_route_table(const char *unit,
1448 const char *filename,
1449 unsigned line,
1450 const char *section,
1451 unsigned section_line,
1452 const char *lvalue,
1453 int ltype,
1454 const char *rvalue,
1455 void *data,
1456 void *userdata) {
fc1ba79d 1457 Network *network = data;
f594276b
JK
1458 uint32_t rt;
1459 int r;
1460
1461 assert(filename);
1462 assert(lvalue);
1463 assert(rvalue);
1464 assert(data);
1465
1466 r = safe_atou32(rvalue, &rt);
1467 if (r < 0) {
1468 log_syntax(unit, LOG_ERR, filename, line, r,
1469 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1470 return 0;
1471 }
1472
fc1ba79d
AR
1473 network->dhcp_route_table = rt;
1474 network->dhcp_route_table_set = true;
f594276b
JK
1475
1476 return 0;
1477}
1478
b2a81c0b
LP
1479DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1480
1481static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1482 [DHCP_USE_DOMAINS_NO] = "no",
1483 [DHCP_USE_DOMAINS_ROUTE] = "route",
1484 [DHCP_USE_DOMAINS_YES] = "yes",
1485};
1486
1487DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
34437b4f
LP
1488
1489DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1490
1491static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1492 [LLDP_MODE_NO] = "no",
1493 [LLDP_MODE_YES] = "yes",
1494 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1495};
1496
1497DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);