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
;
126 network
->link_local
= ADDRESS_FAMILY_IPV6
;
128 network
->ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
129 network
->ipv6_accept_ra
= -1;
130 network
->ipv6_dad_transmits
= -1;
131 network
->ipv6_hop_limit
= -1;
133 r
= config_parse(NULL
, filename
, file
,
140 "DHCPv4\0" /* compat */
144 config_item_perf_lookup
, network_network_gperf_lookup
,
145 false, false, true, network
);
149 /* IPMasquerade=yes implies IPForward=yes */
150 if (network
->ip_masquerade
)
151 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
153 LIST_PREPEND(networks
, manager
->networks
, network
);
155 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
159 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
163 LIST_FOREACH(routes
, route
, network
->static_routes
) {
164 if (!route
->family
) {
165 log_warning("Route section without Gateway field configured in %s. "
166 "Ignoring", filename
);
171 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
172 if (!address
->family
) {
173 log_warning("Address section without Address field configured in %s. "
174 "Ignoring", filename
);
184 int network_load(Manager
*manager
) {
186 _cleanup_strv_free_
char **files
= NULL
;
192 while ((network
= manager
->networks
))
193 network_free(network
);
195 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
197 return log_error_errno(r
, "Failed to enumerate network files: %m");
199 STRV_FOREACH_BACKWARDS(f
, files
) {
200 r
= network_load_one(manager
, *f
);
208 void network_free(Network
*network
) {
218 free(network
->filename
);
220 free(network
->match_mac
);
221 strv_free(network
->match_path
);
222 strv_free(network
->match_driver
);
223 strv_free(network
->match_type
);
224 strv_free(network
->match_name
);
226 free(network
->description
);
227 free(network
->dhcp_vendor_class_identifier
);
228 free(network
->hostname
);
232 strv_free(network
->ntp
);
233 strv_free(network
->dns
);
234 strv_free(network
->domains
);
235 strv_free(network
->bind_carrier
);
237 netdev_unref(network
->bridge
);
239 netdev_unref(network
->bond
);
241 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
242 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
243 netdev_unref(netdev
);
245 hashmap_free(network
->stacked_netdevs
);
247 while ((route
= network
->static_routes
))
250 while ((address
= network
->static_addresses
))
251 address_free(address
);
253 while ((fdb_entry
= network
->static_fdb_entries
))
254 fdb_entry_free(fdb_entry
);
256 hashmap_free(network
->addresses_by_section
);
257 hashmap_free(network
->routes_by_section
);
258 hashmap_free(network
->fdb_entries_by_section
);
260 if (network
->manager
) {
261 if (network
->manager
->networks
)
262 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
264 if (network
->manager
->networks_by_name
)
265 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
270 condition_free_list(network
->match_host
);
271 condition_free_list(network
->match_virt
);
272 condition_free_list(network
->match_kernel
);
273 condition_free_list(network
->match_arch
);
275 free(network
->dhcp_server_timezone
);
276 free(network
->dhcp_server_dns
);
277 free(network
->dhcp_server_ntp
);
282 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
289 network
= hashmap_get(manager
->networks_by_name
, name
);
298 int network_get(Manager
*manager
, struct udev_device
*device
,
299 const char *ifname
, const struct ether_addr
*address
,
302 struct udev_device
*parent
;
303 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
309 path
= udev_device_get_property_value(device
, "ID_PATH");
311 parent
= udev_device_get_parent(device
);
313 parent_driver
= udev_device_get_driver(parent
);
315 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
317 devtype
= udev_device_get_devtype(device
);
320 LIST_FOREACH(networks
, network
, manager
->networks
) {
321 if (net_match_config(network
->match_mac
, network
->match_path
,
322 network
->match_driver
, network
->match_type
,
323 network
->match_name
, network
->match_host
,
324 network
->match_virt
, network
->match_kernel
,
326 address
, path
, parent_driver
, driver
,
328 if (network
->match_name
&& device
) {
330 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
332 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
334 (void) safe_atou8(attr
, &name_assign_type
);
336 if (name_assign_type
== NET_NAME_ENUM
)
337 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
338 ifname
, network
->filename
);
340 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
342 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
354 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
361 link
->network
= network
;
363 if (network
->ipv4ll_route
) {
366 r
= route_new_static(network
, 0, &route
);
370 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst
.in
);
376 route
->family
= AF_INET
;
377 route
->dst_prefixlen
= 16;
378 route
->scope
= RT_SCOPE_LINK
;
379 route
->priority
= IPV4LL_ROUTE_METRIC
;
380 route
->protocol
= RTPROT_STATIC
;
383 if (network
->dns
|| network
->ntp
|| network
->domains
) {
384 manager_dirty(manager
);
391 int config_parse_netdev(const char *unit
,
392 const char *filename
,
395 unsigned section_line
,
401 Network
*network
= userdata
;
402 _cleanup_free_
char *kind_string
= NULL
;
413 kind_string
= strdup(lvalue
);
417 /* the keys are CamelCase versions of the kind */
418 for (p
= kind_string
; *p
; p
++)
421 kind
= netdev_kind_from_string(kind_string
);
422 if (kind
== _NETDEV_KIND_INVALID
) {
423 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid NetDev kind: %s", lvalue
);
427 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
429 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
433 if (netdev
->kind
!= kind
) {
434 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
439 case NETDEV_KIND_BRIDGE
:
440 network
->bridge
= netdev
;
443 case NETDEV_KIND_BOND
:
444 network
->bond
= netdev
;
447 case NETDEV_KIND_VLAN
:
448 case NETDEV_KIND_MACVLAN
:
449 case NETDEV_KIND_MACVTAP
:
450 case NETDEV_KIND_IPVLAN
:
451 case NETDEV_KIND_VXLAN
:
452 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
454 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Can not add VLAN '%s' to network: %m", rvalue
);
460 assert_not_reached("Can not parse NetDev");
468 int config_parse_domains(const char *unit
,
469 const char *filename
,
472 unsigned section_line
,
478 Network
*network
= userdata
;
479 char ***domains
= data
;
483 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
484 lvalue
, ltype
, rvalue
, domains
, userdata
);
489 network
->wildcard_domain
= !!strv_find(*domains
, "*");
491 STRV_FOREACH(domain
, *domains
) {
492 if (is_localhost(*domain
))
493 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
495 r
= dns_name_is_valid(*domain
);
496 if (r
<= 0 && !streq(*domain
, "*")) {
498 log_error_errno(r
, "Failed to validate domain name: %s: %m", *domain
);
500 log_warning("Domain name is not valid, ignoring assignment: %s", *domain
);
505 strv_remove(*domains
, *domain
);
507 /* We removed one entry, make sure we don't skip the next one */
514 int config_parse_tunnel(const char *unit
,
515 const char *filename
,
518 unsigned section_line
,
524 Network
*network
= userdata
;
533 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
535 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
539 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
540 netdev
->kind
!= NETDEV_KIND_SIT
&&
541 netdev
->kind
!= NETDEV_KIND_GRE
&&
542 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
543 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
544 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
545 netdev
->kind
!= NETDEV_KIND_VTI
&&
546 netdev
->kind
!= NETDEV_KIND_VTI6
&&
547 netdev
->kind
!= NETDEV_KIND_IP6TNL
549 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
550 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
554 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
556 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
565 int config_parse_ipv4ll(
567 const char *filename
,
570 unsigned section_line
,
577 AddressFamilyBoolean
*link_local
= data
;
584 /* Note that this is mostly like
585 * config_parse_address_family_boolean(), except that it
586 * applies only to IPv4 */
588 if (parse_boolean(rvalue
))
589 *link_local
|= ADDRESS_FAMILY_IPV4
;
591 *link_local
&= ~ADDRESS_FAMILY_IPV4
;
596 int config_parse_dhcp(
598 const char *filename
,
601 unsigned section_line
,
608 AddressFamilyBoolean
*dhcp
= data
, s
;
615 /* Note that this is mostly like
616 * config_parse_address_family_boolean(), except that it
617 * understands some old names for the enum values */
619 s
= address_family_boolean_from_string(rvalue
);
622 /* Previously, we had a slightly different enum here,
623 * support its values for compatbility. */
625 if (streq(rvalue
, "none"))
626 s
= ADDRESS_FAMILY_NO
;
627 else if (streq(rvalue
, "v4"))
628 s
= ADDRESS_FAMILY_IPV4
;
629 else if (streq(rvalue
, "v6"))
630 s
= ADDRESS_FAMILY_IPV6
;
631 else if (streq(rvalue
, "both"))
632 s
= ADDRESS_FAMILY_YES
;
634 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DHCP option, ignoring: %s", rvalue
);
643 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
644 [DHCP_CLIENT_ID_MAC
] = "mac",
645 [DHCP_CLIENT_ID_DUID
] = "duid"
648 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DCHPClientIdentifier
);
649 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DCHPClientIdentifier
, "Failed to parse client identifier type");
651 int config_parse_ipv6token(
653 const char *filename
,
656 unsigned section_line
,
663 union in_addr_union buffer
;
664 struct in6_addr
*token
= data
;
672 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
674 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
678 r
= in_addr_is_null(AF_INET6
, &buffer
);
680 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
684 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
685 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);
694 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
695 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
696 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
697 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
700 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
702 int config_parse_ipv6_privacy_extensions(
704 const char *filename
,
707 unsigned section_line
,
714 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
720 assert(ipv6_privacy_extensions
);
722 /* Our enum shall be a superset of booleans, hence first try
723 * to parse as boolean, and then as enum */
725 k
= parse_boolean(rvalue
);
727 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
729 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
731 IPv6PrivacyExtensions s
;
733 s
= ipv6_privacy_extensions_from_string(rvalue
);
736 if (streq(rvalue
, "kernel"))
737 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
739 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
744 *ipv6_privacy_extensions
= s
;
750 int config_parse_hostname(
752 const char *filename
,
755 unsigned section_line
,
762 char **hostname
= data
, *hn
= NULL
;
769 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
773 if (!hostname_is_valid(hn
, false)) {
774 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not valid, ignoring assignment: %s", rvalue
);
780 *hostname
= hostname_cleanup(hn
);
784 int config_parse_timezone(
786 const char *filename
,
789 unsigned section_line
,
796 char **datap
= data
, *tz
= NULL
;
803 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
807 if (!timezone_is_valid(tz
)) {
808 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Timezone is not valid, ignoring assignment: %s", rvalue
);
819 int config_parse_dhcp_server_dns(
821 const char *filename
,
824 unsigned section_line
,
832 const char *p
= rvalue
;
840 _cleanup_free_
char *w
= NULL
;
841 struct in_addr a
, *m
;
843 r
= extract_first_word(&p
, &w
, NULL
, 0);
845 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
852 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
853 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
857 m
= realloc(n
->dhcp_server_dns
, (n
->n_dhcp_server_dns
+ 1) * sizeof(struct in_addr
));
861 m
[n
->n_dhcp_server_dns
++] = a
;
862 n
->dhcp_server_dns
= m
;
866 int config_parse_dhcp_server_ntp(
868 const char *filename
,
871 unsigned section_line
,
879 const char *p
= rvalue
;
887 _cleanup_free_
char *w
= NULL
;
888 struct in_addr a
, *m
;
890 r
= extract_first_word(&p
, &w
, NULL
, 0);
892 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
899 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
900 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse NTP server address, ignoring: %s", w
);
904 m
= realloc(n
->dhcp_server_ntp
, (n
->n_dhcp_server_ntp
+ 1) * sizeof(struct in_addr
));
908 m
[n
->n_dhcp_server_ntp
++] = a
;
909 n
->dhcp_server_ntp
= m
;