]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Merge pull request #6855 from keszybz/more-docs
[thirdparty/systemd.git] / src / network / networkd-network.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2013 Tom Gundersen <teg@jklm.no>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <ctype.h>
21 #include <net/if.h>
22
23 #include "alloc-util.h"
24 #include "conf-files.h"
25 #include "conf-parser.h"
26 #include "dns-domain.h"
27 #include "fd-util.h"
28 #include "hostname-util.h"
29 #include "in-addr-util.h"
30 #include "network-internal.h"
31 #include "networkd-manager.h"
32 #include "networkd-network.h"
33 #include "parse-util.h"
34 #include "set.h"
35 #include "stat-util.h"
36 #include "string-table.h"
37 #include "string-util.h"
38 #include "strv.h"
39 #include "util.h"
40
41 static void network_config_hash_func(const void *p, struct siphash *state) {
42 const NetworkConfigSection *c = p;
43
44 siphash24_compress(c->filename, strlen(c->filename), state);
45 siphash24_compress(&c->line, sizeof(c->line), state);
46 }
47
48 static int network_config_compare_func(const void *a, const void *b) {
49 const NetworkConfigSection *x = a, *y = b;
50 int r;
51
52 r = strcmp(x->filename, y->filename);
53 if (r != 0)
54 return r;
55
56 return y->line - x->line;
57 }
58
59 const struct hash_ops network_config_hash_ops = {
60 .hash = network_config_hash_func,
61 .compare = network_config_compare_func,
62 };
63
64 int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
65 NetworkConfigSection *cs;
66
67 cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
68 if (!cs)
69 return -ENOMEM;
70
71 strcpy(cs->filename, filename);
72 cs->line = line;
73
74 *s = cs;
75 cs = NULL;
76
77 return 0;
78 }
79
80 void network_config_section_free(NetworkConfigSection *cs) {
81 free(cs);
82 }
83
84 /* Set defaults following RFC7844 */
85 void network_apply_anonymize_if_set(Network *network) {
86 if (!network->dhcp_anonymize)
87 return;
88 /* RFC7844 3.7
89 SHOULD NOT send the Host Name option */
90 network->dhcp_send_hostname = false;
91 /* RFC7844 section 3.:
92 MAY contain the Client Identifier option
93 Section 3.5:
94 clients MUST use client identifiers based solely
95 on the link-layer address */
96 /* NOTE: Using MAC, as it does not reveal extra information,
97 * and some servers might not answer if this option is not sent */
98 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
99 /* RFC 7844 3.10:
100 SHOULD NOT use the Vendor Class Identifier option */
101 /* NOTE: it was not initiallized to any value in network_load_one. */
102 network->dhcp_vendor_class_identifier = false;
103 /* RFC7844 section 3.6.:
104 The client intending to protect its privacy SHOULD only request a
105 minimal number of options in the PRL and SHOULD also randomly shuffle
106 the ordering of option codes in the PRL. If this random ordering
107 cannot be implemented, the client MAY order the option codes in the
108 PRL by option code number (lowest to highest).
109 */
110 /* NOTE: dhcp_use_mtu is false by default,
111 * though it was not initiallized to any value in network_load_one.
112 * Maybe there should be another var called *send*?
113 * (to use the MTU sent by the server but to do not send
114 * the option in the PRL). */
115 network->dhcp_use_mtu = false;
116 /* RFC7844 section 3.6.
117 * same comments as previous option */
118 network->dhcp_use_routes = false;
119 /* RFC7844 section 3.6.
120 * same comments as previous option */
121 network->dhcp_use_timezone = false;
122 }
123
124 static int network_load_one(Manager *manager, const char *filename) {
125 _cleanup_network_free_ Network *network = NULL;
126 _cleanup_fclose_ FILE *file = NULL;
127 char *d;
128 const char *dropin_dirname;
129 Route *route;
130 Address *address;
131 int r;
132
133 assert(manager);
134 assert(filename);
135
136 file = fopen(filename, "re");
137 if (!file) {
138 if (errno == ENOENT)
139 return 0;
140
141 return -errno;
142 }
143
144 if (null_or_empty_fd(fileno(file))) {
145 log_debug("Skipping empty file: %s", filename);
146 return 0;
147 }
148
149 network = new0(Network, 1);
150 if (!network)
151 return log_oom();
152
153 network->manager = manager;
154
155 LIST_HEAD_INIT(network->static_addresses);
156 LIST_HEAD_INIT(network->static_routes);
157 LIST_HEAD_INIT(network->static_fdb_entries);
158 LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
159 LIST_HEAD_INIT(network->address_labels);
160 LIST_HEAD_INIT(network->static_prefixes);
161 LIST_HEAD_INIT(network->rules);
162
163 network->stacked_netdevs = hashmap_new(&string_hash_ops);
164 if (!network->stacked_netdevs)
165 return log_oom();
166
167 network->addresses_by_section = hashmap_new(&network_config_hash_ops);
168 if (!network->addresses_by_section)
169 return log_oom();
170
171 network->routes_by_section = hashmap_new(&network_config_hash_ops);
172 if (!network->routes_by_section)
173 return log_oom();
174
175 network->fdb_entries_by_section = hashmap_new(NULL);
176 if (!network->fdb_entries_by_section)
177 return log_oom();
178
179 network->address_labels_by_section = hashmap_new(&network_config_hash_ops);
180 if (!network->address_labels_by_section)
181 log_oom();
182
183 network->prefixes_by_section = hashmap_new(&network_config_hash_ops);
184 if (!network->prefixes_by_section)
185 return log_oom();
186
187 network->rules_by_section = hashmap_new(&network_config_hash_ops);
188 if (!network->rules_by_section)
189 return log_oom();
190
191 network->filename = strdup(filename);
192 if (!network->filename)
193 return log_oom();
194
195 network->name = strdup(basename(filename));
196 if (!network->name)
197 return log_oom();
198
199 d = strrchr(network->name, '.');
200 if (!d)
201 return -EINVAL;
202
203 assert(streq(d, ".network"));
204
205 *d = '\0';
206
207 network->dhcp = ADDRESS_FAMILY_NO;
208 network->dhcp_use_ntp = true;
209 network->dhcp_use_dns = true;
210 network->dhcp_use_hostname = true;
211 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
212 network->dhcp_use_routes = true;
213 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
214 network->dhcp_send_hostname = true;
215 /* To enable/disable RFC7844 Anonymity Profiles */
216 network->dhcp_anonymize = false;
217 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
218 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
219 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
220 network->dhcp_route_table = RT_TABLE_MAIN;
221 /* NOTE: the following vars were not set to any default,
222 * even if they are commented in the man?
223 * These vars might be overwriten by network_apply_anonymize_if_set */
224 network->dhcp_vendor_class_identifier = false;
225 network->dhcp_use_mtu = true;
226 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
227 network->dhcp_use_timezone = false;
228
229 network->dhcp_server_emit_dns = true;
230 network->dhcp_server_emit_ntp = true;
231 network->dhcp_server_emit_router = true;
232 network->dhcp_server_emit_timezone = true;
233
234 network->use_bpdu = true;
235 network->allow_port_to_be_root = true;
236 network->unicast_flood = true;
237 network->priority = LINK_BRIDGE_PORT_PRIORITY_INVALID;
238
239 network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
240
241 network->llmnr = RESOLVE_SUPPORT_YES;
242 network->mdns = RESOLVE_SUPPORT_NO;
243 network->dnssec_mode = _DNSSEC_MODE_INVALID;
244
245 network->link_local = ADDRESS_FAMILY_IPV6;
246
247 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
248 network->ipv6_accept_ra = -1;
249 network->ipv6_dad_transmits = -1;
250 network->ipv6_hop_limit = -1;
251 network->ipv6_proxy_ndp = -1;
252 network->duid.type = _DUID_TYPE_INVALID;
253 network->proxy_arp = -1;
254 network->arp = -1;
255 network->ipv6_accept_ra_use_dns = true;
256 network->ipv6_accept_ra_route_table = RT_TABLE_MAIN;
257
258 dropin_dirname = strjoina(network->name, ".network.d");
259
260 r = config_parse_many(filename, network_dirs, dropin_dirname,
261 "Match\0"
262 "Link\0"
263 "Network\0"
264 "Address\0"
265 "IPv6AddressLabel\0"
266 "RoutingPolicyRule\0"
267 "Route\0"
268 "DHCP\0"
269 "DHCPv4\0" /* compat */
270 "DHCPServer\0"
271 "IPv6AcceptRA\0"
272 "IPv6NDPProxyAddress\0"
273 "Bridge\0"
274 "BridgeFDB\0"
275 "BridgeVLAN\0"
276 "IPv6PrefixDelegation\0"
277 "IPv6Prefix\0",
278 config_item_perf_lookup, network_network_gperf_lookup,
279 false, 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 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 free(network->dhcp_hostname);
369
370 free(network->mac);
371
372 strv_free(network->ntp);
373 free(network->dns);
374 strv_free(network->search_domains);
375 strv_free(network->route_domains);
376 strv_free(network->bind_carrier);
377
378 netdev_unref(network->bridge);
379 netdev_unref(network->bond);
380 netdev_unref(network->vrf);
381
382 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
383 hashmap_remove(network->stacked_netdevs, netdev->ifname);
384 netdev_unref(netdev);
385 }
386 hashmap_free(network->stacked_netdevs);
387
388 while ((route = network->static_routes))
389 route_free(route);
390
391 while ((address = network->static_addresses))
392 address_free(address);
393
394 while ((fdb_entry = network->static_fdb_entries))
395 fdb_entry_free(fdb_entry);
396
397 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
398 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
399
400 while ((label = network->address_labels))
401 address_label_free(label);
402
403 while ((prefix = network->static_prefixes))
404 prefix_free(prefix);
405
406 while ((rule = network->rules))
407 routing_policy_rule_free(rule);
408
409 hashmap_free(network->addresses_by_section);
410 hashmap_free(network->routes_by_section);
411 hashmap_free(network->fdb_entries_by_section);
412 hashmap_free(network->address_labels_by_section);
413 hashmap_free(network->prefixes_by_section);
414 hashmap_free(network->rules_by_section);
415
416 if (network->manager) {
417 if (network->manager->networks)
418 LIST_REMOVE(networks, network->manager->networks, network);
419
420 if (network->manager->networks_by_name)
421 hashmap_remove(network->manager->networks_by_name, network->name);
422 }
423
424 free(network->name);
425
426 condition_free_list(network->match_host);
427 condition_free_list(network->match_virt);
428 condition_free_list(network->match_kernel);
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,
483 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, "Can not add NetDev '%s' to network: %m", rvalue);
631 return 0;
632 }
633
634 break;
635 default:
636 assert_not_reached("Can not 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 (netdev->kind != NETDEV_KIND_IPIP &&
752 netdev->kind != NETDEV_KIND_SIT &&
753 netdev->kind != NETDEV_KIND_GRE &&
754 netdev->kind != NETDEV_KIND_GRETAP &&
755 netdev->kind != NETDEV_KIND_IP6GRE &&
756 netdev->kind != NETDEV_KIND_IP6GRETAP &&
757 netdev->kind != NETDEV_KIND_VTI &&
758 netdev->kind != NETDEV_KIND_VTI6 &&
759 netdev->kind != NETDEV_KIND_IP6TNL
760 ) {
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 };
856
857 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
858 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
859
860 int config_parse_ipv6token(
861 const char* unit,
862 const char *filename,
863 unsigned line,
864 const char *section,
865 unsigned section_line,
866 const char *lvalue,
867 int ltype,
868 const char *rvalue,
869 void *data,
870 void *userdata) {
871
872 union in_addr_union buffer;
873 struct in6_addr *token = data;
874 int r;
875
876 assert(filename);
877 assert(lvalue);
878 assert(rvalue);
879 assert(token);
880
881 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
882 if (r < 0) {
883 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
884 return 0;
885 }
886
887 r = in_addr_is_null(AF_INET6, &buffer);
888 if (r != 0) {
889 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
890 return 0;
891 }
892
893 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
894 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
895 return 0;
896 }
897
898 *token = buffer.in6;
899
900 return 0;
901 }
902
903 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
904 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
905 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
906 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
907 };
908
909 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
910
911 int config_parse_ipv6_privacy_extensions(
912 const char* unit,
913 const char *filename,
914 unsigned line,
915 const char *section,
916 unsigned section_line,
917 const char *lvalue,
918 int ltype,
919 const char *rvalue,
920 void *data,
921 void *userdata) {
922
923 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
924 int k;
925
926 assert(filename);
927 assert(lvalue);
928 assert(rvalue);
929 assert(ipv6_privacy_extensions);
930
931 /* Our enum shall be a superset of booleans, hence first try
932 * to parse as boolean, and then as enum */
933
934 k = parse_boolean(rvalue);
935 if (k > 0)
936 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
937 else if (k == 0)
938 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
939 else {
940 IPv6PrivacyExtensions s;
941
942 s = ipv6_privacy_extensions_from_string(rvalue);
943 if (s < 0) {
944
945 if (streq(rvalue, "kernel"))
946 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
947 else {
948 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
949 return 0;
950 }
951 }
952
953 *ipv6_privacy_extensions = s;
954 }
955
956 return 0;
957 }
958
959 int config_parse_hostname(
960 const char *unit,
961 const char *filename,
962 unsigned line,
963 const char *section,
964 unsigned section_line,
965 const char *lvalue,
966 int ltype,
967 const char *rvalue,
968 void *data,
969 void *userdata) {
970
971 char **hostname = data, *hn = NULL;
972 int r;
973
974 assert(filename);
975 assert(lvalue);
976 assert(rvalue);
977
978 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
979 if (r < 0)
980 return r;
981
982 if (!hostname_is_valid(hn, false)) {
983 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
984 free(hn);
985 return 0;
986 }
987
988 free(*hostname);
989 *hostname = hostname_cleanup(hn);
990 return 0;
991 }
992
993 int config_parse_timezone(
994 const char *unit,
995 const char *filename,
996 unsigned line,
997 const char *section,
998 unsigned section_line,
999 const char *lvalue,
1000 int ltype,
1001 const char *rvalue,
1002 void *data,
1003 void *userdata) {
1004
1005 char **datap = data, *tz = NULL;
1006 int r;
1007
1008 assert(filename);
1009 assert(lvalue);
1010 assert(rvalue);
1011
1012 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1013 if (r < 0)
1014 return r;
1015
1016 if (!timezone_is_valid(tz)) {
1017 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
1018 free(tz);
1019 return 0;
1020 }
1021
1022 free(*datap);
1023 *datap = tz;
1024
1025 return 0;
1026 }
1027
1028 int config_parse_dhcp_server_dns(
1029 const char *unit,
1030 const char *filename,
1031 unsigned line,
1032 const char *section,
1033 unsigned section_line,
1034 const char *lvalue,
1035 int ltype,
1036 const char *rvalue,
1037 void *data,
1038 void *userdata) {
1039
1040 Network *n = data;
1041 const char *p = rvalue;
1042 int r;
1043
1044 assert(filename);
1045 assert(lvalue);
1046 assert(rvalue);
1047
1048 for (;;) {
1049 _cleanup_free_ char *w = NULL;
1050 struct in_addr a, *m;
1051
1052 r = extract_first_word(&p, &w, NULL, 0);
1053 if (r == -ENOMEM)
1054 return log_oom();
1055 if (r < 0) {
1056 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1057 return 0;
1058 }
1059 if (r == 0)
1060 break;
1061
1062 if (inet_pton(AF_INET, w, &a) <= 0) {
1063 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1064 continue;
1065 }
1066
1067 m = realloc(n->dhcp_server_dns, (n->n_dhcp_server_dns + 1) * sizeof(struct in_addr));
1068 if (!m)
1069 return log_oom();
1070
1071 m[n->n_dhcp_server_dns++] = a;
1072 n->dhcp_server_dns = m;
1073 }
1074
1075 return 0;
1076 }
1077
1078 int config_parse_radv_dns(
1079 const char *unit,
1080 const char *filename,
1081 unsigned line,
1082 const char *section,
1083 unsigned section_line,
1084 const char *lvalue,
1085 int ltype,
1086 const char *rvalue,
1087 void *data,
1088 void *userdata) {
1089
1090 Network *n = data;
1091 const char *p = rvalue;
1092 int r;
1093
1094 assert(filename);
1095 assert(lvalue);
1096 assert(rvalue);
1097
1098 for (;;) {
1099 _cleanup_free_ char *w = NULL;
1100 union in_addr_union a;
1101
1102 r = extract_first_word(&p, &w, NULL, 0);
1103 if (r == -ENOMEM)
1104 return log_oom();
1105 if (r < 0) {
1106 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1107 return 0;
1108 }
1109 if (r == 0)
1110 break;
1111
1112 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1113 struct in6_addr *m;
1114
1115 m = realloc(n->router_dns, (n->n_router_dns + 1) * sizeof(struct in6_addr));
1116 if (!m)
1117 return log_oom();
1118
1119 m[n->n_router_dns++] = a.in6;
1120 n->router_dns = m;
1121
1122 } else
1123 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1124
1125 }
1126
1127 return 0;
1128 }
1129
1130 int config_parse_radv_search_domains(
1131 const char *unit,
1132 const char *filename,
1133 unsigned line,
1134 const char *section,
1135 unsigned section_line,
1136 const char *lvalue,
1137 int ltype,
1138 const char *rvalue,
1139 void *data,
1140 void *userdata) {
1141
1142 Network *n = data;
1143 const char *p = rvalue;
1144 int r;
1145
1146 assert(filename);
1147 assert(lvalue);
1148 assert(rvalue);
1149
1150 for (;;) {
1151 _cleanup_free_ char *w = NULL;
1152 _cleanup_free_ char *idna = NULL;
1153
1154 r = extract_first_word(&p, &w, NULL, 0);
1155 if (r == -ENOMEM)
1156 return log_oom();
1157 if (r < 0) {
1158 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1159 return 0;
1160 }
1161 if (r == 0)
1162 break;
1163
1164 r = dns_name_apply_idna(w, &idna);
1165 if (r > 0) {
1166 r = strv_push(&n->router_search_domains, idna);
1167 if (r >= 0)
1168 idna = NULL;
1169 } else if (r == 0) {
1170 r = strv_push(&n->router_search_domains, w);
1171 if (r >= 0)
1172 w = NULL;
1173 }
1174 }
1175
1176 return 0;
1177 }
1178
1179 int config_parse_dhcp_server_ntp(
1180 const char *unit,
1181 const char *filename,
1182 unsigned line,
1183 const char *section,
1184 unsigned section_line,
1185 const char *lvalue,
1186 int ltype,
1187 const char *rvalue,
1188 void *data,
1189 void *userdata) {
1190
1191 Network *n = data;
1192 const char *p = rvalue;
1193 int r;
1194
1195 assert(filename);
1196 assert(lvalue);
1197 assert(rvalue);
1198
1199 for (;;) {
1200 _cleanup_free_ char *w = NULL;
1201 struct in_addr a, *m;
1202
1203 r = extract_first_word(&p, &w, NULL, 0);
1204 if (r == -ENOMEM)
1205 return log_oom();
1206 if (r < 0) {
1207 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1208 return 0;
1209 }
1210 if (r == 0)
1211 return 0;
1212
1213 if (inet_pton(AF_INET, w, &a) <= 0) {
1214 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1215 continue;
1216 }
1217
1218 m = realloc(n->dhcp_server_ntp, (n->n_dhcp_server_ntp + 1) * sizeof(struct in_addr));
1219 if (!m)
1220 return log_oom();
1221
1222 m[n->n_dhcp_server_ntp++] = a;
1223 n->dhcp_server_ntp = m;
1224 }
1225 }
1226
1227 int config_parse_dns(
1228 const char *unit,
1229 const char *filename,
1230 unsigned line,
1231 const char *section,
1232 unsigned section_line,
1233 const char *lvalue,
1234 int ltype,
1235 const char *rvalue,
1236 void *data,
1237 void *userdata) {
1238
1239 Network *n = userdata;
1240 int r;
1241
1242 assert(filename);
1243 assert(lvalue);
1244 assert(rvalue);
1245
1246 for (;;) {
1247 _cleanup_free_ char *w = NULL;
1248 union in_addr_union a;
1249 struct in_addr_data *m;
1250 int family;
1251
1252 r = extract_first_word(&rvalue, &w, NULL, 0);
1253 if (r == -ENOMEM)
1254 return log_oom();
1255 if (r < 0) {
1256 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1257 break;
1258 }
1259 if (r == 0)
1260 break;
1261
1262 r = in_addr_from_string_auto(w, &family, &a);
1263 if (r < 0) {
1264 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
1265 continue;
1266 }
1267
1268 m = realloc(n->dns, (n->n_dns + 1) * sizeof(struct in_addr_data));
1269 if (!m)
1270 return log_oom();
1271
1272 m[n->n_dns++] = (struct in_addr_data) {
1273 .family = family,
1274 .address = a,
1275 };
1276
1277 n->dns = m;
1278 }
1279
1280 return 0;
1281 }
1282
1283 int config_parse_dnssec_negative_trust_anchors(
1284 const char *unit,
1285 const char *filename,
1286 unsigned line,
1287 const char *section,
1288 unsigned section_line,
1289 const char *lvalue,
1290 int ltype,
1291 const char *rvalue,
1292 void *data,
1293 void *userdata) {
1294
1295 const char *p = rvalue;
1296 Network *n = data;
1297 int r;
1298
1299 assert(n);
1300 assert(lvalue);
1301 assert(rvalue);
1302
1303 if (isempty(rvalue)) {
1304 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1305 return 0;
1306 }
1307
1308 for (;;) {
1309 _cleanup_free_ char *w = NULL;
1310
1311 r = extract_first_word(&p, &w, NULL, 0);
1312 if (r < 0) {
1313 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1314 break;
1315 }
1316 if (r == 0)
1317 break;
1318
1319 r = dns_name_is_valid(w);
1320 if (r <= 0) {
1321 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1322 continue;
1323 }
1324
1325 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1326 if (r < 0)
1327 return log_oom();
1328
1329 r = set_put(n->dnssec_negative_trust_anchors, w);
1330 if (r < 0)
1331 return log_oom();
1332 if (r > 0)
1333 w = NULL;
1334 }
1335
1336 return 0;
1337 }
1338
1339 int config_parse_ntp(
1340 const char *unit,
1341 const char *filename,
1342 unsigned line,
1343 const char *section,
1344 unsigned section_line,
1345 const char *lvalue,
1346 int ltype,
1347 const char *rvalue,
1348 void *data,
1349 void *userdata) {
1350
1351 char ***l = data;
1352 int r;
1353
1354 assert(l);
1355 assert(lvalue);
1356 assert(rvalue);
1357
1358 if (isempty(rvalue)) {
1359 *l = strv_free(*l);
1360 return 0;
1361 }
1362
1363 for (;;) {
1364 _cleanup_free_ char *w = NULL;
1365
1366 r = extract_first_word(&rvalue, &w, NULL, 0);
1367 if (r == -ENOMEM)
1368 return log_oom();
1369 if (r < 0) {
1370 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1371 break;
1372 }
1373 if (r == 0)
1374 break;
1375
1376 r = dns_name_is_valid_or_address(w);
1377 if (r <= 0) {
1378 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1379 continue;
1380 }
1381
1382 r = strv_push(l, w);
1383 if (r < 0)
1384 return log_oom();
1385
1386 w = NULL;
1387 }
1388
1389 return 0;
1390 }
1391
1392 int config_parse_dhcp_route_table(const char *unit,
1393 const char *filename,
1394 unsigned line,
1395 const char *section,
1396 unsigned section_line,
1397 const char *lvalue,
1398 int ltype,
1399 const char *rvalue,
1400 void *data,
1401 void *userdata) {
1402 uint32_t rt;
1403 int r;
1404
1405 assert(filename);
1406 assert(lvalue);
1407 assert(rvalue);
1408 assert(data);
1409
1410 r = safe_atou32(rvalue, &rt);
1411 if (r < 0) {
1412 log_syntax(unit, LOG_ERR, filename, line, r,
1413 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1414 return 0;
1415 }
1416
1417 *((uint32_t *)data) = rt;
1418
1419 return 0;
1420 }
1421
1422 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1423
1424 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1425 [DHCP_USE_DOMAINS_NO] = "no",
1426 [DHCP_USE_DOMAINS_ROUTE] = "route",
1427 [DHCP_USE_DOMAINS_YES] = "yes",
1428 };
1429
1430 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1431
1432 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1433
1434 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1435 [LLDP_MODE_NO] = "no",
1436 [LLDP_MODE_YES] = "yes",
1437 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1438 };
1439
1440 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);