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