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