]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
hostname-util: get rid of unused parameter of hostname_cleanup()
[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
bd8f6538
TG
114 network->llmnr = LLMNR_SUPPORT_YES;
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:
c4a5ddc9 431 case NETDEV_KIND_IPVLAN:
326cb406 432 case NETDEV_KIND_VXLAN:
6a0a2f86 433 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
326cb406
SS
434 if (r < 0) {
435 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
6a7a4e4d
LP
436 "Can not add VLAN '%s' to network: %m",
437 rvalue);
326cb406
SS
438 return 0;
439 }
440
69a93e7d
TG
441 break;
442 default:
443 assert_not_reached("Can not parse NetDev");
fe6b2d55
TG
444 }
445
47e2dc31
TG
446 netdev_ref(netdev);
447
fe6b2d55
TG
448 return 0;
449}
7951dea2 450
6192b846
TG
451int config_parse_domains(const char *unit,
452 const char *filename,
453 unsigned line,
454 const char *section,
455 unsigned section_line,
456 const char *lvalue,
457 int ltype,
458 const char *rvalue,
459 void *data,
460 void *userdata) {
67272d15 461 Network *network = userdata;
6192b846
TG
462 char ***domains = data;
463 char **domain;
464 int r;
465
466 r = config_parse_strv(unit, filename, line, section, section_line,
467 lvalue, ltype, rvalue, domains, userdata);
468 if (r < 0)
469 return r;
470
471 strv_uniq(*domains);
f15b6e5a 472 network->wildcard_domain = !!strv_find(*domains, "*");
67272d15 473
40274ed6
LP
474 STRV_FOREACH(domain, *domains) {
475 if (is_localhost(*domain))
476 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
37de2509
NO
477 else {
478 r = dns_name_is_valid(*domain);
479 if (r <= 0 && !streq(*domain, "*")) {
480 if (r < 0)
481 log_error_errno(r, "Failed to validate domain name: %s: %m", *domain);
482 if (r == 0)
483 log_warning("Domain name is not valid, ignoring assignment: %s", *domain);
484 } else
485 continue;
486 }
40274ed6
LP
487
488 strv_remove(*domains, *domain);
489
490 /* We removed one entry, make sure we don't skip the next one */
491 domain--;
492 }
f15b6e5a 493
6192b846
TG
494 return 0;
495}
496
7951dea2
SS
497int config_parse_tunnel(const char *unit,
498 const char *filename,
499 unsigned line,
500 const char *section,
501 unsigned section_line,
502 const char *lvalue,
503 int ltype,
504 const char *rvalue,
505 void *data,
506 void *userdata) {
507 Network *network = userdata;
508 NetDev *netdev;
509 int r;
510
511 assert(filename);
512 assert(lvalue);
513 assert(rvalue);
514 assert(data);
515
516 r = netdev_get(network->manager, rvalue, &netdev);
517 if (r < 0) {
6a7a4e4d 518 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
7951dea2
SS
519 return 0;
520 }
521
522 if (netdev->kind != NETDEV_KIND_IPIP &&
523 netdev->kind != NETDEV_KIND_SIT &&
a613382b 524 netdev->kind != NETDEV_KIND_GRE &&
1af2536a 525 netdev->kind != NETDEV_KIND_GRETAP &&
b16492f8
SS
526 netdev->kind != NETDEV_KIND_IP6GRE &&
527 netdev->kind != NETDEV_KIND_IP6GRETAP &&
855ee1a1 528 netdev->kind != NETDEV_KIND_VTI &&
9011ce77 529 netdev->kind != NETDEV_KIND_VTI6 &&
855ee1a1
SS
530 netdev->kind != NETDEV_KIND_IP6TNL
531 ) {
7951dea2
SS
532 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
533 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
534 return 0;
535 }
536
6a0a2f86
TG
537 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
538 if (r < 0) {
6a7a4e4d 539 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
6a0a2f86
TG
540 return 0;
541 }
542
543 netdev_ref(netdev);
7951dea2
SS
544
545 return 0;
546}
bd8f6538 547
d0d6a4cd
TG
548int config_parse_ipv4ll(
549 const char* unit,
550 const char *filename,
551 unsigned line,
552 const char *section,
553 unsigned section_line,
554 const char *lvalue,
555 int ltype,
556 const char *rvalue,
557 void *data,
558 void *userdata) {
559
560 AddressFamilyBoolean *link_local = data;
561
562 assert(filename);
563 assert(lvalue);
564 assert(rvalue);
565 assert(data);
566
567 /* Note that this is mostly like
568 * config_parse_address_family_boolean(), except that it
569 * applies only to IPv4 */
570
571 if (parse_boolean(rvalue))
572 *link_local |= ADDRESS_FAMILY_IPV4;
573 else
574 *link_local &= ~ADDRESS_FAMILY_IPV4;
575
576 return 0;
577}
578
bd8f6538
TG
579int config_parse_dhcp(
580 const char* unit,
581 const char *filename,
582 unsigned line,
583 const char *section,
584 unsigned section_line,
585 const char *lvalue,
586 int ltype,
587 const char *rvalue,
588 void *data,
589 void *userdata) {
590
cb9fc36a 591 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
592
593 assert(filename);
594 assert(lvalue);
595 assert(rvalue);
596 assert(data);
597
769d324c
LP
598 /* Note that this is mostly like
599 * config_parse_address_family_boolean(), except that it
600 * understands some old names for the enum values */
601
cb9fc36a
LP
602 s = address_family_boolean_from_string(rvalue);
603 if (s < 0) {
604
605 /* Previously, we had a slightly different enum here,
606 * support its values for compatbility. */
607
608 if (streq(rvalue, "none"))
609 s = ADDRESS_FAMILY_NO;
610 else if (streq(rvalue, "v4"))
611 s = ADDRESS_FAMILY_IPV4;
612 else if (streq(rvalue, "v6"))
613 s = ADDRESS_FAMILY_IPV6;
614 else if (streq(rvalue, "both"))
615 s = ADDRESS_FAMILY_YES;
616 else {
617 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
618 return 0;
619 }
bd8f6538
TG
620 }
621
cb9fc36a 622 *dhcp = s;
bd8f6538
TG
623 return 0;
624}
625
3e43b2cd
JJ
626static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
627 [DHCP_CLIENT_ID_MAC] = "mac",
628 [DHCP_CLIENT_ID_DUID] = "duid"
629};
630
631DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
632DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
633
bd8f6538
TG
634static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
635 [LLMNR_SUPPORT_NO] = "no",
636 [LLMNR_SUPPORT_YES] = "yes",
637 [LLMNR_SUPPORT_RESOLVE] = "resolve",
638};
639
640DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
641
642int config_parse_llmnr(
643 const char* unit,
644 const char *filename,
645 unsigned line,
646 const char *section,
647 unsigned section_line,
648 const char *lvalue,
649 int ltype,
650 const char *rvalue,
651 void *data,
652 void *userdata) {
653
654 LLMNRSupport *llmnr = data;
655 int k;
656
657 assert(filename);
658 assert(lvalue);
659 assert(rvalue);
7f77697a 660 assert(llmnr);
bd8f6538
TG
661
662 /* Our enum shall be a superset of booleans, hence first try
663 * to parse as boolean, and then as enum */
664
665 k = parse_boolean(rvalue);
666 if (k > 0)
667 *llmnr = LLMNR_SUPPORT_YES;
668 else if (k == 0)
669 *llmnr = LLMNR_SUPPORT_NO;
670 else {
671 LLMNRSupport s;
672
673 s = llmnr_support_from_string(rvalue);
674 if (s < 0){
675 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);
676 return 0;
677 }
678
679 *llmnr = s;
680 }
681
682 return 0;
683}
7f77697a 684
60c35566 685int config_parse_ipv6token(
7f77697a
TG
686 const char* unit,
687 const char *filename,
688 unsigned line,
689 const char *section,
690 unsigned section_line,
691 const char *lvalue,
692 int ltype,
693 const char *rvalue,
694 void *data,
695 void *userdata) {
696
697 union in_addr_union buffer;
698 struct in6_addr *token = data;
699 int r;
700
701 assert(filename);
702 assert(lvalue);
703 assert(rvalue);
704 assert(token);
705
706 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
707 if (r < 0) {
6a7a4e4d 708 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
709 return 0;
710 }
711
712 r = in_addr_is_null(AF_INET6, &buffer);
713 if (r < 0) {
6a7a4e4d 714 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
715 return 0;
716 }
717
718 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
e2acdb6b 719 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
720 return 0;
721 }
722
723 *token = buffer.in6;
724
725 return 0;
726}
8add5f79
NO
727
728int config_parse_address_family_boolean_with_kernel(
729 const char* unit,
730 const char *filename,
731 unsigned line,
732 const char *section,
733 unsigned section_line,
734 const char *lvalue,
735 int ltype,
736 const char *rvalue,
737 void *data,
738 void *userdata) {
739
740 AddressFamilyBoolean *fwd = data, s;
741
742 assert(filename);
743 assert(lvalue);
744 assert(rvalue);
745 assert(data);
746
747 s = address_family_boolean_from_string(rvalue);
748 if (s < 0) {
749 if (streq(rvalue, "kernel"))
750 s = _ADDRESS_FAMILY_BOOLEAN_INVALID;
751 else {
752 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding option, ignoring: %s", rvalue);
753 return 0;
754 }
755 }
756
757 *fwd = s;
758
759 return 0;
760}
49092e22
SS
761
762static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
763 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
764 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
765 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
766};
767
768DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
769
770int config_parse_ipv6_privacy_extensions(
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
782 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
783 int k;
784
785 assert(filename);
786 assert(lvalue);
787 assert(rvalue);
788 assert(ipv6_privacy_extensions);
789
790 /* Our enum shall be a superset of booleans, hence first try
791 * to parse as boolean, and then as enum */
792
793 k = parse_boolean(rvalue);
794 if (k > 0)
1f0d9695 795 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 796 else if (k == 0)
1f0d9695 797 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 798 else {
1f0d9695 799 IPv6PrivacyExtensions s;
49092e22
SS
800
801 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
802 if (s < 0) {
803
804 if (streq(rvalue, "kernel"))
805 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
806 else {
807 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
808 return 0;
809 }
49092e22
SS
810 }
811
812 *ipv6_privacy_extensions = s;
813 }
814
815 return 0;
816}
a7d0ef44
SS
817
818int config_parse_hostname(const char *unit,
819 const char *filename,
820 unsigned line,
821 const char *section,
822 unsigned section_line,
823 const char *lvalue,
824 int ltype,
825 const char *rvalue,
826 void *data,
827 void *userdata) {
828 char **hostname = data;
829 char *hn = NULL;
830 int r;
831
832 assert(filename);
833 assert(lvalue);
834 assert(rvalue);
835
836 r = config_parse_string(unit, filename, line, section, section_line,
837 lvalue, ltype, rvalue, &hn, userdata);
838 if (r < 0)
839 return r;
840
79f17ea6 841 if (!hostname_is_valid(hn, true)) {
a7d0ef44
SS
842 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "hostname is not valid, ignoring assignment: %s", rvalue);
843
844 free(hn);
845 return 0;
846 }
847
ae691c1d 848 *hostname = hostname_cleanup(hn);
a7d0ef44
SS
849
850 return 0;
851}