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
;
125 network
->link_local
= ADDRESS_FAMILY_IPV6
;
127 network
->ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
128 network
->ipv6_accept_ra
= -1;
129 network
->ipv6_dad_transmits
= -1;
130 network
->ipv6_hop_limit
= -1;
132 r
= config_parse(NULL
, filename
, file
,
139 "DHCPv4\0" /* compat */
143 config_item_perf_lookup
, network_network_gperf_lookup
,
144 false, false, true, network
);
148 /* IPMasquerade=yes implies IPForward=yes */
149 if (network
->ip_masquerade
)
150 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
152 LIST_PREPEND(networks
, manager
->networks
, network
);
154 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
158 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
162 LIST_FOREACH(routes
, route
, network
->static_routes
) {
163 if (!route
->family
) {
164 log_warning("Route section without Gateway field configured in %s. "
165 "Ignoring", filename
);
170 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
171 if (!address
->family
) {
172 log_warning("Address section without Address field configured in %s. "
173 "Ignoring", filename
);
183 int network_load(Manager
*manager
) {
185 _cleanup_strv_free_
char **files
= NULL
;
191 while ((network
= manager
->networks
))
192 network_free(network
);
194 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
196 return log_error_errno(r
, "Failed to enumerate network files: %m");
198 STRV_FOREACH_BACKWARDS(f
, files
) {
199 r
= network_load_one(manager
, *f
);
207 void network_free(Network
*network
) {
217 free(network
->filename
);
219 free(network
->match_mac
);
220 strv_free(network
->match_path
);
221 strv_free(network
->match_driver
);
222 strv_free(network
->match_type
);
223 strv_free(network
->match_name
);
225 free(network
->description
);
226 free(network
->dhcp_vendor_class_identifier
);
227 free(network
->hostname
);
231 strv_free(network
->ntp
);
232 strv_free(network
->dns
);
233 strv_free(network
->domains
);
234 strv_free(network
->bind_carrier
);
236 netdev_unref(network
->bridge
);
238 netdev_unref(network
->bond
);
240 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
241 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
242 netdev_unref(netdev
);
244 hashmap_free(network
->stacked_netdevs
);
246 while ((route
= network
->static_routes
))
249 while ((address
= network
->static_addresses
))
250 address_free(address
);
252 while ((fdb_entry
= network
->static_fdb_entries
))
253 fdb_entry_free(fdb_entry
);
255 hashmap_free(network
->addresses_by_section
);
256 hashmap_free(network
->routes_by_section
);
257 hashmap_free(network
->fdb_entries_by_section
);
259 if (network
->manager
) {
260 if (network
->manager
->networks
)
261 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
263 if (network
->manager
->networks_by_name
)
264 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
269 condition_free_list(network
->match_host
);
270 condition_free_list(network
->match_virt
);
271 condition_free_list(network
->match_kernel
);
272 condition_free_list(network
->match_arch
);
274 free(network
->dhcp_server_timezone
);
275 free(network
->dhcp_server_dns
);
276 free(network
->dhcp_server_ntp
);
281 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
288 network
= hashmap_get(manager
->networks_by_name
, name
);
297 int network_get(Manager
*manager
, struct udev_device
*device
,
298 const char *ifname
, const struct ether_addr
*address
,
301 struct udev_device
*parent
;
302 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
308 path
= udev_device_get_property_value(device
, "ID_PATH");
310 parent
= udev_device_get_parent(device
);
312 parent_driver
= udev_device_get_driver(parent
);
314 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
316 devtype
= udev_device_get_devtype(device
);
319 LIST_FOREACH(networks
, network
, manager
->networks
) {
320 if (net_match_config(network
->match_mac
, network
->match_path
,
321 network
->match_driver
, network
->match_type
,
322 network
->match_name
, network
->match_host
,
323 network
->match_virt
, network
->match_kernel
,
325 address
, path
, parent_driver
, driver
,
327 if (network
->match_name
&& device
) {
329 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
331 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
333 (void) safe_atou8(attr
, &name_assign_type
);
335 if (name_assign_type
== NET_NAME_ENUM
)
336 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
337 ifname
, network
->filename
);
339 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
341 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
353 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
360 link
->network
= network
;
362 if (network
->ipv4ll_route
) {
365 r
= route_new_static(network
, 0, &route
);
369 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst
.in
);
375 route
->family
= AF_INET
;
376 route
->dst_prefixlen
= 16;
377 route
->scope
= RT_SCOPE_LINK
;
378 route
->priority
= IPV4LL_ROUTE_METRIC
;
379 route
->protocol
= RTPROT_STATIC
;
382 if (network
->dns
|| network
->ntp
|| network
->domains
) {
383 manager_dirty(manager
);
390 int config_parse_netdev(const char *unit
,
391 const char *filename
,
394 unsigned section_line
,
400 Network
*network
= userdata
;
401 _cleanup_free_
char *kind_string
= NULL
;
412 kind_string
= strdup(lvalue
);
416 /* the keys are CamelCase versions of the kind */
417 for (p
= kind_string
; *p
; p
++)
420 kind
= netdev_kind_from_string(kind_string
);
421 if (kind
== _NETDEV_KIND_INVALID
) {
422 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid NetDev kind: %s", lvalue
);
426 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
428 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
432 if (netdev
->kind
!= kind
) {
433 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
438 case NETDEV_KIND_BRIDGE
:
439 network
->bridge
= netdev
;
442 case NETDEV_KIND_BOND
:
443 network
->bond
= netdev
;
446 case NETDEV_KIND_VLAN
:
447 case NETDEV_KIND_MACVLAN
:
448 case NETDEV_KIND_MACVTAP
:
449 case NETDEV_KIND_IPVLAN
:
450 case NETDEV_KIND_VXLAN
:
451 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
453 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Can not add VLAN '%s' to network: %m", rvalue
);
459 assert_not_reached("Can not parse NetDev");
467 int config_parse_domains(const char *unit
,
468 const char *filename
,
471 unsigned section_line
,
477 Network
*network
= userdata
;
478 char ***domains
= data
;
482 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
483 lvalue
, ltype
, rvalue
, domains
, userdata
);
488 network
->wildcard_domain
= !!strv_find(*domains
, "*");
490 STRV_FOREACH(domain
, *domains
) {
491 if (is_localhost(*domain
))
492 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
494 r
= dns_name_is_valid(*domain
);
495 if (r
<= 0 && !streq(*domain
, "*")) {
497 log_error_errno(r
, "Failed to validate domain name: %s: %m", *domain
);
499 log_warning("Domain name is not valid, ignoring assignment: %s", *domain
);
504 strv_remove(*domains
, *domain
);
506 /* We removed one entry, make sure we don't skip the next one */
513 int config_parse_tunnel(const char *unit
,
514 const char *filename
,
517 unsigned section_line
,
523 Network
*network
= userdata
;
532 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
534 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
538 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
539 netdev
->kind
!= NETDEV_KIND_SIT
&&
540 netdev
->kind
!= NETDEV_KIND_GRE
&&
541 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
542 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
543 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
544 netdev
->kind
!= NETDEV_KIND_VTI
&&
545 netdev
->kind
!= NETDEV_KIND_VTI6
&&
546 netdev
->kind
!= NETDEV_KIND_IP6TNL
548 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
549 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
553 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
555 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
564 int config_parse_ipv4ll(
566 const char *filename
,
569 unsigned section_line
,
576 AddressFamilyBoolean
*link_local
= data
;
583 /* Note that this is mostly like
584 * config_parse_address_family_boolean(), except that it
585 * applies only to IPv4 */
587 if (parse_boolean(rvalue
))
588 *link_local
|= ADDRESS_FAMILY_IPV4
;
590 *link_local
&= ~ADDRESS_FAMILY_IPV4
;
595 int config_parse_dhcp(
597 const char *filename
,
600 unsigned section_line
,
607 AddressFamilyBoolean
*dhcp
= data
, s
;
614 /* Note that this is mostly like
615 * config_parse_address_family_boolean(), except that it
616 * understands some old names for the enum values */
618 s
= address_family_boolean_from_string(rvalue
);
621 /* Previously, we had a slightly different enum here,
622 * support its values for compatbility. */
624 if (streq(rvalue
, "none"))
625 s
= ADDRESS_FAMILY_NO
;
626 else if (streq(rvalue
, "v4"))
627 s
= ADDRESS_FAMILY_IPV4
;
628 else if (streq(rvalue
, "v6"))
629 s
= ADDRESS_FAMILY_IPV6
;
630 else if (streq(rvalue
, "both"))
631 s
= ADDRESS_FAMILY_YES
;
633 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DHCP option, ignoring: %s", rvalue
);
642 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
643 [DHCP_CLIENT_ID_MAC
] = "mac",
644 [DHCP_CLIENT_ID_DUID
] = "duid"
647 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DCHPClientIdentifier
);
648 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DCHPClientIdentifier
, "Failed to parse client identifier type");
650 int config_parse_ipv6token(
652 const char *filename
,
655 unsigned section_line
,
662 union in_addr_union buffer
;
663 struct in6_addr
*token
= data
;
671 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
673 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
677 r
= in_addr_is_null(AF_INET6
, &buffer
);
679 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
683 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
684 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);
693 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
694 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
695 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
696 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
699 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
701 int config_parse_ipv6_privacy_extensions(
703 const char *filename
,
706 unsigned section_line
,
713 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
719 assert(ipv6_privacy_extensions
);
721 /* Our enum shall be a superset of booleans, hence first try
722 * to parse as boolean, and then as enum */
724 k
= parse_boolean(rvalue
);
726 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
728 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
730 IPv6PrivacyExtensions s
;
732 s
= ipv6_privacy_extensions_from_string(rvalue
);
735 if (streq(rvalue
, "kernel"))
736 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
738 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
743 *ipv6_privacy_extensions
= s
;
749 int config_parse_hostname(
751 const char *filename
,
754 unsigned section_line
,
761 char **hostname
= data
, *hn
= NULL
;
768 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
772 if (!hostname_is_valid(hn
, false)) {
773 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not valid, ignoring assignment: %s", rvalue
);
779 *hostname
= hostname_cleanup(hn
);
783 int config_parse_timezone(
785 const char *filename
,
788 unsigned section_line
,
795 char **datap
= data
, *tz
= NULL
;
802 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
806 if (!timezone_is_valid(tz
)) {
807 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Timezone is not valid, ignoring assignment: %s", rvalue
);
818 int config_parse_dhcp_server_dns(
820 const char *filename
,
823 unsigned section_line
,
831 const char *p
= rvalue
;
839 _cleanup_free_
char *w
= NULL
;
840 struct in_addr a
, *m
;
842 r
= extract_first_word(&p
, &w
, NULL
, 0);
844 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
851 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
852 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
856 m
= realloc(n
->dhcp_server_dns
, (n
->n_dhcp_server_dns
+ 1) * sizeof(struct in_addr
));
860 m
[n
->n_dhcp_server_dns
++] = a
;
861 n
->dhcp_server_dns
= m
;
865 int config_parse_dhcp_server_ntp(
867 const char *filename
,
870 unsigned section_line
,
878 const char *p
= rvalue
;
886 _cleanup_free_
char *w
= NULL
;
887 struct in_addr a
, *m
;
889 r
= extract_first_word(&p
, &w
, NULL
, 0);
891 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
898 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
899 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse NTP server address, ignoring: %s", w
);
903 m
= realloc(n
->dhcp_server_ntp
, (n
->n_dhcp_server_ntp
+ 1) * sizeof(struct in_addr
));
907 m
[n
->n_dhcp_server_ntp
++] = a
;
908 n
->dhcp_server_ntp
= m
;