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