]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
networkd: add support to configure virtual CAN device (#4139)
[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 "network-internal.h"
30 #include "networkd-network.h"
31 #include "networkd.h"
32 #include "parse-util.h"
33 #include "set.h"
34 #include "stat-util.h"
35 #include "string-table.h"
36 #include "string-util.h"
37 #include "util.h"
38
39 static int network_load_one(Manager *manager, const char *filename) {
40 _cleanup_network_free_ Network *network = NULL;
41 _cleanup_fclose_ FILE *file = NULL;
42 char *d;
43 Route *route;
44 Address *address;
45 int r;
46
47 assert(manager);
48 assert(filename);
49
50 file = fopen(filename, "re");
51 if (!file) {
52 if (errno == ENOENT)
53 return 0;
54
55 return -errno;
56 }
57
58 if (null_or_empty_fd(fileno(file))) {
59 log_debug("Skipping empty file: %s", filename);
60 return 0;
61 }
62
63 network = new0(Network, 1);
64 if (!network)
65 return log_oom();
66
67 network->manager = manager;
68
69 LIST_HEAD_INIT(network->static_addresses);
70 LIST_HEAD_INIT(network->static_routes);
71 LIST_HEAD_INIT(network->static_fdb_entries);
72
73 network->stacked_netdevs = hashmap_new(&string_hash_ops);
74 if (!network->stacked_netdevs)
75 return log_oom();
76
77 network->addresses_by_section = hashmap_new(NULL);
78 if (!network->addresses_by_section)
79 return log_oom();
80
81 network->routes_by_section = hashmap_new(NULL);
82 if (!network->routes_by_section)
83 return log_oom();
84
85 network->fdb_entries_by_section = hashmap_new(NULL);
86 if (!network->fdb_entries_by_section)
87 return log_oom();
88
89 network->filename = strdup(filename);
90 if (!network->filename)
91 return log_oom();
92
93 network->name = strdup(basename(filename));
94 if (!network->name)
95 return log_oom();
96
97 d = strrchr(network->name, '.');
98 if (!d)
99 return -EINVAL;
100
101 assert(streq(d, ".network"));
102
103 *d = '\0';
104
105 network->dhcp = ADDRESS_FAMILY_NO;
106 network->dhcp_use_ntp = true;
107 network->dhcp_use_dns = true;
108 network->dhcp_use_hostname = true;
109 network->dhcp_use_routes = true;
110 network->dhcp_send_hostname = true;
111 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
112 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
113
114 network->dhcp_server_emit_dns = true;
115 network->dhcp_server_emit_ntp = true;
116 network->dhcp_server_emit_router = true;
117 network->dhcp_server_emit_timezone = true;
118
119 network->use_bpdu = true;
120 network->allow_port_to_be_root = true;
121 network->unicast_flood = true;
122
123 network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
124
125 network->llmnr = RESOLVE_SUPPORT_YES;
126 network->mdns = RESOLVE_SUPPORT_NO;
127 network->dnssec_mode = _DNSSEC_MODE_INVALID;
128
129 network->link_local = ADDRESS_FAMILY_IPV6;
130
131 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
132 network->ipv6_accept_ra = -1;
133 network->ipv6_dad_transmits = -1;
134 network->ipv6_hop_limit = -1;
135 network->duid.type = _DUID_TYPE_INVALID;
136 network->proxy_arp = -1;
137 network->arp = -1;
138 network->ipv6_accept_ra_use_dns = true;
139
140 r = config_parse(NULL, filename, file,
141 "Match\0"
142 "Link\0"
143 "Network\0"
144 "Address\0"
145 "Route\0"
146 "DHCP\0"
147 "DHCPv4\0" /* compat */
148 "DHCPServer\0"
149 "IPv6AcceptRA\0"
150 "Bridge\0"
151 "BridgeFDB\0"
152 "BridgeVLAN\0",
153 config_item_perf_lookup, network_network_gperf_lookup,
154 false, false, true, network);
155 if (r < 0)
156 return r;
157
158 /* IPMasquerade=yes implies IPForward=yes */
159 if (network->ip_masquerade)
160 network->ip_forward |= ADDRESS_FAMILY_IPV4;
161
162 LIST_PREPEND(networks, manager->networks, network);
163
164 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
165 if (r < 0)
166 return r;
167
168 r = hashmap_put(manager->networks_by_name, network->name, network);
169 if (r < 0)
170 return r;
171
172 LIST_FOREACH(routes, route, network->static_routes) {
173 if (!route->family) {
174 log_warning("Route section without Gateway field configured in %s. "
175 "Ignoring", filename);
176 return 0;
177 }
178 }
179
180 LIST_FOREACH(addresses, address, network->static_addresses) {
181 if (!address->family) {
182 log_warning("Address section without Address field configured in %s. "
183 "Ignoring", filename);
184 return 0;
185 }
186 }
187
188 network = NULL;
189
190 return 0;
191 }
192
193 int network_load(Manager *manager) {
194 Network *network;
195 _cleanup_strv_free_ char **files = NULL;
196 char **f;
197 int r;
198
199 assert(manager);
200
201 while ((network = manager->networks))
202 network_free(network);
203
204 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
205 if (r < 0)
206 return log_error_errno(r, "Failed to enumerate network files: %m");
207
208 STRV_FOREACH_BACKWARDS(f, files) {
209 r = network_load_one(manager, *f);
210 if (r < 0)
211 return r;
212 }
213
214 return 0;
215 }
216
217 void network_free(Network *network) {
218 NetDev *netdev;
219 Route *route;
220 Address *address;
221 FdbEntry *fdb_entry;
222 Iterator i;
223
224 if (!network)
225 return;
226
227 free(network->filename);
228
229 free(network->match_mac);
230 strv_free(network->match_path);
231 strv_free(network->match_driver);
232 strv_free(network->match_type);
233 strv_free(network->match_name);
234
235 free(network->description);
236 free(network->dhcp_vendor_class_identifier);
237 free(network->dhcp_hostname);
238
239 free(network->mac);
240
241 strv_free(network->ntp);
242 strv_free(network->dns);
243 strv_free(network->search_domains);
244 strv_free(network->route_domains);
245 strv_free(network->bind_carrier);
246
247 netdev_unref(network->bridge);
248 netdev_unref(network->bond);
249 netdev_unref(network->vrf);
250
251 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
252 hashmap_remove(network->stacked_netdevs, netdev->ifname);
253 netdev_unref(netdev);
254 }
255 hashmap_free(network->stacked_netdevs);
256
257 while ((route = network->static_routes))
258 route_free(route);
259
260 while ((address = network->static_addresses))
261 address_free(address);
262
263 while ((fdb_entry = network->static_fdb_entries))
264 fdb_entry_free(fdb_entry);
265
266 hashmap_free(network->addresses_by_section);
267 hashmap_free(network->routes_by_section);
268 hashmap_free(network->fdb_entries_by_section);
269
270 if (network->manager) {
271 if (network->manager->networks)
272 LIST_REMOVE(networks, network->manager->networks, network);
273
274 if (network->manager->networks_by_name)
275 hashmap_remove(network->manager->networks_by_name, network->name);
276 }
277
278 free(network->name);
279
280 condition_free_list(network->match_host);
281 condition_free_list(network->match_virt);
282 condition_free_list(network->match_kernel);
283 condition_free_list(network->match_arch);
284
285 free(network->dhcp_server_timezone);
286 free(network->dhcp_server_dns);
287 free(network->dhcp_server_ntp);
288
289 set_free_free(network->dnssec_negative_trust_anchors);
290
291 free(network);
292 }
293
294 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
295 Network *network;
296
297 assert(manager);
298 assert(name);
299 assert(ret);
300
301 network = hashmap_get(manager->networks_by_name, name);
302 if (!network)
303 return -ENOENT;
304
305 *ret = network;
306
307 return 0;
308 }
309
310 int network_get(Manager *manager, struct udev_device *device,
311 const char *ifname, const struct ether_addr *address,
312 Network **ret) {
313 Network *network;
314 struct udev_device *parent;
315 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
316
317 assert(manager);
318 assert(ret);
319
320 if (device) {
321 path = udev_device_get_property_value(device, "ID_PATH");
322
323 parent = udev_device_get_parent(device);
324 if (parent)
325 parent_driver = udev_device_get_driver(parent);
326
327 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
328
329 devtype = udev_device_get_devtype(device);
330 }
331
332 LIST_FOREACH(networks, network, manager->networks) {
333 if (net_match_config(network->match_mac, network->match_path,
334 network->match_driver, network->match_type,
335 network->match_name, network->match_host,
336 network->match_virt, network->match_kernel,
337 network->match_arch,
338 address, path, parent_driver, driver,
339 devtype, ifname)) {
340 if (network->match_name && device) {
341 const char *attr;
342 uint8_t name_assign_type = NET_NAME_UNKNOWN;
343
344 attr = udev_device_get_sysattr_value(device, "name_assign_type");
345 if (attr)
346 (void) safe_atou8(attr, &name_assign_type);
347
348 if (name_assign_type == NET_NAME_ENUM)
349 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
350 ifname, network->filename);
351 else
352 log_debug("%s: found matching network '%s'", ifname, network->filename);
353 } else
354 log_debug("%s: found matching network '%s'", ifname, network->filename);
355
356 *ret = network;
357 return 0;
358 }
359 }
360
361 *ret = NULL;
362
363 return -ENOENT;
364 }
365
366 int network_apply(Manager *manager, Network *network, Link *link) {
367 int r;
368
369 assert(manager);
370 assert(network);
371 assert(link);
372
373 link->network = network;
374
375 if (network->ipv4ll_route) {
376 Route *route;
377
378 r = route_new_static(network, 0, &route);
379 if (r < 0)
380 return r;
381
382 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
383 if (r == 0)
384 return -EINVAL;
385 if (r < 0)
386 return -errno;
387
388 route->family = AF_INET;
389 route->dst_prefixlen = 16;
390 route->scope = RT_SCOPE_LINK;
391 route->priority = IPV4LL_ROUTE_METRIC;
392 route->protocol = RTPROT_STATIC;
393 }
394
395 if (!strv_isempty(network->dns) ||
396 !strv_isempty(network->ntp) ||
397 !strv_isempty(network->search_domains) ||
398 !strv_isempty(network->route_domains))
399 link_dirty(link);
400
401 return 0;
402 }
403
404 bool network_has_static_ipv6_addresses(Network *network) {
405 Address *address;
406
407 assert(network);
408
409 LIST_FOREACH(addresses, address, network->static_addresses) {
410 if (address->family == AF_INET6)
411 return true;
412 }
413
414 return false;
415 }
416
417 int config_parse_netdev(const char *unit,
418 const char *filename,
419 unsigned line,
420 const char *section,
421 unsigned section_line,
422 const char *lvalue,
423 int ltype,
424 const char *rvalue,
425 void *data,
426 void *userdata) {
427 Network *network = userdata;
428 _cleanup_free_ char *kind_string = NULL;
429 char *p;
430 NetDev *netdev;
431 NetDevKind kind;
432 int r;
433
434 assert(filename);
435 assert(lvalue);
436 assert(rvalue);
437 assert(data);
438
439 kind_string = strdup(lvalue);
440 if (!kind_string)
441 return log_oom();
442
443 /* the keys are CamelCase versions of the kind */
444 for (p = kind_string; *p; p++)
445 *p = tolower(*p);
446
447 kind = netdev_kind_from_string(kind_string);
448 if (kind == _NETDEV_KIND_INVALID) {
449 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
450 return 0;
451 }
452
453 r = netdev_get(network->manager, rvalue, &netdev);
454 if (r < 0) {
455 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
456 return 0;
457 }
458
459 if (netdev->kind != kind) {
460 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
461 return 0;
462 }
463
464 switch (kind) {
465 case NETDEV_KIND_BRIDGE:
466 network->bridge = netdev;
467
468 break;
469 case NETDEV_KIND_BOND:
470 network->bond = netdev;
471
472 break;
473 case NETDEV_KIND_VRF:
474 network->vrf = netdev;
475
476 break;
477 case NETDEV_KIND_VLAN:
478 case NETDEV_KIND_MACVLAN:
479 case NETDEV_KIND_MACVTAP:
480 case NETDEV_KIND_IPVLAN:
481 case NETDEV_KIND_VXLAN:
482 case NETDEV_KIND_VCAN:
483 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
484 if (r < 0) {
485 log_syntax(unit, LOG_ERR, filename, line, r, "Can not add VLAN '%s' to network: %m", rvalue);
486 return 0;
487 }
488
489 break;
490 default:
491 assert_not_reached("Can not parse NetDev");
492 }
493
494 netdev_ref(netdev);
495
496 return 0;
497 }
498
499 int config_parse_domains(
500 const char *unit,
501 const char *filename,
502 unsigned line,
503 const char *section,
504 unsigned section_line,
505 const char *lvalue,
506 int ltype,
507 const char *rvalue,
508 void *data,
509 void *userdata) {
510
511 const char *p;
512 Network *n = data;
513 int r;
514
515 assert(n);
516 assert(lvalue);
517 assert(rvalue);
518
519 if (isempty(rvalue)) {
520 n->search_domains = strv_free(n->search_domains);
521 n->route_domains = strv_free(n->route_domains);
522 return 0;
523 }
524
525 p = rvalue;
526 for (;;) {
527 _cleanup_free_ char *w = NULL, *normalized = NULL;
528 const char *domain;
529 bool is_route;
530
531 r = extract_first_word(&p, &w, NULL, 0);
532 if (r < 0) {
533 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
534 break;
535 }
536 if (r == 0)
537 break;
538
539 is_route = w[0] == '~';
540 domain = is_route ? w + 1 : w;
541
542 if (dns_name_is_root(domain) || streq(domain, "*")) {
543 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
544 * routing domain, unconditionally. */
545 is_route = true;
546 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
547
548 } else {
549 r = dns_name_normalize(domain, &normalized);
550 if (r < 0) {
551 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
552 continue;
553 }
554
555 domain = normalized;
556
557 if (is_localhost(domain)) {
558 log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain);
559 continue;
560 }
561 }
562
563 if (is_route) {
564 r = strv_extend(&n->route_domains, domain);
565 if (r < 0)
566 return log_oom();
567
568 } else {
569 r = strv_extend(&n->search_domains, domain);
570 if (r < 0)
571 return log_oom();
572 }
573 }
574
575 strv_uniq(n->route_domains);
576 strv_uniq(n->search_domains);
577
578 return 0;
579 }
580
581 int config_parse_tunnel(const char *unit,
582 const char *filename,
583 unsigned line,
584 const char *section,
585 unsigned section_line,
586 const char *lvalue,
587 int ltype,
588 const char *rvalue,
589 void *data,
590 void *userdata) {
591 Network *network = userdata;
592 NetDev *netdev;
593 int r;
594
595 assert(filename);
596 assert(lvalue);
597 assert(rvalue);
598 assert(data);
599
600 r = netdev_get(network->manager, rvalue, &netdev);
601 if (r < 0) {
602 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
603 return 0;
604 }
605
606 if (netdev->kind != NETDEV_KIND_IPIP &&
607 netdev->kind != NETDEV_KIND_SIT &&
608 netdev->kind != NETDEV_KIND_GRE &&
609 netdev->kind != NETDEV_KIND_GRETAP &&
610 netdev->kind != NETDEV_KIND_IP6GRE &&
611 netdev->kind != NETDEV_KIND_IP6GRETAP &&
612 netdev->kind != NETDEV_KIND_VTI &&
613 netdev->kind != NETDEV_KIND_VTI6 &&
614 netdev->kind != NETDEV_KIND_IP6TNL
615 ) {
616 log_syntax(unit, LOG_ERR, filename, line, 0,
617 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
618 return 0;
619 }
620
621 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
622 if (r < 0) {
623 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
624 return 0;
625 }
626
627 netdev_ref(netdev);
628
629 return 0;
630 }
631
632 int config_parse_ipv4ll(
633 const char* unit,
634 const char *filename,
635 unsigned line,
636 const char *section,
637 unsigned section_line,
638 const char *lvalue,
639 int ltype,
640 const char *rvalue,
641 void *data,
642 void *userdata) {
643
644 AddressFamilyBoolean *link_local = data;
645
646 assert(filename);
647 assert(lvalue);
648 assert(rvalue);
649 assert(data);
650
651 /* Note that this is mostly like
652 * config_parse_address_family_boolean(), except that it
653 * applies only to IPv4 */
654
655 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
656
657 return 0;
658 }
659
660 int config_parse_dhcp(
661 const char* unit,
662 const char *filename,
663 unsigned line,
664 const char *section,
665 unsigned section_line,
666 const char *lvalue,
667 int ltype,
668 const char *rvalue,
669 void *data,
670 void *userdata) {
671
672 AddressFamilyBoolean *dhcp = data, s;
673
674 assert(filename);
675 assert(lvalue);
676 assert(rvalue);
677 assert(data);
678
679 /* Note that this is mostly like
680 * config_parse_address_family_boolean(), except that it
681 * understands some old names for the enum values */
682
683 s = address_family_boolean_from_string(rvalue);
684 if (s < 0) {
685
686 /* Previously, we had a slightly different enum here,
687 * support its values for compatbility. */
688
689 if (streq(rvalue, "none"))
690 s = ADDRESS_FAMILY_NO;
691 else if (streq(rvalue, "v4"))
692 s = ADDRESS_FAMILY_IPV4;
693 else if (streq(rvalue, "v6"))
694 s = ADDRESS_FAMILY_IPV6;
695 else if (streq(rvalue, "both"))
696 s = ADDRESS_FAMILY_YES;
697 else {
698 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
699 return 0;
700 }
701 }
702
703 *dhcp = s;
704 return 0;
705 }
706
707 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
708 [DHCP_CLIENT_ID_MAC] = "mac",
709 [DHCP_CLIENT_ID_DUID] = "duid"
710 };
711
712 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
713 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
714
715 int config_parse_ipv6token(
716 const char* unit,
717 const char *filename,
718 unsigned line,
719 const char *section,
720 unsigned section_line,
721 const char *lvalue,
722 int ltype,
723 const char *rvalue,
724 void *data,
725 void *userdata) {
726
727 union in_addr_union buffer;
728 struct in6_addr *token = data;
729 int r;
730
731 assert(filename);
732 assert(lvalue);
733 assert(rvalue);
734 assert(token);
735
736 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
737 if (r < 0) {
738 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
739 return 0;
740 }
741
742 r = in_addr_is_null(AF_INET6, &buffer);
743 if (r != 0) {
744 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
745 return 0;
746 }
747
748 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
749 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
750 return 0;
751 }
752
753 *token = buffer.in6;
754
755 return 0;
756 }
757
758 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
759 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
760 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
761 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
762 };
763
764 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
765
766 int config_parse_ipv6_privacy_extensions(
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 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
779 int k;
780
781 assert(filename);
782 assert(lvalue);
783 assert(rvalue);
784 assert(ipv6_privacy_extensions);
785
786 /* Our enum shall be a superset of booleans, hence first try
787 * to parse as boolean, and then as enum */
788
789 k = parse_boolean(rvalue);
790 if (k > 0)
791 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
792 else if (k == 0)
793 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
794 else {
795 IPv6PrivacyExtensions s;
796
797 s = ipv6_privacy_extensions_from_string(rvalue);
798 if (s < 0) {
799
800 if (streq(rvalue, "kernel"))
801 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
802 else {
803 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
804 return 0;
805 }
806 }
807
808 *ipv6_privacy_extensions = s;
809 }
810
811 return 0;
812 }
813
814 int config_parse_hostname(
815 const char *unit,
816 const char *filename,
817 unsigned line,
818 const char *section,
819 unsigned section_line,
820 const char *lvalue,
821 int ltype,
822 const char *rvalue,
823 void *data,
824 void *userdata) {
825
826 char **hostname = data, *hn = NULL;
827 int r;
828
829 assert(filename);
830 assert(lvalue);
831 assert(rvalue);
832
833 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
834 if (r < 0)
835 return r;
836
837 if (!hostname_is_valid(hn, false)) {
838 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
839 free(hn);
840 return 0;
841 }
842
843 free(*hostname);
844 *hostname = hostname_cleanup(hn);
845 return 0;
846 }
847
848 int config_parse_timezone(
849 const char *unit,
850 const char *filename,
851 unsigned line,
852 const char *section,
853 unsigned section_line,
854 const char *lvalue,
855 int ltype,
856 const char *rvalue,
857 void *data,
858 void *userdata) {
859
860 char **datap = data, *tz = NULL;
861 int r;
862
863 assert(filename);
864 assert(lvalue);
865 assert(rvalue);
866
867 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
868 if (r < 0)
869 return r;
870
871 if (!timezone_is_valid(tz)) {
872 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
873 free(tz);
874 return 0;
875 }
876
877 free(*datap);
878 *datap = tz;
879
880 return 0;
881 }
882
883 int config_parse_dhcp_server_dns(
884 const char *unit,
885 const char *filename,
886 unsigned line,
887 const char *section,
888 unsigned section_line,
889 const char *lvalue,
890 int ltype,
891 const char *rvalue,
892 void *data,
893 void *userdata) {
894
895 Network *n = data;
896 const char *p = rvalue;
897 int r;
898
899 assert(filename);
900 assert(lvalue);
901 assert(rvalue);
902
903 for (;;) {
904 _cleanup_free_ char *w = NULL;
905 struct in_addr a, *m;
906
907 r = extract_first_word(&p, &w, NULL, 0);
908 if (r < 0) {
909 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
910 return 0;
911 }
912
913 if (r == 0)
914 return 0;
915
916 if (inet_pton(AF_INET, w, &a) <= 0) {
917 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
918 continue;
919 }
920
921 m = realloc(n->dhcp_server_dns, (n->n_dhcp_server_dns + 1) * sizeof(struct in_addr));
922 if (!m)
923 return log_oom();
924
925 m[n->n_dhcp_server_dns++] = a;
926 n->dhcp_server_dns = m;
927 }
928 }
929
930 int config_parse_dhcp_server_ntp(
931 const char *unit,
932 const char *filename,
933 unsigned line,
934 const char *section,
935 unsigned section_line,
936 const char *lvalue,
937 int ltype,
938 const char *rvalue,
939 void *data,
940 void *userdata) {
941
942 Network *n = data;
943 const char *p = rvalue;
944 int r;
945
946 assert(filename);
947 assert(lvalue);
948 assert(rvalue);
949
950 for (;;) {
951 _cleanup_free_ char *w = NULL;
952 struct in_addr a, *m;
953
954 r = extract_first_word(&p, &w, NULL, 0);
955 if (r < 0) {
956 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
957 return 0;
958 }
959
960 if (r == 0)
961 return 0;
962
963 if (inet_pton(AF_INET, w, &a) <= 0) {
964 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
965 continue;
966 }
967
968 m = realloc(n->dhcp_server_ntp, (n->n_dhcp_server_ntp + 1) * sizeof(struct in_addr));
969 if (!m)
970 return log_oom();
971
972 m[n->n_dhcp_server_ntp++] = a;
973 n->dhcp_server_ntp = m;
974 }
975 }
976
977 int config_parse_dnssec_negative_trust_anchors(
978 const char *unit,
979 const char *filename,
980 unsigned line,
981 const char *section,
982 unsigned section_line,
983 const char *lvalue,
984 int ltype,
985 const char *rvalue,
986 void *data,
987 void *userdata) {
988
989 const char *p = rvalue;
990 Network *n = data;
991 int r;
992
993 assert(n);
994 assert(lvalue);
995 assert(rvalue);
996
997 if (isempty(rvalue)) {
998 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
999 return 0;
1000 }
1001
1002 for (;;) {
1003 _cleanup_free_ char *w = NULL;
1004
1005 r = extract_first_word(&p, &w, NULL, 0);
1006 if (r < 0) {
1007 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1008 break;
1009 }
1010 if (r == 0)
1011 break;
1012
1013 r = dns_name_is_valid(w);
1014 if (r <= 0) {
1015 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1016 continue;
1017 }
1018
1019 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1020 if (r < 0)
1021 return log_oom();
1022
1023 r = set_put(n->dnssec_negative_trust_anchors, w);
1024 if (r < 0)
1025 return log_oom();
1026 if (r > 0)
1027 w = NULL;
1028 }
1029
1030 return 0;
1031 }
1032
1033 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1034
1035 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1036 [DHCP_USE_DOMAINS_NO] = "no",
1037 [DHCP_USE_DOMAINS_ROUTE] = "route",
1038 [DHCP_USE_DOMAINS_YES] = "yes",
1039 };
1040
1041 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1042
1043 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1044
1045 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1046 [LLDP_MODE_NO] = "no",
1047 [LLDP_MODE_YES] = "yes",
1048 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1049 };
1050
1051 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);