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