]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Minor line wrapping adjustment
[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 network->dhcp_route_table_set = false;
222 /* NOTE: the following vars were not set to any default,
223 * even if they are commented in the man?
224 * These vars might be overwriten by network_apply_anonymize_if_set */
225 network->dhcp_vendor_class_identifier = false;
226 network->dhcp_use_mtu = true;
227 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
228 network->dhcp_use_timezone = false;
229
230 network->dhcp_server_emit_dns = true;
231 network->dhcp_server_emit_ntp = true;
232 network->dhcp_server_emit_router = true;
233 network->dhcp_server_emit_timezone = true;
234
235 network->use_bpdu = true;
236 network->allow_port_to_be_root = true;
237 network->unicast_flood = true;
238 network->priority = LINK_BRIDGE_PORT_PRIORITY_INVALID;
239
240 network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
241
242 network->llmnr = RESOLVE_SUPPORT_YES;
243 network->mdns = RESOLVE_SUPPORT_NO;
244 network->dnssec_mode = _DNSSEC_MODE_INVALID;
245
246 network->link_local = ADDRESS_FAMILY_IPV6;
247
248 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
249 network->ipv6_accept_ra = -1;
250 network->ipv6_dad_transmits = -1;
251 network->ipv6_hop_limit = -1;
252 network->ipv6_proxy_ndp = -1;
253 network->duid.type = _DUID_TYPE_INVALID;
254 network->proxy_arp = -1;
255 network->arp = -1;
256 network->ipv6_accept_ra_use_dns = true;
257 network->ipv6_accept_ra_route_table = RT_TABLE_MAIN;
258
259 dropin_dirname = strjoina(network->name, ".network.d");
260
261 r = config_parse_many(filename, network_dirs, dropin_dirname,
262 "Match\0"
263 "Link\0"
264 "Network\0"
265 "Address\0"
266 "IPv6AddressLabel\0"
267 "RoutingPolicyRule\0"
268 "Route\0"
269 "DHCP\0"
270 "DHCPv4\0" /* compat */
271 "DHCPServer\0"
272 "IPv6AcceptRA\0"
273 "IPv6NDPProxyAddress\0"
274 "Bridge\0"
275 "BridgeFDB\0"
276 "BridgeVLAN\0"
277 "IPv6PrefixDelegation\0"
278 "IPv6Prefix\0",
279 config_item_perf_lookup, network_network_gperf_lookup,
280 false, network);
281 if (r < 0)
282 return r;
283
284 network_apply_anonymize_if_set(network);
285
286 /* IPMasquerade=yes implies IPForward=yes */
287 if (network->ip_masquerade)
288 network->ip_forward |= ADDRESS_FAMILY_IPV4;
289
290 LIST_PREPEND(networks, manager->networks, network);
291
292 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
293 if (r < 0)
294 return r;
295
296 r = hashmap_put(manager->networks_by_name, network->name, network);
297 if (r < 0)
298 return r;
299
300 LIST_FOREACH(routes, route, network->static_routes) {
301 if (!route->family) {
302 log_warning("Route section without Gateway field configured in %s. "
303 "Ignoring", filename);
304 return 0;
305 }
306 }
307
308 LIST_FOREACH(addresses, address, network->static_addresses) {
309 if (!address->family) {
310 log_warning("Address section without Address field configured in %s. "
311 "Ignoring", filename);
312 return 0;
313 }
314 }
315
316 network = NULL;
317
318 return 0;
319 }
320
321 int network_load(Manager *manager) {
322 Network *network;
323 _cleanup_strv_free_ char **files = NULL;
324 char **f;
325 int r;
326
327 assert(manager);
328
329 while ((network = manager->networks))
330 network_free(network);
331
332 r = conf_files_list_strv(&files, ".network", NULL, 0, network_dirs);
333 if (r < 0)
334 return log_error_errno(r, "Failed to enumerate network files: %m");
335
336 STRV_FOREACH_BACKWARDS(f, files) {
337 r = network_load_one(manager, *f);
338 if (r < 0)
339 return r;
340 }
341
342 return 0;
343 }
344
345 void network_free(Network *network) {
346 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
347 RoutingPolicyRule *rule;
348 FdbEntry *fdb_entry;
349 AddressLabel *label;
350 Prefix *prefix;
351 Address *address;
352 NetDev *netdev;
353 Route *route;
354 Iterator i;
355
356 if (!network)
357 return;
358
359 free(network->filename);
360
361 free(network->match_mac);
362 strv_free(network->match_path);
363 strv_free(network->match_driver);
364 strv_free(network->match_type);
365 strv_free(network->match_name);
366
367 free(network->description);
368 free(network->dhcp_vendor_class_identifier);
369 free(network->dhcp_hostname);
370
371 free(network->mac);
372
373 strv_free(network->ntp);
374 free(network->dns);
375 strv_free(network->search_domains);
376 strv_free(network->route_domains);
377 strv_free(network->bind_carrier);
378
379 netdev_unref(network->bridge);
380 netdev_unref(network->bond);
381 netdev_unref(network->vrf);
382
383 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
384 hashmap_remove(network->stacked_netdevs, netdev->ifname);
385 netdev_unref(netdev);
386 }
387 hashmap_free(network->stacked_netdevs);
388
389 while ((route = network->static_routes))
390 route_free(route);
391
392 while ((address = network->static_addresses))
393 address_free(address);
394
395 while ((fdb_entry = network->static_fdb_entries))
396 fdb_entry_free(fdb_entry);
397
398 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
399 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
400
401 while ((label = network->address_labels))
402 address_label_free(label);
403
404 while ((prefix = network->static_prefixes))
405 prefix_free(prefix);
406
407 while ((rule = network->rules))
408 routing_policy_rule_free(rule);
409
410 hashmap_free(network->addresses_by_section);
411 hashmap_free(network->routes_by_section);
412 hashmap_free(network->fdb_entries_by_section);
413 hashmap_free(network->address_labels_by_section);
414 hashmap_free(network->prefixes_by_section);
415 hashmap_free(network->rules_by_section);
416
417 if (network->manager) {
418 if (network->manager->networks)
419 LIST_REMOVE(networks, network->manager->networks, network);
420
421 if (network->manager->networks_by_name)
422 hashmap_remove(network->manager->networks_by_name, network->name);
423 }
424
425 free(network->name);
426
427 condition_free_list(network->match_host);
428 condition_free_list(network->match_virt);
429 condition_free_list(network->match_kernel);
430 condition_free_list(network->match_arch);
431
432 free(network->dhcp_server_timezone);
433 free(network->dhcp_server_dns);
434 free(network->dhcp_server_ntp);
435
436 set_free_free(network->dnssec_negative_trust_anchors);
437
438 free(network);
439 }
440
441 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
442 Network *network;
443
444 assert(manager);
445 assert(name);
446 assert(ret);
447
448 network = hashmap_get(manager->networks_by_name, name);
449 if (!network)
450 return -ENOENT;
451
452 *ret = network;
453
454 return 0;
455 }
456
457 int network_get(Manager *manager, struct udev_device *device,
458 const char *ifname, const struct ether_addr *address,
459 Network **ret) {
460 Network *network;
461 struct udev_device *parent;
462 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
463
464 assert(manager);
465 assert(ret);
466
467 if (device) {
468 path = udev_device_get_property_value(device, "ID_PATH");
469
470 parent = udev_device_get_parent(device);
471 if (parent)
472 parent_driver = udev_device_get_driver(parent);
473
474 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
475
476 devtype = udev_device_get_devtype(device);
477 }
478
479 LIST_FOREACH(networks, network, manager->networks) {
480 if (net_match_config(network->match_mac, network->match_path,
481 network->match_driver, network->match_type,
482 network->match_name, network->match_host,
483 network->match_virt, network->match_kernel,
484 network->match_arch,
485 address, path, parent_driver, driver,
486 devtype, ifname)) {
487 if (network->match_name && device) {
488 const char *attr;
489 uint8_t name_assign_type = NET_NAME_UNKNOWN;
490
491 attr = udev_device_get_sysattr_value(device, "name_assign_type");
492 if (attr)
493 (void) safe_atou8(attr, &name_assign_type);
494
495 if (name_assign_type == NET_NAME_ENUM)
496 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
497 ifname, network->filename);
498 else
499 log_debug("%s: found matching network '%s'", ifname, network->filename);
500 } else
501 log_debug("%s: found matching network '%s'", ifname, network->filename);
502
503 *ret = network;
504 return 0;
505 }
506 }
507
508 *ret = NULL;
509
510 return -ENOENT;
511 }
512
513 int network_apply(Network *network, Link *link) {
514 int r;
515
516 assert(network);
517 assert(link);
518
519 link->network = network;
520
521 if (network->ipv4ll_route) {
522 Route *route;
523
524 r = route_new_static(network, NULL, 0, &route);
525 if (r < 0)
526 return r;
527
528 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
529 if (r == 0)
530 return -EINVAL;
531 if (r < 0)
532 return -errno;
533
534 route->family = AF_INET;
535 route->dst_prefixlen = 16;
536 route->scope = RT_SCOPE_LINK;
537 route->priority = IPV4LL_ROUTE_METRIC;
538 route->protocol = RTPROT_STATIC;
539 }
540
541 if (network->n_dns > 0 ||
542 !strv_isempty(network->ntp) ||
543 !strv_isempty(network->search_domains) ||
544 !strv_isempty(network->route_domains))
545 link_dirty(link);
546
547 return 0;
548 }
549
550 bool network_has_static_ipv6_addresses(Network *network) {
551 Address *address;
552
553 assert(network);
554
555 LIST_FOREACH(addresses, address, network->static_addresses) {
556 if (address->family == AF_INET6)
557 return true;
558 }
559
560 return false;
561 }
562
563 int config_parse_netdev(const char *unit,
564 const char *filename,
565 unsigned line,
566 const char *section,
567 unsigned section_line,
568 const char *lvalue,
569 int ltype,
570 const char *rvalue,
571 void *data,
572 void *userdata) {
573 Network *network = userdata;
574 _cleanup_free_ char *kind_string = NULL;
575 char *p;
576 NetDev *netdev;
577 NetDevKind kind;
578 int r;
579
580 assert(filename);
581 assert(lvalue);
582 assert(rvalue);
583 assert(data);
584
585 kind_string = strdup(lvalue);
586 if (!kind_string)
587 return log_oom();
588
589 /* the keys are CamelCase versions of the kind */
590 for (p = kind_string; *p; p++)
591 *p = tolower(*p);
592
593 kind = netdev_kind_from_string(kind_string);
594 if (kind == _NETDEV_KIND_INVALID) {
595 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
596 return 0;
597 }
598
599 r = netdev_get(network->manager, rvalue, &netdev);
600 if (r < 0) {
601 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
602 return 0;
603 }
604
605 if (netdev->kind != kind) {
606 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
607 return 0;
608 }
609
610 switch (kind) {
611 case NETDEV_KIND_BRIDGE:
612 network->bridge = netdev;
613
614 break;
615 case NETDEV_KIND_BOND:
616 network->bond = netdev;
617
618 break;
619 case NETDEV_KIND_VRF:
620 network->vrf = netdev;
621
622 break;
623 case NETDEV_KIND_VLAN:
624 case NETDEV_KIND_MACVLAN:
625 case NETDEV_KIND_MACVTAP:
626 case NETDEV_KIND_IPVLAN:
627 case NETDEV_KIND_VXLAN:
628 case NETDEV_KIND_VCAN:
629 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
630 if (r < 0) {
631 log_syntax(unit, LOG_ERR, filename, line, r, "Can not add NetDev '%s' to network: %m", rvalue);
632 return 0;
633 }
634
635 break;
636 default:
637 assert_not_reached("Can not parse NetDev");
638 }
639
640 netdev_ref(netdev);
641
642 return 0;
643 }
644
645 int config_parse_domains(
646 const char *unit,
647 const char *filename,
648 unsigned line,
649 const char *section,
650 unsigned section_line,
651 const char *lvalue,
652 int ltype,
653 const char *rvalue,
654 void *data,
655 void *userdata) {
656
657 const char *p;
658 Network *n = data;
659 int r;
660
661 assert(n);
662 assert(lvalue);
663 assert(rvalue);
664
665 if (isempty(rvalue)) {
666 n->search_domains = strv_free(n->search_domains);
667 n->route_domains = strv_free(n->route_domains);
668 return 0;
669 }
670
671 p = rvalue;
672 for (;;) {
673 _cleanup_free_ char *w = NULL, *normalized = NULL;
674 const char *domain;
675 bool is_route;
676
677 r = extract_first_word(&p, &w, NULL, 0);
678 if (r < 0) {
679 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
680 break;
681 }
682 if (r == 0)
683 break;
684
685 is_route = w[0] == '~';
686 domain = is_route ? w + 1 : w;
687
688 if (dns_name_is_root(domain) || streq(domain, "*")) {
689 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
690 * routing domain, unconditionally. */
691 is_route = true;
692 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
693
694 } else {
695 r = dns_name_normalize(domain, &normalized);
696 if (r < 0) {
697 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
698 continue;
699 }
700
701 domain = normalized;
702
703 if (is_localhost(domain)) {
704 log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain);
705 continue;
706 }
707 }
708
709 if (is_route) {
710 r = strv_extend(&n->route_domains, domain);
711 if (r < 0)
712 return log_oom();
713
714 } else {
715 r = strv_extend(&n->search_domains, domain);
716 if (r < 0)
717 return log_oom();
718 }
719 }
720
721 strv_uniq(n->route_domains);
722 strv_uniq(n->search_domains);
723
724 return 0;
725 }
726
727 int config_parse_tunnel(const char *unit,
728 const char *filename,
729 unsigned line,
730 const char *section,
731 unsigned section_line,
732 const char *lvalue,
733 int ltype,
734 const char *rvalue,
735 void *data,
736 void *userdata) {
737 Network *network = userdata;
738 NetDev *netdev;
739 int r;
740
741 assert(filename);
742 assert(lvalue);
743 assert(rvalue);
744 assert(data);
745
746 r = netdev_get(network->manager, rvalue, &netdev);
747 if (r < 0) {
748 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
749 return 0;
750 }
751
752 if (!IN_SET(netdev->kind,
753 NETDEV_KIND_IPIP,
754 NETDEV_KIND_SIT,
755 NETDEV_KIND_GRE,
756 NETDEV_KIND_GRETAP,
757 NETDEV_KIND_IP6GRE,
758 NETDEV_KIND_IP6GRETAP,
759 NETDEV_KIND_VTI,
760 NETDEV_KIND_VTI6,
761 NETDEV_KIND_IP6TNL)) {
762 log_syntax(unit, LOG_ERR, filename, line, 0,
763 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
764 return 0;
765 }
766
767 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
768 if (r < 0) {
769 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
770 return 0;
771 }
772
773 netdev_ref(netdev);
774
775 return 0;
776 }
777
778 int config_parse_ipv4ll(
779 const char* unit,
780 const char *filename,
781 unsigned line,
782 const char *section,
783 unsigned section_line,
784 const char *lvalue,
785 int ltype,
786 const char *rvalue,
787 void *data,
788 void *userdata) {
789
790 AddressFamilyBoolean *link_local = data;
791
792 assert(filename);
793 assert(lvalue);
794 assert(rvalue);
795 assert(data);
796
797 /* Note that this is mostly like
798 * config_parse_address_family_boolean(), except that it
799 * applies only to IPv4 */
800
801 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
802
803 return 0;
804 }
805
806 int config_parse_dhcp(
807 const char* unit,
808 const char *filename,
809 unsigned line,
810 const char *section,
811 unsigned section_line,
812 const char *lvalue,
813 int ltype,
814 const char *rvalue,
815 void *data,
816 void *userdata) {
817
818 AddressFamilyBoolean *dhcp = data, s;
819
820 assert(filename);
821 assert(lvalue);
822 assert(rvalue);
823 assert(data);
824
825 /* Note that this is mostly like
826 * config_parse_address_family_boolean(), except that it
827 * understands some old names for the enum values */
828
829 s = address_family_boolean_from_string(rvalue);
830 if (s < 0) {
831
832 /* Previously, we had a slightly different enum here,
833 * support its values for compatbility. */
834
835 if (streq(rvalue, "none"))
836 s = ADDRESS_FAMILY_NO;
837 else if (streq(rvalue, "v4"))
838 s = ADDRESS_FAMILY_IPV4;
839 else if (streq(rvalue, "v6"))
840 s = ADDRESS_FAMILY_IPV6;
841 else if (streq(rvalue, "both"))
842 s = ADDRESS_FAMILY_YES;
843 else {
844 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
845 return 0;
846 }
847 }
848
849 *dhcp = s;
850 return 0;
851 }
852
853 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
854 [DHCP_CLIENT_ID_MAC] = "mac",
855 [DHCP_CLIENT_ID_DUID] = "duid"
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 can not 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 can not 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)) {
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 = realloc(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 = realloc(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 = realloc(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 = realloc(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_route_table(const char *unit,
1394 const char *filename,
1395 unsigned line,
1396 const char *section,
1397 unsigned section_line,
1398 const char *lvalue,
1399 int ltype,
1400 const char *rvalue,
1401 void *data,
1402 void *userdata) {
1403 Network *network = data;
1404 uint32_t rt;
1405 int r;
1406
1407 assert(filename);
1408 assert(lvalue);
1409 assert(rvalue);
1410 assert(data);
1411
1412 r = safe_atou32(rvalue, &rt);
1413 if (r < 0) {
1414 log_syntax(unit, LOG_ERR, filename, line, r,
1415 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1416 return 0;
1417 }
1418
1419 network->dhcp_route_table = rt;
1420 network->dhcp_route_table_set = true;
1421
1422 return 0;
1423 }
1424
1425 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1426
1427 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1428 [DHCP_USE_DOMAINS_NO] = "no",
1429 [DHCP_USE_DOMAINS_ROUTE] = "route",
1430 [DHCP_USE_DOMAINS_YES] = "yes",
1431 };
1432
1433 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1434
1435 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1436
1437 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1438 [LLDP_MODE_NO] = "no",
1439 [LLDP_MODE_YES] = "yes",
1440 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1441 };
1442
1443 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);