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"
29 #include "dns-domain.h"
30 #include "network-internal.h"
33 #include "networkd-network.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
->dhcp_server_emit_dns
= true;
111 network
->dhcp_server_emit_ntp
= true;
112 network
->dhcp_server_emit_timezone
= true;
114 network
->use_bpdu
= true;
115 network
->allow_port_to_be_root
= true;
116 network
->unicast_flood
= true;
118 network
->llmnr
= RESOLVE_SUPPORT_YES
;
120 network
->link_local
= ADDRESS_FAMILY_IPV6
;
122 network
->ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
124 r
= config_parse(NULL
, filename
, file
,
131 "DHCPv4\0" /* compat */
135 config_item_perf_lookup
, network_network_gperf_lookup
,
136 false, false, true, network
);
140 /* IPMasquerade=yes implies IPForward=yes */
141 if (network
->ip_masquerade
)
142 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
144 LIST_PREPEND(networks
, manager
->networks
, network
);
146 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
150 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
154 LIST_FOREACH(routes
, route
, network
->static_routes
) {
155 if (!route
->family
) {
156 log_warning("Route section without Gateway field configured in %s. "
157 "Ignoring", filename
);
162 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
163 if (!address
->family
) {
164 log_warning("Address section without Address field configured in %s. "
165 "Ignoring", filename
);
175 int network_load(Manager
*manager
) {
177 _cleanup_strv_free_
char **files
= NULL
;
183 while ((network
= manager
->networks
))
184 network_free(network
);
186 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
188 return log_error_errno(r
, "Failed to enumerate network files: %m");
190 STRV_FOREACH_BACKWARDS(f
, files
) {
191 r
= network_load_one(manager
, *f
);
199 void network_free(Network
*network
) {
209 free(network
->filename
);
211 free(network
->match_mac
);
212 strv_free(network
->match_path
);
213 strv_free(network
->match_driver
);
214 strv_free(network
->match_type
);
215 strv_free(network
->match_name
);
217 free(network
->description
);
218 free(network
->dhcp_vendor_class_identifier
);
219 free(network
->hostname
);
223 strv_free(network
->ntp
);
224 strv_free(network
->dns
);
225 strv_free(network
->domains
);
226 strv_free(network
->bind_carrier
);
228 netdev_unref(network
->bridge
);
230 netdev_unref(network
->bond
);
232 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
233 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
234 netdev_unref(netdev
);
236 hashmap_free(network
->stacked_netdevs
);
238 while ((route
= network
->static_routes
))
241 while ((address
= network
->static_addresses
))
242 address_free(address
);
244 while ((fdb_entry
= network
->static_fdb_entries
))
245 fdb_entry_free(fdb_entry
);
247 hashmap_free(network
->addresses_by_section
);
248 hashmap_free(network
->routes_by_section
);
249 hashmap_free(network
->fdb_entries_by_section
);
251 if (network
->manager
) {
252 if (network
->manager
->networks
)
253 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
255 if (network
->manager
->networks_by_name
)
256 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
261 condition_free_list(network
->match_host
);
262 condition_free_list(network
->match_virt
);
263 condition_free_list(network
->match_kernel
);
264 condition_free_list(network
->match_arch
);
266 free(network
->dhcp_server_timezone
);
267 free(network
->dhcp_server_dns
);
268 free(network
->dhcp_server_ntp
);
273 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
280 network
= hashmap_get(manager
->networks_by_name
, name
);
289 int network_get(Manager
*manager
, struct udev_device
*device
,
290 const char *ifname
, const struct ether_addr
*address
,
293 struct udev_device
*parent
;
294 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
300 path
= udev_device_get_property_value(device
, "ID_PATH");
302 parent
= udev_device_get_parent(device
);
304 parent_driver
= udev_device_get_driver(parent
);
306 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
308 devtype
= udev_device_get_devtype(device
);
311 LIST_FOREACH(networks
, network
, manager
->networks
) {
312 if (net_match_config(network
->match_mac
, network
->match_path
,
313 network
->match_driver
, network
->match_type
,
314 network
->match_name
, network
->match_host
,
315 network
->match_virt
, network
->match_kernel
,
317 address
, path
, parent_driver
, driver
,
319 if (network
->match_name
&& device
) {
321 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
323 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
325 (void) safe_atou8(attr
, &name_assign_type
);
327 if (name_assign_type
== NET_NAME_ENUM
)
328 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
329 IFNAMSIZ
, ifname
, network
->filename
);
331 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
333 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
345 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
348 link
->network
= network
;
350 if (network
->ipv4ll_route
) {
353 r
= route_new_static(network
, 0, &route
);
357 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst_addr
.in
);
363 route
->family
= AF_INET
;
364 route
->dst_prefixlen
= 16;
365 route
->scope
= RT_SCOPE_LINK
;
366 route
->metrics
= IPV4LL_ROUTE_METRIC
;
367 route
->protocol
= RTPROT_STATIC
;
370 if (network
->dns
|| network
->ntp
) {
379 int config_parse_netdev(const char *unit
,
380 const char *filename
,
383 unsigned section_line
,
389 Network
*network
= userdata
;
390 _cleanup_free_
char *kind_string
= NULL
;
401 kind_string
= strdup(lvalue
);
405 /* the keys are CamelCase versions of the kind */
406 for (p
= kind_string
; *p
; p
++)
409 kind
= netdev_kind_from_string(kind_string
);
410 if (kind
== _NETDEV_KIND_INVALID
) {
411 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
412 "Invalid NetDev kind: %s", lvalue
);
416 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
418 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
419 "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
423 if (netdev
->kind
!= kind
) {
424 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
425 "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
430 case NETDEV_KIND_BRIDGE
:
431 network
->bridge
= netdev
;
434 case NETDEV_KIND_BOND
:
435 network
->bond
= netdev
;
438 case NETDEV_KIND_VLAN
:
439 case NETDEV_KIND_MACVLAN
:
440 case NETDEV_KIND_MACVTAP
:
441 case NETDEV_KIND_IPVLAN
:
442 case NETDEV_KIND_VXLAN
:
443 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
445 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
446 "Can not add VLAN '%s' to network: %m",
453 assert_not_reached("Can not parse NetDev");
461 int config_parse_domains(const char *unit
,
462 const char *filename
,
465 unsigned section_line
,
471 Network
*network
= userdata
;
472 char ***domains
= data
;
476 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
477 lvalue
, ltype
, rvalue
, domains
, userdata
);
482 network
->wildcard_domain
= !!strv_find(*domains
, "*");
484 STRV_FOREACH(domain
, *domains
) {
485 if (is_localhost(*domain
))
486 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
488 r
= dns_name_is_valid(*domain
);
489 if (r
<= 0 && !streq(*domain
, "*")) {
491 log_error_errno(r
, "Failed to validate domain name: %s: %m", *domain
);
493 log_warning("Domain name is not valid, ignoring assignment: %s", *domain
);
498 strv_remove(*domains
, *domain
);
500 /* We removed one entry, make sure we don't skip the next one */
507 int config_parse_tunnel(const char *unit
,
508 const char *filename
,
511 unsigned section_line
,
517 Network
*network
= userdata
;
526 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
528 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
532 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
533 netdev
->kind
!= NETDEV_KIND_SIT
&&
534 netdev
->kind
!= NETDEV_KIND_GRE
&&
535 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
536 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
537 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
538 netdev
->kind
!= NETDEV_KIND_VTI
&&
539 netdev
->kind
!= NETDEV_KIND_VTI6
&&
540 netdev
->kind
!= NETDEV_KIND_IP6TNL
542 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
543 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
547 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
549 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
558 int config_parse_ipv4ll(
560 const char *filename
,
563 unsigned section_line
,
570 AddressFamilyBoolean
*link_local
= data
;
577 /* Note that this is mostly like
578 * config_parse_address_family_boolean(), except that it
579 * applies only to IPv4 */
581 if (parse_boolean(rvalue
))
582 *link_local
|= ADDRESS_FAMILY_IPV4
;
584 *link_local
&= ~ADDRESS_FAMILY_IPV4
;
589 int config_parse_dhcp(
591 const char *filename
,
594 unsigned section_line
,
601 AddressFamilyBoolean
*dhcp
= data
, s
;
608 /* Note that this is mostly like
609 * config_parse_address_family_boolean(), except that it
610 * understands some old names for the enum values */
612 s
= address_family_boolean_from_string(rvalue
);
615 /* Previously, we had a slightly different enum here,
616 * support its values for compatbility. */
618 if (streq(rvalue
, "none"))
619 s
= ADDRESS_FAMILY_NO
;
620 else if (streq(rvalue
, "v4"))
621 s
= ADDRESS_FAMILY_IPV4
;
622 else if (streq(rvalue
, "v6"))
623 s
= ADDRESS_FAMILY_IPV6
;
624 else if (streq(rvalue
, "both"))
625 s
= ADDRESS_FAMILY_YES
;
627 log_syntax(unit
, LOG_ERR
, filename
, line
, s
, "Failed to parse DHCP option, ignoring: %s", rvalue
);
636 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
637 [DHCP_CLIENT_ID_MAC
] = "mac",
638 [DHCP_CLIENT_ID_DUID
] = "duid"
641 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DCHPClientIdentifier
);
642 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DCHPClientIdentifier
, "Failed to parse client identifier type");
644 int config_parse_ipv6token(
646 const char *filename
,
649 unsigned section_line
,
656 union in_addr_union buffer
;
657 struct in6_addr
*token
= data
;
665 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
667 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
671 r
= in_addr_is_null(AF_INET6
, &buffer
);
673 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
677 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
678 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);
687 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
688 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
689 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
690 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
693 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
695 int config_parse_ipv6_privacy_extensions(
697 const char *filename
,
700 unsigned section_line
,
707 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
713 assert(ipv6_privacy_extensions
);
715 /* Our enum shall be a superset of booleans, hence first try
716 * to parse as boolean, and then as enum */
718 k
= parse_boolean(rvalue
);
720 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
722 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
724 IPv6PrivacyExtensions s
;
726 s
= ipv6_privacy_extensions_from_string(rvalue
);
729 if (streq(rvalue
, "kernel"))
730 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
732 log_syntax(unit
, LOG_ERR
, filename
, line
, s
, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
737 *ipv6_privacy_extensions
= s
;
743 int config_parse_hostname(
745 const char *filename
,
748 unsigned section_line
,
755 char **hostname
= data
, *hn
= NULL
;
762 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
766 if (!hostname_is_valid(hn
, false)) {
767 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Hostname is not valid, ignoring assignment: %s", rvalue
);
773 *hostname
= hostname_cleanup(hn
);
777 int config_parse_timezone(
779 const char *filename
,
782 unsigned section_line
,
789 char **datap
= data
, *tz
= NULL
;
796 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
800 if (!timezone_is_valid(tz
)) {
801 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Timezone is not valid, ignoring assignment: %s", rvalue
);
812 int config_parse_dhcp_server_dns(
814 const char *filename
,
817 unsigned section_line
,
825 const char *p
= rvalue
;
833 _cleanup_free_
char *w
= NULL
;
834 struct in_addr a
, *m
;
836 r
= extract_first_word(&p
, &w
, NULL
, 0);
838 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
845 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
846 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse DNS server address, ignoring: %s", w
);
850 m
= realloc(n
->dhcp_server_dns
, (n
->n_dhcp_server_dns
+ 1) * sizeof(struct in_addr
));
854 m
[n
->n_dhcp_server_dns
++] = a
;
855 n
->dhcp_server_dns
= m
;
859 int config_parse_dhcp_server_ntp(
861 const char *filename
,
864 unsigned section_line
,
872 const char *p
= rvalue
;
880 _cleanup_free_
char *w
= NULL
;
881 struct in_addr a
, *m
;
883 r
= extract_first_word(&p
, &w
, NULL
, 0);
885 log_syntax(unit
, LOG_ERR
, filename
, r
, line
, "Failed to extract word, ignoring: %s", rvalue
);
892 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
893 log_syntax(unit
, LOG_ERR
, filename
, r
, line
, "Failed to parse NTP server address, ignoring: %s", w
);
897 m
= realloc(n
->dhcp_server_ntp
, (n
->n_dhcp_server_ntp
+ 1) * sizeof(struct in_addr
));
901 m
[n
->n_dhcp_server_ntp
++] = a
;
902 n
->dhcp_server_ntp
= m
;