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