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