]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
tree-wide: use `!IN_SET(..)` for `a != b && a != c && …`
[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, NETDEV_KIND_IPIP, NETDEV_KIND_SIT, NETDEV_KIND_GRE, NETDEV_KIND_GRETAP, NETDEV_KIND_IP6GRE, NETDEV_KIND_IP6GRETAP, NETDEV_KIND_VTI, NETDEV_KIND_VTI6, NETDEV_KIND_IP6TNL)) {
753 log_syntax(unit, LOG_ERR, filename, line, 0,
754 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
755 return 0;
756 }
757
758 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
759 if (r < 0) {
760 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
761 return 0;
762 }
763
764 netdev_ref(netdev);
765
766 return 0;
767 }
768
769 int config_parse_ipv4ll(
770 const char* unit,
771 const char *filename,
772 unsigned line,
773 const char *section,
774 unsigned section_line,
775 const char *lvalue,
776 int ltype,
777 const char *rvalue,
778 void *data,
779 void *userdata) {
780
781 AddressFamilyBoolean *link_local = data;
782
783 assert(filename);
784 assert(lvalue);
785 assert(rvalue);
786 assert(data);
787
788 /* Note that this is mostly like
789 * config_parse_address_family_boolean(), except that it
790 * applies only to IPv4 */
791
792 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
793
794 return 0;
795 }
796
797 int config_parse_dhcp(
798 const char* unit,
799 const char *filename,
800 unsigned line,
801 const char *section,
802 unsigned section_line,
803 const char *lvalue,
804 int ltype,
805 const char *rvalue,
806 void *data,
807 void *userdata) {
808
809 AddressFamilyBoolean *dhcp = data, s;
810
811 assert(filename);
812 assert(lvalue);
813 assert(rvalue);
814 assert(data);
815
816 /* Note that this is mostly like
817 * config_parse_address_family_boolean(), except that it
818 * understands some old names for the enum values */
819
820 s = address_family_boolean_from_string(rvalue);
821 if (s < 0) {
822
823 /* Previously, we had a slightly different enum here,
824 * support its values for compatbility. */
825
826 if (streq(rvalue, "none"))
827 s = ADDRESS_FAMILY_NO;
828 else if (streq(rvalue, "v4"))
829 s = ADDRESS_FAMILY_IPV4;
830 else if (streq(rvalue, "v6"))
831 s = ADDRESS_FAMILY_IPV6;
832 else if (streq(rvalue, "both"))
833 s = ADDRESS_FAMILY_YES;
834 else {
835 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
836 return 0;
837 }
838 }
839
840 *dhcp = s;
841 return 0;
842 }
843
844 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
845 [DHCP_CLIENT_ID_MAC] = "mac",
846 [DHCP_CLIENT_ID_DUID] = "duid"
847 };
848
849 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
850 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
851
852 int config_parse_ipv6token(
853 const char* unit,
854 const char *filename,
855 unsigned line,
856 const char *section,
857 unsigned section_line,
858 const char *lvalue,
859 int ltype,
860 const char *rvalue,
861 void *data,
862 void *userdata) {
863
864 union in_addr_union buffer;
865 struct in6_addr *token = data;
866 int r;
867
868 assert(filename);
869 assert(lvalue);
870 assert(rvalue);
871 assert(token);
872
873 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
874 if (r < 0) {
875 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
876 return 0;
877 }
878
879 r = in_addr_is_null(AF_INET6, &buffer);
880 if (r != 0) {
881 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
882 return 0;
883 }
884
885 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
886 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
887 return 0;
888 }
889
890 *token = buffer.in6;
891
892 return 0;
893 }
894
895 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
896 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
897 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
898 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
899 };
900
901 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
902
903 int config_parse_ipv6_privacy_extensions(
904 const char* unit,
905 const char *filename,
906 unsigned line,
907 const char *section,
908 unsigned section_line,
909 const char *lvalue,
910 int ltype,
911 const char *rvalue,
912 void *data,
913 void *userdata) {
914
915 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
916 int k;
917
918 assert(filename);
919 assert(lvalue);
920 assert(rvalue);
921 assert(ipv6_privacy_extensions);
922
923 /* Our enum shall be a superset of booleans, hence first try
924 * to parse as boolean, and then as enum */
925
926 k = parse_boolean(rvalue);
927 if (k > 0)
928 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
929 else if (k == 0)
930 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
931 else {
932 IPv6PrivacyExtensions s;
933
934 s = ipv6_privacy_extensions_from_string(rvalue);
935 if (s < 0) {
936
937 if (streq(rvalue, "kernel"))
938 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
939 else {
940 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
941 return 0;
942 }
943 }
944
945 *ipv6_privacy_extensions = s;
946 }
947
948 return 0;
949 }
950
951 int config_parse_hostname(
952 const char *unit,
953 const char *filename,
954 unsigned line,
955 const char *section,
956 unsigned section_line,
957 const char *lvalue,
958 int ltype,
959 const char *rvalue,
960 void *data,
961 void *userdata) {
962
963 char **hostname = data, *hn = NULL;
964 int r;
965
966 assert(filename);
967 assert(lvalue);
968 assert(rvalue);
969
970 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
971 if (r < 0)
972 return r;
973
974 if (!hostname_is_valid(hn, false)) {
975 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
976 free(hn);
977 return 0;
978 }
979
980 free(*hostname);
981 *hostname = hostname_cleanup(hn);
982 return 0;
983 }
984
985 int config_parse_timezone(
986 const char *unit,
987 const char *filename,
988 unsigned line,
989 const char *section,
990 unsigned section_line,
991 const char *lvalue,
992 int ltype,
993 const char *rvalue,
994 void *data,
995 void *userdata) {
996
997 char **datap = data, *tz = NULL;
998 int r;
999
1000 assert(filename);
1001 assert(lvalue);
1002 assert(rvalue);
1003
1004 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1005 if (r < 0)
1006 return r;
1007
1008 if (!timezone_is_valid(tz)) {
1009 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
1010 free(tz);
1011 return 0;
1012 }
1013
1014 free(*datap);
1015 *datap = tz;
1016
1017 return 0;
1018 }
1019
1020 int config_parse_dhcp_server_dns(
1021 const char *unit,
1022 const char *filename,
1023 unsigned line,
1024 const char *section,
1025 unsigned section_line,
1026 const char *lvalue,
1027 int ltype,
1028 const char *rvalue,
1029 void *data,
1030 void *userdata) {
1031
1032 Network *n = data;
1033 const char *p = rvalue;
1034 int r;
1035
1036 assert(filename);
1037 assert(lvalue);
1038 assert(rvalue);
1039
1040 for (;;) {
1041 _cleanup_free_ char *w = NULL;
1042 struct in_addr a, *m;
1043
1044 r = extract_first_word(&p, &w, NULL, 0);
1045 if (r == -ENOMEM)
1046 return log_oom();
1047 if (r < 0) {
1048 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1049 return 0;
1050 }
1051 if (r == 0)
1052 break;
1053
1054 if (inet_pton(AF_INET, w, &a) <= 0) {
1055 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1056 continue;
1057 }
1058
1059 m = realloc(n->dhcp_server_dns, (n->n_dhcp_server_dns + 1) * sizeof(struct in_addr));
1060 if (!m)
1061 return log_oom();
1062
1063 m[n->n_dhcp_server_dns++] = a;
1064 n->dhcp_server_dns = m;
1065 }
1066
1067 return 0;
1068 }
1069
1070 int config_parse_radv_dns(
1071 const char *unit,
1072 const char *filename,
1073 unsigned line,
1074 const char *section,
1075 unsigned section_line,
1076 const char *lvalue,
1077 int ltype,
1078 const char *rvalue,
1079 void *data,
1080 void *userdata) {
1081
1082 Network *n = data;
1083 const char *p = rvalue;
1084 int r;
1085
1086 assert(filename);
1087 assert(lvalue);
1088 assert(rvalue);
1089
1090 for (;;) {
1091 _cleanup_free_ char *w = NULL;
1092 union in_addr_union a;
1093
1094 r = extract_first_word(&p, &w, NULL, 0);
1095 if (r == -ENOMEM)
1096 return log_oom();
1097 if (r < 0) {
1098 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1099 return 0;
1100 }
1101 if (r == 0)
1102 break;
1103
1104 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1105 struct in6_addr *m;
1106
1107 m = realloc(n->router_dns, (n->n_router_dns + 1) * sizeof(struct in6_addr));
1108 if (!m)
1109 return log_oom();
1110
1111 m[n->n_router_dns++] = a.in6;
1112 n->router_dns = m;
1113
1114 } else
1115 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1116
1117 }
1118
1119 return 0;
1120 }
1121
1122 int config_parse_radv_search_domains(
1123 const char *unit,
1124 const char *filename,
1125 unsigned line,
1126 const char *section,
1127 unsigned section_line,
1128 const char *lvalue,
1129 int ltype,
1130 const char *rvalue,
1131 void *data,
1132 void *userdata) {
1133
1134 Network *n = data;
1135 const char *p = rvalue;
1136 int r;
1137
1138 assert(filename);
1139 assert(lvalue);
1140 assert(rvalue);
1141
1142 for (;;) {
1143 _cleanup_free_ char *w = NULL;
1144 _cleanup_free_ char *idna = NULL;
1145
1146 r = extract_first_word(&p, &w, NULL, 0);
1147 if (r == -ENOMEM)
1148 return log_oom();
1149 if (r < 0) {
1150 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1151 return 0;
1152 }
1153 if (r == 0)
1154 break;
1155
1156 r = dns_name_apply_idna(w, &idna);
1157 if (r > 0) {
1158 r = strv_push(&n->router_search_domains, idna);
1159 if (r >= 0)
1160 idna = NULL;
1161 } else if (r == 0) {
1162 r = strv_push(&n->router_search_domains, w);
1163 if (r >= 0)
1164 w = NULL;
1165 }
1166 }
1167
1168 return 0;
1169 }
1170
1171 int config_parse_dhcp_server_ntp(
1172 const char *unit,
1173 const char *filename,
1174 unsigned line,
1175 const char *section,
1176 unsigned section_line,
1177 const char *lvalue,
1178 int ltype,
1179 const char *rvalue,
1180 void *data,
1181 void *userdata) {
1182
1183 Network *n = data;
1184 const char *p = rvalue;
1185 int r;
1186
1187 assert(filename);
1188 assert(lvalue);
1189 assert(rvalue);
1190
1191 for (;;) {
1192 _cleanup_free_ char *w = NULL;
1193 struct in_addr a, *m;
1194
1195 r = extract_first_word(&p, &w, NULL, 0);
1196 if (r == -ENOMEM)
1197 return log_oom();
1198 if (r < 0) {
1199 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1200 return 0;
1201 }
1202 if (r == 0)
1203 return 0;
1204
1205 if (inet_pton(AF_INET, w, &a) <= 0) {
1206 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1207 continue;
1208 }
1209
1210 m = realloc(n->dhcp_server_ntp, (n->n_dhcp_server_ntp + 1) * sizeof(struct in_addr));
1211 if (!m)
1212 return log_oom();
1213
1214 m[n->n_dhcp_server_ntp++] = a;
1215 n->dhcp_server_ntp = m;
1216 }
1217 }
1218
1219 int config_parse_dns(
1220 const char *unit,
1221 const char *filename,
1222 unsigned line,
1223 const char *section,
1224 unsigned section_line,
1225 const char *lvalue,
1226 int ltype,
1227 const char *rvalue,
1228 void *data,
1229 void *userdata) {
1230
1231 Network *n = userdata;
1232 int r;
1233
1234 assert(filename);
1235 assert(lvalue);
1236 assert(rvalue);
1237
1238 for (;;) {
1239 _cleanup_free_ char *w = NULL;
1240 union in_addr_union a;
1241 struct in_addr_data *m;
1242 int family;
1243
1244 r = extract_first_word(&rvalue, &w, NULL, 0);
1245 if (r == -ENOMEM)
1246 return log_oom();
1247 if (r < 0) {
1248 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1249 break;
1250 }
1251 if (r == 0)
1252 break;
1253
1254 r = in_addr_from_string_auto(w, &family, &a);
1255 if (r < 0) {
1256 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
1257 continue;
1258 }
1259
1260 m = realloc(n->dns, (n->n_dns + 1) * sizeof(struct in_addr_data));
1261 if (!m)
1262 return log_oom();
1263
1264 m[n->n_dns++] = (struct in_addr_data) {
1265 .family = family,
1266 .address = a,
1267 };
1268
1269 n->dns = m;
1270 }
1271
1272 return 0;
1273 }
1274
1275 int config_parse_dnssec_negative_trust_anchors(
1276 const char *unit,
1277 const char *filename,
1278 unsigned line,
1279 const char *section,
1280 unsigned section_line,
1281 const char *lvalue,
1282 int ltype,
1283 const char *rvalue,
1284 void *data,
1285 void *userdata) {
1286
1287 const char *p = rvalue;
1288 Network *n = data;
1289 int r;
1290
1291 assert(n);
1292 assert(lvalue);
1293 assert(rvalue);
1294
1295 if (isempty(rvalue)) {
1296 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1297 return 0;
1298 }
1299
1300 for (;;) {
1301 _cleanup_free_ char *w = NULL;
1302
1303 r = extract_first_word(&p, &w, NULL, 0);
1304 if (r < 0) {
1305 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1306 break;
1307 }
1308 if (r == 0)
1309 break;
1310
1311 r = dns_name_is_valid(w);
1312 if (r <= 0) {
1313 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1314 continue;
1315 }
1316
1317 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1318 if (r < 0)
1319 return log_oom();
1320
1321 r = set_put(n->dnssec_negative_trust_anchors, w);
1322 if (r < 0)
1323 return log_oom();
1324 if (r > 0)
1325 w = NULL;
1326 }
1327
1328 return 0;
1329 }
1330
1331 int config_parse_ntp(
1332 const char *unit,
1333 const char *filename,
1334 unsigned line,
1335 const char *section,
1336 unsigned section_line,
1337 const char *lvalue,
1338 int ltype,
1339 const char *rvalue,
1340 void *data,
1341 void *userdata) {
1342
1343 char ***l = data;
1344 int r;
1345
1346 assert(l);
1347 assert(lvalue);
1348 assert(rvalue);
1349
1350 if (isempty(rvalue)) {
1351 *l = strv_free(*l);
1352 return 0;
1353 }
1354
1355 for (;;) {
1356 _cleanup_free_ char *w = NULL;
1357
1358 r = extract_first_word(&rvalue, &w, NULL, 0);
1359 if (r == -ENOMEM)
1360 return log_oom();
1361 if (r < 0) {
1362 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1363 break;
1364 }
1365 if (r == 0)
1366 break;
1367
1368 r = dns_name_is_valid_or_address(w);
1369 if (r <= 0) {
1370 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1371 continue;
1372 }
1373
1374 r = strv_push(l, w);
1375 if (r < 0)
1376 return log_oom();
1377
1378 w = NULL;
1379 }
1380
1381 return 0;
1382 }
1383
1384 int config_parse_dhcp_route_table(const char *unit,
1385 const char *filename,
1386 unsigned line,
1387 const char *section,
1388 unsigned section_line,
1389 const char *lvalue,
1390 int ltype,
1391 const char *rvalue,
1392 void *data,
1393 void *userdata) {
1394 Network *network = data;
1395 uint32_t rt;
1396 int r;
1397
1398 assert(filename);
1399 assert(lvalue);
1400 assert(rvalue);
1401 assert(data);
1402
1403 r = safe_atou32(rvalue, &rt);
1404 if (r < 0) {
1405 log_syntax(unit, LOG_ERR, filename, line, r,
1406 "Unable to read RouteTable, ignoring assignment: %s", rvalue);
1407 return 0;
1408 }
1409
1410 network->dhcp_route_table = rt;
1411 network->dhcp_route_table_set = true;
1412
1413 return 0;
1414 }
1415
1416 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1417
1418 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1419 [DHCP_USE_DOMAINS_NO] = "no",
1420 [DHCP_USE_DOMAINS_ROUTE] = "route",
1421 [DHCP_USE_DOMAINS_YES] = "yes",
1422 };
1423
1424 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1425
1426 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1427
1428 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1429 [LLDP_MODE_NO] = "no",
1430 [LLDP_MODE_YES] = "yes",
1431 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1432 };
1433
1434 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);