]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
1f1cdced8f12e76810edf9abf853c4a27db1c5f0
[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 if (x->line < y->line)
40 return -1;
41 if (x->line > y->line)
42 return 1;
43
44 return 0;
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 network->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID;
240
241 network->link_local = ADDRESS_FAMILY_IPV6;
242
243 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
244 network->ipv6_accept_ra = -1;
245 network->ipv6_dad_transmits = -1;
246 network->ipv6_hop_limit = -1;
247 network->ipv6_proxy_ndp = -1;
248 network->duid.type = _DUID_TYPE_INVALID;
249 network->proxy_arp = -1;
250 network->arp = -1;
251 network->multicast = -1;
252 network->allmulticast = -1;
253 network->ipv6_accept_ra_use_dns = true;
254 network->ipv6_accept_ra_route_table = RT_TABLE_MAIN;
255 network->ipv6_mtu = 0;
256
257 dropin_dirname = strjoina(network->name, ".network.d");
258
259 r = config_parse_many(filename, network_dirs, dropin_dirname,
260 "Match\0"
261 "Link\0"
262 "Network\0"
263 "Address\0"
264 "IPv6AddressLabel\0"
265 "RoutingPolicyRule\0"
266 "Route\0"
267 "DHCP\0"
268 "DHCPv4\0" /* compat */
269 "DHCPServer\0"
270 "IPv6AcceptRA\0"
271 "IPv6NDPProxyAddress\0"
272 "Bridge\0"
273 "BridgeFDB\0"
274 "BridgeVLAN\0"
275 "IPv6PrefixDelegation\0"
276 "IPv6Prefix\0"
277 "CAN\0",
278 config_item_perf_lookup, network_network_gperf_lookup,
279 CONFIG_PARSE_WARN, network);
280 if (r < 0)
281 return r;
282
283 network_apply_anonymize_if_set(network);
284
285 /* IPMasquerade=yes implies IPForward=yes */
286 if (network->ip_masquerade)
287 network->ip_forward |= ADDRESS_FAMILY_IPV4;
288
289 LIST_PREPEND(networks, manager->networks, network);
290
291 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
292 if (r < 0)
293 return r;
294
295 r = hashmap_put(manager->networks_by_name, network->name, network);
296 if (r < 0)
297 return r;
298
299 LIST_FOREACH(routes, route, network->static_routes) {
300 if (!route->family) {
301 log_warning("Route section without Gateway field configured in %s. "
302 "Ignoring", filename);
303 return 0;
304 }
305 }
306
307 LIST_FOREACH(addresses, address, network->static_addresses) {
308 if (!address->family) {
309 log_warning("Address section without Address field configured in %s. "
310 "Ignoring", filename);
311 return 0;
312 }
313 }
314
315 network = NULL;
316
317 return 0;
318 }
319
320 int network_load(Manager *manager) {
321 Network *network;
322 _cleanup_strv_free_ char **files = NULL;
323 char **f;
324 int r;
325
326 assert(manager);
327
328 while ((network = manager->networks))
329 network_free(network);
330
331 r = conf_files_list_strv(&files, ".network", NULL, 0, network_dirs);
332 if (r < 0)
333 return log_error_errno(r, "Failed to enumerate network files: %m");
334
335 STRV_FOREACH_BACKWARDS(f, files) {
336 r = network_load_one(manager, *f);
337 if (r < 0)
338 return r;
339 }
340
341 return 0;
342 }
343
344 void network_free(Network *network) {
345 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
346 RoutingPolicyRule *rule;
347 FdbEntry *fdb_entry;
348 AddressLabel *label;
349 Prefix *prefix;
350 Address *address;
351 NetDev *netdev;
352 Route *route;
353 Iterator i;
354
355 if (!network)
356 return;
357
358 free(network->filename);
359
360 set_free_free(network->match_mac);
361 strv_free(network->match_path);
362 strv_free(network->match_driver);
363 strv_free(network->match_type);
364 strv_free(network->match_name);
365
366 free(network->description);
367 free(network->dhcp_vendor_class_identifier);
368 strv_free(network->dhcp_user_class);
369 free(network->dhcp_hostname);
370
371 free(network->mac);
372
373 strv_free(network->ntp);
374 free(network->dns);
375 strv_free(network->search_domains);
376 strv_free(network->route_domains);
377 strv_free(network->bind_carrier);
378
379 netdev_unref(network->bridge);
380 netdev_unref(network->bond);
381 netdev_unref(network->vrf);
382
383 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
384 hashmap_remove(network->stacked_netdevs, netdev->ifname);
385 netdev_unref(netdev);
386 }
387 hashmap_free(network->stacked_netdevs);
388
389 while ((route = network->static_routes))
390 route_free(route);
391
392 while ((address = network->static_addresses))
393 address_free(address);
394
395 while ((fdb_entry = network->static_fdb_entries))
396 fdb_entry_free(fdb_entry);
397
398 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
399 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
400
401 while ((label = network->address_labels))
402 address_label_free(label);
403
404 while ((prefix = network->static_prefixes))
405 prefix_free(prefix);
406
407 while ((rule = network->rules))
408 routing_policy_rule_free(rule);
409
410 hashmap_free(network->addresses_by_section);
411 hashmap_free(network->routes_by_section);
412 hashmap_free(network->fdb_entries_by_section);
413 hashmap_free(network->address_labels_by_section);
414 hashmap_free(network->prefixes_by_section);
415 hashmap_free(network->rules_by_section);
416
417 if (network->manager) {
418 if (network->manager->networks)
419 LIST_REMOVE(networks, network->manager->networks, network);
420
421 if (network->manager->networks_by_name)
422 hashmap_remove(network->manager->networks_by_name, network->name);
423 }
424
425 free(network->name);
426
427 condition_free_list(network->match_host);
428 condition_free_list(network->match_virt);
429 condition_free_list(network->match_kernel_cmdline);
430 condition_free_list(network->match_kernel_version);
431 condition_free_list(network->match_arch);
432
433 free(network->dhcp_server_timezone);
434 free(network->dhcp_server_dns);
435 free(network->dhcp_server_ntp);
436
437 set_free_free(network->dnssec_negative_trust_anchors);
438
439 free(network);
440 }
441
442 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
443 Network *network;
444
445 assert(manager);
446 assert(name);
447 assert(ret);
448
449 network = hashmap_get(manager->networks_by_name, name);
450 if (!network)
451 return -ENOENT;
452
453 *ret = network;
454
455 return 0;
456 }
457
458 int network_get(Manager *manager, struct udev_device *device,
459 const char *ifname, const struct ether_addr *address,
460 Network **ret) {
461 Network *network;
462 struct udev_device *parent;
463 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
464
465 assert(manager);
466 assert(ret);
467
468 if (device) {
469 path = udev_device_get_property_value(device, "ID_PATH");
470
471 parent = udev_device_get_parent(device);
472 if (parent)
473 parent_driver = udev_device_get_driver(parent);
474
475 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
476
477 devtype = udev_device_get_devtype(device);
478 }
479
480 LIST_FOREACH(networks, network, manager->networks) {
481 if (net_match_config(network->match_mac, network->match_path,
482 network->match_driver, network->match_type,
483 network->match_name, network->match_host,
484 network->match_virt, network->match_kernel_cmdline,
485 network->match_kernel_version, network->match_arch,
486 address, path, parent_driver, driver,
487 devtype, ifname)) {
488 if (network->match_name && device) {
489 const char *attr;
490 uint8_t name_assign_type = NET_NAME_UNKNOWN;
491
492 attr = udev_device_get_sysattr_value(device, "name_assign_type");
493 if (attr)
494 (void) safe_atou8(attr, &name_assign_type);
495
496 if (name_assign_type == NET_NAME_ENUM)
497 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
498 ifname, network->filename);
499 else
500 log_debug("%s: found matching network '%s'", ifname, network->filename);
501 } else
502 log_debug("%s: found matching network '%s'", ifname, network->filename);
503
504 *ret = network;
505 return 0;
506 }
507 }
508
509 *ret = NULL;
510
511 return -ENOENT;
512 }
513
514 int network_apply(Network *network, Link *link) {
515 int r;
516
517 assert(network);
518 assert(link);
519
520 link->network = network;
521
522 if (network->ipv4ll_route) {
523 Route *route;
524
525 r = route_new_static(network, NULL, 0, &route);
526 if (r < 0)
527 return r;
528
529 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
530 if (r == 0)
531 return -EINVAL;
532 if (r < 0)
533 return -errno;
534
535 route->family = AF_INET;
536 route->dst_prefixlen = 16;
537 route->scope = RT_SCOPE_LINK;
538 route->priority = IPV4LL_ROUTE_METRIC;
539 route->protocol = RTPROT_STATIC;
540 }
541
542 if (network->n_dns > 0 ||
543 !strv_isempty(network->ntp) ||
544 !strv_isempty(network->search_domains) ||
545 !strv_isempty(network->route_domains))
546 link_dirty(link);
547
548 return 0;
549 }
550
551 bool network_has_static_ipv6_addresses(Network *network) {
552 Address *address;
553
554 assert(network);
555
556 LIST_FOREACH(addresses, address, network->static_addresses) {
557 if (address->family == AF_INET6)
558 return true;
559 }
560
561 return false;
562 }
563
564 int config_parse_netdev(const char *unit,
565 const char *filename,
566 unsigned line,
567 const char *section,
568 unsigned section_line,
569 const char *lvalue,
570 int ltype,
571 const char *rvalue,
572 void *data,
573 void *userdata) {
574 Network *network = userdata;
575 _cleanup_free_ char *kind_string = NULL;
576 char *p;
577 NetDev *netdev;
578 NetDevKind kind;
579 int r;
580
581 assert(filename);
582 assert(lvalue);
583 assert(rvalue);
584 assert(data);
585
586 kind_string = strdup(lvalue);
587 if (!kind_string)
588 return log_oom();
589
590 /* the keys are CamelCase versions of the kind */
591 for (p = kind_string; *p; p++)
592 *p = tolower(*p);
593
594 kind = netdev_kind_from_string(kind_string);
595 if (kind == _NETDEV_KIND_INVALID) {
596 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
597 return 0;
598 }
599
600 r = netdev_get(network->manager, rvalue, &netdev);
601 if (r < 0) {
602 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
603 return 0;
604 }
605
606 if (netdev->kind != kind) {
607 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
608 return 0;
609 }
610
611 switch (kind) {
612 case NETDEV_KIND_BRIDGE:
613 network->bridge = netdev;
614
615 break;
616 case NETDEV_KIND_BOND:
617 network->bond = netdev;
618
619 break;
620 case NETDEV_KIND_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 char **hostname = data, *hn = NULL;
975 int r;
976
977 assert(filename);
978 assert(lvalue);
979 assert(rvalue);
980
981 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
982 if (r < 0)
983 return r;
984
985 if (!hostname_is_valid(hn, false)) {
986 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
987 free(hn);
988 return 0;
989 }
990
991 free(*hostname);
992 *hostname = hostname_cleanup(hn);
993 return 0;
994 }
995
996 int config_parse_timezone(
997 const char *unit,
998 const char *filename,
999 unsigned line,
1000 const char *section,
1001 unsigned section_line,
1002 const char *lvalue,
1003 int ltype,
1004 const char *rvalue,
1005 void *data,
1006 void *userdata) {
1007
1008 char **datap = data, *tz = NULL;
1009 int r;
1010
1011 assert(filename);
1012 assert(lvalue);
1013 assert(rvalue);
1014
1015 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1016 if (r < 0)
1017 return r;
1018
1019 if (!timezone_is_valid(tz, LOG_ERR)) {
1020 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
1021 free(tz);
1022 return 0;
1023 }
1024
1025 free(*datap);
1026 *datap = tz;
1027
1028 return 0;
1029 }
1030
1031 int config_parse_dhcp_server_dns(
1032 const char *unit,
1033 const char *filename,
1034 unsigned line,
1035 const char *section,
1036 unsigned section_line,
1037 const char *lvalue,
1038 int ltype,
1039 const char *rvalue,
1040 void *data,
1041 void *userdata) {
1042
1043 Network *n = data;
1044 const char *p = rvalue;
1045 int r;
1046
1047 assert(filename);
1048 assert(lvalue);
1049 assert(rvalue);
1050
1051 for (;;) {
1052 _cleanup_free_ char *w = NULL;
1053 struct in_addr a, *m;
1054
1055 r = extract_first_word(&p, &w, NULL, 0);
1056 if (r == -ENOMEM)
1057 return log_oom();
1058 if (r < 0) {
1059 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1060 return 0;
1061 }
1062 if (r == 0)
1063 break;
1064
1065 if (inet_pton(AF_INET, w, &a) <= 0) {
1066 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1067 continue;
1068 }
1069
1070 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1071 if (!m)
1072 return log_oom();
1073
1074 m[n->n_dhcp_server_dns++] = a;
1075 n->dhcp_server_dns = m;
1076 }
1077
1078 return 0;
1079 }
1080
1081 int config_parse_radv_dns(
1082 const char *unit,
1083 const char *filename,
1084 unsigned line,
1085 const char *section,
1086 unsigned section_line,
1087 const char *lvalue,
1088 int ltype,
1089 const char *rvalue,
1090 void *data,
1091 void *userdata) {
1092
1093 Network *n = data;
1094 const char *p = rvalue;
1095 int r;
1096
1097 assert(filename);
1098 assert(lvalue);
1099 assert(rvalue);
1100
1101 for (;;) {
1102 _cleanup_free_ char *w = NULL;
1103 union in_addr_union a;
1104
1105 r = extract_first_word(&p, &w, NULL, 0);
1106 if (r == -ENOMEM)
1107 return log_oom();
1108 if (r < 0) {
1109 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1110 return 0;
1111 }
1112 if (r == 0)
1113 break;
1114
1115 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1116 struct in6_addr *m;
1117
1118 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
1119 if (!m)
1120 return log_oom();
1121
1122 m[n->n_router_dns++] = a.in6;
1123 n->router_dns = m;
1124
1125 } else
1126 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1127
1128 }
1129
1130 return 0;
1131 }
1132
1133 int config_parse_radv_search_domains(
1134 const char *unit,
1135 const char *filename,
1136 unsigned line,
1137 const char *section,
1138 unsigned section_line,
1139 const char *lvalue,
1140 int ltype,
1141 const char *rvalue,
1142 void *data,
1143 void *userdata) {
1144
1145 Network *n = data;
1146 const char *p = rvalue;
1147 int r;
1148
1149 assert(filename);
1150 assert(lvalue);
1151 assert(rvalue);
1152
1153 for (;;) {
1154 _cleanup_free_ char *w = NULL;
1155 _cleanup_free_ char *idna = NULL;
1156
1157 r = extract_first_word(&p, &w, NULL, 0);
1158 if (r == -ENOMEM)
1159 return log_oom();
1160 if (r < 0) {
1161 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1162 return 0;
1163 }
1164 if (r == 0)
1165 break;
1166
1167 r = dns_name_apply_idna(w, &idna);
1168 if (r > 0) {
1169 r = strv_push(&n->router_search_domains, idna);
1170 if (r >= 0)
1171 idna = NULL;
1172 } else if (r == 0) {
1173 r = strv_push(&n->router_search_domains, w);
1174 if (r >= 0)
1175 w = NULL;
1176 }
1177 }
1178
1179 return 0;
1180 }
1181
1182 int config_parse_dhcp_server_ntp(
1183 const char *unit,
1184 const char *filename,
1185 unsigned line,
1186 const char *section,
1187 unsigned section_line,
1188 const char *lvalue,
1189 int ltype,
1190 const char *rvalue,
1191 void *data,
1192 void *userdata) {
1193
1194 Network *n = data;
1195 const char *p = rvalue;
1196 int r;
1197
1198 assert(filename);
1199 assert(lvalue);
1200 assert(rvalue);
1201
1202 for (;;) {
1203 _cleanup_free_ char *w = NULL;
1204 struct in_addr a, *m;
1205
1206 r = extract_first_word(&p, &w, NULL, 0);
1207 if (r == -ENOMEM)
1208 return log_oom();
1209 if (r < 0) {
1210 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1211 return 0;
1212 }
1213 if (r == 0)
1214 return 0;
1215
1216 if (inet_pton(AF_INET, w, &a) <= 0) {
1217 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1218 continue;
1219 }
1220
1221 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1222 if (!m)
1223 return log_oom();
1224
1225 m[n->n_dhcp_server_ntp++] = a;
1226 n->dhcp_server_ntp = m;
1227 }
1228 }
1229
1230 int config_parse_dns(
1231 const char *unit,
1232 const char *filename,
1233 unsigned line,
1234 const char *section,
1235 unsigned section_line,
1236 const char *lvalue,
1237 int ltype,
1238 const char *rvalue,
1239 void *data,
1240 void *userdata) {
1241
1242 Network *n = userdata;
1243 int r;
1244
1245 assert(filename);
1246 assert(lvalue);
1247 assert(rvalue);
1248
1249 for (;;) {
1250 _cleanup_free_ char *w = NULL;
1251 union in_addr_union a;
1252 struct in_addr_data *m;
1253 int family;
1254
1255 r = extract_first_word(&rvalue, &w, NULL, 0);
1256 if (r == -ENOMEM)
1257 return log_oom();
1258 if (r < 0) {
1259 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1260 break;
1261 }
1262 if (r == 0)
1263 break;
1264
1265 r = in_addr_from_string_auto(w, &family, &a);
1266 if (r < 0) {
1267 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
1268 continue;
1269 }
1270
1271 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
1272 if (!m)
1273 return log_oom();
1274
1275 m[n->n_dns++] = (struct in_addr_data) {
1276 .family = family,
1277 .address = a,
1278 };
1279
1280 n->dns = m;
1281 }
1282
1283 return 0;
1284 }
1285
1286 int config_parse_dnssec_negative_trust_anchors(
1287 const char *unit,
1288 const char *filename,
1289 unsigned line,
1290 const char *section,
1291 unsigned section_line,
1292 const char *lvalue,
1293 int ltype,
1294 const char *rvalue,
1295 void *data,
1296 void *userdata) {
1297
1298 const char *p = rvalue;
1299 Network *n = data;
1300 int r;
1301
1302 assert(n);
1303 assert(lvalue);
1304 assert(rvalue);
1305
1306 if (isempty(rvalue)) {
1307 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1308 return 0;
1309 }
1310
1311 for (;;) {
1312 _cleanup_free_ char *w = NULL;
1313
1314 r = extract_first_word(&p, &w, NULL, 0);
1315 if (r < 0) {
1316 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1317 break;
1318 }
1319 if (r == 0)
1320 break;
1321
1322 r = dns_name_is_valid(w);
1323 if (r <= 0) {
1324 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1325 continue;
1326 }
1327
1328 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1329 if (r < 0)
1330 return log_oom();
1331
1332 r = set_put(n->dnssec_negative_trust_anchors, w);
1333 if (r < 0)
1334 return log_oom();
1335 if (r > 0)
1336 w = NULL;
1337 }
1338
1339 return 0;
1340 }
1341
1342 int config_parse_ntp(
1343 const char *unit,
1344 const char *filename,
1345 unsigned line,
1346 const char *section,
1347 unsigned section_line,
1348 const char *lvalue,
1349 int ltype,
1350 const char *rvalue,
1351 void *data,
1352 void *userdata) {
1353
1354 char ***l = data;
1355 int r;
1356
1357 assert(l);
1358 assert(lvalue);
1359 assert(rvalue);
1360
1361 if (isempty(rvalue)) {
1362 *l = strv_free(*l);
1363 return 0;
1364 }
1365
1366 for (;;) {
1367 _cleanup_free_ char *w = NULL;
1368
1369 r = extract_first_word(&rvalue, &w, NULL, 0);
1370 if (r == -ENOMEM)
1371 return log_oom();
1372 if (r < 0) {
1373 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1374 break;
1375 }
1376 if (r == 0)
1377 break;
1378
1379 r = dns_name_is_valid_or_address(w);
1380 if (r <= 0) {
1381 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1382 continue;
1383 }
1384
1385 r = strv_push(l, w);
1386 if (r < 0)
1387 return log_oom();
1388
1389 w = NULL;
1390 }
1391
1392 return 0;
1393 }
1394
1395 int config_parse_dhcp_user_class(
1396 const char *unit,
1397 const char *filename,
1398 unsigned line,
1399 const char *section,
1400 unsigned section_line,
1401 const char *lvalue,
1402 int ltype,
1403 const char *rvalue,
1404 void *data,
1405 void *userdata) {
1406
1407 char ***l = data;
1408 int r;
1409
1410 assert(l);
1411 assert(lvalue);
1412 assert(rvalue);
1413
1414 if (isempty(rvalue)) {
1415 *l = strv_free(*l);
1416 return 0;
1417 }
1418
1419 for (;;) {
1420 _cleanup_free_ char *w = NULL;
1421
1422 r = extract_first_word(&rvalue, &w, NULL, 0);
1423 if (r == -ENOMEM)
1424 return log_oom();
1425 if (r < 0) {
1426 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split user classes option, ignoring: %s", rvalue);
1427 break;
1428 }
1429 if (r == 0)
1430 break;
1431
1432 if (strlen(w) > 255) {
1433 log_syntax(unit, LOG_ERR, filename, line, r, "%s length is not in the range 1-255, ignoring.", w);
1434 continue;
1435 }
1436
1437 r = strv_push(l, w);
1438 if (r < 0)
1439 return log_oom();
1440
1441 w = NULL;
1442 }
1443
1444 return 0;
1445 }
1446
1447 int config_parse_dhcp_route_table(const char *unit,
1448 const char *filename,
1449 unsigned line,
1450 const char *section,
1451 unsigned section_line,
1452 const char *lvalue,
1453 int ltype,
1454 const char *rvalue,
1455 void *data,
1456 void *userdata) {
1457 Network *network = data;
1458 uint32_t rt;
1459 int r;
1460
1461 assert(filename);
1462 assert(lvalue);
1463 assert(rvalue);
1464 assert(data);
1465
1466 r = safe_atou32(rvalue, &rt);
1467 if (r < 0) {
1468 log_syntax(unit, LOG_ERR, filename, line, r,
1469 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1470 return 0;
1471 }
1472
1473 network->dhcp_route_table = rt;
1474 network->dhcp_route_table_set = true;
1475
1476 return 0;
1477 }
1478
1479 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1480
1481 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1482 [DHCP_USE_DOMAINS_NO] = "no",
1483 [DHCP_USE_DOMAINS_ROUTE] = "route",
1484 [DHCP_USE_DOMAINS_YES] = "yes",
1485 };
1486
1487 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1488
1489 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1490
1491 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1492 [LLDP_MODE_NO] = "no",
1493 [LLDP_MODE_YES] = "yes",
1494 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1495 };
1496
1497 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);