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"
36 #include "stat-util.h"
37 #include "string-table.h"
38 #include "string-util.h"
41 static int network_load_one(Manager
*manager
, const char *filename
) {
42 _cleanup_network_free_ Network
*network
= NULL
;
43 _cleanup_fclose_
FILE *file
= NULL
;
52 file
= fopen(filename
, "re");
60 if (null_or_empty_fd(fileno(file
))) {
61 log_debug("Skipping empty file: %s", filename
);
65 network
= new0(Network
, 1);
69 network
->manager
= manager
;
71 LIST_HEAD_INIT(network
->static_addresses
);
72 LIST_HEAD_INIT(network
->static_routes
);
73 LIST_HEAD_INIT(network
->static_fdb_entries
);
75 network
->stacked_netdevs
= hashmap_new(&string_hash_ops
);
76 if (!network
->stacked_netdevs
)
79 network
->addresses_by_section
= hashmap_new(NULL
);
80 if (!network
->addresses_by_section
)
83 network
->routes_by_section
= hashmap_new(NULL
);
84 if (!network
->routes_by_section
)
87 network
->fdb_entries_by_section
= hashmap_new(NULL
);
88 if (!network
->fdb_entries_by_section
)
91 network
->filename
= strdup(filename
);
92 if (!network
->filename
)
95 network
->name
= strdup(basename(filename
));
99 d
= strrchr(network
->name
, '.');
103 assert(streq(d
, ".network"));
107 network
->dhcp
= ADDRESS_FAMILY_NO
;
108 network
->dhcp_ntp
= true;
109 network
->dhcp_dns
= true;
110 network
->dhcp_hostname
= true;
111 network
->dhcp_routes
= true;
112 network
->dhcp_sendhost
= true;
113 network
->dhcp_route_metric
= DHCP_ROUTE_METRIC
;
114 network
->dhcp_client_identifier
= DHCP_CLIENT_ID_DUID
;
116 network
->dhcp_server_emit_dns
= true;
117 network
->dhcp_server_emit_ntp
= true;
118 network
->dhcp_server_emit_timezone
= true;
120 network
->use_bpdu
= true;
121 network
->allow_port_to_be_root
= true;
122 network
->unicast_flood
= true;
124 network
->llmnr
= RESOLVE_SUPPORT_YES
;
125 network
->mdns
= RESOLVE_SUPPORT_NO
;
126 network
->dnssec_mode
= _DNSSEC_MODE_INVALID
;
128 network
->link_local
= ADDRESS_FAMILY_IPV6
;
130 network
->ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
131 network
->ipv6_accept_ra
= -1;
132 network
->ipv6_dad_transmits
= -1;
133 network
->ipv6_hop_limit
= -1;
135 r
= config_parse(NULL
, filename
, file
,
142 "DHCPv4\0" /* compat */
146 config_item_perf_lookup
, network_network_gperf_lookup
,
147 false, false, true, network
);
151 /* IPMasquerade=yes implies IPForward=yes */
152 if (network
->ip_masquerade
)
153 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
155 LIST_PREPEND(networks
, manager
->networks
, network
);
157 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
161 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
165 LIST_FOREACH(routes
, route
, network
->static_routes
) {
166 if (!route
->family
) {
167 log_warning("Route section without Gateway field configured in %s. "
168 "Ignoring", filename
);
173 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
174 if (!address
->family
) {
175 log_warning("Address section without Address field configured in %s. "
176 "Ignoring", filename
);
186 int network_load(Manager
*manager
) {
188 _cleanup_strv_free_
char **files
= NULL
;
194 while ((network
= manager
->networks
))
195 network_free(network
);
197 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
199 return log_error_errno(r
, "Failed to enumerate network files: %m");
201 STRV_FOREACH_BACKWARDS(f
, files
) {
202 r
= network_load_one(manager
, *f
);
210 void network_free(Network
*network
) {
220 free(network
->filename
);
222 free(network
->match_mac
);
223 strv_free(network
->match_path
);
224 strv_free(network
->match_driver
);
225 strv_free(network
->match_type
);
226 strv_free(network
->match_name
);
228 free(network
->description
);
229 free(network
->dhcp_vendor_class_identifier
);
230 free(network
->hostname
);
234 strv_free(network
->ntp
);
235 strv_free(network
->dns
);
236 strv_free(network
->domains
);
237 strv_free(network
->bind_carrier
);
239 netdev_unref(network
->bridge
);
241 netdev_unref(network
->bond
);
243 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
244 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
245 netdev_unref(netdev
);
247 hashmap_free(network
->stacked_netdevs
);
249 while ((route
= network
->static_routes
))
252 while ((address
= network
->static_addresses
))
253 address_free(address
);
255 while ((fdb_entry
= network
->static_fdb_entries
))
256 fdb_entry_free(fdb_entry
);
258 hashmap_free(network
->addresses_by_section
);
259 hashmap_free(network
->routes_by_section
);
260 hashmap_free(network
->fdb_entries_by_section
);
262 if (network
->manager
) {
263 if (network
->manager
->networks
)
264 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
266 if (network
->manager
->networks_by_name
)
267 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
272 condition_free_list(network
->match_host
);
273 condition_free_list(network
->match_virt
);
274 condition_free_list(network
->match_kernel
);
275 condition_free_list(network
->match_arch
);
277 free(network
->dhcp_server_timezone
);
278 free(network
->dhcp_server_dns
);
279 free(network
->dhcp_server_ntp
);
281 set_free_free(network
->dnssec_negative_trust_anchors
);
286 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
293 network
= hashmap_get(manager
->networks_by_name
, name
);
302 int network_get(Manager
*manager
, struct udev_device
*device
,
303 const char *ifname
, const struct ether_addr
*address
,
306 struct udev_device
*parent
;
307 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
313 path
= udev_device_get_property_value(device
, "ID_PATH");
315 parent
= udev_device_get_parent(device
);
317 parent_driver
= udev_device_get_driver(parent
);
319 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
321 devtype
= udev_device_get_devtype(device
);
324 LIST_FOREACH(networks
, network
, manager
->networks
) {
325 if (net_match_config(network
->match_mac
, network
->match_path
,
326 network
->match_driver
, network
->match_type
,
327 network
->match_name
, network
->match_host
,
328 network
->match_virt
, network
->match_kernel
,
330 address
, path
, parent_driver
, driver
,
332 if (network
->match_name
&& device
) {
334 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
336 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
338 (void) safe_atou8(attr
, &name_assign_type
);
340 if (name_assign_type
== NET_NAME_ENUM
)
341 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
342 ifname
, network
->filename
);
344 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
346 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
358 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
365 link
->network
= network
;
367 if (network
->ipv4ll_route
) {
370 r
= route_new_static(network
, 0, &route
);
374 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst
.in
);
380 route
->family
= AF_INET
;
381 route
->dst_prefixlen
= 16;
382 route
->scope
= RT_SCOPE_LINK
;
383 route
->priority
= IPV4LL_ROUTE_METRIC
;
384 route
->protocol
= RTPROT_STATIC
;
387 if (network
->dns
|| network
->ntp
|| network
->domains
) {
388 manager_dirty(manager
);
395 int config_parse_netdev(const char *unit
,
396 const char *filename
,
399 unsigned section_line
,
405 Network
*network
= userdata
;
406 _cleanup_free_
char *kind_string
= NULL
;
417 kind_string
= strdup(lvalue
);
421 /* the keys are CamelCase versions of the kind */
422 for (p
= kind_string
; *p
; p
++)
425 kind
= netdev_kind_from_string(kind_string
);
426 if (kind
== _NETDEV_KIND_INVALID
) {
427 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid NetDev kind: %s", lvalue
);
431 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
433 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
437 if (netdev
->kind
!= kind
) {
438 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
443 case NETDEV_KIND_BRIDGE
:
444 network
->bridge
= netdev
;
447 case NETDEV_KIND_BOND
:
448 network
->bond
= netdev
;
451 case NETDEV_KIND_VLAN
:
452 case NETDEV_KIND_MACVLAN
:
453 case NETDEV_KIND_MACVTAP
:
454 case NETDEV_KIND_IPVLAN
:
455 case NETDEV_KIND_VXLAN
:
456 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
458 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Can not add VLAN '%s' to network: %m", rvalue
);
464 assert_not_reached("Can not parse NetDev");
472 int config_parse_domains(const char *unit
,
473 const char *filename
,
476 unsigned section_line
,
482 Network
*network
= userdata
;
483 char ***domains
= data
;
487 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
488 lvalue
, ltype
, rvalue
, domains
, userdata
);
493 network
->wildcard_domain
= !!strv_find(*domains
, "*");
495 STRV_FOREACH(domain
, *domains
) {
496 if (is_localhost(*domain
))
497 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
499 r
= dns_name_is_valid(*domain
);
500 if (r
<= 0 && !streq(*domain
, "*")) {
502 log_error_errno(r
, "Failed to validate domain name: %s: %m", *domain
);
504 log_warning("Domain name is not valid, ignoring assignment: %s", *domain
);
509 strv_remove(*domains
, *domain
);
511 /* We removed one entry, make sure we don't skip the next one */
518 int config_parse_tunnel(const char *unit
,
519 const char *filename
,
522 unsigned section_line
,
528 Network
*network
= userdata
;
537 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
539 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
543 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
544 netdev
->kind
!= NETDEV_KIND_SIT
&&
545 netdev
->kind
!= NETDEV_KIND_GRE
&&
546 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
547 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
548 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
549 netdev
->kind
!= NETDEV_KIND_VTI
&&
550 netdev
->kind
!= NETDEV_KIND_VTI6
&&
551 netdev
->kind
!= NETDEV_KIND_IP6TNL
553 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
554 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
558 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
560 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
569 int config_parse_ipv4ll(
571 const char *filename
,
574 unsigned section_line
,
581 AddressFamilyBoolean
*link_local
= data
;
588 /* Note that this is mostly like
589 * config_parse_address_family_boolean(), except that it
590 * applies only to IPv4 */
592 if (parse_boolean(rvalue
))
593 *link_local
|= ADDRESS_FAMILY_IPV4
;
595 *link_local
&= ~ADDRESS_FAMILY_IPV4
;
600 int config_parse_dhcp(
602 const char *filename
,
605 unsigned section_line
,
612 AddressFamilyBoolean
*dhcp
= data
, s
;
619 /* Note that this is mostly like
620 * config_parse_address_family_boolean(), except that it
621 * understands some old names for the enum values */
623 s
= address_family_boolean_from_string(rvalue
);
626 /* Previously, we had a slightly different enum here,
627 * support its values for compatbility. */
629 if (streq(rvalue
, "none"))
630 s
= ADDRESS_FAMILY_NO
;
631 else if (streq(rvalue
, "v4"))
632 s
= ADDRESS_FAMILY_IPV4
;
633 else if (streq(rvalue
, "v6"))
634 s
= ADDRESS_FAMILY_IPV6
;
635 else if (streq(rvalue
, "both"))
636 s
= ADDRESS_FAMILY_YES
;
638 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DHCP option, ignoring: %s", rvalue
);
647 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
648 [DHCP_CLIENT_ID_MAC
] = "mac",
649 [DHCP_CLIENT_ID_DUID
] = "duid"
652 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DCHPClientIdentifier
);
653 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DCHPClientIdentifier
, "Failed to parse client identifier type");
655 int config_parse_ipv6token(
657 const char *filename
,
660 unsigned section_line
,
667 union in_addr_union buffer
;
668 struct in6_addr
*token
= data
;
676 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
678 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
682 r
= in_addr_is_null(AF_INET6
, &buffer
);
684 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
688 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
689 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);
698 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
699 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
700 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
701 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
704 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
706 int config_parse_ipv6_privacy_extensions(
708 const char *filename
,
711 unsigned section_line
,
718 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
724 assert(ipv6_privacy_extensions
);
726 /* Our enum shall be a superset of booleans, hence first try
727 * to parse as boolean, and then as enum */
729 k
= parse_boolean(rvalue
);
731 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
733 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
735 IPv6PrivacyExtensions s
;
737 s
= ipv6_privacy_extensions_from_string(rvalue
);
740 if (streq(rvalue
, "kernel"))
741 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
743 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
748 *ipv6_privacy_extensions
= s
;
754 int config_parse_hostname(
756 const char *filename
,
759 unsigned section_line
,
766 char **hostname
= data
, *hn
= NULL
;
773 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
777 if (!hostname_is_valid(hn
, false)) {
778 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not valid, ignoring assignment: %s", rvalue
);
784 *hostname
= hostname_cleanup(hn
);
788 int config_parse_timezone(
790 const char *filename
,
793 unsigned section_line
,
800 char **datap
= data
, *tz
= NULL
;
807 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
811 if (!timezone_is_valid(tz
)) {
812 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Timezone is not valid, ignoring assignment: %s", rvalue
);
823 int config_parse_dhcp_server_dns(
825 const char *filename
,
828 unsigned section_line
,
836 const char *p
= rvalue
;
844 _cleanup_free_
char *w
= NULL
;
845 struct in_addr a
, *m
;
847 r
= extract_first_word(&p
, &w
, NULL
, 0);
849 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
856 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
857 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
861 m
= realloc(n
->dhcp_server_dns
, (n
->n_dhcp_server_dns
+ 1) * sizeof(struct in_addr
));
865 m
[n
->n_dhcp_server_dns
++] = a
;
866 n
->dhcp_server_dns
= m
;
870 int config_parse_dhcp_server_ntp(
872 const char *filename
,
875 unsigned section_line
,
883 const char *p
= rvalue
;
891 _cleanup_free_
char *w
= NULL
;
892 struct in_addr a
, *m
;
894 r
= extract_first_word(&p
, &w
, NULL
, 0);
896 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
903 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
904 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse NTP server address, ignoring: %s", w
);
908 m
= realloc(n
->dhcp_server_ntp
, (n
->n_dhcp_server_ntp
+ 1) * sizeof(struct in_addr
));
912 m
[n
->n_dhcp_server_ntp
++] = a
;
913 n
->dhcp_server_ntp
= m
;
917 int config_parse_dnssec_negative_trust_anchors(
919 const char *filename
,
922 unsigned section_line
,
929 const char *p
= rvalue
;
937 if (isempty(rvalue
)) {
938 n
->dnssec_negative_trust_anchors
= set_free_free(n
->dnssec_negative_trust_anchors
);
943 _cleanup_free_
char *w
= NULL
;
945 r
= extract_first_word(&p
, &w
, NULL
, 0);
947 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue
);
953 r
= dns_name_is_valid(w
);
955 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s is not a valid domain name, ignoring.", w
);
959 r
= set_put(n
->dnssec_negative_trust_anchors
, w
);