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 r
= config_parse(NULL
, filename
, file
,
124 config_item_perf_lookup
, network_network_gperf_lookup
,
125 false, false, true, network
);
129 /* IPMasquerade=yes implies IPForward=yes */
130 if (network
->ip_masquerade
)
131 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
133 LIST_PREPEND(networks
, manager
->networks
, network
);
135 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
139 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
143 LIST_FOREACH(routes
, route
, network
->static_routes
) {
144 if (!route
->family
) {
145 log_warning("Route section without Gateway field configured in %s. "
146 "Ignoring", filename
);
151 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
152 if (!address
->family
) {
153 log_warning("Address section without Address field configured in %s. "
154 "Ignoring", filename
);
164 int network_load(Manager
*manager
) {
166 _cleanup_strv_free_
char **files
= NULL
;
172 while ((network
= manager
->networks
))
173 network_free(network
);
175 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
177 return log_error_errno(r
, "Failed to enumerate network files: %m");
179 STRV_FOREACH_BACKWARDS(f
, files
) {
180 r
= network_load_one(manager
, *f
);
188 void network_free(Network
*network
) {
198 free(network
->filename
);
200 free(network
->match_mac
);
201 strv_free(network
->match_path
);
202 strv_free(network
->match_driver
);
203 strv_free(network
->match_type
);
204 strv_free(network
->match_name
);
206 free(network
->description
);
207 free(network
->dhcp_vendor_class_identifier
);
211 strv_free(network
->ntp
);
212 strv_free(network
->dns
);
213 strv_free(network
->domains
);
214 strv_free(network
->bind_carrier
);
216 netdev_unref(network
->bridge
);
218 netdev_unref(network
->bond
);
220 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
221 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
222 netdev_unref(netdev
);
224 hashmap_free(network
->stacked_netdevs
);
226 while ((route
= network
->static_routes
))
229 while ((address
= network
->static_addresses
))
230 address_free(address
);
232 while ((fdb_entry
= network
->static_fdb_entries
))
233 fdb_entry_free(fdb_entry
);
235 hashmap_free(network
->addresses_by_section
);
236 hashmap_free(network
->routes_by_section
);
237 hashmap_free(network
->fdb_entries_by_section
);
239 if (network
->manager
) {
240 if (network
->manager
->networks
)
241 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
243 if (network
->manager
->networks_by_name
)
244 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
249 condition_free_list(network
->match_host
);
250 condition_free_list(network
->match_virt
);
251 condition_free_list(network
->match_kernel
);
252 condition_free_list(network
->match_arch
);
257 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
264 network
= hashmap_get(manager
->networks_by_name
, name
);
273 int network_get(Manager
*manager
, struct udev_device
*device
,
274 const char *ifname
, const struct ether_addr
*address
,
277 struct udev_device
*parent
;
278 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
284 path
= udev_device_get_property_value(device
, "ID_PATH");
286 parent
= udev_device_get_parent(device
);
288 parent_driver
= udev_device_get_driver(parent
);
290 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
292 devtype
= udev_device_get_devtype(device
);
295 LIST_FOREACH(networks
, network
, manager
->networks
) {
296 if (net_match_config(network
->match_mac
, network
->match_path
,
297 network
->match_driver
, network
->match_type
,
298 network
->match_name
, network
->match_host
,
299 network
->match_virt
, network
->match_kernel
,
301 address
, path
, parent_driver
, driver
,
303 if (network
->match_name
&& device
) {
305 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
307 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
309 (void) safe_atou8(attr
, &name_assign_type
);
311 if (name_assign_type
== NET_NAME_ENUM
)
312 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
313 IFNAMSIZ
, ifname
, network
->filename
);
315 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
317 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
329 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
332 link
->network
= network
;
334 if (network
->ipv4ll_route
) {
337 r
= route_new_static(network
, 0, &route
);
341 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst_addr
.in
);
347 route
->family
= AF_INET
;
348 route
->dst_prefixlen
= 16;
349 route
->scope
= RT_SCOPE_LINK
;
350 route
->metrics
= IPV4LL_ROUTE_METRIC
;
351 route
->protocol
= RTPROT_STATIC
;
354 if (network
->dns
|| network
->ntp
) {
363 int config_parse_netdev(const char *unit
,
364 const char *filename
,
367 unsigned section_line
,
373 Network
*network
= userdata
;
374 _cleanup_free_
char *kind_string
= NULL
;
385 kind_string
= strdup(lvalue
);
389 /* the keys are CamelCase versions of the kind */
390 for (p
= kind_string
; *p
; p
++)
393 kind
= netdev_kind_from_string(kind_string
);
394 if (kind
== _NETDEV_KIND_INVALID
) {
395 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
396 "Invalid NetDev kind: %s", lvalue
);
400 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
402 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
403 "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
407 if (netdev
->kind
!= kind
) {
408 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
409 "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
414 case NETDEV_KIND_BRIDGE
:
415 network
->bridge
= netdev
;
418 case NETDEV_KIND_BOND
:
419 network
->bond
= netdev
;
422 case NETDEV_KIND_VLAN
:
423 case NETDEV_KIND_MACVLAN
:
424 case NETDEV_KIND_IPVLAN
:
425 case NETDEV_KIND_VXLAN
:
426 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
428 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
429 "Can not add VLAN '%s' to network: %m",
436 assert_not_reached("Can not parse NetDev");
444 int config_parse_domains(const char *unit
,
445 const char *filename
,
448 unsigned section_line
,
454 Network
*network
= userdata
;
455 char ***domains
= data
;
459 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
460 lvalue
, ltype
, rvalue
, domains
, userdata
);
465 network
->wildcard_domain
= !!strv_find(*domains
, "*");
467 STRV_FOREACH(domain
, *domains
) {
468 if (is_localhost(*domain
))
469 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
471 r
= dns_name_is_valid(*domain
);
472 if (r
<= 0 && !streq(*domain
, "*")) {
474 log_error_errno(r
, "Failed to validate domain name: %s: %m", *domain
);
476 log_warning("Domain name is not valid, ignoring assignment: %s", *domain
);
481 strv_remove(*domains
, *domain
);
483 /* We removed one entry, make sure we don't skip the next one */
490 int config_parse_tunnel(const char *unit
,
491 const char *filename
,
494 unsigned section_line
,
500 Network
*network
= userdata
;
509 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
511 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
515 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
516 netdev
->kind
!= NETDEV_KIND_SIT
&&
517 netdev
->kind
!= NETDEV_KIND_GRE
&&
518 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
519 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
520 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
521 netdev
->kind
!= NETDEV_KIND_VTI
&&
522 netdev
->kind
!= NETDEV_KIND_VTI6
&&
523 netdev
->kind
!= NETDEV_KIND_IP6TNL
525 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
526 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
530 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
532 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
541 int config_parse_ipv4ll(
543 const char *filename
,
546 unsigned section_line
,
553 AddressFamilyBoolean
*link_local
= data
;
560 /* Note that this is mostly like
561 * config_parse_address_family_boolean(), except that it
562 * applies only to IPv4 */
564 if (parse_boolean(rvalue
))
565 *link_local
|= ADDRESS_FAMILY_IPV4
;
567 *link_local
&= ~ADDRESS_FAMILY_IPV4
;
572 int config_parse_dhcp(
574 const char *filename
,
577 unsigned section_line
,
584 AddressFamilyBoolean
*dhcp
= data
, s
;
591 /* Note that this is mostly like
592 * config_parse_address_family_boolean(), except that it
593 * understands some old names for the enum values */
595 s
= address_family_boolean_from_string(rvalue
);
598 /* Previously, we had a slightly different enum here,
599 * support its values for compatbility. */
601 if (streq(rvalue
, "none"))
602 s
= ADDRESS_FAMILY_NO
;
603 else if (streq(rvalue
, "v4"))
604 s
= ADDRESS_FAMILY_IPV4
;
605 else if (streq(rvalue
, "v6"))
606 s
= ADDRESS_FAMILY_IPV6
;
607 else if (streq(rvalue
, "both"))
608 s
= ADDRESS_FAMILY_YES
;
610 log_syntax(unit
, LOG_ERR
, filename
, line
, s
, "Failed to parse DHCP option, ignoring: %s", rvalue
);
619 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
620 [DHCP_CLIENT_ID_MAC
] = "mac",
621 [DHCP_CLIENT_ID_DUID
] = "duid"
624 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DCHPClientIdentifier
);
625 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DCHPClientIdentifier
, "Failed to parse client identifier type");
627 static const char* const llmnr_support_table
[_LLMNR_SUPPORT_MAX
] = {
628 [LLMNR_SUPPORT_NO
] = "no",
629 [LLMNR_SUPPORT_YES
] = "yes",
630 [LLMNR_SUPPORT_RESOLVE
] = "resolve",
633 DEFINE_STRING_TABLE_LOOKUP(llmnr_support
, LLMNRSupport
);
635 int config_parse_llmnr(
637 const char *filename
,
640 unsigned section_line
,
647 LLMNRSupport
*llmnr
= data
;
655 /* Our enum shall be a superset of booleans, hence first try
656 * to parse as boolean, and then as enum */
658 k
= parse_boolean(rvalue
);
660 *llmnr
= LLMNR_SUPPORT_YES
;
662 *llmnr
= LLMNR_SUPPORT_NO
;
666 s
= llmnr_support_from_string(rvalue
);
668 log_syntax(unit
, LOG_ERR
, filename
, line
, -s
, "Failed to parse LLMNR option, ignoring: %s", rvalue
);
678 int config_parse_ipv6token(
680 const char *filename
,
683 unsigned section_line
,
690 union in_addr_union buffer
;
691 struct in6_addr
*token
= data
;
699 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
701 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
705 r
= in_addr_is_null(AF_INET6
, &buffer
);
707 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
711 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
712 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);