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