Line data Source code
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 :
22 : #include <ctype.h>
23 : #include <net/if.h>
24 :
25 : #include "conf-files.h"
26 : #include "conf-parser.h"
27 : #include "util.h"
28 : #include "hostname-util.h"
29 : #include "networkd.h"
30 : #include "networkd-netdev.h"
31 : #include "networkd-link.h"
32 : #include "network-internal.h"
33 : #include "dns-domain.h"
34 :
35 3 : static int network_load_one(Manager *manager, const char *filename) {
36 6 : _cleanup_network_free_ Network *network = NULL;
37 6 : _cleanup_fclose_ FILE *file = NULL;
38 : char *d;
39 : Route *route;
40 : Address *address;
41 : int r;
42 :
43 3 : assert(manager);
44 3 : assert(filename);
45 :
46 3 : file = fopen(filename, "re");
47 3 : if (!file) {
48 0 : if (errno == ENOENT)
49 0 : return 0;
50 : else
51 0 : return -errno;
52 : }
53 :
54 3 : if (null_or_empty_fd(fileno(file))) {
55 0 : log_debug("Skipping empty file: %s", filename);
56 0 : return 0;
57 : }
58 :
59 3 : network = new0(Network, 1);
60 3 : if (!network)
61 0 : return log_oom();
62 :
63 3 : network->manager = manager;
64 :
65 3 : LIST_HEAD_INIT(network->static_addresses);
66 3 : LIST_HEAD_INIT(network->static_routes);
67 3 : LIST_HEAD_INIT(network->static_fdb_entries);
68 :
69 3 : network->stacked_netdevs = hashmap_new(&string_hash_ops);
70 3 : if (!network->stacked_netdevs)
71 0 : return log_oom();
72 :
73 3 : network->addresses_by_section = hashmap_new(NULL);
74 3 : if (!network->addresses_by_section)
75 0 : return log_oom();
76 :
77 3 : network->routes_by_section = hashmap_new(NULL);
78 3 : if (!network->routes_by_section)
79 0 : return log_oom();
80 :
81 3 : network->fdb_entries_by_section = hashmap_new(NULL);
82 3 : if (!network->fdb_entries_by_section)
83 0 : return log_oom();
84 :
85 3 : network->filename = strdup(filename);
86 3 : if (!network->filename)
87 0 : return log_oom();
88 :
89 3 : network->name = strdup(basename(filename));
90 3 : if (!network->name)
91 0 : return log_oom();
92 :
93 3 : d = strrchr(network->name, '.');
94 3 : if (!d)
95 0 : return -EINVAL;
96 :
97 3 : assert(streq(d, ".network"));
98 :
99 3 : *d = '\0';
100 :
101 3 : network->dhcp = ADDRESS_FAMILY_NO;
102 3 : network->dhcp_ntp = true;
103 3 : network->dhcp_dns = true;
104 3 : network->dhcp_hostname = true;
105 3 : network->dhcp_routes = true;
106 3 : network->dhcp_sendhost = true;
107 3 : network->dhcp_route_metric = DHCP_ROUTE_METRIC;
108 3 : network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
109 :
110 3 : network->use_bpdu = true;
111 3 : network->allow_port_to_be_root = true;
112 3 : network->unicast_flood = true;
113 :
114 3 : network->llmnr = LLMNR_SUPPORT_YES;
115 :
116 3 : network->link_local = ADDRESS_FAMILY_IPV6;
117 :
118 3 : network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
119 :
120 3 : r = config_parse(NULL, filename, file,
121 : "Match\0"
122 : "Link\0"
123 : "Network\0"
124 : "Address\0"
125 : "Route\0"
126 : "DHCP\0"
127 : "DHCPv4\0"
128 : "Bridge\0"
129 : "BridgeFDB\0",
130 : config_item_perf_lookup, network_network_gperf_lookup,
131 : false, false, true, network);
132 3 : if (r < 0)
133 0 : return r;
134 :
135 : /* IPMasquerade=yes implies IPForward=yes */
136 3 : if (network->ip_masquerade)
137 1 : network->ip_forward |= ADDRESS_FAMILY_IPV4;
138 :
139 3 : LIST_PREPEND(networks, manager->networks, network);
140 :
141 3 : r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
142 3 : if (r < 0)
143 0 : return r;
144 :
145 3 : r = hashmap_put(manager->networks_by_name, network->name, network);
146 3 : if (r < 0)
147 0 : return r;
148 :
149 3 : LIST_FOREACH(routes, route, network->static_routes) {
150 0 : if (!route->family) {
151 0 : log_warning("Route section without Gateway field configured in %s. "
152 : "Ignoring", filename);
153 0 : return 0;
154 : }
155 : }
156 :
157 4 : LIST_FOREACH(addresses, address, network->static_addresses) {
158 1 : if (!address->family) {
159 0 : log_warning("Address section without Address field configured in %s. "
160 : "Ignoring", filename);
161 0 : return 0;
162 : }
163 : }
164 :
165 3 : network = NULL;
166 :
167 3 : return 0;
168 : }
169 :
170 1 : int network_load(Manager *manager) {
171 : Network *network;
172 2 : _cleanup_strv_free_ char **files = NULL;
173 : char **f;
174 : int r;
175 :
176 1 : assert(manager);
177 :
178 2 : while ((network = manager->networks))
179 0 : network_free(network);
180 :
181 1 : r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
182 1 : if (r < 0)
183 0 : return log_error_errno(r, "Failed to enumerate network files: %m");
184 :
185 4 : STRV_FOREACH_BACKWARDS(f, files) {
186 3 : r = network_load_one(manager, *f);
187 3 : if (r < 0)
188 0 : return r;
189 : }
190 :
191 1 : return 0;
192 : }
193 :
194 3 : void network_free(Network *network) {
195 : NetDev *netdev;
196 : Route *route;
197 : Address *address;
198 : FdbEntry *fdb_entry;
199 : Iterator i;
200 :
201 3 : if (!network)
202 0 : return;
203 :
204 3 : free(network->filename);
205 :
206 3 : free(network->match_mac);
207 3 : strv_free(network->match_path);
208 3 : strv_free(network->match_driver);
209 3 : strv_free(network->match_type);
210 3 : strv_free(network->match_name);
211 :
212 3 : free(network->description);
213 3 : free(network->dhcp_vendor_class_identifier);
214 3 : free(network->hostname);
215 :
216 3 : free(network->mac);
217 :
218 3 : strv_free(network->ntp);
219 3 : strv_free(network->dns);
220 3 : strv_free(network->domains);
221 3 : strv_free(network->bind_carrier);
222 :
223 3 : netdev_unref(network->bridge);
224 :
225 3 : netdev_unref(network->bond);
226 :
227 6 : HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
228 0 : hashmap_remove(network->stacked_netdevs, netdev->ifname);
229 0 : netdev_unref(netdev);
230 : }
231 3 : hashmap_free(network->stacked_netdevs);
232 :
233 6 : while ((route = network->static_routes))
234 0 : route_free(route);
235 :
236 7 : while ((address = network->static_addresses))
237 1 : address_free(address);
238 :
239 6 : while ((fdb_entry = network->static_fdb_entries))
240 0 : fdb_entry_free(fdb_entry);
241 :
242 3 : hashmap_free(network->addresses_by_section);
243 3 : hashmap_free(network->routes_by_section);
244 3 : hashmap_free(network->fdb_entries_by_section);
245 :
246 3 : if (network->manager) {
247 3 : if (network->manager->networks)
248 3 : LIST_REMOVE(networks, network->manager->networks, network);
249 :
250 3 : if (network->manager->networks_by_name)
251 3 : hashmap_remove(network->manager->networks_by_name, network->name);
252 : }
253 :
254 3 : free(network->name);
255 :
256 3 : condition_free_list(network->match_host);
257 3 : condition_free_list(network->match_virt);
258 3 : condition_free_list(network->match_kernel);
259 3 : condition_free_list(network->match_arch);
260 :
261 3 : free(network);
262 : }
263 :
264 0 : int network_get_by_name(Manager *manager, const char *name, Network **ret) {
265 : Network *network;
266 :
267 0 : assert(manager);
268 0 : assert(name);
269 0 : assert(ret);
270 :
271 0 : network = hashmap_get(manager->networks_by_name, name);
272 0 : if (!network)
273 0 : return -ENOENT;
274 :
275 0 : *ret = network;
276 :
277 0 : return 0;
278 : }
279 :
280 1 : int network_get(Manager *manager, struct udev_device *device,
281 : const char *ifname, const struct ether_addr *address,
282 : Network **ret) {
283 : Network *network;
284 : struct udev_device *parent;
285 1 : const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
286 :
287 1 : assert(manager);
288 1 : assert(ret);
289 :
290 1 : if (device) {
291 1 : path = udev_device_get_property_value(device, "ID_PATH");
292 :
293 1 : parent = udev_device_get_parent(device);
294 1 : if (parent)
295 0 : parent_driver = udev_device_get_driver(parent);
296 :
297 1 : driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
298 :
299 1 : devtype = udev_device_get_devtype(device);
300 : }
301 :
302 4 : LIST_FOREACH(networks, network, manager->networks) {
303 6 : if (net_match_config(network->match_mac, network->match_path,
304 3 : network->match_driver, network->match_type,
305 3 : network->match_name, network->match_host,
306 : network->match_virt, network->match_kernel,
307 : network->match_arch,
308 : address, path, parent_driver, driver,
309 : devtype, ifname)) {
310 0 : if (network->match_name && device) {
311 : const char *attr;
312 0 : uint8_t name_assign_type = NET_NAME_UNKNOWN;
313 :
314 0 : attr = udev_device_get_sysattr_value(device, "name_assign_type");
315 0 : if (attr)
316 0 : (void) safe_atou8(attr, &name_assign_type);
317 :
318 0 : if (name_assign_type == NET_NAME_ENUM)
319 0 : log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
320 : IFNAMSIZ, ifname, network->filename);
321 : else
322 0 : log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
323 : } else
324 0 : log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
325 :
326 0 : *ret = network;
327 0 : return 0;
328 : }
329 : }
330 :
331 1 : *ret = NULL;
332 :
333 1 : return -ENOENT;
334 : }
335 :
336 0 : int network_apply(Manager *manager, Network *network, Link *link) {
337 : int r;
338 :
339 0 : link->network = network;
340 :
341 0 : if (network->ipv4ll_route) {
342 : Route *route;
343 :
344 0 : r = route_new_static(network, 0, &route);
345 0 : if (r < 0)
346 0 : return r;
347 :
348 0 : r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
349 0 : if (r == 0)
350 0 : return -EINVAL;
351 0 : if (r < 0)
352 0 : return -errno;
353 :
354 0 : route->family = AF_INET;
355 0 : route->dst_prefixlen = 16;
356 0 : route->scope = RT_SCOPE_LINK;
357 0 : route->metrics = IPV4LL_ROUTE_METRIC;
358 0 : route->protocol = RTPROT_STATIC;
359 : }
360 :
361 0 : if (network->dns || network->ntp) {
362 0 : r = link_save(link);
363 0 : if (r < 0)
364 0 : return r;
365 : }
366 :
367 0 : return 0;
368 : }
369 :
370 0 : int config_parse_netdev(const char *unit,
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 0 : Network *network = userdata;
381 0 : _cleanup_free_ char *kind_string = NULL;
382 : char *p;
383 : NetDev *netdev;
384 : NetDevKind kind;
385 : int r;
386 :
387 0 : assert(filename);
388 0 : assert(lvalue);
389 0 : assert(rvalue);
390 0 : assert(data);
391 :
392 0 : kind_string = strdup(lvalue);
393 0 : if (!kind_string)
394 0 : return log_oom();
395 :
396 : /* the keys are CamelCase versions of the kind */
397 0 : for (p = kind_string; *p; p++)
398 0 : *p = tolower(*p);
399 :
400 0 : kind = netdev_kind_from_string(kind_string);
401 0 : if (kind == _NETDEV_KIND_INVALID) {
402 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
403 : "Invalid NetDev kind: %s", lvalue);
404 0 : return 0;
405 : }
406 :
407 0 : r = netdev_get(network->manager, rvalue, &netdev);
408 0 : if (r < 0) {
409 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
410 : "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
411 0 : return 0;
412 : }
413 :
414 0 : if (netdev->kind != kind) {
415 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
416 : "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
417 0 : return 0;
418 : }
419 :
420 0 : switch (kind) {
421 : case NETDEV_KIND_BRIDGE:
422 0 : network->bridge = netdev;
423 :
424 0 : break;
425 : case NETDEV_KIND_BOND:
426 0 : network->bond = netdev;
427 :
428 0 : break;
429 : case NETDEV_KIND_VLAN:
430 : case NETDEV_KIND_MACVLAN:
431 : case NETDEV_KIND_MACVTAP:
432 : case NETDEV_KIND_IPVLAN:
433 : case NETDEV_KIND_VXLAN:
434 0 : r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
435 0 : if (r < 0) {
436 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
437 : "Can not add VLAN '%s' to network: %m",
438 : rvalue);
439 0 : return 0;
440 : }
441 :
442 0 : break;
443 : default:
444 0 : assert_not_reached("Can not parse NetDev");
445 : }
446 :
447 0 : netdev_ref(netdev);
448 :
449 0 : return 0;
450 : }
451 :
452 0 : int 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) {
462 0 : Network *network = userdata;
463 0 : char ***domains = data;
464 : char **domain;
465 : int r;
466 :
467 0 : r = config_parse_strv(unit, filename, line, section, section_line,
468 : lvalue, ltype, rvalue, domains, userdata);
469 0 : if (r < 0)
470 0 : return r;
471 :
472 0 : strv_uniq(*domains);
473 0 : network->wildcard_domain = !!strv_find(*domains, "*");
474 :
475 0 : STRV_FOREACH(domain, *domains) {
476 0 : if (is_localhost(*domain))
477 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
478 : else {
479 0 : r = dns_name_is_valid(*domain);
480 0 : if (r <= 0 && !streq(*domain, "*")) {
481 0 : if (r < 0)
482 0 : log_error_errno(r, "Failed to validate domain name: %s: %m", *domain);
483 0 : if (r == 0)
484 0 : log_warning("Domain name is not valid, ignoring assignment: %s", *domain);
485 : } else
486 0 : continue;
487 : }
488 :
489 0 : strv_remove(*domains, *domain);
490 :
491 : /* We removed one entry, make sure we don't skip the next one */
492 0 : domain--;
493 : }
494 :
495 0 : return 0;
496 : }
497 :
498 0 : int 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 0 : Network *network = userdata;
509 : NetDev *netdev;
510 : int r;
511 :
512 0 : assert(filename);
513 0 : assert(lvalue);
514 0 : assert(rvalue);
515 0 : assert(data);
516 :
517 0 : r = netdev_get(network->manager, rvalue, &netdev);
518 0 : if (r < 0) {
519 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
520 0 : return 0;
521 : }
522 :
523 0 : if (netdev->kind != NETDEV_KIND_IPIP &&
524 0 : netdev->kind != NETDEV_KIND_SIT &&
525 0 : netdev->kind != NETDEV_KIND_GRE &&
526 0 : netdev->kind != NETDEV_KIND_GRETAP &&
527 0 : netdev->kind != NETDEV_KIND_IP6GRE &&
528 0 : netdev->kind != NETDEV_KIND_IP6GRETAP &&
529 0 : netdev->kind != NETDEV_KIND_VTI &&
530 0 : netdev->kind != NETDEV_KIND_VTI6 &&
531 0 : netdev->kind != NETDEV_KIND_IP6TNL
532 : ) {
533 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
534 : "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
535 0 : return 0;
536 : }
537 :
538 0 : r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
539 0 : if (r < 0) {
540 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
541 0 : return 0;
542 : }
543 :
544 0 : netdev_ref(netdev);
545 :
546 0 : return 0;
547 : }
548 :
549 0 : int 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 0 : AddressFamilyBoolean *link_local = data;
562 :
563 0 : assert(filename);
564 0 : assert(lvalue);
565 0 : assert(rvalue);
566 0 : 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 0 : if (parse_boolean(rvalue))
573 0 : *link_local |= ADDRESS_FAMILY_IPV4;
574 : else
575 0 : *link_local &= ~ADDRESS_FAMILY_IPV4;
576 :
577 0 : return 0;
578 : }
579 :
580 2 : int 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 :
592 2 : AddressFamilyBoolean *dhcp = data, s;
593 :
594 2 : assert(filename);
595 2 : assert(lvalue);
596 2 : assert(rvalue);
597 2 : assert(data);
598 :
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 :
603 2 : s = address_family_boolean_from_string(rvalue);
604 2 : if (s < 0) {
605 :
606 : /* Previously, we had a slightly different enum here,
607 : * support its values for compatbility. */
608 :
609 0 : if (streq(rvalue, "none"))
610 0 : s = ADDRESS_FAMILY_NO;
611 0 : else if (streq(rvalue, "v4"))
612 0 : s = ADDRESS_FAMILY_IPV4;
613 0 : else if (streq(rvalue, "v6"))
614 0 : s = ADDRESS_FAMILY_IPV6;
615 0 : else if (streq(rvalue, "both"))
616 0 : s = ADDRESS_FAMILY_YES;
617 : else {
618 0 : log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
619 0 : return 0;
620 : }
621 : }
622 :
623 2 : *dhcp = s;
624 2 : return 0;
625 : }
626 :
627 : static 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 :
632 0 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
633 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
634 :
635 : static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
636 : [LLMNR_SUPPORT_NO] = "no",
637 : [LLMNR_SUPPORT_YES] = "yes",
638 : [LLMNR_SUPPORT_RESOLVE] = "resolve",
639 : };
640 :
641 0 : DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
642 :
643 0 : int config_parse_llmnr(
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 :
655 0 : LLMNRSupport *llmnr = data;
656 : int k;
657 :
658 0 : assert(filename);
659 0 : assert(lvalue);
660 0 : assert(rvalue);
661 0 : assert(llmnr);
662 :
663 : /* Our enum shall be a superset of booleans, hence first try
664 : * to parse as boolean, and then as enum */
665 :
666 0 : k = parse_boolean(rvalue);
667 0 : if (k > 0)
668 0 : *llmnr = LLMNR_SUPPORT_YES;
669 0 : else if (k == 0)
670 0 : *llmnr = LLMNR_SUPPORT_NO;
671 : else {
672 : LLMNRSupport s;
673 :
674 0 : s = llmnr_support_from_string(rvalue);
675 0 : if (s < 0){
676 0 : log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);
677 0 : return 0;
678 : }
679 :
680 0 : *llmnr = s;
681 : }
682 :
683 0 : return 0;
684 : }
685 :
686 0 : int config_parse_ipv6token(
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 0 : struct in6_addr *token = data;
700 : int r;
701 :
702 0 : assert(filename);
703 0 : assert(lvalue);
704 0 : assert(rvalue);
705 0 : assert(token);
706 :
707 0 : r = in_addr_from_string(AF_INET6, rvalue, &buffer);
708 0 : if (r < 0) {
709 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
710 0 : return 0;
711 : }
712 :
713 0 : r = in_addr_is_null(AF_INET6, &buffer);
714 0 : if (r < 0) {
715 0 : log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
716 0 : return 0;
717 : }
718 :
719 0 : if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
720 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
721 0 : return 0;
722 : }
723 :
724 0 : *token = buffer.in6;
725 :
726 0 : return 0;
727 : }
728 :
729 0 : int 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 0 : AddressFamilyBoolean *fwd = data, s;
742 :
743 0 : assert(filename);
744 0 : assert(lvalue);
745 0 : assert(rvalue);
746 0 : assert(data);
747 :
748 0 : s = address_family_boolean_from_string(rvalue);
749 0 : if (s < 0) {
750 0 : if (streq(rvalue, "kernel"))
751 0 : s = _ADDRESS_FAMILY_BOOLEAN_INVALID;
752 : else {
753 0 : log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding option, ignoring: %s", rvalue);
754 0 : return 0;
755 : }
756 : }
757 :
758 0 : *fwd = s;
759 :
760 0 : return 0;
761 : }
762 :
763 : static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
764 : [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
765 : [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
766 : [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
767 : };
768 :
769 0 : DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
770 :
771 0 : int 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 0 : IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
784 : int k;
785 :
786 0 : assert(filename);
787 0 : assert(lvalue);
788 0 : assert(rvalue);
789 0 : 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 0 : k = parse_boolean(rvalue);
795 0 : if (k > 0)
796 0 : *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
797 0 : else if (k == 0)
798 0 : *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
799 : else {
800 : IPv6PrivacyExtensions s;
801 :
802 0 : s = ipv6_privacy_extensions_from_string(rvalue);
803 0 : if (s < 0) {
804 :
805 0 : if (streq(rvalue, "kernel"))
806 0 : s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
807 : else {
808 0 : log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
809 0 : return 0;
810 : }
811 : }
812 :
813 0 : *ipv6_privacy_extensions = s;
814 : }
815 :
816 0 : return 0;
817 : }
818 :
819 0 : int config_parse_hostname(const char *unit,
820 : const char *filename,
821 : unsigned line,
822 : const char *section,
823 : unsigned section_line,
824 : const char *lvalue,
825 : int ltype,
826 : const char *rvalue,
827 : void *data,
828 : void *userdata) {
829 0 : char **hostname = data;
830 0 : char *hn = NULL;
831 : int r;
832 :
833 0 : assert(filename);
834 0 : assert(lvalue);
835 0 : assert(rvalue);
836 :
837 0 : r = config_parse_string(unit, filename, line, section, section_line,
838 : lvalue, ltype, rvalue, &hn, userdata);
839 0 : if (r < 0)
840 0 : return r;
841 :
842 0 : if (!hostname_is_valid(hn)) {
843 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL, "hostname is not valid, ignoring assignment: %s", rvalue);
844 :
845 0 : free(hn);
846 0 : return 0;
847 : }
848 :
849 0 : *hostname = hn;
850 :
851 0 : return 0;
852 : }
|