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