]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
networkd: fix route_new_static assert when IPv4LLRoute=true (#5676)
[thirdparty/systemd.git] / src / network / networkd-network.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2013 Tom Gundersen <teg@jklm.no>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <ctype.h>
21 #include <net/if.h>
22
23 #include "alloc-util.h"
24 #include "conf-files.h"
25 #include "conf-parser.h"
26 #include "dns-domain.h"
27 #include "fd-util.h"
28 #include "hostname-util.h"
29 #include "network-internal.h"
30 #include "networkd-manager.h"
31 #include "networkd-network.h"
32 #include "parse-util.h"
33 #include "set.h"
34 #include "stat-util.h"
35 #include "string-table.h"
36 #include "string-util.h"
37 #include "util.h"
38
39 static void network_config_hash_func(const void *p, struct siphash *state) {
40 const NetworkConfigSection *c = p;
41
42 siphash24_compress(c->filename, strlen(c->filename), state);
43 siphash24_compress(&c->line, sizeof(c->line), state);
44 }
45
46 static int network_config_compare_func(const void *a, const void *b) {
47 const NetworkConfigSection *x = a, *y = b;
48 int r;
49
50 r = strcmp(x->filename, y->filename);
51 if (r != 0)
52 return r;
53
54 return y->line - x->line;
55 }
56
57 const struct hash_ops network_config_hash_ops = {
58 .hash = network_config_hash_func,
59 .compare = network_config_compare_func,
60 };
61
62 int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
63 NetworkConfigSection *cs;
64
65 cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
66 if (!cs)
67 return -ENOMEM;
68
69 strcpy(cs->filename, filename);
70 cs->line = line;
71
72 *s = cs;
73 cs = NULL;
74
75 return 0;
76 }
77
78 void network_config_section_free(NetworkConfigSection *cs) {
79 free(cs);
80 }
81
82 static int network_load_one(Manager *manager, const char *filename) {
83 _cleanup_network_free_ Network *network = NULL;
84 _cleanup_fclose_ FILE *file = NULL;
85 char *d;
86 const char *dropin_dirname;
87 Route *route;
88 Address *address;
89 int r;
90
91 assert(manager);
92 assert(filename);
93
94 file = fopen(filename, "re");
95 if (!file) {
96 if (errno == ENOENT)
97 return 0;
98
99 return -errno;
100 }
101
102 if (null_or_empty_fd(fileno(file))) {
103 log_debug("Skipping empty file: %s", filename);
104 return 0;
105 }
106
107 network = new0(Network, 1);
108 if (!network)
109 return log_oom();
110
111 network->manager = manager;
112
113 LIST_HEAD_INIT(network->static_addresses);
114 LIST_HEAD_INIT(network->static_routes);
115 LIST_HEAD_INIT(network->static_fdb_entries);
116 LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
117
118 network->stacked_netdevs = hashmap_new(&string_hash_ops);
119 if (!network->stacked_netdevs)
120 return log_oom();
121
122 network->addresses_by_section = hashmap_new(&network_config_hash_ops);
123 if (!network->addresses_by_section)
124 return log_oom();
125
126 network->routes_by_section = hashmap_new(&network_config_hash_ops);
127 if (!network->routes_by_section)
128 return log_oom();
129
130 network->fdb_entries_by_section = hashmap_new(NULL);
131 if (!network->fdb_entries_by_section)
132 return log_oom();
133
134 network->filename = strdup(filename);
135 if (!network->filename)
136 return log_oom();
137
138 network->name = strdup(basename(filename));
139 if (!network->name)
140 return log_oom();
141
142 d = strrchr(network->name, '.');
143 if (!d)
144 return -EINVAL;
145
146 assert(streq(d, ".network"));
147
148 *d = '\0';
149
150 network->dhcp = ADDRESS_FAMILY_NO;
151 network->dhcp_use_ntp = true;
152 network->dhcp_use_dns = true;
153 network->dhcp_use_hostname = true;
154 network->dhcp_use_routes = true;
155 network->dhcp_send_hostname = true;
156 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
157 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
158 network->dhcp_route_table = RT_TABLE_MAIN;
159
160 network->dhcp_server_emit_dns = true;
161 network->dhcp_server_emit_ntp = true;
162 network->dhcp_server_emit_router = true;
163 network->dhcp_server_emit_timezone = true;
164
165 network->use_bpdu = true;
166 network->allow_port_to_be_root = true;
167 network->unicast_flood = true;
168
169 network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
170
171 network->llmnr = RESOLVE_SUPPORT_YES;
172 network->mdns = RESOLVE_SUPPORT_NO;
173 network->dnssec_mode = _DNSSEC_MODE_INVALID;
174
175 network->link_local = ADDRESS_FAMILY_IPV6;
176
177 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
178 network->ipv6_accept_ra = -1;
179 network->ipv6_dad_transmits = -1;
180 network->ipv6_hop_limit = -1;
181 network->duid.type = _DUID_TYPE_INVALID;
182 network->proxy_arp = -1;
183 network->arp = -1;
184 network->ipv6_accept_ra_use_dns = true;
185 network->ipv6_accept_ra_route_table = RT_TABLE_MAIN;
186
187 dropin_dirname = strjoina(network->name, ".network.d");
188
189 r = config_parse_many(filename, network_dirs, dropin_dirname,
190 "Match\0"
191 "Link\0"
192 "Network\0"
193 "Address\0"
194 "Route\0"
195 "DHCP\0"
196 "DHCPv4\0" /* compat */
197 "DHCPServer\0"
198 "IPv6AcceptRA\0"
199 "IPv6NDPProxyAddress\0"
200 "Bridge\0"
201 "BridgeFDB\0"
202 "BridgeVLAN\0",
203 config_item_perf_lookup, network_network_gperf_lookup,
204 false, network);
205 if (r < 0)
206 return r;
207
208 /* IPMasquerade=yes implies IPForward=yes */
209 if (network->ip_masquerade)
210 network->ip_forward |= ADDRESS_FAMILY_IPV4;
211
212 LIST_PREPEND(networks, manager->networks, network);
213
214 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
215 if (r < 0)
216 return r;
217
218 r = hashmap_put(manager->networks_by_name, network->name, network);
219 if (r < 0)
220 return r;
221
222 LIST_FOREACH(routes, route, network->static_routes) {
223 if (!route->family) {
224 log_warning("Route section without Gateway field configured in %s. "
225 "Ignoring", filename);
226 return 0;
227 }
228 }
229
230 LIST_FOREACH(addresses, address, network->static_addresses) {
231 if (!address->family) {
232 log_warning("Address section without Address field configured in %s. "
233 "Ignoring", filename);
234 return 0;
235 }
236 }
237
238 network = NULL;
239
240 return 0;
241 }
242
243 int network_load(Manager *manager) {
244 Network *network;
245 _cleanup_strv_free_ char **files = NULL;
246 char **f;
247 int r;
248
249 assert(manager);
250
251 while ((network = manager->networks))
252 network_free(network);
253
254 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
255 if (r < 0)
256 return log_error_errno(r, "Failed to enumerate network files: %m");
257
258 STRV_FOREACH_BACKWARDS(f, files) {
259 r = network_load_one(manager, *f);
260 if (r < 0)
261 return r;
262 }
263
264 return 0;
265 }
266
267 void network_free(Network *network) {
268 NetDev *netdev;
269 Route *route;
270 Address *address;
271 FdbEntry *fdb_entry;
272 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
273 Iterator i;
274
275 if (!network)
276 return;
277
278 free(network->filename);
279
280 free(network->match_mac);
281 strv_free(network->match_path);
282 strv_free(network->match_driver);
283 strv_free(network->match_type);
284 strv_free(network->match_name);
285
286 free(network->description);
287 free(network->dhcp_vendor_class_identifier);
288 free(network->dhcp_hostname);
289
290 free(network->mac);
291
292 strv_free(network->ntp);
293 free(network->dns);
294 strv_free(network->search_domains);
295 strv_free(network->route_domains);
296 strv_free(network->bind_carrier);
297
298 netdev_unref(network->bridge);
299 netdev_unref(network->bond);
300 netdev_unref(network->vrf);
301
302 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
303 hashmap_remove(network->stacked_netdevs, netdev->ifname);
304 netdev_unref(netdev);
305 }
306 hashmap_free(network->stacked_netdevs);
307
308 while ((route = network->static_routes))
309 route_free(route);
310
311 while ((address = network->static_addresses))
312 address_free(address);
313
314 while ((fdb_entry = network->static_fdb_entries))
315 fdb_entry_free(fdb_entry);
316
317 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
318 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
319
320 hashmap_free(network->addresses_by_section);
321 hashmap_free(network->routes_by_section);
322 hashmap_free(network->fdb_entries_by_section);
323
324 if (network->manager) {
325 if (network->manager->networks)
326 LIST_REMOVE(networks, network->manager->networks, network);
327
328 if (network->manager->networks_by_name)
329 hashmap_remove(network->manager->networks_by_name, network->name);
330 }
331
332 free(network->name);
333
334 condition_free_list(network->match_host);
335 condition_free_list(network->match_virt);
336 condition_free_list(network->match_kernel);
337 condition_free_list(network->match_arch);
338
339 free(network->dhcp_server_timezone);
340 free(network->dhcp_server_dns);
341 free(network->dhcp_server_ntp);
342
343 set_free_free(network->dnssec_negative_trust_anchors);
344
345 free(network);
346 }
347
348 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
349 Network *network;
350
351 assert(manager);
352 assert(name);
353 assert(ret);
354
355 network = hashmap_get(manager->networks_by_name, name);
356 if (!network)
357 return -ENOENT;
358
359 *ret = network;
360
361 return 0;
362 }
363
364 int network_get(Manager *manager, struct udev_device *device,
365 const char *ifname, const struct ether_addr *address,
366 Network **ret) {
367 Network *network;
368 struct udev_device *parent;
369 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
370
371 assert(manager);
372 assert(ret);
373
374 if (device) {
375 path = udev_device_get_property_value(device, "ID_PATH");
376
377 parent = udev_device_get_parent(device);
378 if (parent)
379 parent_driver = udev_device_get_driver(parent);
380
381 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
382
383 devtype = udev_device_get_devtype(device);
384 }
385
386 LIST_FOREACH(networks, network, manager->networks) {
387 if (net_match_config(network->match_mac, network->match_path,
388 network->match_driver, network->match_type,
389 network->match_name, network->match_host,
390 network->match_virt, network->match_kernel,
391 network->match_arch,
392 address, path, parent_driver, driver,
393 devtype, ifname)) {
394 if (network->match_name && device) {
395 const char *attr;
396 uint8_t name_assign_type = NET_NAME_UNKNOWN;
397
398 attr = udev_device_get_sysattr_value(device, "name_assign_type");
399 if (attr)
400 (void) safe_atou8(attr, &name_assign_type);
401
402 if (name_assign_type == NET_NAME_ENUM)
403 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
404 ifname, network->filename);
405 else
406 log_debug("%s: found matching network '%s'", ifname, network->filename);
407 } else
408 log_debug("%s: found matching network '%s'", ifname, network->filename);
409
410 *ret = network;
411 return 0;
412 }
413 }
414
415 *ret = NULL;
416
417 return -ENOENT;
418 }
419
420 int network_apply(Network *network, Link *link) {
421 int r;
422
423 assert(network);
424 assert(link);
425
426 link->network = network;
427
428 if (network->ipv4ll_route) {
429 Route *route;
430
431 r = route_new_static(network, NULL, 0, &route);
432 if (r < 0)
433 return r;
434
435 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
436 if (r == 0)
437 return -EINVAL;
438 if (r < 0)
439 return -errno;
440
441 route->family = AF_INET;
442 route->dst_prefixlen = 16;
443 route->scope = RT_SCOPE_LINK;
444 route->priority = IPV4LL_ROUTE_METRIC;
445 route->protocol = RTPROT_STATIC;
446 }
447
448 if (network->n_dns > 0 ||
449 !strv_isempty(network->ntp) ||
450 !strv_isempty(network->search_domains) ||
451 !strv_isempty(network->route_domains))
452 link_dirty(link);
453
454 return 0;
455 }
456
457 bool network_has_static_ipv6_addresses(Network *network) {
458 Address *address;
459
460 assert(network);
461
462 LIST_FOREACH(addresses, address, network->static_addresses) {
463 if (address->family == AF_INET6)
464 return true;
465 }
466
467 return false;
468 }
469
470 int config_parse_netdev(const char *unit,
471 const char *filename,
472 unsigned line,
473 const char *section,
474 unsigned section_line,
475 const char *lvalue,
476 int ltype,
477 const char *rvalue,
478 void *data,
479 void *userdata) {
480 Network *network = userdata;
481 _cleanup_free_ char *kind_string = NULL;
482 char *p;
483 NetDev *netdev;
484 NetDevKind kind;
485 int r;
486
487 assert(filename);
488 assert(lvalue);
489 assert(rvalue);
490 assert(data);
491
492 kind_string = strdup(lvalue);
493 if (!kind_string)
494 return log_oom();
495
496 /* the keys are CamelCase versions of the kind */
497 for (p = kind_string; *p; p++)
498 *p = tolower(*p);
499
500 kind = netdev_kind_from_string(kind_string);
501 if (kind == _NETDEV_KIND_INVALID) {
502 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
503 return 0;
504 }
505
506 r = netdev_get(network->manager, rvalue, &netdev);
507 if (r < 0) {
508 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
509 return 0;
510 }
511
512 if (netdev->kind != kind) {
513 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
514 return 0;
515 }
516
517 switch (kind) {
518 case NETDEV_KIND_BRIDGE:
519 network->bridge = netdev;
520
521 break;
522 case NETDEV_KIND_BOND:
523 network->bond = netdev;
524
525 break;
526 case NETDEV_KIND_VRF:
527 network->vrf = netdev;
528
529 break;
530 case NETDEV_KIND_VLAN:
531 case NETDEV_KIND_MACVLAN:
532 case NETDEV_KIND_MACVTAP:
533 case NETDEV_KIND_IPVLAN:
534 case NETDEV_KIND_VXLAN:
535 case NETDEV_KIND_VCAN:
536 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
537 if (r < 0) {
538 log_syntax(unit, LOG_ERR, filename, line, r, "Can not add NetDev '%s' to network: %m", rvalue);
539 return 0;
540 }
541
542 break;
543 default:
544 assert_not_reached("Can not parse NetDev");
545 }
546
547 netdev_ref(netdev);
548
549 return 0;
550 }
551
552 int config_parse_domains(
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 const char *p;
565 Network *n = data;
566 int r;
567
568 assert(n);
569 assert(lvalue);
570 assert(rvalue);
571
572 if (isempty(rvalue)) {
573 n->search_domains = strv_free(n->search_domains);
574 n->route_domains = strv_free(n->route_domains);
575 return 0;
576 }
577
578 p = rvalue;
579 for (;;) {
580 _cleanup_free_ char *w = NULL, *normalized = NULL;
581 const char *domain;
582 bool is_route;
583
584 r = extract_first_word(&p, &w, NULL, 0);
585 if (r < 0) {
586 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
587 break;
588 }
589 if (r == 0)
590 break;
591
592 is_route = w[0] == '~';
593 domain = is_route ? w + 1 : w;
594
595 if (dns_name_is_root(domain) || streq(domain, "*")) {
596 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
597 * routing domain, unconditionally. */
598 is_route = true;
599 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
600
601 } else {
602 r = dns_name_normalize(domain, &normalized);
603 if (r < 0) {
604 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
605 continue;
606 }
607
608 domain = normalized;
609
610 if (is_localhost(domain)) {
611 log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain);
612 continue;
613 }
614 }
615
616 if (is_route) {
617 r = strv_extend(&n->route_domains, domain);
618 if (r < 0)
619 return log_oom();
620
621 } else {
622 r = strv_extend(&n->search_domains, domain);
623 if (r < 0)
624 return log_oom();
625 }
626 }
627
628 strv_uniq(n->route_domains);
629 strv_uniq(n->search_domains);
630
631 return 0;
632 }
633
634 int config_parse_tunnel(const char *unit,
635 const char *filename,
636 unsigned line,
637 const char *section,
638 unsigned section_line,
639 const char *lvalue,
640 int ltype,
641 const char *rvalue,
642 void *data,
643 void *userdata) {
644 Network *network = userdata;
645 NetDev *netdev;
646 int r;
647
648 assert(filename);
649 assert(lvalue);
650 assert(rvalue);
651 assert(data);
652
653 r = netdev_get(network->manager, rvalue, &netdev);
654 if (r < 0) {
655 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
656 return 0;
657 }
658
659 if (netdev->kind != NETDEV_KIND_IPIP &&
660 netdev->kind != NETDEV_KIND_SIT &&
661 netdev->kind != NETDEV_KIND_GRE &&
662 netdev->kind != NETDEV_KIND_GRETAP &&
663 netdev->kind != NETDEV_KIND_IP6GRE &&
664 netdev->kind != NETDEV_KIND_IP6GRETAP &&
665 netdev->kind != NETDEV_KIND_VTI &&
666 netdev->kind != NETDEV_KIND_VTI6 &&
667 netdev->kind != NETDEV_KIND_IP6TNL
668 ) {
669 log_syntax(unit, LOG_ERR, filename, line, 0,
670 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
671 return 0;
672 }
673
674 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
675 if (r < 0) {
676 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
677 return 0;
678 }
679
680 netdev_ref(netdev);
681
682 return 0;
683 }
684
685 int config_parse_ipv4ll(
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 AddressFamilyBoolean *link_local = data;
698
699 assert(filename);
700 assert(lvalue);
701 assert(rvalue);
702 assert(data);
703
704 /* Note that this is mostly like
705 * config_parse_address_family_boolean(), except that it
706 * applies only to IPv4 */
707
708 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
709
710 return 0;
711 }
712
713 int config_parse_dhcp(
714 const char* unit,
715 const char *filename,
716 unsigned line,
717 const char *section,
718 unsigned section_line,
719 const char *lvalue,
720 int ltype,
721 const char *rvalue,
722 void *data,
723 void *userdata) {
724
725 AddressFamilyBoolean *dhcp = data, s;
726
727 assert(filename);
728 assert(lvalue);
729 assert(rvalue);
730 assert(data);
731
732 /* Note that this is mostly like
733 * config_parse_address_family_boolean(), except that it
734 * understands some old names for the enum values */
735
736 s = address_family_boolean_from_string(rvalue);
737 if (s < 0) {
738
739 /* Previously, we had a slightly different enum here,
740 * support its values for compatbility. */
741
742 if (streq(rvalue, "none"))
743 s = ADDRESS_FAMILY_NO;
744 else if (streq(rvalue, "v4"))
745 s = ADDRESS_FAMILY_IPV4;
746 else if (streq(rvalue, "v6"))
747 s = ADDRESS_FAMILY_IPV6;
748 else if (streq(rvalue, "both"))
749 s = ADDRESS_FAMILY_YES;
750 else {
751 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
752 return 0;
753 }
754 }
755
756 *dhcp = s;
757 return 0;
758 }
759
760 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
761 [DHCP_CLIENT_ID_MAC] = "mac",
762 [DHCP_CLIENT_ID_DUID] = "duid"
763 };
764
765 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
766 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
767
768 int config_parse_ipv6token(
769 const char* unit,
770 const char *filename,
771 unsigned line,
772 const char *section,
773 unsigned section_line,
774 const char *lvalue,
775 int ltype,
776 const char *rvalue,
777 void *data,
778 void *userdata) {
779
780 union in_addr_union buffer;
781 struct in6_addr *token = data;
782 int r;
783
784 assert(filename);
785 assert(lvalue);
786 assert(rvalue);
787 assert(token);
788
789 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
790 if (r < 0) {
791 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
792 return 0;
793 }
794
795 r = in_addr_is_null(AF_INET6, &buffer);
796 if (r != 0) {
797 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
798 return 0;
799 }
800
801 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
802 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
803 return 0;
804 }
805
806 *token = buffer.in6;
807
808 return 0;
809 }
810
811 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
812 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
813 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
814 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
815 };
816
817 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
818
819 int config_parse_ipv6_privacy_extensions(
820 const char* unit,
821 const char *filename,
822 unsigned line,
823 const char *section,
824 unsigned section_line,
825 const char *lvalue,
826 int ltype,
827 const char *rvalue,
828 void *data,
829 void *userdata) {
830
831 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
832 int k;
833
834 assert(filename);
835 assert(lvalue);
836 assert(rvalue);
837 assert(ipv6_privacy_extensions);
838
839 /* Our enum shall be a superset of booleans, hence first try
840 * to parse as boolean, and then as enum */
841
842 k = parse_boolean(rvalue);
843 if (k > 0)
844 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
845 else if (k == 0)
846 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
847 else {
848 IPv6PrivacyExtensions s;
849
850 s = ipv6_privacy_extensions_from_string(rvalue);
851 if (s < 0) {
852
853 if (streq(rvalue, "kernel"))
854 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
855 else {
856 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
857 return 0;
858 }
859 }
860
861 *ipv6_privacy_extensions = s;
862 }
863
864 return 0;
865 }
866
867 int config_parse_hostname(
868 const char *unit,
869 const char *filename,
870 unsigned line,
871 const char *section,
872 unsigned section_line,
873 const char *lvalue,
874 int ltype,
875 const char *rvalue,
876 void *data,
877 void *userdata) {
878
879 char **hostname = data, *hn = NULL;
880 int r;
881
882 assert(filename);
883 assert(lvalue);
884 assert(rvalue);
885
886 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
887 if (r < 0)
888 return r;
889
890 if (!hostname_is_valid(hn, false)) {
891 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
892 free(hn);
893 return 0;
894 }
895
896 free(*hostname);
897 *hostname = hostname_cleanup(hn);
898 return 0;
899 }
900
901 int config_parse_timezone(
902 const char *unit,
903 const char *filename,
904 unsigned line,
905 const char *section,
906 unsigned section_line,
907 const char *lvalue,
908 int ltype,
909 const char *rvalue,
910 void *data,
911 void *userdata) {
912
913 char **datap = data, *tz = NULL;
914 int r;
915
916 assert(filename);
917 assert(lvalue);
918 assert(rvalue);
919
920 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
921 if (r < 0)
922 return r;
923
924 if (!timezone_is_valid(tz)) {
925 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
926 free(tz);
927 return 0;
928 }
929
930 free(*datap);
931 *datap = tz;
932
933 return 0;
934 }
935
936 int config_parse_dhcp_server_dns(
937 const char *unit,
938 const char *filename,
939 unsigned line,
940 const char *section,
941 unsigned section_line,
942 const char *lvalue,
943 int ltype,
944 const char *rvalue,
945 void *data,
946 void *userdata) {
947
948 Network *n = data;
949 const char *p = rvalue;
950 int r;
951
952 assert(filename);
953 assert(lvalue);
954 assert(rvalue);
955
956 for (;;) {
957 _cleanup_free_ char *w = NULL;
958 struct in_addr a, *m;
959
960 r = extract_first_word(&p, &w, NULL, 0);
961 if (r == -ENOMEM)
962 return log_oom();
963 if (r < 0) {
964 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
965 return 0;
966 }
967 if (r == 0)
968 break;
969
970 if (inet_pton(AF_INET, w, &a) <= 0) {
971 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
972 continue;
973 }
974
975 m = realloc(n->dhcp_server_dns, (n->n_dhcp_server_dns + 1) * sizeof(struct in_addr));
976 if (!m)
977 return log_oom();
978
979 m[n->n_dhcp_server_dns++] = a;
980 n->dhcp_server_dns = m;
981 }
982
983 return 0;
984 }
985
986 int config_parse_dhcp_server_ntp(
987 const char *unit,
988 const char *filename,
989 unsigned line,
990 const char *section,
991 unsigned section_line,
992 const char *lvalue,
993 int ltype,
994 const char *rvalue,
995 void *data,
996 void *userdata) {
997
998 Network *n = data;
999 const char *p = rvalue;
1000 int r;
1001
1002 assert(filename);
1003 assert(lvalue);
1004 assert(rvalue);
1005
1006 for (;;) {
1007 _cleanup_free_ char *w = NULL;
1008 struct in_addr a, *m;
1009
1010 r = extract_first_word(&p, &w, NULL, 0);
1011 if (r == -ENOMEM)
1012 return log_oom();
1013 if (r < 0) {
1014 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1015 return 0;
1016 }
1017 if (r == 0)
1018 return 0;
1019
1020 if (inet_pton(AF_INET, w, &a) <= 0) {
1021 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1022 continue;
1023 }
1024
1025 m = realloc(n->dhcp_server_ntp, (n->n_dhcp_server_ntp + 1) * sizeof(struct in_addr));
1026 if (!m)
1027 return log_oom();
1028
1029 m[n->n_dhcp_server_ntp++] = a;
1030 n->dhcp_server_ntp = m;
1031 }
1032 }
1033
1034 int config_parse_dns(
1035 const char *unit,
1036 const char *filename,
1037 unsigned line,
1038 const char *section,
1039 unsigned section_line,
1040 const char *lvalue,
1041 int ltype,
1042 const char *rvalue,
1043 void *data,
1044 void *userdata) {
1045
1046 Network *n = userdata;
1047 int r;
1048
1049 assert(filename);
1050 assert(lvalue);
1051 assert(rvalue);
1052
1053 for (;;) {
1054 _cleanup_free_ char *w = NULL;
1055 union in_addr_union a;
1056 struct in_addr_data *m;
1057 int family;
1058
1059 r = extract_first_word(&rvalue, &w, NULL, 0);
1060 if (r == -ENOMEM)
1061 return log_oom();
1062 if (r < 0) {
1063 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1064 break;
1065 }
1066 if (r == 0)
1067 break;
1068
1069 r = in_addr_from_string_auto(w, &family, &a);
1070 if (r < 0) {
1071 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
1072 continue;
1073 }
1074
1075 m = realloc(n->dns, (n->n_dns + 1) * sizeof(struct in_addr_data));
1076 if (!m)
1077 return log_oom();
1078
1079 m[n->n_dns++] = (struct in_addr_data) {
1080 .family = family,
1081 .address = a,
1082 };
1083
1084 n->dns = m;
1085 }
1086
1087 return 0;
1088 }
1089
1090 int config_parse_dnssec_negative_trust_anchors(
1091 const char *unit,
1092 const char *filename,
1093 unsigned line,
1094 const char *section,
1095 unsigned section_line,
1096 const char *lvalue,
1097 int ltype,
1098 const char *rvalue,
1099 void *data,
1100 void *userdata) {
1101
1102 const char *p = rvalue;
1103 Network *n = data;
1104 int r;
1105
1106 assert(n);
1107 assert(lvalue);
1108 assert(rvalue);
1109
1110 if (isempty(rvalue)) {
1111 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1112 return 0;
1113 }
1114
1115 for (;;) {
1116 _cleanup_free_ char *w = NULL;
1117
1118 r = extract_first_word(&p, &w, NULL, 0);
1119 if (r < 0) {
1120 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1121 break;
1122 }
1123 if (r == 0)
1124 break;
1125
1126 r = dns_name_is_valid(w);
1127 if (r <= 0) {
1128 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1129 continue;
1130 }
1131
1132 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1133 if (r < 0)
1134 return log_oom();
1135
1136 r = set_put(n->dnssec_negative_trust_anchors, w);
1137 if (r < 0)
1138 return log_oom();
1139 if (r > 0)
1140 w = NULL;
1141 }
1142
1143 return 0;
1144 }
1145
1146 int config_parse_ntp(
1147 const char *unit,
1148 const char *filename,
1149 unsigned line,
1150 const char *section,
1151 unsigned section_line,
1152 const char *lvalue,
1153 int ltype,
1154 const char *rvalue,
1155 void *data,
1156 void *userdata) {
1157
1158 char ***l = data;
1159 int r;
1160
1161 assert(l);
1162 assert(lvalue);
1163 assert(rvalue);
1164
1165 if (isempty(rvalue)) {
1166 *l = strv_free(*l);
1167 return 0;
1168 }
1169
1170 for (;;) {
1171 _cleanup_free_ char *w = NULL;
1172
1173 r = extract_first_word(&rvalue, &w, NULL, 0);
1174 if (r == -ENOMEM)
1175 return log_oom();
1176 if (r < 0) {
1177 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1178 break;
1179 }
1180 if (r == 0)
1181 break;
1182
1183 r = dns_name_is_valid_or_address(w);
1184 if (r <= 0) {
1185 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1186 continue;
1187 }
1188
1189 r = strv_push(l, w);
1190 if (r < 0)
1191 return log_oom();
1192
1193 w = NULL;
1194 }
1195
1196 return 0;
1197 }
1198
1199 int config_parse_dhcp_route_table(const char *unit,
1200 const char *filename,
1201 unsigned line,
1202 const char *section,
1203 unsigned section_line,
1204 const char *lvalue,
1205 int ltype,
1206 const char *rvalue,
1207 void *data,
1208 void *userdata) {
1209 uint32_t rt;
1210 int r;
1211
1212 assert(filename);
1213 assert(lvalue);
1214 assert(rvalue);
1215 assert(data);
1216
1217 r = safe_atou32(rvalue, &rt);
1218 if (r < 0) {
1219 log_syntax(unit, LOG_ERR, filename, line, r,
1220 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1221 return 0;
1222 }
1223
1224 *((uint32_t *)data) = rt;
1225
1226 return 0;
1227 }
1228
1229 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1230
1231 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1232 [DHCP_USE_DOMAINS_NO] = "no",
1233 [DHCP_USE_DOMAINS_ROUTE] = "route",
1234 [DHCP_USE_DOMAINS_YES] = "yes",
1235 };
1236
1237 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1238
1239 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1240
1241 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1242 [LLDP_MODE_NO] = "no",
1243 [LLDP_MODE_YES] = "yes",
1244 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1245 };
1246
1247 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);