]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
dhcp: be more careful when parsing strings from DHCP packets
[thirdparty/systemd.git] / src / network / networkd-network.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
69a93e7d 22#include <ctype.h>
987efa17 23#include <net/if.h>
69a93e7d 24
f579559b
TG
25#include "conf-files.h"
26#include "conf-parser.h"
477e73b5 27#include "util.h"
958b66ea 28#include "hostname-util.h"
5a8bcb67
LP
29#include "networkd.h"
30#include "networkd-netdev.h"
31#include "networkd-link.h"
32#include "network-internal.h"
37de2509 33#include "dns-domain.h"
f579559b
TG
34
35static int network_load_one(Manager *manager, const char *filename) {
36 _cleanup_network_free_ Network *network = NULL;
37 _cleanup_fclose_ FILE *file = NULL;
dbffab87 38 char *d;
b3070dc0
TG
39 Route *route;
40 Address *address;
f579559b
TG
41 int r;
42
bf1bc670
TA
43 assert(manager);
44 assert(filename);
45
f579559b
TG
46 file = fopen(filename, "re");
47 if (!file) {
48 if (errno == ENOENT)
49 return 0;
50 else
ecb08ec6 51 return -errno;
f579559b
TG
52 }
53
ed88bcfb
ZJS
54 if (null_or_empty_fd(fileno(file))) {
55 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
56 return 0;
57 }
58
f579559b
TG
59 network = new0(Network, 1);
60 if (!network)
61 return log_oom();
62
5a3eb5a7
TG
63 network->manager = manager;
64
f048a16b
TG
65 LIST_HEAD_INIT(network->static_addresses);
66 LIST_HEAD_INIT(network->static_routes);
b98b483b 67 LIST_HEAD_INIT(network->static_fdb_entries);
f579559b 68
d5099efc 69 network->stacked_netdevs = hashmap_new(&string_hash_ops);
6a0a2f86 70 if (!network->stacked_netdevs)
326cb406
SS
71 return log_oom();
72
d5099efc 73 network->addresses_by_section = hashmap_new(NULL);
6ae115c1
TG
74 if (!network->addresses_by_section)
75 return log_oom();
76
d5099efc 77 network->routes_by_section = hashmap_new(NULL);
6ae115c1
TG
78 if (!network->routes_by_section)
79 return log_oom();
80
b98b483b
AR
81 network->fdb_entries_by_section = hashmap_new(NULL);
82 if (!network->fdb_entries_by_section)
83 return log_oom();
84
6ae115c1
TG
85 network->filename = strdup(filename);
86 if (!network->filename)
87 return log_oom();
88
dbffab87
TG
89 network->name = strdup(basename(filename));
90 if (!network->name)
91 return log_oom();
92
93 d = strrchr(network->name, '.');
94 if (!d)
95 return -EINVAL;
96
97 assert(streq(d, ".network"));
98
99 *d = '\0';
100
cb9fc36a 101 network->dhcp = ADDRESS_FAMILY_NO;
bcb7a07e 102 network->dhcp_ntp = true;
5be4d38e 103 network->dhcp_dns = true;
1346b1f0 104 network->dhcp_hostname = true;
e1ea665e 105 network->dhcp_routes = true;
4cc7a82c 106 network->dhcp_sendhost = true;
84b5b79a 107 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
3e43b2cd 108 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
5be4d38e 109
84c34096 110 network->use_bpdu = true;
23da66bb 111 network->allow_port_to_be_root = true;
072f9e4a 112 network->unicast_flood = true;
84c34096 113
a7e5da6e 114 network->llmnr = RESOLVE_SUPPORT_YES;
bd8f6538 115
d0d6a4cd
TG
116 network->link_local = ADDRESS_FAMILY_IPV6;
117
1f0d9695 118 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 119
e9f3d2d5 120 r = config_parse(NULL, filename, file,
c106cc36
TG
121 "Match\0"
122 "Link\0"
123 "Network\0"
124 "Address\0"
125 "Route\0"
126 "DHCP\0"
127 "DHCPv4\0"
b98b483b
AR
128 "Bridge\0"
129 "BridgeFDB\0",
e9f3d2d5 130 config_item_perf_lookup, network_network_gperf_lookup,
36f822c4
ZJS
131 false, false, true, network);
132 if (r < 0)
f579559b 133 return r;
f579559b 134
5a8bcb67
LP
135 /* IPMasquerade=yes implies IPForward=yes */
136 if (network->ip_masquerade)
769d324c 137 network->ip_forward |= ADDRESS_FAMILY_IPV4;
5a8bcb67 138
f579559b 139 LIST_PREPEND(networks, manager->networks, network);
b3070dc0 140
dbffab87
TG
141 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
142 if (r < 0)
143 return r;
144
145 r = hashmap_put(manager->networks_by_name, network->name, network);
146 if (r < 0)
147 return r;
148
3d3d4255 149 LIST_FOREACH(routes, route, network->static_routes) {
b3070dc0
TG
150 if (!route->family) {
151 log_warning("Route section without Gateway field configured in %s. "
152 "Ignoring", filename);
153 return 0;
154 }
b3070dc0
TG
155 }
156
3d3d4255 157 LIST_FOREACH(addresses, address, network->static_addresses) {
b3070dc0
TG
158 if (!address->family) {
159 log_warning("Address section without Address field configured in %s. "
160 "Ignoring", filename);
161 return 0;
162 }
163 }
164
f579559b
TG
165 network = NULL;
166
167 return 0;
168}
169
170int network_load(Manager *manager) {
171 Network *network;
477e73b5
ZJS
172 _cleanup_strv_free_ char **files = NULL;
173 char **f;
f579559b
TG
174 int r;
175
176 assert(manager);
177
178 while ((network = manager->networks))
179 network_free(network);
180
2ad8416d 181 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
f647962d
MS
182 if (r < 0)
183 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b
TG
184
185 STRV_FOREACH_BACKWARDS(f, files) {
186 r = network_load_one(manager, *f);
187 if (r < 0)
188 return r;
189 }
190
f579559b
TG
191 return 0;
192}
193
f579559b 194void network_free(Network *network) {
47e2dc31 195 NetDev *netdev;
f579559b
TG
196 Route *route;
197 Address *address;
b98b483b 198 FdbEntry *fdb_entry;
06f021a8 199 Iterator i;
f579559b
TG
200
201 if (!network)
202 return;
203
204 free(network->filename);
205
206 free(network->match_mac);
5256e00e
TG
207 strv_free(network->match_path);
208 strv_free(network->match_driver);
209 strv_free(network->match_type);
210 strv_free(network->match_name);
f579559b
TG
211
212 free(network->description);
edb85f0d 213 free(network->dhcp_vendor_class_identifier);
a7d0ef44 214 free(network->hostname);
f579559b 215
c106cc36
TG
216 free(network->mac);
217
b0e39c82
TG
218 strv_free(network->ntp);
219 strv_free(network->dns);
486d1a81 220 strv_free(network->domains);
0d4ad91d 221 strv_free(network->bind_carrier);
3bef724f 222
47e2dc31
TG
223 netdev_unref(network->bridge);
224
225 netdev_unref(network->bond);
226
2c36be2f
TG
227 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
228 hashmap_remove(network->stacked_netdevs, netdev->ifname);
326cb406 229 netdev_unref(netdev);
2c36be2f 230 }
6a0a2f86 231 hashmap_free(network->stacked_netdevs);
326cb406 232
f048a16b 233 while ((route = network->static_routes))
f579559b
TG
234 route_free(route);
235
f048a16b 236 while ((address = network->static_addresses))
f579559b
TG
237 address_free(address);
238
b98b483b
AR
239 while ((fdb_entry = network->static_fdb_entries))
240 fdb_entry_free(fdb_entry);
241
6ae115c1
TG
242 hashmap_free(network->addresses_by_section);
243 hashmap_free(network->routes_by_section);
b98b483b 244 hashmap_free(network->fdb_entries_by_section);
6ae115c1 245
dbffab87
TG
246 if (network->manager) {
247 if (network->manager->networks)
248 LIST_REMOVE(networks, network->manager->networks, network);
249
250 if (network->manager->networks_by_name)
251 hashmap_remove(network->manager->networks_by_name, network->name);
252 }
253
254 free(network->name);
f579559b 255
79e16ce3
LP
256 condition_free_list(network->match_host);
257 condition_free_list(network->match_virt);
258 condition_free_list(network->match_kernel);
259 condition_free_list(network->match_arch);
260
f579559b
TG
261 free(network);
262}
263
dbffab87
TG
264int network_get_by_name(Manager *manager, const char *name, Network **ret) {
265 Network *network;
266
267 assert(manager);
268 assert(name);
269 assert(ret);
270
271 network = hashmap_get(manager->networks_by_name, name);
272 if (!network)
273 return -ENOENT;
274
275 *ret = network;
276
277 return 0;
278}
279
505f8da7
TG
280int network_get(Manager *manager, struct udev_device *device,
281 const char *ifname, const struct ether_addr *address,
282 Network **ret) {
f579559b 283 Network *network;
af3aa302 284 struct udev_device *parent;
24c083df 285 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
f579559b
TG
286
287 assert(manager);
f579559b 288 assert(ret);
af3aa302 289
24c083df
TG
290 if (device) {
291 path = udev_device_get_property_value(device, "ID_PATH");
af3aa302 292
24c083df
TG
293 parent = udev_device_get_parent(device);
294 if (parent)
295 parent_driver = udev_device_get_driver(parent);
af3aa302 296
24c083df 297 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
af3aa302 298
24c083df
TG
299 devtype = udev_device_get_devtype(device);
300 }
f579559b 301
f579559b
TG
302 LIST_FOREACH(networks, network, manager->networks) {
303 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
304 network->match_driver, network->match_type,
305 network->match_name, network->match_host,
306 network->match_virt, network->match_kernel,
307 network->match_arch,
af3aa302
TG
308 address, path, parent_driver, driver,
309 devtype, ifname)) {
24c083df 310 if (network->match_name && device) {
ca6038b8
TG
311 const char *attr;
312 uint8_t name_assign_type = NET_NAME_UNKNOWN;
313
32bc8adc 314 attr = udev_device_get_sysattr_value(device, "name_assign_type");
285760fe 315 if (attr)
dc751688 316 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
317
318 if (name_assign_type == NET_NAME_ENUM)
ca6038b8 319 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
32bc8adc
TG
320 IFNAMSIZ, ifname, network->filename);
321 else
322 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
323 } else
324 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
325
f579559b
TG
326 *ret = network;
327 return 0;
328 }
329 }
330
331 *ret = NULL;
332
333 return -ENOENT;
334}
335
336int network_apply(Manager *manager, Network *network, Link *link) {
f579559b
TG
337 int r;
338
f579559b
TG
339 link->network = network;
340
bfa695b5
TG
341 if (network->ipv4ll_route) {
342 Route *route;
343
344 r = route_new_static(network, 0, &route);
345 if (r < 0)
346 return r;
347
348 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
349 if (r == 0)
350 return -EINVAL;
351 if (r < 0)
352 return -errno;
353
354 route->family = AF_INET;
355 route->dst_prefixlen = 16;
356 route->scope = RT_SCOPE_LINK;
357 route->metrics = IPV4LL_ROUTE_METRIC;
358 route->protocol = RTPROT_STATIC;
359 }
360
bcb7a07e 361 if (network->dns || network->ntp) {
091a364c 362 r = link_save(link);
3bef724f
TG
363 if (r < 0)
364 return r;
365 }
366
f579559b
TG
367 return 0;
368}
02b59d57 369
69a93e7d 370int config_parse_netdev(const char *unit,
02b59d57
TG
371 const char *filename,
372 unsigned line,
373 const char *section,
374 unsigned section_line,
375 const char *lvalue,
376 int ltype,
377 const char *rvalue,
378 void *data,
379 void *userdata) {
380 Network *network = userdata;
31d0ac36
TG
381 _cleanup_free_ char *kind_string = NULL;
382 char *p;
1a436809 383 NetDev *netdev;
69a93e7d 384 NetDevKind kind;
02b59d57
TG
385 int r;
386
387 assert(filename);
388 assert(lvalue);
389 assert(rvalue);
390 assert(data);
391
69a93e7d
TG
392 kind_string = strdup(lvalue);
393 if (!kind_string)
394 return log_oom();
52433f6b 395
69a93e7d
TG
396 /* the keys are CamelCase versions of the kind */
397 for (p = kind_string; *p; p++)
398 *p = tolower(*p);
52433f6b 399
69a93e7d
TG
400 kind = netdev_kind_from_string(kind_string);
401 if (kind == _NETDEV_KIND_INVALID) {
52433f6b 402 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 403 "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
404 return 0;
405 }
406
54abf461
TG
407 r = netdev_get(network->manager, rvalue, &netdev);
408 if (r < 0) {
409 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 410 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
411 return 0;
412 }
413
69a93e7d 414 if (netdev->kind != kind) {
54abf461 415 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 416 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
417 return 0;
418 }
419
69a93e7d
TG
420 switch (kind) {
421 case NETDEV_KIND_BRIDGE:
422 network->bridge = netdev;
54abf461 423
69a93e7d
TG
424 break;
425 case NETDEV_KIND_BOND:
426 network->bond = netdev;
fe6b2d55 427
69a93e7d
TG
428 break;
429 case NETDEV_KIND_VLAN:
69a93e7d 430 case NETDEV_KIND_MACVLAN:
f33ff02b 431 case NETDEV_KIND_MACVTAP:
c4a5ddc9 432 case NETDEV_KIND_IPVLAN:
326cb406 433 case NETDEV_KIND_VXLAN:
6a0a2f86 434 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
326cb406
SS
435 if (r < 0) {
436 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
6a7a4e4d
LP
437 "Can not add VLAN '%s' to network: %m",
438 rvalue);
326cb406
SS
439 return 0;
440 }
441
69a93e7d
TG
442 break;
443 default:
444 assert_not_reached("Can not parse NetDev");
fe6b2d55
TG
445 }
446
47e2dc31
TG
447 netdev_ref(netdev);
448
fe6b2d55
TG
449 return 0;
450}
7951dea2 451
6192b846
TG
452int config_parse_domains(const char *unit,
453 const char *filename,
454 unsigned line,
455 const char *section,
456 unsigned section_line,
457 const char *lvalue,
458 int ltype,
459 const char *rvalue,
460 void *data,
461 void *userdata) {
67272d15 462 Network *network = userdata;
6192b846
TG
463 char ***domains = data;
464 char **domain;
465 int r;
466
467 r = config_parse_strv(unit, filename, line, section, section_line,
468 lvalue, ltype, rvalue, domains, userdata);
469 if (r < 0)
470 return r;
471
472 strv_uniq(*domains);
f15b6e5a 473 network->wildcard_domain = !!strv_find(*domains, "*");
67272d15 474
40274ed6
LP
475 STRV_FOREACH(domain, *domains) {
476 if (is_localhost(*domain))
477 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
37de2509
NO
478 else {
479 r = dns_name_is_valid(*domain);
480 if (r <= 0 && !streq(*domain, "*")) {
481 if (r < 0)
482 log_error_errno(r, "Failed to validate domain name: %s: %m", *domain);
483 if (r == 0)
484 log_warning("Domain name is not valid, ignoring assignment: %s", *domain);
485 } else
486 continue;
487 }
40274ed6
LP
488
489 strv_remove(*domains, *domain);
490
491 /* We removed one entry, make sure we don't skip the next one */
492 domain--;
493 }
f15b6e5a 494
6192b846
TG
495 return 0;
496}
497
7951dea2
SS
498int config_parse_tunnel(const char *unit,
499 const char *filename,
500 unsigned line,
501 const char *section,
502 unsigned section_line,
503 const char *lvalue,
504 int ltype,
505 const char *rvalue,
506 void *data,
507 void *userdata) {
508 Network *network = userdata;
509 NetDev *netdev;
510 int r;
511
512 assert(filename);
513 assert(lvalue);
514 assert(rvalue);
515 assert(data);
516
517 r = netdev_get(network->manager, rvalue, &netdev);
518 if (r < 0) {
6a7a4e4d 519 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
7951dea2
SS
520 return 0;
521 }
522
523 if (netdev->kind != NETDEV_KIND_IPIP &&
524 netdev->kind != NETDEV_KIND_SIT &&
a613382b 525 netdev->kind != NETDEV_KIND_GRE &&
1af2536a 526 netdev->kind != NETDEV_KIND_GRETAP &&
b16492f8
SS
527 netdev->kind != NETDEV_KIND_IP6GRE &&
528 netdev->kind != NETDEV_KIND_IP6GRETAP &&
855ee1a1 529 netdev->kind != NETDEV_KIND_VTI &&
9011ce77 530 netdev->kind != NETDEV_KIND_VTI6 &&
855ee1a1
SS
531 netdev->kind != NETDEV_KIND_IP6TNL
532 ) {
7951dea2
SS
533 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
534 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
535 return 0;
536 }
537
6a0a2f86
TG
538 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
539 if (r < 0) {
6a7a4e4d 540 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
6a0a2f86
TG
541 return 0;
542 }
543
544 netdev_ref(netdev);
7951dea2
SS
545
546 return 0;
547}
bd8f6538 548
d0d6a4cd
TG
549int config_parse_ipv4ll(
550 const char* unit,
551 const char *filename,
552 unsigned line,
553 const char *section,
554 unsigned section_line,
555 const char *lvalue,
556 int ltype,
557 const char *rvalue,
558 void *data,
559 void *userdata) {
560
561 AddressFamilyBoolean *link_local = data;
562
563 assert(filename);
564 assert(lvalue);
565 assert(rvalue);
566 assert(data);
567
568 /* Note that this is mostly like
569 * config_parse_address_family_boolean(), except that it
570 * applies only to IPv4 */
571
572 if (parse_boolean(rvalue))
573 *link_local |= ADDRESS_FAMILY_IPV4;
574 else
575 *link_local &= ~ADDRESS_FAMILY_IPV4;
576
577 return 0;
578}
579
bd8f6538
TG
580int config_parse_dhcp(
581 const char* unit,
582 const char *filename,
583 unsigned line,
584 const char *section,
585 unsigned section_line,
586 const char *lvalue,
587 int ltype,
588 const char *rvalue,
589 void *data,
590 void *userdata) {
591
cb9fc36a 592 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
593
594 assert(filename);
595 assert(lvalue);
596 assert(rvalue);
597 assert(data);
598
769d324c
LP
599 /* Note that this is mostly like
600 * config_parse_address_family_boolean(), except that it
601 * understands some old names for the enum values */
602
cb9fc36a
LP
603 s = address_family_boolean_from_string(rvalue);
604 if (s < 0) {
605
606 /* Previously, we had a slightly different enum here,
607 * support its values for compatbility. */
608
609 if (streq(rvalue, "none"))
610 s = ADDRESS_FAMILY_NO;
611 else if (streq(rvalue, "v4"))
612 s = ADDRESS_FAMILY_IPV4;
613 else if (streq(rvalue, "v6"))
614 s = ADDRESS_FAMILY_IPV6;
615 else if (streq(rvalue, "both"))
616 s = ADDRESS_FAMILY_YES;
617 else {
618 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
619 return 0;
620 }
bd8f6538
TG
621 }
622
cb9fc36a 623 *dhcp = s;
bd8f6538
TG
624 return 0;
625}
626
3e43b2cd
JJ
627static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
628 [DHCP_CLIENT_ID_MAC] = "mac",
629 [DHCP_CLIENT_ID_DUID] = "duid"
630};
631
632DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
633DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
634
a7e5da6e
DM
635static const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = {
636 [RESOLVE_SUPPORT_NO] = "no",
637 [RESOLVE_SUPPORT_YES] = "yes",
638 [RESOLVE_SUPPORT_RESOLVE] = "resolve",
bd8f6538
TG
639};
640
a7e5da6e 641DEFINE_STRING_TABLE_LOOKUP(resolve_support, ResolveSupport);
bd8f6538 642
a7e5da6e 643int config_parse_resolve(
bd8f6538
TG
644 const char* unit,
645 const char *filename,
646 unsigned line,
647 const char *section,
648 unsigned section_line,
649 const char *lvalue,
650 int ltype,
651 const char *rvalue,
652 void *data,
653 void *userdata) {
654
a7e5da6e 655 ResolveSupport *resolve = data;
bd8f6538
TG
656 int k;
657
658 assert(filename);
659 assert(lvalue);
660 assert(rvalue);
a7e5da6e 661 assert(resolve);
bd8f6538
TG
662
663 /* Our enum shall be a superset of booleans, hence first try
664 * to parse as boolean, and then as enum */
665
666 k = parse_boolean(rvalue);
667 if (k > 0)
a7e5da6e 668 *resolve = RESOLVE_SUPPORT_YES;
bd8f6538 669 else if (k == 0)
a7e5da6e 670 *resolve = RESOLVE_SUPPORT_NO;
bd8f6538 671 else {
a7e5da6e 672 ResolveSupport s;
bd8f6538 673
a7e5da6e 674 s = resolve_support_from_string(rvalue);
bd8f6538 675 if (s < 0){
a7e5da6e 676 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse %s option, ignoring: %s", lvalue, rvalue);
bd8f6538
TG
677 return 0;
678 }
679
a7e5da6e 680 *resolve = s;
bd8f6538
TG
681 }
682
683 return 0;
684}
7f77697a 685
60c35566 686int config_parse_ipv6token(
7f77697a
TG
687 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
698 union in_addr_union buffer;
699 struct in6_addr *token = data;
700 int r;
701
702 assert(filename);
703 assert(lvalue);
704 assert(rvalue);
705 assert(token);
706
707 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
708 if (r < 0) {
6a7a4e4d 709 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
710 return 0;
711 }
712
713 r = in_addr_is_null(AF_INET6, &buffer);
714 if (r < 0) {
6a7a4e4d 715 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
716 return 0;
717 }
718
719 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
e2acdb6b 720 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
721 return 0;
722 }
723
724 *token = buffer.in6;
725
726 return 0;
727}
8add5f79
NO
728
729int config_parse_address_family_boolean_with_kernel(
730 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
741 AddressFamilyBoolean *fwd = data, s;
742
743 assert(filename);
744 assert(lvalue);
745 assert(rvalue);
746 assert(data);
747
748 s = address_family_boolean_from_string(rvalue);
749 if (s < 0) {
750 if (streq(rvalue, "kernel"))
751 s = _ADDRESS_FAMILY_BOOLEAN_INVALID;
752 else {
753 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding option, ignoring: %s", rvalue);
754 return 0;
755 }
756 }
757
758 *fwd = s;
759
760 return 0;
761}
49092e22
SS
762
763static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
764 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
765 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
766 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
767};
768
769DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
770
771int config_parse_ipv6_privacy_extensions(
772 const char* unit,
773 const char *filename,
774 unsigned line,
775 const char *section,
776 unsigned section_line,
777 const char *lvalue,
778 int ltype,
779 const char *rvalue,
780 void *data,
781 void *userdata) {
782
783 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
784 int k;
785
786 assert(filename);
787 assert(lvalue);
788 assert(rvalue);
789 assert(ipv6_privacy_extensions);
790
791 /* Our enum shall be a superset of booleans, hence first try
792 * to parse as boolean, and then as enum */
793
794 k = parse_boolean(rvalue);
795 if (k > 0)
1f0d9695 796 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 797 else if (k == 0)
1f0d9695 798 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 799 else {
1f0d9695 800 IPv6PrivacyExtensions s;
49092e22
SS
801
802 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
803 if (s < 0) {
804
805 if (streq(rvalue, "kernel"))
806 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
807 else {
808 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
809 return 0;
810 }
49092e22
SS
811 }
812
813 *ipv6_privacy_extensions = s;
814 }
815
816 return 0;
817}
a7d0ef44 818
1ac608c9
LP
819int config_parse_hostname(
820 const char *unit,
821 const char *filename,
822 unsigned line,
823 const char *section,
824 unsigned section_line,
825 const char *lvalue,
826 int ltype,
827 const char *rvalue,
828 void *data,
829 void *userdata) {
830
831 char **hostname = data, *hn = NULL;
a7d0ef44
SS
832 int r;
833
834 assert(filename);
835 assert(lvalue);
836 assert(rvalue);
837
1ac608c9 838 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
839 if (r < 0)
840 return r;
841
1ac608c9
LP
842 if (!hostname_is_valid(hn, false)) {
843 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
844 free(hn);
845 return 0;
846 }
847
1ac608c9 848 free(*hostname);
ae691c1d 849 *hostname = hostname_cleanup(hn);
a7d0ef44
SS
850 return 0;
851}