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