1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "conf-files.h"
26 #include "conf-parser.h"
28 #include "hostname-util.h"
30 #include "networkd-netdev.h"
31 #include "networkd-link.h"
32 #include "network-internal.h"
33 #include "dns-domain.h"
35 static int network_load_one(Manager
*manager
, const char *filename
) {
36 _cleanup_network_free_ Network
*network
= NULL
;
37 _cleanup_fclose_
FILE *file
= NULL
;
46 file
= fopen(filename
, "re");
54 if (null_or_empty_fd(fileno(file
))) {
55 log_debug("Skipping empty file: %s", filename
);
59 network
= new0(Network
, 1);
63 network
->manager
= manager
;
65 LIST_HEAD_INIT(network
->static_addresses
);
66 LIST_HEAD_INIT(network
->static_routes
);
67 LIST_HEAD_INIT(network
->static_fdb_entries
);
69 network
->stacked_netdevs
= hashmap_new(&string_hash_ops
);
70 if (!network
->stacked_netdevs
)
73 network
->addresses_by_section
= hashmap_new(NULL
);
74 if (!network
->addresses_by_section
)
77 network
->routes_by_section
= hashmap_new(NULL
);
78 if (!network
->routes_by_section
)
81 network
->fdb_entries_by_section
= hashmap_new(NULL
);
82 if (!network
->fdb_entries_by_section
)
85 network
->filename
= strdup(filename
);
86 if (!network
->filename
)
89 network
->name
= strdup(basename(filename
));
93 d
= strrchr(network
->name
, '.');
97 assert(streq(d
, ".network"));
101 network
->dhcp
= ADDRESS_FAMILY_NO
;
102 network
->dhcp_ntp
= true;
103 network
->dhcp_dns
= true;
104 network
->dhcp_hostname
= true;
105 network
->dhcp_routes
= true;
106 network
->dhcp_sendhost
= true;
107 network
->dhcp_route_metric
= DHCP_ROUTE_METRIC
;
108 network
->dhcp_client_identifier
= DHCP_CLIENT_ID_DUID
;
110 network
->use_bpdu
= true;
111 network
->allow_port_to_be_root
= true;
112 network
->unicast_flood
= true;
114 network
->llmnr
= LLMNR_SUPPORT_YES
;
116 network
->link_local
= ADDRESS_FAMILY_IPV6
;
118 network
->ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
120 r
= config_parse(NULL
, filename
, file
,
130 config_item_perf_lookup
, network_network_gperf_lookup
,
131 false, false, true, network
);
135 /* IPMasquerade=yes implies IPForward=yes */
136 if (network
->ip_masquerade
)
137 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
139 LIST_PREPEND(networks
, manager
->networks
, network
);
141 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
145 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
149 LIST_FOREACH(routes
, route
, network
->static_routes
) {
150 if (!route
->family
) {
151 log_warning("Route section without Gateway field configured in %s. "
152 "Ignoring", filename
);
157 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
158 if (!address
->family
) {
159 log_warning("Address section without Address field configured in %s. "
160 "Ignoring", filename
);
170 int network_load(Manager
*manager
) {
172 _cleanup_strv_free_
char **files
= NULL
;
178 while ((network
= manager
->networks
))
179 network_free(network
);
181 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
183 return log_error_errno(r
, "Failed to enumerate network files: %m");
185 STRV_FOREACH_BACKWARDS(f
, files
) {
186 r
= network_load_one(manager
, *f
);
194 void network_free(Network
*network
) {
204 free(network
->filename
);
206 free(network
->match_mac
);
207 strv_free(network
->match_path
);
208 strv_free(network
->match_driver
);
209 strv_free(network
->match_type
);
210 strv_free(network
->match_name
);
212 free(network
->description
);
213 free(network
->dhcp_vendor_class_identifier
);
214 free(network
->hostname
);
218 strv_free(network
->ntp
);
219 strv_free(network
->dns
);
220 strv_free(network
->domains
);
221 strv_free(network
->bind_carrier
);
223 netdev_unref(network
->bridge
);
225 netdev_unref(network
->bond
);
227 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
228 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
229 netdev_unref(netdev
);
231 hashmap_free(network
->stacked_netdevs
);
233 while ((route
= network
->static_routes
))
236 while ((address
= network
->static_addresses
))
237 address_free(address
);
239 while ((fdb_entry
= network
->static_fdb_entries
))
240 fdb_entry_free(fdb_entry
);
242 hashmap_free(network
->addresses_by_section
);
243 hashmap_free(network
->routes_by_section
);
244 hashmap_free(network
->fdb_entries_by_section
);
246 if (network
->manager
) {
247 if (network
->manager
->networks
)
248 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
250 if (network
->manager
->networks_by_name
)
251 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
256 condition_free_list(network
->match_host
);
257 condition_free_list(network
->match_virt
);
258 condition_free_list(network
->match_kernel
);
259 condition_free_list(network
->match_arch
);
264 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
271 network
= hashmap_get(manager
->networks_by_name
, name
);
280 int network_get(Manager
*manager
, struct udev_device
*device
,
281 const char *ifname
, const struct ether_addr
*address
,
284 struct udev_device
*parent
;
285 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
291 path
= udev_device_get_property_value(device
, "ID_PATH");
293 parent
= udev_device_get_parent(device
);
295 parent_driver
= udev_device_get_driver(parent
);
297 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
299 devtype
= udev_device_get_devtype(device
);
302 LIST_FOREACH(networks
, network
, manager
->networks
) {
303 if (net_match_config(network
->match_mac
, network
->match_path
,
304 network
->match_driver
, network
->match_type
,
305 network
->match_name
, network
->match_host
,
306 network
->match_virt
, network
->match_kernel
,
308 address
, path
, parent_driver
, driver
,
310 if (network
->match_name
&& device
) {
312 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
314 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
316 (void) safe_atou8(attr
, &name_assign_type
);
318 if (name_assign_type
== NET_NAME_ENUM
)
319 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
320 IFNAMSIZ
, ifname
, network
->filename
);
322 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
324 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
336 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
339 link
->network
= network
;
341 if (network
->ipv4ll_route
) {
344 r
= route_new_static(network
, 0, &route
);
348 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst_addr
.in
);
354 route
->family
= AF_INET
;
355 route
->dst_prefixlen
= 16;
356 route
->scope
= RT_SCOPE_LINK
;
357 route
->metrics
= IPV4LL_ROUTE_METRIC
;
358 route
->protocol
= RTPROT_STATIC
;
361 if (network
->dns
|| network
->ntp
) {
370 int config_parse_netdev(const char *unit
,
371 const char *filename
,
374 unsigned section_line
,
380 Network
*network
= userdata
;
381 _cleanup_free_
char *kind_string
= NULL
;
392 kind_string
= strdup(lvalue
);
396 /* the keys are CamelCase versions of the kind */
397 for (p
= kind_string
; *p
; p
++)
400 kind
= netdev_kind_from_string(kind_string
);
401 if (kind
== _NETDEV_KIND_INVALID
) {
402 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
403 "Invalid NetDev kind: %s", lvalue
);
407 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
409 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
410 "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
414 if (netdev
->kind
!= kind
) {
415 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
416 "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
421 case NETDEV_KIND_BRIDGE
:
422 network
->bridge
= netdev
;
425 case NETDEV_KIND_BOND
:
426 network
->bond
= netdev
;
429 case NETDEV_KIND_VLAN
:
430 case NETDEV_KIND_MACVLAN
:
431 case NETDEV_KIND_IPVLAN
:
432 case NETDEV_KIND_VXLAN
:
433 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
435 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
436 "Can not add VLAN '%s' to network: %m",
443 assert_not_reached("Can not parse NetDev");
451 int config_parse_domains(const char *unit
,
452 const char *filename
,
455 unsigned section_line
,
461 Network
*network
= userdata
;
462 char ***domains
= data
;
466 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
467 lvalue
, ltype
, rvalue
, domains
, userdata
);
472 network
->wildcard_domain
= !!strv_find(*domains
, "*");
474 STRV_FOREACH(domain
, *domains
) {
475 if (is_localhost(*domain
))
476 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
478 r
= dns_name_is_valid(*domain
);
479 if (r
<= 0 && !streq(*domain
, "*")) {
481 log_error_errno(r
, "Failed to validate domain name: %s: %m", *domain
);
483 log_warning("Domain name is not valid, ignoring assignment: %s", *domain
);
488 strv_remove(*domains
, *domain
);
490 /* We removed one entry, make sure we don't skip the next one */
497 int config_parse_tunnel(const char *unit
,
498 const char *filename
,
501 unsigned section_line
,
507 Network
*network
= userdata
;
516 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
518 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
522 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
523 netdev
->kind
!= NETDEV_KIND_SIT
&&
524 netdev
->kind
!= NETDEV_KIND_GRE
&&
525 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
526 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
527 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
528 netdev
->kind
!= NETDEV_KIND_VTI
&&
529 netdev
->kind
!= NETDEV_KIND_VTI6
&&
530 netdev
->kind
!= NETDEV_KIND_IP6TNL
532 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
533 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
537 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
539 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
548 int config_parse_ipv4ll(
550 const char *filename
,
553 unsigned section_line
,
560 AddressFamilyBoolean
*link_local
= data
;
567 /* Note that this is mostly like
568 * config_parse_address_family_boolean(), except that it
569 * applies only to IPv4 */
571 if (parse_boolean(rvalue
))
572 *link_local
|= ADDRESS_FAMILY_IPV4
;
574 *link_local
&= ~ADDRESS_FAMILY_IPV4
;
579 int config_parse_dhcp(
581 const char *filename
,
584 unsigned section_line
,
591 AddressFamilyBoolean
*dhcp
= data
, s
;
598 /* Note that this is mostly like
599 * config_parse_address_family_boolean(), except that it
600 * understands some old names for the enum values */
602 s
= address_family_boolean_from_string(rvalue
);
605 /* Previously, we had a slightly different enum here,
606 * support its values for compatbility. */
608 if (streq(rvalue
, "none"))
609 s
= ADDRESS_FAMILY_NO
;
610 else if (streq(rvalue
, "v4"))
611 s
= ADDRESS_FAMILY_IPV4
;
612 else if (streq(rvalue
, "v6"))
613 s
= ADDRESS_FAMILY_IPV6
;
614 else if (streq(rvalue
, "both"))
615 s
= ADDRESS_FAMILY_YES
;
617 log_syntax(unit
, LOG_ERR
, filename
, line
, s
, "Failed to parse DHCP option, ignoring: %s", rvalue
);
626 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
627 [DHCP_CLIENT_ID_MAC
] = "mac",
628 [DHCP_CLIENT_ID_DUID
] = "duid"
631 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DCHPClientIdentifier
);
632 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DCHPClientIdentifier
, "Failed to parse client identifier type");
634 static const char* const llmnr_support_table
[_LLMNR_SUPPORT_MAX
] = {
635 [LLMNR_SUPPORT_NO
] = "no",
636 [LLMNR_SUPPORT_YES
] = "yes",
637 [LLMNR_SUPPORT_RESOLVE
] = "resolve",
640 DEFINE_STRING_TABLE_LOOKUP(llmnr_support
, LLMNRSupport
);
642 int config_parse_llmnr(
644 const char *filename
,
647 unsigned section_line
,
654 LLMNRSupport
*llmnr
= data
;
662 /* Our enum shall be a superset of booleans, hence first try
663 * to parse as boolean, and then as enum */
665 k
= parse_boolean(rvalue
);
667 *llmnr
= LLMNR_SUPPORT_YES
;
669 *llmnr
= LLMNR_SUPPORT_NO
;
673 s
= llmnr_support_from_string(rvalue
);
675 log_syntax(unit
, LOG_ERR
, filename
, line
, -s
, "Failed to parse LLMNR option, ignoring: %s", rvalue
);
685 int config_parse_ipv6token(
687 const char *filename
,
690 unsigned section_line
,
697 union in_addr_union buffer
;
698 struct in6_addr
*token
= data
;
706 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
708 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
712 r
= in_addr_is_null(AF_INET6
, &buffer
);
714 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
718 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
719 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);
728 int config_parse_address_family_boolean_with_kernel(
730 const char *filename
,
733 unsigned section_line
,
740 AddressFamilyBoolean
*fwd
= data
, s
;
747 s
= address_family_boolean_from_string(rvalue
);
749 if (streq(rvalue
, "kernel"))
750 s
= _ADDRESS_FAMILY_BOOLEAN_INVALID
;
752 log_syntax(unit
, LOG_ERR
, filename
, line
, s
, "Failed to parse IPForwarding option, ignoring: %s", rvalue
);
762 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
763 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
764 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
765 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
768 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
770 int config_parse_ipv6_privacy_extensions(
772 const char *filename
,
775 unsigned section_line
,
782 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
788 assert(ipv6_privacy_extensions
);
790 /* Our enum shall be a superset of booleans, hence first try
791 * to parse as boolean, and then as enum */
793 k
= parse_boolean(rvalue
);
795 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
797 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
799 IPv6PrivacyExtensions s
;
801 s
= ipv6_privacy_extensions_from_string(rvalue
);
804 if (streq(rvalue
, "kernel"))
805 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
807 log_syntax(unit
, LOG_ERR
, filename
, line
, s
, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
812 *ipv6_privacy_extensions
= s
;
818 int config_parse_hostname(const char *unit
,
819 const char *filename
,
822 unsigned section_line
,
828 char **hostname
= data
;
836 r
= config_parse_string(unit
, filename
, line
, section
, section_line
,
837 lvalue
, ltype
, rvalue
, &hn
, userdata
);
841 if (!hostname_is_valid(hn
, true)) {
842 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "hostname is not valid, ignoring assignment: %s", rvalue
);
848 *hostname
= hostname_cleanup(hn
);