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