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