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