]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: fix alignment
[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
7169cdc8
YW
284 if (network->mtu > 0 && network->dhcp_use_mtu) {
285 log_warning("MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set in %s. "
286 "Disabling UseMTU=.", filename);
287 network->dhcp_use_mtu = false;
288 }
289
f579559b 290 LIST_PREPEND(networks, manager->networks, network);
b3070dc0 291
dbffab87
TG
292 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
293 if (r < 0)
294 return r;
295
296 r = hashmap_put(manager->networks_by_name, network->name, network);
297 if (r < 0)
298 return r;
299
3d3d4255 300 LIST_FOREACH(routes, route, network->static_routes) {
b3070dc0
TG
301 if (!route->family) {
302 log_warning("Route section without Gateway field configured in %s. "
303 "Ignoring", filename);
304 return 0;
305 }
b3070dc0
TG
306 }
307
3d3d4255 308 LIST_FOREACH(addresses, address, network->static_addresses) {
b3070dc0
TG
309 if (!address->family) {
310 log_warning("Address section without Address field configured in %s. "
311 "Ignoring", filename);
312 return 0;
313 }
314 }
315
f579559b
TG
316 network = NULL;
317
318 return 0;
319}
320
321int network_load(Manager *manager) {
322 Network *network;
477e73b5
ZJS
323 _cleanup_strv_free_ char **files = NULL;
324 char **f;
f579559b
TG
325 int r;
326
327 assert(manager);
328
329 while ((network = manager->networks))
330 network_free(network);
331
b5084605 332 r = conf_files_list_strv(&files, ".network", NULL, 0, network_dirs);
f647962d
MS
333 if (r < 0)
334 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b
TG
335
336 STRV_FOREACH_BACKWARDS(f, files) {
337 r = network_load_one(manager, *f);
338 if (r < 0)
339 return r;
340 }
341
f579559b
TG
342 return 0;
343}
344
f579559b 345void network_free(Network *network) {
a0e5c15d 346 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
347 RoutingPolicyRule *rule;
348 FdbEntry *fdb_entry;
95b74ef6 349 AddressLabel *label;
057abfd8 350 Prefix *prefix;
bce67bbe
SS
351 Address *address;
352 NetDev *netdev;
353 Route *route;
06f021a8 354 Iterator i;
f579559b
TG
355
356 if (!network)
357 return;
358
359 free(network->filename);
360
e90d0374 361 set_free_free(network->match_mac);
5256e00e
TG
362 strv_free(network->match_path);
363 strv_free(network->match_driver);
364 strv_free(network->match_type);
365 strv_free(network->match_name);
f579559b
TG
366
367 free(network->description);
edb85f0d 368 free(network->dhcp_vendor_class_identifier);
af1c0de0 369 strv_free(network->dhcp_user_class);
27cb34f5 370 free(network->dhcp_hostname);
f579559b 371
c106cc36
TG
372 free(network->mac);
373
b0e39c82 374 strv_free(network->ntp);
5512a963 375 free(network->dns);
3df9bec5
LP
376 strv_free(network->search_domains);
377 strv_free(network->route_domains);
0d4ad91d 378 strv_free(network->bind_carrier);
3bef724f 379
47e2dc31 380 netdev_unref(network->bridge);
47e2dc31 381 netdev_unref(network->bond);
6cb955c6 382 netdev_unref(network->vrf);
47e2dc31 383
2c36be2f
TG
384 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
385 hashmap_remove(network->stacked_netdevs, netdev->ifname);
326cb406 386 netdev_unref(netdev);
2c36be2f 387 }
6a0a2f86 388 hashmap_free(network->stacked_netdevs);
326cb406 389
f048a16b 390 while ((route = network->static_routes))
f579559b
TG
391 route_free(route);
392
f048a16b 393 while ((address = network->static_addresses))
f579559b
TG
394 address_free(address);
395
b98b483b
AR
396 while ((fdb_entry = network->static_fdb_entries))
397 fdb_entry_free(fdb_entry);
398
a0e5c15d
FK
399 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
400 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
401
95b74ef6
SS
402 while ((label = network->address_labels))
403 address_label_free(label);
404
057abfd8
PF
405 while ((prefix = network->static_prefixes))
406 prefix_free(prefix);
407
bce67bbe
SS
408 while ((rule = network->rules))
409 routing_policy_rule_free(rule);
410
6ae115c1
TG
411 hashmap_free(network->addresses_by_section);
412 hashmap_free(network->routes_by_section);
b98b483b 413 hashmap_free(network->fdb_entries_by_section);
95b74ef6 414 hashmap_free(network->address_labels_by_section);
057abfd8 415 hashmap_free(network->prefixes_by_section);
bce67bbe 416 hashmap_free(network->rules_by_section);
6ae115c1 417
dbffab87
TG
418 if (network->manager) {
419 if (network->manager->networks)
420 LIST_REMOVE(networks, network->manager->networks, network);
421
422 if (network->manager->networks_by_name)
423 hashmap_remove(network->manager->networks_by_name, network->name);
27dfc982
YW
424
425 if (network->manager->duids_requesting_uuid)
426 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
427 }
428
429 free(network->name);
f579559b 430
79e16ce3
LP
431 condition_free_list(network->match_host);
432 condition_free_list(network->match_virt);
5022f08a
LP
433 condition_free_list(network->match_kernel_cmdline);
434 condition_free_list(network->match_kernel_version);
79e16ce3
LP
435 condition_free_list(network->match_arch);
436
8eb9058d 437 free(network->dhcp_server_timezone);
1a04db0f
LP
438 free(network->dhcp_server_dns);
439 free(network->dhcp_server_ntp);
8eb9058d 440
8a516214
LP
441 set_free_free(network->dnssec_negative_trust_anchors);
442
f579559b
TG
443 free(network);
444}
445
dbffab87
TG
446int network_get_by_name(Manager *manager, const char *name, Network **ret) {
447 Network *network;
448
449 assert(manager);
450 assert(name);
451 assert(ret);
452
453 network = hashmap_get(manager->networks_by_name, name);
454 if (!network)
455 return -ENOENT;
456
457 *ret = network;
458
459 return 0;
460}
461
51517f9e 462int network_get(Manager *manager, sd_device *device,
505f8da7
TG
463 const char *ifname, const struct ether_addr *address,
464 Network **ret) {
24c083df 465 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
51517f9e
YW
466 sd_device *parent;
467 Network *network;
f579559b
TG
468
469 assert(manager);
f579559b 470 assert(ret);
af3aa302 471
24c083df 472 if (device) {
51517f9e 473 (void) sd_device_get_property_value(device, "ID_PATH", &path);
af3aa302 474
51517f9e
YW
475 if (sd_device_get_parent(device, &parent) >= 0)
476 (void) sd_device_get_driver(parent, &parent_driver);
af3aa302 477
51517f9e 478 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
af3aa302 479
51517f9e 480 (void) sd_device_get_devtype(device, &devtype);
24c083df 481 }
f579559b 482
f579559b
TG
483 LIST_FOREACH(networks, network, manager->networks) {
484 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
485 network->match_driver, network->match_type,
486 network->match_name, network->match_host,
5022f08a
LP
487 network->match_virt, network->match_kernel_cmdline,
488 network->match_kernel_version, network->match_arch,
af3aa302
TG
489 address, path, parent_driver, driver,
490 devtype, ifname)) {
24c083df 491 if (network->match_name && device) {
ca6038b8
TG
492 const char *attr;
493 uint8_t name_assign_type = NET_NAME_UNKNOWN;
494
51517f9e 495 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
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) {
87ac8d99 634 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
326cb406
SS
635 return 0;
636 }
637
69a93e7d
TG
638 break;
639 default:
87ac8d99 640 assert_not_reached("Cannot 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",
dace710c
YW
858 [DHCP_CLIENT_ID_DUID] = "duid",
859 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
3e43b2cd
JJ
860};
861
499d555a
SS
862DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
863DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
3e43b2cd 864
60c35566 865int config_parse_ipv6token(
7f77697a
TG
866 const char* unit,
867 const char *filename,
868 unsigned line,
869 const char *section,
870 unsigned section_line,
871 const char *lvalue,
872 int ltype,
873 const char *rvalue,
874 void *data,
875 void *userdata) {
876
877 union in_addr_union buffer;
878 struct in6_addr *token = data;
879 int r;
880
881 assert(filename);
882 assert(lvalue);
883 assert(rvalue);
884 assert(token);
885
886 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
887 if (r < 0) {
6a7a4e4d 888 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
889 return 0;
890 }
891
892 r = in_addr_is_null(AF_INET6, &buffer);
12ca818f 893 if (r != 0) {
87ac8d99 894 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
895 return 0;
896 }
897
898 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
87ac8d99 899 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
900 return 0;
901 }
902
903 *token = buffer.in6;
904
905 return 0;
906}
8add5f79 907
49092e22 908static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
909 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
910 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
911 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
912};
913
914DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
915
916int config_parse_ipv6_privacy_extensions(
917 const char* unit,
918 const char *filename,
919 unsigned line,
920 const char *section,
921 unsigned section_line,
922 const char *lvalue,
923 int ltype,
924 const char *rvalue,
925 void *data,
926 void *userdata) {
927
928 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
929 int k;
930
931 assert(filename);
932 assert(lvalue);
933 assert(rvalue);
934 assert(ipv6_privacy_extensions);
935
936 /* Our enum shall be a superset of booleans, hence first try
937 * to parse as boolean, and then as enum */
938
939 k = parse_boolean(rvalue);
940 if (k > 0)
1f0d9695 941 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 942 else if (k == 0)
1f0d9695 943 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 944 else {
1f0d9695 945 IPv6PrivacyExtensions s;
49092e22
SS
946
947 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
948 if (s < 0) {
949
950 if (streq(rvalue, "kernel"))
951 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
952 else {
12ca818f 953 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1f0d9695
LP
954 return 0;
955 }
49092e22
SS
956 }
957
958 *ipv6_privacy_extensions = s;
959 }
960
961 return 0;
962}
a7d0ef44 963
1ac608c9
LP
964int config_parse_hostname(
965 const char *unit,
966 const char *filename,
967 unsigned line,
968 const char *section,
969 unsigned section_line,
970 const char *lvalue,
971 int ltype,
972 const char *rvalue,
973 void *data,
974 void *userdata) {
975
6528693a
YW
976 _cleanup_free_ char *hn = NULL;
977 char **hostname = data;
a7d0ef44
SS
978 int r;
979
980 assert(filename);
981 assert(lvalue);
982 assert(rvalue);
983
1ac608c9 984 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
985 if (r < 0)
986 return r;
987
1ac608c9 988 if (!hostname_is_valid(hn, false)) {
12ca818f 989 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
990 return 0;
991 }
992
6528693a
YW
993 r = dns_name_is_valid(hn);
994 if (r < 0) {
995 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
996 return 0;
997 }
998 if (r == 0) {
999 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
1000 return 0;
1001 }
1002
1003 return free_and_replace(*hostname, hn);
a7d0ef44 1004}
8eb9058d
LP
1005
1006int config_parse_timezone(
1007 const char *unit,
1008 const char *filename,
1009 unsigned line,
1010 const char *section,
1011 unsigned section_line,
1012 const char *lvalue,
1013 int ltype,
1014 const char *rvalue,
1015 void *data,
1016 void *userdata) {
1017
19f9e4e2
YW
1018 _cleanup_free_ char *tz = NULL;
1019 char **datap = data;
8eb9058d
LP
1020 int r;
1021
1022 assert(filename);
1023 assert(lvalue);
1024 assert(rvalue);
1025
1026 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1027 if (r < 0)
1028 return r;
1029
089fb865 1030 if (!timezone_is_valid(tz, LOG_ERR)) {
12ca818f 1031 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1032 return 0;
1033 }
1034
19f9e4e2 1035 return free_and_replace(*datap, tz);
8eb9058d 1036}
1a04db0f
LP
1037
1038int config_parse_dhcp_server_dns(
1039 const char *unit,
1040 const char *filename,
1041 unsigned line,
1042 const char *section,
1043 unsigned section_line,
1044 const char *lvalue,
1045 int ltype,
1046 const char *rvalue,
1047 void *data,
1048 void *userdata) {
1049
1050 Network *n = data;
1051 const char *p = rvalue;
1052 int r;
1053
1054 assert(filename);
1055 assert(lvalue);
1056 assert(rvalue);
1057
1058 for (;;) {
1059 _cleanup_free_ char *w = NULL;
1060 struct in_addr a, *m;
1061
1062 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1063 if (r == -ENOMEM)
1064 return log_oom();
1a04db0f
LP
1065 if (r < 0) {
1066 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1067 return 0;
1068 }
1a04db0f 1069 if (r == 0)
fa105ce6 1070 break;
1a04db0f
LP
1071
1072 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 1073 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1a04db0f
LP
1074 continue;
1075 }
1076
62d74c78 1077 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1a04db0f
LP
1078 if (!m)
1079 return log_oom();
1080
1081 m[n->n_dhcp_server_dns++] = a;
1082 n->dhcp_server_dns = m;
1083 }
fa105ce6 1084
88295a05
PF
1085 return 0;
1086}
1087
1088int config_parse_radv_dns(
1089 const char *unit,
1090 const char *filename,
1091 unsigned line,
1092 const char *section,
1093 unsigned section_line,
1094 const char *lvalue,
1095 int ltype,
1096 const char *rvalue,
1097 void *data,
1098 void *userdata) {
1099
1100 Network *n = data;
1101 const char *p = rvalue;
1102 int r;
1103
1104 assert(filename);
1105 assert(lvalue);
1106 assert(rvalue);
1107
1108 for (;;) {
1109 _cleanup_free_ char *w = NULL;
1110 union in_addr_union a;
1111
1112 r = extract_first_word(&p, &w, NULL, 0);
1113 if (r == -ENOMEM)
1114 return log_oom();
1115 if (r < 0) {
1116 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1117 return 0;
1118 }
1119 if (r == 0)
1120 break;
1121
1122 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1123 struct in6_addr *m;
1124
62d74c78 1125 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
88295a05
PF
1126 if (!m)
1127 return log_oom();
1128
1129 m[n->n_router_dns++] = a.in6;
1130 n->router_dns = m;
1131
1132 } else
1133 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1134
1135 }
1136
700f1186
PF
1137 return 0;
1138}
1139
1140int config_parse_radv_search_domains(
1141 const char *unit,
1142 const char *filename,
1143 unsigned line,
1144 const char *section,
1145 unsigned section_line,
1146 const char *lvalue,
1147 int ltype,
1148 const char *rvalue,
1149 void *data,
1150 void *userdata) {
1151
1152 Network *n = data;
1153 const char *p = rvalue;
1154 int r;
1155
1156 assert(filename);
1157 assert(lvalue);
1158 assert(rvalue);
1159
1160 for (;;) {
1161 _cleanup_free_ char *w = NULL;
1162 _cleanup_free_ char *idna = NULL;
1163
1164 r = extract_first_word(&p, &w, NULL, 0);
1165 if (r == -ENOMEM)
1166 return log_oom();
1167 if (r < 0) {
1168 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1169 return 0;
1170 }
1171 if (r == 0)
1172 break;
1173
1174 r = dns_name_apply_idna(w, &idna);
1175 if (r > 0) {
1176 r = strv_push(&n->router_search_domains, idna);
1177 if (r >= 0)
1178 idna = NULL;
1179 } else if (r == 0) {
1180 r = strv_push(&n->router_search_domains, w);
1181 if (r >= 0)
1182 w = NULL;
1183 }
1184 }
1185
fa105ce6 1186 return 0;
1a04db0f
LP
1187}
1188
1189int config_parse_dhcp_server_ntp(
1190 const char *unit,
1191 const char *filename,
1192 unsigned line,
1193 const char *section,
1194 unsigned section_line,
1195 const char *lvalue,
1196 int ltype,
1197 const char *rvalue,
1198 void *data,
1199 void *userdata) {
1200
1201 Network *n = data;
1202 const char *p = rvalue;
1203 int r;
1204
1205 assert(filename);
1206 assert(lvalue);
1207 assert(rvalue);
1208
1209 for (;;) {
1210 _cleanup_free_ char *w = NULL;
1211 struct in_addr a, *m;
1212
1213 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1214 if (r == -ENOMEM)
1215 return log_oom();
1a04db0f 1216 if (r < 0) {
12ca818f 1217 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1218 return 0;
1219 }
1a04db0f
LP
1220 if (r == 0)
1221 return 0;
1222
1223 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 1224 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1a04db0f
LP
1225 continue;
1226 }
1227
62d74c78 1228 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1a04db0f
LP
1229 if (!m)
1230 return log_oom();
1231
1232 m[n->n_dhcp_server_ntp++] = a;
1233 n->dhcp_server_ntp = m;
1234 }
1235}
8a516214 1236
53253824
SS
1237int config_parse_dns(
1238 const char *unit,
1239 const char *filename,
1240 unsigned line,
1241 const char *section,
1242 unsigned section_line,
1243 const char *lvalue,
1244 int ltype,
1245 const char *rvalue,
1246 void *data,
1247 void *userdata) {
1248
1249 Network *n = userdata;
1250 int r;
1251
1252 assert(filename);
1253 assert(lvalue);
1254 assert(rvalue);
1255
1256 for (;;) {
1257 _cleanup_free_ char *w = NULL;
1258 union in_addr_union a;
5512a963 1259 struct in_addr_data *m;
53253824
SS
1260 int family;
1261
5512a963 1262 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1263 if (r == -ENOMEM)
1264 return log_oom();
1265 if (r < 0) {
1266 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1267 break;
1268 }
5512a963
LP
1269 if (r == 0)
1270 break;
53253824
SS
1271
1272 r = in_addr_from_string_auto(w, &family, &a);
1273 if (r < 0) {
5512a963 1274 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1275 continue;
1276 }
1277
62d74c78 1278 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1279 if (!m)
53253824
SS
1280 return log_oom();
1281
5512a963
LP
1282 m[n->n_dns++] = (struct in_addr_data) {
1283 .family = family,
1284 .address = a,
1285 };
1286
1287 n->dns = m;
53253824
SS
1288 }
1289
1290 return 0;
1291}
1292
8a516214
LP
1293int config_parse_dnssec_negative_trust_anchors(
1294 const char *unit,
1295 const char *filename,
1296 unsigned line,
1297 const char *section,
1298 unsigned section_line,
1299 const char *lvalue,
1300 int ltype,
1301 const char *rvalue,
1302 void *data,
1303 void *userdata) {
1304
1305 const char *p = rvalue;
1306 Network *n = data;
1307 int r;
1308
3df9bec5 1309 assert(n);
8a516214
LP
1310 assert(lvalue);
1311 assert(rvalue);
1312
1313 if (isempty(rvalue)) {
1314 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1315 return 0;
1316 }
1317
1318 for (;;) {
1319 _cleanup_free_ char *w = NULL;
1320
1321 r = extract_first_word(&p, &w, NULL, 0);
1322 if (r < 0) {
1323 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1324 break;
1325 }
1326 if (r == 0)
1327 break;
1328
1329 r = dns_name_is_valid(w);
1330 if (r <= 0) {
1331 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1332 continue;
1333 }
1334
cbbf38ae
LP
1335 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1336 if (r < 0)
1337 return log_oom();
1338
8a516214
LP
1339 r = set_put(n->dnssec_negative_trust_anchors, w);
1340 if (r < 0)
1341 return log_oom();
1342 if (r > 0)
1343 w = NULL;
1344 }
1345
1346 return 0;
1347}
b2a81c0b 1348
26575990
LP
1349int config_parse_ntp(
1350 const char *unit,
1351 const char *filename,
1352 unsigned line,
1353 const char *section,
1354 unsigned section_line,
1355 const char *lvalue,
1356 int ltype,
1357 const char *rvalue,
1358 void *data,
1359 void *userdata) {
1360
1361 char ***l = data;
1362 int r;
1363
1364 assert(l);
1365 assert(lvalue);
1366 assert(rvalue);
1367
1368 if (isempty(rvalue)) {
1369 *l = strv_free(*l);
1370 return 0;
1371 }
1372
1373 for (;;) {
1374 _cleanup_free_ char *w = NULL;
1375
1376 r = extract_first_word(&rvalue, &w, NULL, 0);
1377 if (r == -ENOMEM)
1378 return log_oom();
1379 if (r < 0) {
1380 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1381 break;
1382 }
1383 if (r == 0)
1384 break;
1385
1386 r = dns_name_is_valid_or_address(w);
1387 if (r <= 0) {
1388 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1389 continue;
af1c0de0
SS
1390 }
1391
1392 r = strv_push(l, w);
1393 if (r < 0)
1394 return log_oom();
1395
1396 w = NULL;
1397 }
1398
1399 return 0;
1400}
1401
1402int config_parse_dhcp_user_class(
1403 const char *unit,
1404 const char *filename,
1405 unsigned line,
1406 const char *section,
1407 unsigned section_line,
1408 const char *lvalue,
1409 int ltype,
1410 const char *rvalue,
1411 void *data,
1412 void *userdata) {
1413
1414 char ***l = data;
1415 int r;
1416
1417 assert(l);
1418 assert(lvalue);
1419 assert(rvalue);
1420
1421 if (isempty(rvalue)) {
1422 *l = strv_free(*l);
1423 return 0;
1424 }
1425
1426 for (;;) {
1427 _cleanup_free_ char *w = NULL;
1428
1429 r = extract_first_word(&rvalue, &w, NULL, 0);
1430 if (r == -ENOMEM)
1431 return log_oom();
1432 if (r < 0) {
1433 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split user classes option, ignoring: %s", rvalue);
1434 break;
1435 }
1436 if (r == 0)
1437 break;
1438
1439 if (strlen(w) > 255) {
1440 log_syntax(unit, LOG_ERR, filename, line, r, "%s length is not in the range 1-255, ignoring.", w);
1441 continue;
26575990
LP
1442 }
1443
1444 r = strv_push(l, w);
1445 if (r < 0)
1446 return log_oom();
1447
1448 w = NULL;
1449 }
1450
1451 return 0;
1452}
1453
f594276b
JK
1454int config_parse_dhcp_route_table(const char *unit,
1455 const char *filename,
1456 unsigned line,
1457 const char *section,
1458 unsigned section_line,
1459 const char *lvalue,
1460 int ltype,
1461 const char *rvalue,
1462 void *data,
1463 void *userdata) {
fc1ba79d 1464 Network *network = data;
f594276b
JK
1465 uint32_t rt;
1466 int r;
1467
1468 assert(filename);
1469 assert(lvalue);
1470 assert(rvalue);
1471 assert(data);
1472
1473 r = safe_atou32(rvalue, &rt);
1474 if (r < 0) {
1475 log_syntax(unit, LOG_ERR, filename, line, r,
1476 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1477 return 0;
1478 }
1479
fc1ba79d
AR
1480 network->dhcp_route_table = rt;
1481 network->dhcp_route_table_set = true;
f594276b
JK
1482
1483 return 0;
1484}
1485
b2a81c0b
LP
1486DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1487
1488static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1489 [DHCP_USE_DOMAINS_NO] = "no",
1490 [DHCP_USE_DOMAINS_ROUTE] = "route",
1491 [DHCP_USE_DOMAINS_YES] = "yes",
1492};
1493
1494DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
34437b4f
LP
1495
1496DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1497
1498static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1499 [LLDP_MODE_NO] = "no",
1500 [LLDP_MODE_YES] = "yes",
1501 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1502};
1503
1504DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);