]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
networkd: split up networkd.h into per-object header files
[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"
37de2509 29#include "dns-domain.h"
fc2f9534
LP
30#include "network-internal.h"
31
32#include "networkd.h"
33#include "networkd-network.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"
8eb9058d
LP
127 "DHCPv4\0" /* compat */
128 "DHCPServer\0"
b98b483b
AR
129 "Bridge\0"
130 "BridgeFDB\0",
e9f3d2d5 131 config_item_perf_lookup, network_network_gperf_lookup,
36f822c4
ZJS
132 false, false, true, network);
133 if (r < 0)
f579559b 134 return r;
f579559b 135
5a8bcb67
LP
136 /* IPMasquerade=yes implies IPForward=yes */
137 if (network->ip_masquerade)
769d324c 138 network->ip_forward |= ADDRESS_FAMILY_IPV4;
5a8bcb67 139
f579559b 140 LIST_PREPEND(networks, manager->networks, network);
b3070dc0 141
dbffab87
TG
142 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
143 if (r < 0)
144 return r;
145
146 r = hashmap_put(manager->networks_by_name, network->name, network);
147 if (r < 0)
148 return r;
149
3d3d4255 150 LIST_FOREACH(routes, route, network->static_routes) {
b3070dc0
TG
151 if (!route->family) {
152 log_warning("Route section without Gateway field configured in %s. "
153 "Ignoring", filename);
154 return 0;
155 }
b3070dc0
TG
156 }
157
3d3d4255 158 LIST_FOREACH(addresses, address, network->static_addresses) {
b3070dc0
TG
159 if (!address->family) {
160 log_warning("Address section without Address field configured in %s. "
161 "Ignoring", filename);
162 return 0;
163 }
164 }
165
f579559b
TG
166 network = NULL;
167
168 return 0;
169}
170
171int network_load(Manager *manager) {
172 Network *network;
477e73b5
ZJS
173 _cleanup_strv_free_ char **files = NULL;
174 char **f;
f579559b
TG
175 int r;
176
177 assert(manager);
178
179 while ((network = manager->networks))
180 network_free(network);
181
2ad8416d 182 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
f647962d
MS
183 if (r < 0)
184 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b
TG
185
186 STRV_FOREACH_BACKWARDS(f, files) {
187 r = network_load_one(manager, *f);
188 if (r < 0)
189 return r;
190 }
191
f579559b
TG
192 return 0;
193}
194
f579559b 195void network_free(Network *network) {
47e2dc31 196 NetDev *netdev;
f579559b
TG
197 Route *route;
198 Address *address;
b98b483b 199 FdbEntry *fdb_entry;
06f021a8 200 Iterator i;
f579559b
TG
201
202 if (!network)
203 return;
204
205 free(network->filename);
206
207 free(network->match_mac);
5256e00e
TG
208 strv_free(network->match_path);
209 strv_free(network->match_driver);
210 strv_free(network->match_type);
211 strv_free(network->match_name);
f579559b
TG
212
213 free(network->description);
edb85f0d 214 free(network->dhcp_vendor_class_identifier);
a7d0ef44 215 free(network->hostname);
f579559b 216
c106cc36
TG
217 free(network->mac);
218
b0e39c82
TG
219 strv_free(network->ntp);
220 strv_free(network->dns);
486d1a81 221 strv_free(network->domains);
0d4ad91d 222 strv_free(network->bind_carrier);
3bef724f 223
47e2dc31
TG
224 netdev_unref(network->bridge);
225
226 netdev_unref(network->bond);
227
2c36be2f
TG
228 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
229 hashmap_remove(network->stacked_netdevs, netdev->ifname);
326cb406 230 netdev_unref(netdev);
2c36be2f 231 }
6a0a2f86 232 hashmap_free(network->stacked_netdevs);
326cb406 233
f048a16b 234 while ((route = network->static_routes))
f579559b
TG
235 route_free(route);
236
f048a16b 237 while ((address = network->static_addresses))
f579559b
TG
238 address_free(address);
239
b98b483b
AR
240 while ((fdb_entry = network->static_fdb_entries))
241 fdb_entry_free(fdb_entry);
242
6ae115c1
TG
243 hashmap_free(network->addresses_by_section);
244 hashmap_free(network->routes_by_section);
b98b483b 245 hashmap_free(network->fdb_entries_by_section);
6ae115c1 246
dbffab87
TG
247 if (network->manager) {
248 if (network->manager->networks)
249 LIST_REMOVE(networks, network->manager->networks, network);
250
251 if (network->manager->networks_by_name)
252 hashmap_remove(network->manager->networks_by_name, network->name);
253 }
254
255 free(network->name);
f579559b 256
79e16ce3
LP
257 condition_free_list(network->match_host);
258 condition_free_list(network->match_virt);
259 condition_free_list(network->match_kernel);
260 condition_free_list(network->match_arch);
261
8eb9058d
LP
262 free(network->dhcp_server_timezone);
263
f579559b
TG
264 free(network);
265}
266
dbffab87
TG
267int network_get_by_name(Manager *manager, const char *name, Network **ret) {
268 Network *network;
269
270 assert(manager);
271 assert(name);
272 assert(ret);
273
274 network = hashmap_get(manager->networks_by_name, name);
275 if (!network)
276 return -ENOENT;
277
278 *ret = network;
279
280 return 0;
281}
282
505f8da7
TG
283int network_get(Manager *manager, struct udev_device *device,
284 const char *ifname, const struct ether_addr *address,
285 Network **ret) {
f579559b 286 Network *network;
af3aa302 287 struct udev_device *parent;
24c083df 288 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
f579559b
TG
289
290 assert(manager);
f579559b 291 assert(ret);
af3aa302 292
24c083df
TG
293 if (device) {
294 path = udev_device_get_property_value(device, "ID_PATH");
af3aa302 295
24c083df
TG
296 parent = udev_device_get_parent(device);
297 if (parent)
298 parent_driver = udev_device_get_driver(parent);
af3aa302 299
24c083df 300 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
af3aa302 301
24c083df
TG
302 devtype = udev_device_get_devtype(device);
303 }
f579559b 304
f579559b
TG
305 LIST_FOREACH(networks, network, manager->networks) {
306 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
307 network->match_driver, network->match_type,
308 network->match_name, network->match_host,
309 network->match_virt, network->match_kernel,
310 network->match_arch,
af3aa302
TG
311 address, path, parent_driver, driver,
312 devtype, ifname)) {
24c083df 313 if (network->match_name && device) {
ca6038b8
TG
314 const char *attr;
315 uint8_t name_assign_type = NET_NAME_UNKNOWN;
316
32bc8adc 317 attr = udev_device_get_sysattr_value(device, "name_assign_type");
285760fe 318 if (attr)
dc751688 319 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
320
321 if (name_assign_type == NET_NAME_ENUM)
ca6038b8 322 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
32bc8adc
TG
323 IFNAMSIZ, ifname, network->filename);
324 else
325 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
326 } else
327 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
328
f579559b
TG
329 *ret = network;
330 return 0;
331 }
332 }
333
334 *ret = NULL;
335
336 return -ENOENT;
337}
338
339int network_apply(Manager *manager, Network *network, Link *link) {
f579559b
TG
340 int r;
341
f579559b
TG
342 link->network = network;
343
bfa695b5
TG
344 if (network->ipv4ll_route) {
345 Route *route;
346
347 r = route_new_static(network, 0, &route);
348 if (r < 0)
349 return r;
350
351 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
352 if (r == 0)
353 return -EINVAL;
354 if (r < 0)
355 return -errno;
356
357 route->family = AF_INET;
358 route->dst_prefixlen = 16;
359 route->scope = RT_SCOPE_LINK;
360 route->metrics = IPV4LL_ROUTE_METRIC;
361 route->protocol = RTPROT_STATIC;
362 }
363
bcb7a07e 364 if (network->dns || network->ntp) {
091a364c 365 r = link_save(link);
3bef724f
TG
366 if (r < 0)
367 return r;
368 }
369
f579559b
TG
370 return 0;
371}
02b59d57 372
69a93e7d 373int config_parse_netdev(const char *unit,
02b59d57
TG
374 const char *filename,
375 unsigned line,
376 const char *section,
377 unsigned section_line,
378 const char *lvalue,
379 int ltype,
380 const char *rvalue,
381 void *data,
382 void *userdata) {
383 Network *network = userdata;
31d0ac36
TG
384 _cleanup_free_ char *kind_string = NULL;
385 char *p;
1a436809 386 NetDev *netdev;
69a93e7d 387 NetDevKind kind;
02b59d57
TG
388 int r;
389
390 assert(filename);
391 assert(lvalue);
392 assert(rvalue);
393 assert(data);
394
69a93e7d
TG
395 kind_string = strdup(lvalue);
396 if (!kind_string)
397 return log_oom();
52433f6b 398
69a93e7d
TG
399 /* the keys are CamelCase versions of the kind */
400 for (p = kind_string; *p; p++)
401 *p = tolower(*p);
52433f6b 402
69a93e7d
TG
403 kind = netdev_kind_from_string(kind_string);
404 if (kind == _NETDEV_KIND_INVALID) {
52433f6b 405 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 406 "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
407 return 0;
408 }
409
54abf461
TG
410 r = netdev_get(network->manager, rvalue, &netdev);
411 if (r < 0) {
412 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 413 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
414 return 0;
415 }
416
69a93e7d 417 if (netdev->kind != kind) {
54abf461 418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 419 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
420 return 0;
421 }
422
69a93e7d
TG
423 switch (kind) {
424 case NETDEV_KIND_BRIDGE:
425 network->bridge = netdev;
54abf461 426
69a93e7d
TG
427 break;
428 case NETDEV_KIND_BOND:
429 network->bond = netdev;
fe6b2d55 430
69a93e7d
TG
431 break;
432 case NETDEV_KIND_VLAN:
69a93e7d 433 case NETDEV_KIND_MACVLAN:
f33ff02b 434 case NETDEV_KIND_MACVTAP:
c4a5ddc9 435 case NETDEV_KIND_IPVLAN:
326cb406 436 case NETDEV_KIND_VXLAN:
6a0a2f86 437 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
326cb406
SS
438 if (r < 0) {
439 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
6a7a4e4d
LP
440 "Can not add VLAN '%s' to network: %m",
441 rvalue);
326cb406
SS
442 return 0;
443 }
444
69a93e7d
TG
445 break;
446 default:
447 assert_not_reached("Can not parse NetDev");
fe6b2d55
TG
448 }
449
47e2dc31
TG
450 netdev_ref(netdev);
451
fe6b2d55
TG
452 return 0;
453}
7951dea2 454
6192b846
TG
455int config_parse_domains(const char *unit,
456 const char *filename,
457 unsigned line,
458 const char *section,
459 unsigned section_line,
460 const char *lvalue,
461 int ltype,
462 const char *rvalue,
463 void *data,
464 void *userdata) {
67272d15 465 Network *network = userdata;
6192b846
TG
466 char ***domains = data;
467 char **domain;
468 int r;
469
470 r = config_parse_strv(unit, filename, line, section, section_line,
471 lvalue, ltype, rvalue, domains, userdata);
472 if (r < 0)
473 return r;
474
475 strv_uniq(*domains);
f15b6e5a 476 network->wildcard_domain = !!strv_find(*domains, "*");
67272d15 477
40274ed6
LP
478 STRV_FOREACH(domain, *domains) {
479 if (is_localhost(*domain))
480 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
37de2509
NO
481 else {
482 r = dns_name_is_valid(*domain);
483 if (r <= 0 && !streq(*domain, "*")) {
484 if (r < 0)
485 log_error_errno(r, "Failed to validate domain name: %s: %m", *domain);
486 if (r == 0)
487 log_warning("Domain name is not valid, ignoring assignment: %s", *domain);
488 } else
489 continue;
490 }
40274ed6
LP
491
492 strv_remove(*domains, *domain);
493
494 /* We removed one entry, make sure we don't skip the next one */
495 domain--;
496 }
f15b6e5a 497
6192b846
TG
498 return 0;
499}
500
7951dea2
SS
501int config_parse_tunnel(const char *unit,
502 const char *filename,
503 unsigned line,
504 const char *section,
505 unsigned section_line,
506 const char *lvalue,
507 int ltype,
508 const char *rvalue,
509 void *data,
510 void *userdata) {
511 Network *network = userdata;
512 NetDev *netdev;
513 int r;
514
515 assert(filename);
516 assert(lvalue);
517 assert(rvalue);
518 assert(data);
519
520 r = netdev_get(network->manager, rvalue, &netdev);
521 if (r < 0) {
6a7a4e4d 522 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
7951dea2
SS
523 return 0;
524 }
525
526 if (netdev->kind != NETDEV_KIND_IPIP &&
527 netdev->kind != NETDEV_KIND_SIT &&
a613382b 528 netdev->kind != NETDEV_KIND_GRE &&
1af2536a 529 netdev->kind != NETDEV_KIND_GRETAP &&
b16492f8
SS
530 netdev->kind != NETDEV_KIND_IP6GRE &&
531 netdev->kind != NETDEV_KIND_IP6GRETAP &&
855ee1a1 532 netdev->kind != NETDEV_KIND_VTI &&
9011ce77 533 netdev->kind != NETDEV_KIND_VTI6 &&
855ee1a1
SS
534 netdev->kind != NETDEV_KIND_IP6TNL
535 ) {
7951dea2
SS
536 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
537 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
538 return 0;
539 }
540
6a0a2f86
TG
541 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
542 if (r < 0) {
6a7a4e4d 543 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
6a0a2f86
TG
544 return 0;
545 }
546
547 netdev_ref(netdev);
7951dea2
SS
548
549 return 0;
550}
bd8f6538 551
d0d6a4cd
TG
552int config_parse_ipv4ll(
553 const char* unit,
554 const char *filename,
555 unsigned line,
556 const char *section,
557 unsigned section_line,
558 const char *lvalue,
559 int ltype,
560 const char *rvalue,
561 void *data,
562 void *userdata) {
563
564 AddressFamilyBoolean *link_local = data;
565
566 assert(filename);
567 assert(lvalue);
568 assert(rvalue);
569 assert(data);
570
571 /* Note that this is mostly like
572 * config_parse_address_family_boolean(), except that it
573 * applies only to IPv4 */
574
575 if (parse_boolean(rvalue))
576 *link_local |= ADDRESS_FAMILY_IPV4;
577 else
578 *link_local &= ~ADDRESS_FAMILY_IPV4;
579
580 return 0;
581}
582
bd8f6538
TG
583int config_parse_dhcp(
584 const char* unit,
585 const char *filename,
586 unsigned line,
587 const char *section,
588 unsigned section_line,
589 const char *lvalue,
590 int ltype,
591 const char *rvalue,
592 void *data,
593 void *userdata) {
594
cb9fc36a 595 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
596
597 assert(filename);
598 assert(lvalue);
599 assert(rvalue);
600 assert(data);
601
769d324c
LP
602 /* Note that this is mostly like
603 * config_parse_address_family_boolean(), except that it
604 * understands some old names for the enum values */
605
cb9fc36a
LP
606 s = address_family_boolean_from_string(rvalue);
607 if (s < 0) {
608
609 /* Previously, we had a slightly different enum here,
610 * support its values for compatbility. */
611
612 if (streq(rvalue, "none"))
613 s = ADDRESS_FAMILY_NO;
614 else if (streq(rvalue, "v4"))
615 s = ADDRESS_FAMILY_IPV4;
616 else if (streq(rvalue, "v6"))
617 s = ADDRESS_FAMILY_IPV6;
618 else if (streq(rvalue, "both"))
619 s = ADDRESS_FAMILY_YES;
620 else {
621 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
622 return 0;
623 }
bd8f6538
TG
624 }
625
cb9fc36a 626 *dhcp = s;
bd8f6538
TG
627 return 0;
628}
629
3e43b2cd
JJ
630static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
631 [DHCP_CLIENT_ID_MAC] = "mac",
632 [DHCP_CLIENT_ID_DUID] = "duid"
633};
634
635DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
636DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
637
60c35566 638int config_parse_ipv6token(
7f77697a
TG
639 const char* unit,
640 const char *filename,
641 unsigned line,
642 const char *section,
643 unsigned section_line,
644 const char *lvalue,
645 int ltype,
646 const char *rvalue,
647 void *data,
648 void *userdata) {
649
650 union in_addr_union buffer;
651 struct in6_addr *token = data;
652 int r;
653
654 assert(filename);
655 assert(lvalue);
656 assert(rvalue);
657 assert(token);
658
659 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
660 if (r < 0) {
6a7a4e4d 661 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
662 return 0;
663 }
664
665 r = in_addr_is_null(AF_INET6, &buffer);
666 if (r < 0) {
6a7a4e4d 667 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
668 return 0;
669 }
670
671 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
e2acdb6b 672 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
673 return 0;
674 }
675
676 *token = buffer.in6;
677
678 return 0;
679}
8add5f79 680
49092e22 681static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
682 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
683 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
684 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
685};
686
687DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
688
689int config_parse_ipv6_privacy_extensions(
690 const char* unit,
691 const char *filename,
692 unsigned line,
693 const char *section,
694 unsigned section_line,
695 const char *lvalue,
696 int ltype,
697 const char *rvalue,
698 void *data,
699 void *userdata) {
700
701 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
702 int k;
703
704 assert(filename);
705 assert(lvalue);
706 assert(rvalue);
707 assert(ipv6_privacy_extensions);
708
709 /* Our enum shall be a superset of booleans, hence first try
710 * to parse as boolean, and then as enum */
711
712 k = parse_boolean(rvalue);
713 if (k > 0)
1f0d9695 714 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 715 else if (k == 0)
1f0d9695 716 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 717 else {
1f0d9695 718 IPv6PrivacyExtensions s;
49092e22
SS
719
720 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
721 if (s < 0) {
722
723 if (streq(rvalue, "kernel"))
724 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
725 else {
726 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
727 return 0;
728 }
49092e22
SS
729 }
730
731 *ipv6_privacy_extensions = s;
732 }
733
734 return 0;
735}
a7d0ef44 736
1ac608c9
LP
737int config_parse_hostname(
738 const char *unit,
739 const char *filename,
740 unsigned line,
741 const char *section,
742 unsigned section_line,
743 const char *lvalue,
744 int ltype,
745 const char *rvalue,
746 void *data,
747 void *userdata) {
748
749 char **hostname = data, *hn = NULL;
a7d0ef44
SS
750 int r;
751
752 assert(filename);
753 assert(lvalue);
754 assert(rvalue);
755
1ac608c9 756 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
757 if (r < 0)
758 return r;
759
1ac608c9
LP
760 if (!hostname_is_valid(hn, false)) {
761 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
762 free(hn);
763 return 0;
764 }
765
1ac608c9 766 free(*hostname);
ae691c1d 767 *hostname = hostname_cleanup(hn);
a7d0ef44
SS
768 return 0;
769}
8eb9058d
LP
770
771int config_parse_timezone(
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 char **timezone = data, *tz = NULL;
784 int r;
785
786 assert(filename);
787 assert(lvalue);
788 assert(rvalue);
789
790 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
791 if (r < 0)
792 return r;
793
794 if (!timezone_is_valid(tz)) {
795 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Timezone is not valid, ignoring assignment: %s", rvalue);
796 free(tz);
797 return 0;
798 }
799
800 free(*timezone);
801 *timezone = tz;
802
803 return 0;
804}