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
->llmnr
= LLMNR_SUPPORT_YES
;
112 network
->link_local
= ADDRESS_FAMILY_IPV6
;
114 network
->ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
116 r
= config_parse(NULL
, filename
, file
,
126 config_item_perf_lookup
, network_network_gperf_lookup
,
127 false, false, true, network
);
131 /* IPMasquerade=yes implies IPForward=yes */
132 if (network
->ip_masquerade
)
133 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
135 LIST_PREPEND(networks
, manager
->networks
, network
);
137 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
141 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
145 LIST_FOREACH(routes
, route
, network
->static_routes
) {
146 if (!route
->family
) {
147 log_warning("Route section without Gateway field configured in %s. "
148 "Ignoring", filename
);
153 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
154 if (!address
->family
) {
155 log_warning("Address section without Address field configured in %s. "
156 "Ignoring", filename
);
166 int network_load(Manager
*manager
) {
168 _cleanup_strv_free_
char **files
= NULL
;
174 while ((network
= manager
->networks
))
175 network_free(network
);
177 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
179 return log_error_errno(r
, "Failed to enumerate network files: %m");
181 STRV_FOREACH_BACKWARDS(f
, files
) {
182 r
= network_load_one(manager
, *f
);
190 void network_free(Network
*network
) {
200 free(network
->filename
);
202 free(network
->match_mac
);
203 strv_free(network
->match_path
);
204 strv_free(network
->match_driver
);
205 strv_free(network
->match_type
);
206 strv_free(network
->match_name
);
208 free(network
->description
);
209 free(network
->dhcp_vendor_class_identifier
);
213 strv_free(network
->ntp
);
214 strv_free(network
->dns
);
215 strv_free(network
->domains
);
216 strv_free(network
->bind_carrier
);
218 netdev_unref(network
->bridge
);
220 netdev_unref(network
->bond
);
222 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
223 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
224 netdev_unref(netdev
);
226 hashmap_free(network
->stacked_netdevs
);
228 while ((route
= network
->static_routes
))
231 while ((address
= network
->static_addresses
))
232 address_free(address
);
234 while ((fdb_entry
= network
->static_fdb_entries
))
235 fdb_entry_free(fdb_entry
);
237 hashmap_free(network
->addresses_by_section
);
238 hashmap_free(network
->routes_by_section
);
239 hashmap_free(network
->fdb_entries_by_section
);
241 if (network
->manager
) {
242 if (network
->manager
->networks
)
243 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
245 if (network
->manager
->networks_by_name
)
246 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
251 condition_free_list(network
->match_host
);
252 condition_free_list(network
->match_virt
);
253 condition_free_list(network
->match_kernel
);
254 condition_free_list(network
->match_arch
);
259 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
266 network
= hashmap_get(manager
->networks_by_name
, name
);
275 int network_get(Manager
*manager
, struct udev_device
*device
,
276 const char *ifname
, const struct ether_addr
*address
,
279 struct udev_device
*parent
;
280 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
286 path
= udev_device_get_property_value(device
, "ID_PATH");
288 parent
= udev_device_get_parent(device
);
290 parent_driver
= udev_device_get_driver(parent
);
292 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
294 devtype
= udev_device_get_devtype(device
);
297 LIST_FOREACH(networks
, network
, manager
->networks
) {
298 if (net_match_config(network
->match_mac
, network
->match_path
,
299 network
->match_driver
, network
->match_type
,
300 network
->match_name
, network
->match_host
,
301 network
->match_virt
, network
->match_kernel
,
303 address
, path
, parent_driver
, driver
,
305 if (network
->match_name
&& device
) {
307 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
309 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
311 (void) safe_atou8(attr
, &name_assign_type
);
313 if (name_assign_type
== NET_NAME_ENUM
)
314 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
315 IFNAMSIZ
, ifname
, network
->filename
);
317 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
319 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
331 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
334 link
->network
= network
;
336 if (network
->ipv4ll_route
) {
339 r
= route_new_static(network
, 0, &route
);
343 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst_addr
.in
);
349 route
->family
= AF_INET
;
350 route
->dst_prefixlen
= 16;
351 route
->scope
= RT_SCOPE_LINK
;
352 route
->metrics
= IPV4LL_ROUTE_METRIC
;
353 route
->protocol
= RTPROT_STATIC
;
356 if (network
->dns
|| network
->ntp
) {
365 int config_parse_netdev(const char *unit
,
366 const char *filename
,
369 unsigned section_line
,
375 Network
*network
= userdata
;
376 _cleanup_free_
char *kind_string
= NULL
;
387 kind_string
= strdup(lvalue
);
391 /* the keys are CamelCase versions of the kind */
392 for (p
= kind_string
; *p
; p
++)
395 kind
= netdev_kind_from_string(kind_string
);
396 if (kind
== _NETDEV_KIND_INVALID
) {
397 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
398 "Invalid NetDev kind: %s", lvalue
);
402 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
404 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
405 "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
409 if (netdev
->kind
!= kind
) {
410 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
411 "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
416 case NETDEV_KIND_BRIDGE
:
417 network
->bridge
= netdev
;
420 case NETDEV_KIND_BOND
:
421 network
->bond
= netdev
;
424 case NETDEV_KIND_VLAN
:
425 case NETDEV_KIND_MACVLAN
:
426 case NETDEV_KIND_IPVLAN
:
427 case NETDEV_KIND_VXLAN
:
428 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
430 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
431 "Can not add VLAN '%s' to network: %m",
438 assert_not_reached("Can not parse NetDev");
446 int config_parse_domains(const char *unit
,
447 const char *filename
,
450 unsigned section_line
,
456 Network
*network
= userdata
;
457 char ***domains
= data
;
461 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
462 lvalue
, ltype
, rvalue
, domains
, userdata
);
467 network
->wildcard_domain
= !!strv_find(*domains
, "*");
469 STRV_FOREACH(domain
, *domains
) {
470 if (is_localhost(*domain
))
471 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
473 r
= dns_name_is_valid(*domain
);
474 if (r
<= 0 && !streq(*domain
, "*")) {
476 log_error_errno(r
, "Failed to validate domain name: %s: %m", *domain
);
478 log_warning("Domain name is not valid, ignoring assignment: %s", *domain
);
483 strv_remove(*domains
, *domain
);
485 /* We removed one entry, make sure we don't skip the next one */
492 int config_parse_tunnel(const char *unit
,
493 const char *filename
,
496 unsigned section_line
,
502 Network
*network
= userdata
;
511 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
513 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
517 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
518 netdev
->kind
!= NETDEV_KIND_SIT
&&
519 netdev
->kind
!= NETDEV_KIND_GRE
&&
520 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
521 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
522 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
523 netdev
->kind
!= NETDEV_KIND_VTI
&&
524 netdev
->kind
!= NETDEV_KIND_VTI6
&&
525 netdev
->kind
!= NETDEV_KIND_IP6TNL
527 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
528 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
532 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
534 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
543 int config_parse_ipv4ll(
545 const char *filename
,
548 unsigned section_line
,
555 AddressFamilyBoolean
*link_local
= data
;
562 /* Note that this is mostly like
563 * config_parse_address_family_boolean(), except that it
564 * applies only to IPv4 */
566 if (parse_boolean(rvalue
))
567 *link_local
|= ADDRESS_FAMILY_IPV4
;
569 *link_local
&= ~ADDRESS_FAMILY_IPV4
;
574 int config_parse_dhcp(
576 const char *filename
,
579 unsigned section_line
,
586 AddressFamilyBoolean
*dhcp
= data
, s
;
593 /* Note that this is mostly like
594 * config_parse_address_family_boolean(), except that it
595 * understands some old names for the enum values */
597 s
= address_family_boolean_from_string(rvalue
);
600 /* Previously, we had a slightly different enum here,
601 * support its values for compatbility. */
603 if (streq(rvalue
, "none"))
604 s
= ADDRESS_FAMILY_NO
;
605 else if (streq(rvalue
, "v4"))
606 s
= ADDRESS_FAMILY_IPV4
;
607 else if (streq(rvalue
, "v6"))
608 s
= ADDRESS_FAMILY_IPV6
;
609 else if (streq(rvalue
, "both"))
610 s
= ADDRESS_FAMILY_YES
;
612 log_syntax(unit
, LOG_ERR
, filename
, line
, s
, "Failed to parse DHCP option, ignoring: %s", rvalue
);
621 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
622 [DHCP_CLIENT_ID_MAC
] = "mac",
623 [DHCP_CLIENT_ID_DUID
] = "duid"
626 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DCHPClientIdentifier
);
627 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DCHPClientIdentifier
, "Failed to parse client identifier type");
629 static const char* const llmnr_support_table
[_LLMNR_SUPPORT_MAX
] = {
630 [LLMNR_SUPPORT_NO
] = "no",
631 [LLMNR_SUPPORT_YES
] = "yes",
632 [LLMNR_SUPPORT_RESOLVE
] = "resolve",
635 DEFINE_STRING_TABLE_LOOKUP(llmnr_support
, LLMNRSupport
);
637 int config_parse_llmnr(
639 const char *filename
,
642 unsigned section_line
,
649 LLMNRSupport
*llmnr
= data
;
657 /* Our enum shall be a superset of booleans, hence first try
658 * to parse as boolean, and then as enum */
660 k
= parse_boolean(rvalue
);
662 *llmnr
= LLMNR_SUPPORT_YES
;
664 *llmnr
= LLMNR_SUPPORT_NO
;
668 s
= llmnr_support_from_string(rvalue
);
670 log_syntax(unit
, LOG_ERR
, filename
, line
, -s
, "Failed to parse LLMNR option, ignoring: %s", rvalue
);
680 int config_parse_ipv6token(
682 const char *filename
,
685 unsigned section_line
,
692 union in_addr_union buffer
;
693 struct in6_addr
*token
= data
;
701 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
703 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
707 r
= in_addr_is_null(AF_INET6
, &buffer
);
709 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
713 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
714 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);
723 int config_parse_address_family_boolean_with_kernel(
725 const char *filename
,
728 unsigned section_line
,
735 AddressFamilyBoolean
*fwd
= data
, s
;
742 s
= address_family_boolean_from_string(rvalue
);
744 if (streq(rvalue
, "kernel"))
745 s
= _ADDRESS_FAMILY_BOOLEAN_INVALID
;
747 log_syntax(unit
, LOG_ERR
, filename
, line
, s
, "Failed to parse IPForwarding option, ignoring: %s", rvalue
);
757 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
758 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
759 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
760 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
763 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
765 int config_parse_ipv6_privacy_extensions(
767 const char *filename
,
770 unsigned section_line
,
777 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
783 assert(ipv6_privacy_extensions
);
785 /* Our enum shall be a superset of booleans, hence first try
786 * to parse as boolean, and then as enum */
788 k
= parse_boolean(rvalue
);
790 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
792 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
794 IPv6PrivacyExtensions s
;
796 s
= ipv6_privacy_extensions_from_string(rvalue
);
799 if (streq(rvalue
, "kernel"))
800 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
802 log_syntax(unit
, LOG_ERR
, filename
, line
, s
, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
807 *ipv6_privacy_extensions
= s
;