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 "alloc-util.h"
26 #include "conf-files.h"
27 #include "conf-parser.h"
28 #include "dns-domain.h"
30 #include "hostname-util.h"
31 #include "network-internal.h"
32 #include "networkd-network.h"
34 #include "parse-util.h"
35 #include "stat-util.h"
36 #include "string-table.h"
37 #include "string-util.h"
40 static int network_load_one(Manager
*manager
, const char *filename
) {
41 _cleanup_network_free_ Network
*network
= NULL
;
42 _cleanup_fclose_
FILE *file
= NULL
;
51 file
= fopen(filename
, "re");
59 if (null_or_empty_fd(fileno(file
))) {
60 log_debug("Skipping empty file: %s", filename
);
64 network
= new0(Network
, 1);
68 network
->manager
= manager
;
70 LIST_HEAD_INIT(network
->static_addresses
);
71 LIST_HEAD_INIT(network
->static_routes
);
72 LIST_HEAD_INIT(network
->static_fdb_entries
);
74 network
->stacked_netdevs
= hashmap_new(&string_hash_ops
);
75 if (!network
->stacked_netdevs
)
78 network
->addresses_by_section
= hashmap_new(NULL
);
79 if (!network
->addresses_by_section
)
82 network
->routes_by_section
= hashmap_new(NULL
);
83 if (!network
->routes_by_section
)
86 network
->fdb_entries_by_section
= hashmap_new(NULL
);
87 if (!network
->fdb_entries_by_section
)
90 network
->filename
= strdup(filename
);
91 if (!network
->filename
)
94 network
->name
= strdup(basename(filename
));
98 d
= strrchr(network
->name
, '.');
102 assert(streq(d
, ".network"));
106 network
->dhcp
= ADDRESS_FAMILY_NO
;
107 network
->dhcp_ntp
= true;
108 network
->dhcp_dns
= true;
109 network
->dhcp_hostname
= true;
110 network
->dhcp_routes
= true;
111 network
->dhcp_sendhost
= true;
112 network
->dhcp_route_metric
= DHCP_ROUTE_METRIC
;
113 network
->dhcp_client_identifier
= DHCP_CLIENT_ID_DUID
;
115 network
->dhcp_server_emit_dns
= true;
116 network
->dhcp_server_emit_ntp
= true;
117 network
->dhcp_server_emit_timezone
= true;
119 network
->use_bpdu
= true;
120 network
->allow_port_to_be_root
= true;
121 network
->unicast_flood
= true;
123 network
->llmnr
= RESOLVE_SUPPORT_YES
;
124 network
->mdns
= RESOLVE_SUPPORT_NO
;
125 network
->dnssec_mode
= _DNSSEC_MODE_INVALID
;
127 network
->link_local
= ADDRESS_FAMILY_IPV6
;
129 network
->ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
130 network
->ipv6_accept_ra
= -1;
131 network
->ipv6_dad_transmits
= -1;
132 network
->ipv6_hop_limit
= -1;
134 r
= config_parse(NULL
, filename
, file
,
141 "DHCPv4\0" /* compat */
145 config_item_perf_lookup
, network_network_gperf_lookup
,
146 false, false, true, network
);
150 /* IPMasquerade=yes implies IPForward=yes */
151 if (network
->ip_masquerade
)
152 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
154 LIST_PREPEND(networks
, manager
->networks
, network
);
156 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
160 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
164 LIST_FOREACH(routes
, route
, network
->static_routes
) {
165 if (!route
->family
) {
166 log_warning("Route section without Gateway field configured in %s. "
167 "Ignoring", filename
);
172 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
173 if (!address
->family
) {
174 log_warning("Address section without Address field configured in %s. "
175 "Ignoring", filename
);
185 int network_load(Manager
*manager
) {
187 _cleanup_strv_free_
char **files
= NULL
;
193 while ((network
= manager
->networks
))
194 network_free(network
);
196 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
198 return log_error_errno(r
, "Failed to enumerate network files: %m");
200 STRV_FOREACH_BACKWARDS(f
, files
) {
201 r
= network_load_one(manager
, *f
);
209 void network_free(Network
*network
) {
219 free(network
->filename
);
221 free(network
->match_mac
);
222 strv_free(network
->match_path
);
223 strv_free(network
->match_driver
);
224 strv_free(network
->match_type
);
225 strv_free(network
->match_name
);
227 free(network
->description
);
228 free(network
->dhcp_vendor_class_identifier
);
229 free(network
->hostname
);
233 strv_free(network
->ntp
);
234 strv_free(network
->dns
);
235 strv_free(network
->domains
);
236 strv_free(network
->bind_carrier
);
238 netdev_unref(network
->bridge
);
240 netdev_unref(network
->bond
);
242 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
243 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
244 netdev_unref(netdev
);
246 hashmap_free(network
->stacked_netdevs
);
248 while ((route
= network
->static_routes
))
251 while ((address
= network
->static_addresses
))
252 address_free(address
);
254 while ((fdb_entry
= network
->static_fdb_entries
))
255 fdb_entry_free(fdb_entry
);
257 hashmap_free(network
->addresses_by_section
);
258 hashmap_free(network
->routes_by_section
);
259 hashmap_free(network
->fdb_entries_by_section
);
261 if (network
->manager
) {
262 if (network
->manager
->networks
)
263 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
265 if (network
->manager
->networks_by_name
)
266 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
271 condition_free_list(network
->match_host
);
272 condition_free_list(network
->match_virt
);
273 condition_free_list(network
->match_kernel
);
274 condition_free_list(network
->match_arch
);
276 free(network
->dhcp_server_timezone
);
277 free(network
->dhcp_server_dns
);
278 free(network
->dhcp_server_ntp
);
283 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
290 network
= hashmap_get(manager
->networks_by_name
, name
);
299 int network_get(Manager
*manager
, struct udev_device
*device
,
300 const char *ifname
, const struct ether_addr
*address
,
303 struct udev_device
*parent
;
304 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
310 path
= udev_device_get_property_value(device
, "ID_PATH");
312 parent
= udev_device_get_parent(device
);
314 parent_driver
= udev_device_get_driver(parent
);
316 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
318 devtype
= udev_device_get_devtype(device
);
321 LIST_FOREACH(networks
, network
, manager
->networks
) {
322 if (net_match_config(network
->match_mac
, network
->match_path
,
323 network
->match_driver
, network
->match_type
,
324 network
->match_name
, network
->match_host
,
325 network
->match_virt
, network
->match_kernel
,
327 address
, path
, parent_driver
, driver
,
329 if (network
->match_name
&& device
) {
331 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
333 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
335 (void) safe_atou8(attr
, &name_assign_type
);
337 if (name_assign_type
== NET_NAME_ENUM
)
338 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
339 ifname
, network
->filename
);
341 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
343 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
355 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
362 link
->network
= network
;
364 if (network
->ipv4ll_route
) {
367 r
= route_new_static(network
, 0, &route
);
371 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst
.in
);
377 route
->family
= AF_INET
;
378 route
->dst_prefixlen
= 16;
379 route
->scope
= RT_SCOPE_LINK
;
380 route
->priority
= IPV4LL_ROUTE_METRIC
;
381 route
->protocol
= RTPROT_STATIC
;
384 if (network
->dns
|| network
->ntp
|| network
->domains
) {
385 manager_dirty(manager
);
392 int config_parse_netdev(const char *unit
,
393 const char *filename
,
396 unsigned section_line
,
402 Network
*network
= userdata
;
403 _cleanup_free_
char *kind_string
= NULL
;
414 kind_string
= strdup(lvalue
);
418 /* the keys are CamelCase versions of the kind */
419 for (p
= kind_string
; *p
; p
++)
422 kind
= netdev_kind_from_string(kind_string
);
423 if (kind
== _NETDEV_KIND_INVALID
) {
424 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid NetDev kind: %s", lvalue
);
428 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
430 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
434 if (netdev
->kind
!= kind
) {
435 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
440 case NETDEV_KIND_BRIDGE
:
441 network
->bridge
= netdev
;
444 case NETDEV_KIND_BOND
:
445 network
->bond
= netdev
;
448 case NETDEV_KIND_VLAN
:
449 case NETDEV_KIND_MACVLAN
:
450 case NETDEV_KIND_MACVTAP
:
451 case NETDEV_KIND_IPVLAN
:
452 case NETDEV_KIND_VXLAN
:
453 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
455 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Can not add VLAN '%s' to network: %m", rvalue
);
461 assert_not_reached("Can not parse NetDev");
469 int config_parse_domains(const char *unit
,
470 const char *filename
,
473 unsigned section_line
,
479 Network
*network
= userdata
;
480 char ***domains
= data
;
484 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
485 lvalue
, ltype
, rvalue
, domains
, userdata
);
490 network
->wildcard_domain
= !!strv_find(*domains
, "*");
492 STRV_FOREACH(domain
, *domains
) {
493 if (is_localhost(*domain
))
494 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
496 r
= dns_name_is_valid(*domain
);
497 if (r
<= 0 && !streq(*domain
, "*")) {
499 log_error_errno(r
, "Failed to validate domain name: %s: %m", *domain
);
501 log_warning("Domain name is not valid, ignoring assignment: %s", *domain
);
506 strv_remove(*domains
, *domain
);
508 /* We removed one entry, make sure we don't skip the next one */
515 int config_parse_tunnel(const char *unit
,
516 const char *filename
,
519 unsigned section_line
,
525 Network
*network
= userdata
;
534 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
536 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
540 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
541 netdev
->kind
!= NETDEV_KIND_SIT
&&
542 netdev
->kind
!= NETDEV_KIND_GRE
&&
543 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
544 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
545 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
546 netdev
->kind
!= NETDEV_KIND_VTI
&&
547 netdev
->kind
!= NETDEV_KIND_VTI6
&&
548 netdev
->kind
!= NETDEV_KIND_IP6TNL
550 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
551 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
555 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
557 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
566 int config_parse_ipv4ll(
568 const char *filename
,
571 unsigned section_line
,
578 AddressFamilyBoolean
*link_local
= data
;
585 /* Note that this is mostly like
586 * config_parse_address_family_boolean(), except that it
587 * applies only to IPv4 */
589 if (parse_boolean(rvalue
))
590 *link_local
|= ADDRESS_FAMILY_IPV4
;
592 *link_local
&= ~ADDRESS_FAMILY_IPV4
;
597 int config_parse_dhcp(
599 const char *filename
,
602 unsigned section_line
,
609 AddressFamilyBoolean
*dhcp
= data
, s
;
616 /* Note that this is mostly like
617 * config_parse_address_family_boolean(), except that it
618 * understands some old names for the enum values */
620 s
= address_family_boolean_from_string(rvalue
);
623 /* Previously, we had a slightly different enum here,
624 * support its values for compatbility. */
626 if (streq(rvalue
, "none"))
627 s
= ADDRESS_FAMILY_NO
;
628 else if (streq(rvalue
, "v4"))
629 s
= ADDRESS_FAMILY_IPV4
;
630 else if (streq(rvalue
, "v6"))
631 s
= ADDRESS_FAMILY_IPV6
;
632 else if (streq(rvalue
, "both"))
633 s
= ADDRESS_FAMILY_YES
;
635 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DHCP option, ignoring: %s", rvalue
);
644 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
645 [DHCP_CLIENT_ID_MAC
] = "mac",
646 [DHCP_CLIENT_ID_DUID
] = "duid"
649 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DCHPClientIdentifier
);
650 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DCHPClientIdentifier
, "Failed to parse client identifier type");
652 int config_parse_ipv6token(
654 const char *filename
,
657 unsigned section_line
,
664 union in_addr_union buffer
;
665 struct in6_addr
*token
= data
;
673 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
675 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
679 r
= in_addr_is_null(AF_INET6
, &buffer
);
681 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
685 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
686 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);
695 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
696 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
697 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
698 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
701 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
703 int config_parse_ipv6_privacy_extensions(
705 const char *filename
,
708 unsigned section_line
,
715 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
721 assert(ipv6_privacy_extensions
);
723 /* Our enum shall be a superset of booleans, hence first try
724 * to parse as boolean, and then as enum */
726 k
= parse_boolean(rvalue
);
728 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
730 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
732 IPv6PrivacyExtensions s
;
734 s
= ipv6_privacy_extensions_from_string(rvalue
);
737 if (streq(rvalue
, "kernel"))
738 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
740 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
745 *ipv6_privacy_extensions
= s
;
751 int config_parse_hostname(
753 const char *filename
,
756 unsigned section_line
,
763 char **hostname
= data
, *hn
= NULL
;
770 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
774 if (!hostname_is_valid(hn
, false)) {
775 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not valid, ignoring assignment: %s", rvalue
);
781 *hostname
= hostname_cleanup(hn
);
785 int config_parse_timezone(
787 const char *filename
,
790 unsigned section_line
,
797 char **datap
= data
, *tz
= NULL
;
804 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
808 if (!timezone_is_valid(tz
)) {
809 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Timezone is not valid, ignoring assignment: %s", rvalue
);
820 int config_parse_dhcp_server_dns(
822 const char *filename
,
825 unsigned section_line
,
833 const char *p
= rvalue
;
841 _cleanup_free_
char *w
= NULL
;
842 struct in_addr a
, *m
;
844 r
= extract_first_word(&p
, &w
, NULL
, 0);
846 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
853 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
854 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
858 m
= realloc(n
->dhcp_server_dns
, (n
->n_dhcp_server_dns
+ 1) * sizeof(struct in_addr
));
862 m
[n
->n_dhcp_server_dns
++] = a
;
863 n
->dhcp_server_dns
= m
;
867 int config_parse_dhcp_server_ntp(
869 const char *filename
,
872 unsigned section_line
,
880 const char *p
= rvalue
;
888 _cleanup_free_
char *w
= NULL
;
889 struct in_addr a
, *m
;
891 r
= extract_first_word(&p
, &w
, NULL
, 0);
893 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
900 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
901 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse NTP server address, ignoring: %s", w
);
905 m
= realloc(n
->dhcp_server_ntp
, (n
->n_dhcp_server_ntp
+ 1) * sizeof(struct in_addr
));
909 m
[n
->n_dhcp_server_ntp
++] = a
;
910 n
->dhcp_server_ntp
= m
;