]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
udevd: make udev_ctrl_connection global
[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"
5a8bcb67
LP
28#include "networkd.h"
29#include "networkd-netdev.h"
30#include "networkd-link.h"
31#include "network-internal.h"
f579559b
TG
32
33static int network_load_one(Manager *manager, const char *filename) {
34 _cleanup_network_free_ Network *network = NULL;
35 _cleanup_fclose_ FILE *file = NULL;
dbffab87 36 char *d;
b3070dc0
TG
37 Route *route;
38 Address *address;
f579559b
TG
39 int r;
40
bf1bc670
TA
41 assert(manager);
42 assert(filename);
43
f579559b
TG
44 file = fopen(filename, "re");
45 if (!file) {
46 if (errno == ENOENT)
47 return 0;
48 else
ecb08ec6 49 return -errno;
f579559b
TG
50 }
51
ed88bcfb
ZJS
52 if (null_or_empty_fd(fileno(file))) {
53 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
54 return 0;
55 }
56
f579559b
TG
57 network = new0(Network, 1);
58 if (!network)
59 return log_oom();
60
5a3eb5a7
TG
61 network->manager = manager;
62
f048a16b
TG
63 LIST_HEAD_INIT(network->static_addresses);
64 LIST_HEAD_INIT(network->static_routes);
b98b483b 65 LIST_HEAD_INIT(network->static_fdb_entries);
f579559b 66
d5099efc 67 network->stacked_netdevs = hashmap_new(&string_hash_ops);
6a0a2f86 68 if (!network->stacked_netdevs)
326cb406
SS
69 return log_oom();
70
d5099efc 71 network->addresses_by_section = hashmap_new(NULL);
6ae115c1
TG
72 if (!network->addresses_by_section)
73 return log_oom();
74
d5099efc 75 network->routes_by_section = hashmap_new(NULL);
6ae115c1
TG
76 if (!network->routes_by_section)
77 return log_oom();
78
b98b483b
AR
79 network->fdb_entries_by_section = hashmap_new(NULL);
80 if (!network->fdb_entries_by_section)
81 return log_oom();
82
6ae115c1
TG
83 network->filename = strdup(filename);
84 if (!network->filename)
85 return log_oom();
86
dbffab87
TG
87 network->name = strdup(basename(filename));
88 if (!network->name)
89 return log_oom();
90
91 d = strrchr(network->name, '.');
92 if (!d)
93 return -EINVAL;
94
95 assert(streq(d, ".network"));
96
97 *d = '\0';
98
cb9fc36a 99 network->dhcp = ADDRESS_FAMILY_NO;
bcb7a07e 100 network->dhcp_ntp = true;
5be4d38e 101 network->dhcp_dns = true;
1346b1f0 102 network->dhcp_hostname = true;
e1ea665e 103 network->dhcp_routes = true;
4cc7a82c 104 network->dhcp_sendhost = true;
84b5b79a 105 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
3e43b2cd 106 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
5be4d38e 107
bd8f6538
TG
108 network->llmnr = LLMNR_SUPPORT_YES;
109
d0d6a4cd
TG
110 network->link_local = ADDRESS_FAMILY_IPV6;
111
e9f3d2d5 112 r = config_parse(NULL, filename, file,
c106cc36
TG
113 "Match\0"
114 "Link\0"
115 "Network\0"
116 "Address\0"
117 "Route\0"
118 "DHCP\0"
119 "DHCPv4\0"
b98b483b
AR
120 "Bridge\0"
121 "BridgeFDB\0",
e9f3d2d5 122 config_item_perf_lookup, network_network_gperf_lookup,
36f822c4
ZJS
123 false, false, true, network);
124 if (r < 0)
f579559b 125 return r;
f579559b 126
5a8bcb67
LP
127 /* IPMasquerade=yes implies IPForward=yes */
128 if (network->ip_masquerade)
769d324c 129 network->ip_forward |= ADDRESS_FAMILY_IPV4;
5a8bcb67 130
f579559b 131 LIST_PREPEND(networks, manager->networks, network);
b3070dc0 132
dbffab87
TG
133 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
134 if (r < 0)
135 return r;
136
137 r = hashmap_put(manager->networks_by_name, network->name, network);
138 if (r < 0)
139 return r;
140
3d3d4255 141 LIST_FOREACH(routes, route, network->static_routes) {
b3070dc0
TG
142 if (!route->family) {
143 log_warning("Route section without Gateway field configured in %s. "
144 "Ignoring", filename);
145 return 0;
146 }
b3070dc0
TG
147 }
148
3d3d4255 149 LIST_FOREACH(addresses, address, network->static_addresses) {
b3070dc0
TG
150 if (!address->family) {
151 log_warning("Address section without Address field configured in %s. "
152 "Ignoring", filename);
153 return 0;
154 }
155 }
156
f579559b
TG
157 network = NULL;
158
159 return 0;
160}
161
162int network_load(Manager *manager) {
163 Network *network;
477e73b5
ZJS
164 _cleanup_strv_free_ char **files = NULL;
165 char **f;
f579559b
TG
166 int r;
167
168 assert(manager);
169
170 while ((network = manager->networks))
171 network_free(network);
172
2ad8416d 173 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
f647962d
MS
174 if (r < 0)
175 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b
TG
176
177 STRV_FOREACH_BACKWARDS(f, files) {
178 r = network_load_one(manager, *f);
179 if (r < 0)
180 return r;
181 }
182
f579559b
TG
183 return 0;
184}
185
f579559b 186void network_free(Network *network) {
47e2dc31 187 NetDev *netdev;
f579559b
TG
188 Route *route;
189 Address *address;
b98b483b 190 FdbEntry *fdb_entry;
06f021a8 191 Iterator i;
f579559b
TG
192
193 if (!network)
194 return;
195
196 free(network->filename);
197
198 free(network->match_mac);
5256e00e
TG
199 strv_free(network->match_path);
200 strv_free(network->match_driver);
201 strv_free(network->match_type);
202 strv_free(network->match_name);
f579559b
TG
203
204 free(network->description);
edb85f0d 205 free(network->dhcp_vendor_class_identifier);
f579559b 206
c106cc36
TG
207 free(network->mac);
208
b0e39c82
TG
209 strv_free(network->ntp);
210 strv_free(network->dns);
486d1a81 211 strv_free(network->domains);
0d4ad91d 212 strv_free(network->bind_carrier);
3bef724f 213
47e2dc31
TG
214 netdev_unref(network->bridge);
215
216 netdev_unref(network->bond);
217
2c36be2f
TG
218 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
219 hashmap_remove(network->stacked_netdevs, netdev->ifname);
326cb406 220 netdev_unref(netdev);
2c36be2f 221 }
6a0a2f86 222 hashmap_free(network->stacked_netdevs);
326cb406 223
f048a16b 224 while ((route = network->static_routes))
f579559b
TG
225 route_free(route);
226
f048a16b 227 while ((address = network->static_addresses))
f579559b
TG
228 address_free(address);
229
b98b483b
AR
230 while ((fdb_entry = network->static_fdb_entries))
231 fdb_entry_free(fdb_entry);
232
6ae115c1
TG
233 hashmap_free(network->addresses_by_section);
234 hashmap_free(network->routes_by_section);
b98b483b 235 hashmap_free(network->fdb_entries_by_section);
6ae115c1 236
dbffab87
TG
237 if (network->manager) {
238 if (network->manager->networks)
239 LIST_REMOVE(networks, network->manager->networks, network);
240
241 if (network->manager->networks_by_name)
242 hashmap_remove(network->manager->networks_by_name, network->name);
243 }
244
245 free(network->name);
f579559b 246
79e16ce3
LP
247 condition_free_list(network->match_host);
248 condition_free_list(network->match_virt);
249 condition_free_list(network->match_kernel);
250 condition_free_list(network->match_arch);
251
f579559b
TG
252 free(network);
253}
254
dbffab87
TG
255int network_get_by_name(Manager *manager, const char *name, Network **ret) {
256 Network *network;
257
258 assert(manager);
259 assert(name);
260 assert(ret);
261
262 network = hashmap_get(manager->networks_by_name, name);
263 if (!network)
264 return -ENOENT;
265
266 *ret = network;
267
268 return 0;
269}
270
505f8da7
TG
271int network_get(Manager *manager, struct udev_device *device,
272 const char *ifname, const struct ether_addr *address,
273 Network **ret) {
f579559b 274 Network *network;
af3aa302
TG
275 struct udev_device *parent;
276 const char *path, *parent_driver, *driver, *devtype;
f579559b
TG
277
278 assert(manager);
f579559b 279 assert(ret);
af3aa302
TG
280 assert(device);
281
282 path = udev_device_get_property_value(device, "ID_PATH");
283
284 parent = udev_device_get_parent(device);
285 if (parent)
286 parent_driver = udev_device_get_driver(parent);
287 else
288 parent_driver = NULL;
289
290 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
291
292 devtype = udev_device_get_devtype(device);
f579559b 293
f579559b
TG
294 LIST_FOREACH(networks, network, manager->networks) {
295 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
296 network->match_driver, network->match_type,
297 network->match_name, network->match_host,
298 network->match_virt, network->match_kernel,
299 network->match_arch,
af3aa302
TG
300 address, path, parent_driver, driver,
301 devtype, ifname)) {
32bc8adc 302 if (network->match_name) {
ca6038b8
TG
303 const char *attr;
304 uint8_t name_assign_type = NET_NAME_UNKNOWN;
305
32bc8adc 306 attr = udev_device_get_sysattr_value(device, "name_assign_type");
285760fe 307 if (attr)
dc751688 308 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
309
310 if (name_assign_type == NET_NAME_ENUM)
ca6038b8 311 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
32bc8adc
TG
312 IFNAMSIZ, ifname, network->filename);
313 else
314 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
315 } else
316 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
317
f579559b
TG
318 *ret = network;
319 return 0;
320 }
321 }
322
323 *ret = NULL;
324
325 return -ENOENT;
326}
327
328int network_apply(Manager *manager, Network *network, Link *link) {
f579559b
TG
329 int r;
330
f579559b
TG
331 link->network = network;
332
bfa695b5
TG
333 if (network->ipv4ll_route) {
334 Route *route;
335
336 r = route_new_static(network, 0, &route);
337 if (r < 0)
338 return r;
339
340 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
341 if (r == 0)
342 return -EINVAL;
343 if (r < 0)
344 return -errno;
345
346 route->family = AF_INET;
347 route->dst_prefixlen = 16;
348 route->scope = RT_SCOPE_LINK;
349 route->metrics = IPV4LL_ROUTE_METRIC;
350 route->protocol = RTPROT_STATIC;
351 }
352
bcb7a07e 353 if (network->dns || network->ntp) {
091a364c 354 r = link_save(link);
3bef724f
TG
355 if (r < 0)
356 return r;
357 }
358
f579559b
TG
359 return 0;
360}
02b59d57 361
69a93e7d 362int config_parse_netdev(const char *unit,
02b59d57
TG
363 const char *filename,
364 unsigned line,
365 const char *section,
366 unsigned section_line,
367 const char *lvalue,
368 int ltype,
369 const char *rvalue,
370 void *data,
371 void *userdata) {
372 Network *network = userdata;
31d0ac36
TG
373 _cleanup_free_ char *kind_string = NULL;
374 char *p;
1a436809 375 NetDev *netdev;
69a93e7d 376 NetDevKind kind;
02b59d57
TG
377 int r;
378
379 assert(filename);
380 assert(lvalue);
381 assert(rvalue);
382 assert(data);
383
69a93e7d
TG
384 kind_string = strdup(lvalue);
385 if (!kind_string)
386 return log_oom();
52433f6b 387
69a93e7d
TG
388 /* the keys are CamelCase versions of the kind */
389 for (p = kind_string; *p; p++)
390 *p = tolower(*p);
52433f6b 391
69a93e7d
TG
392 kind = netdev_kind_from_string(kind_string);
393 if (kind == _NETDEV_KIND_INVALID) {
52433f6b 394 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 395 "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
396 return 0;
397 }
398
54abf461
TG
399 r = netdev_get(network->manager, rvalue, &netdev);
400 if (r < 0) {
401 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 402 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
403 return 0;
404 }
405
69a93e7d 406 if (netdev->kind != kind) {
54abf461 407 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
69a93e7d 408 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
409 return 0;
410 }
411
69a93e7d
TG
412 switch (kind) {
413 case NETDEV_KIND_BRIDGE:
414 network->bridge = netdev;
54abf461 415
69a93e7d
TG
416 break;
417 case NETDEV_KIND_BOND:
418 network->bond = netdev;
fe6b2d55 419
69a93e7d
TG
420 break;
421 case NETDEV_KIND_VLAN:
69a93e7d 422 case NETDEV_KIND_MACVLAN:
c4a5ddc9 423 case NETDEV_KIND_IPVLAN:
326cb406 424 case NETDEV_KIND_VXLAN:
6a0a2f86 425 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
326cb406
SS
426 if (r < 0) {
427 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
6a7a4e4d
LP
428 "Can not add VLAN '%s' to network: %m",
429 rvalue);
326cb406
SS
430 return 0;
431 }
432
69a93e7d
TG
433 break;
434 default:
435 assert_not_reached("Can not parse NetDev");
fe6b2d55
TG
436 }
437
47e2dc31
TG
438 netdev_ref(netdev);
439
fe6b2d55
TG
440 return 0;
441}
7951dea2 442
6192b846
TG
443int config_parse_domains(const char *unit,
444 const char *filename,
445 unsigned line,
446 const char *section,
447 unsigned section_line,
448 const char *lvalue,
449 int ltype,
450 const char *rvalue,
451 void *data,
452 void *userdata) {
67272d15 453 Network *network = userdata;
6192b846
TG
454 char ***domains = data;
455 char **domain;
456 int r;
457
458 r = config_parse_strv(unit, filename, line, section, section_line,
459 lvalue, ltype, rvalue, domains, userdata);
460 if (r < 0)
461 return r;
462
463 strv_uniq(*domains);
f15b6e5a 464 network->wildcard_domain = !!strv_find(*domains, "*");
67272d15 465
40274ed6
LP
466 STRV_FOREACH(domain, *domains) {
467 if (is_localhost(*domain))
468 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
469 else if (!hostname_is_valid(*domain)) {
470 if (!streq(*domain, "*"))
471 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "domain name is not valid, ignoring assignment: %s", *domain);
472 } else
473 continue;
474
475 strv_remove(*domains, *domain);
476
477 /* We removed one entry, make sure we don't skip the next one */
478 domain--;
479 }
f15b6e5a 480
6192b846
TG
481 return 0;
482}
483
7951dea2
SS
484int config_parse_tunnel(const char *unit,
485 const char *filename,
486 unsigned line,
487 const char *section,
488 unsigned section_line,
489 const char *lvalue,
490 int ltype,
491 const char *rvalue,
492 void *data,
493 void *userdata) {
494 Network *network = userdata;
495 NetDev *netdev;
496 int r;
497
498 assert(filename);
499 assert(lvalue);
500 assert(rvalue);
501 assert(data);
502
503 r = netdev_get(network->manager, rvalue, &netdev);
504 if (r < 0) {
6a7a4e4d 505 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
7951dea2
SS
506 return 0;
507 }
508
509 if (netdev->kind != NETDEV_KIND_IPIP &&
510 netdev->kind != NETDEV_KIND_SIT &&
a613382b 511 netdev->kind != NETDEV_KIND_GRE &&
1af2536a 512 netdev->kind != NETDEV_KIND_GRETAP &&
b16492f8
SS
513 netdev->kind != NETDEV_KIND_IP6GRE &&
514 netdev->kind != NETDEV_KIND_IP6GRETAP &&
855ee1a1 515 netdev->kind != NETDEV_KIND_VTI &&
9011ce77 516 netdev->kind != NETDEV_KIND_VTI6 &&
855ee1a1
SS
517 netdev->kind != NETDEV_KIND_IP6TNL
518 ) {
7951dea2
SS
519 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
520 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
521 return 0;
522 }
523
6a0a2f86
TG
524 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
525 if (r < 0) {
6a7a4e4d 526 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
6a0a2f86
TG
527 return 0;
528 }
529
530 netdev_ref(netdev);
7951dea2
SS
531
532 return 0;
533}
bd8f6538 534
d0d6a4cd
TG
535int config_parse_ipv4ll(
536 const char* unit,
537 const char *filename,
538 unsigned line,
539 const char *section,
540 unsigned section_line,
541 const char *lvalue,
542 int ltype,
543 const char *rvalue,
544 void *data,
545 void *userdata) {
546
547 AddressFamilyBoolean *link_local = data;
548
549 assert(filename);
550 assert(lvalue);
551 assert(rvalue);
552 assert(data);
553
554 /* Note that this is mostly like
555 * config_parse_address_family_boolean(), except that it
556 * applies only to IPv4 */
557
558 if (parse_boolean(rvalue))
559 *link_local |= ADDRESS_FAMILY_IPV4;
560 else
561 *link_local &= ~ADDRESS_FAMILY_IPV4;
562
563 return 0;
564}
565
bd8f6538
TG
566int config_parse_dhcp(
567 const char* unit,
568 const char *filename,
569 unsigned line,
570 const char *section,
571 unsigned section_line,
572 const char *lvalue,
573 int ltype,
574 const char *rvalue,
575 void *data,
576 void *userdata) {
577
cb9fc36a 578 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
579
580 assert(filename);
581 assert(lvalue);
582 assert(rvalue);
583 assert(data);
584
769d324c
LP
585 /* Note that this is mostly like
586 * config_parse_address_family_boolean(), except that it
587 * understands some old names for the enum values */
588
cb9fc36a
LP
589 s = address_family_boolean_from_string(rvalue);
590 if (s < 0) {
591
592 /* Previously, we had a slightly different enum here,
593 * support its values for compatbility. */
594
595 if (streq(rvalue, "none"))
596 s = ADDRESS_FAMILY_NO;
597 else if (streq(rvalue, "v4"))
598 s = ADDRESS_FAMILY_IPV4;
599 else if (streq(rvalue, "v6"))
600 s = ADDRESS_FAMILY_IPV6;
601 else if (streq(rvalue, "both"))
602 s = ADDRESS_FAMILY_YES;
603 else {
604 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
605 return 0;
606 }
bd8f6538
TG
607 }
608
cb9fc36a 609 *dhcp = s;
bd8f6538
TG
610 return 0;
611}
612
3e43b2cd
JJ
613static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
614 [DHCP_CLIENT_ID_MAC] = "mac",
615 [DHCP_CLIENT_ID_DUID] = "duid"
616};
617
618DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
619DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
620
bd8f6538
TG
621static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
622 [LLMNR_SUPPORT_NO] = "no",
623 [LLMNR_SUPPORT_YES] = "yes",
624 [LLMNR_SUPPORT_RESOLVE] = "resolve",
625};
626
627DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
628
629int config_parse_llmnr(
630 const char* unit,
631 const char *filename,
632 unsigned line,
633 const char *section,
634 unsigned section_line,
635 const char *lvalue,
636 int ltype,
637 const char *rvalue,
638 void *data,
639 void *userdata) {
640
641 LLMNRSupport *llmnr = data;
642 int k;
643
644 assert(filename);
645 assert(lvalue);
646 assert(rvalue);
7f77697a 647 assert(llmnr);
bd8f6538
TG
648
649 /* Our enum shall be a superset of booleans, hence first try
650 * to parse as boolean, and then as enum */
651
652 k = parse_boolean(rvalue);
653 if (k > 0)
654 *llmnr = LLMNR_SUPPORT_YES;
655 else if (k == 0)
656 *llmnr = LLMNR_SUPPORT_NO;
657 else {
658 LLMNRSupport s;
659
660 s = llmnr_support_from_string(rvalue);
661 if (s < 0){
662 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);
663 return 0;
664 }
665
666 *llmnr = s;
667 }
668
669 return 0;
670}
7f77697a 671
60c35566 672int config_parse_ipv6token(
7f77697a
TG
673 const char* unit,
674 const char *filename,
675 unsigned line,
676 const char *section,
677 unsigned section_line,
678 const char *lvalue,
679 int ltype,
680 const char *rvalue,
681 void *data,
682 void *userdata) {
683
684 union in_addr_union buffer;
685 struct in6_addr *token = data;
686 int r;
687
688 assert(filename);
689 assert(lvalue);
690 assert(rvalue);
691 assert(token);
692
693 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
694 if (r < 0) {
6a7a4e4d 695 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
696 return 0;
697 }
698
699 r = in_addr_is_null(AF_INET6, &buffer);
700 if (r < 0) {
6a7a4e4d 701 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
702 return 0;
703 }
704
705 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
e2acdb6b 706 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
707 return 0;
708 }
709
710 *token = buffer.in6;
711
712 return 0;
713}