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