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