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;
131 r
= config_parse(NULL
, filename
, file
,
138 "DHCPv4\0" /* compat */
142 config_item_perf_lookup
, network_network_gperf_lookup
,
143 false, false, true, network
);
147 /* IPMasquerade=yes implies IPForward=yes */
148 if (network
->ip_masquerade
)
149 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
151 LIST_PREPEND(networks
, manager
->networks
, network
);
153 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
157 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
161 LIST_FOREACH(routes
, route
, network
->static_routes
) {
162 if (!route
->family
) {
163 log_warning("Route section without Gateway field configured in %s. "
164 "Ignoring", filename
);
169 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
170 if (!address
->family
) {
171 log_warning("Address section without Address field configured in %s. "
172 "Ignoring", filename
);
182 int network_load(Manager
*manager
) {
184 _cleanup_strv_free_
char **files
= NULL
;
190 while ((network
= manager
->networks
))
191 network_free(network
);
193 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
195 return log_error_errno(r
, "Failed to enumerate network files: %m");
197 STRV_FOREACH_BACKWARDS(f
, files
) {
198 r
= network_load_one(manager
, *f
);
206 void network_free(Network
*network
) {
216 free(network
->filename
);
218 free(network
->match_mac
);
219 strv_free(network
->match_path
);
220 strv_free(network
->match_driver
);
221 strv_free(network
->match_type
);
222 strv_free(network
->match_name
);
224 free(network
->description
);
225 free(network
->dhcp_vendor_class_identifier
);
226 free(network
->hostname
);
230 strv_free(network
->ntp
);
231 strv_free(network
->dns
);
232 strv_free(network
->domains
);
233 strv_free(network
->bind_carrier
);
235 netdev_unref(network
->bridge
);
237 netdev_unref(network
->bond
);
239 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
240 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
241 netdev_unref(netdev
);
243 hashmap_free(network
->stacked_netdevs
);
245 while ((route
= network
->static_routes
))
248 while ((address
= network
->static_addresses
))
249 address_free(address
);
251 while ((fdb_entry
= network
->static_fdb_entries
))
252 fdb_entry_free(fdb_entry
);
254 hashmap_free(network
->addresses_by_section
);
255 hashmap_free(network
->routes_by_section
);
256 hashmap_free(network
->fdb_entries_by_section
);
258 if (network
->manager
) {
259 if (network
->manager
->networks
)
260 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
262 if (network
->manager
->networks_by_name
)
263 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
268 condition_free_list(network
->match_host
);
269 condition_free_list(network
->match_virt
);
270 condition_free_list(network
->match_kernel
);
271 condition_free_list(network
->match_arch
);
273 free(network
->dhcp_server_timezone
);
274 free(network
->dhcp_server_dns
);
275 free(network
->dhcp_server_ntp
);
280 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
287 network
= hashmap_get(manager
->networks_by_name
, name
);
296 int network_get(Manager
*manager
, struct udev_device
*device
,
297 const char *ifname
, const struct ether_addr
*address
,
300 struct udev_device
*parent
;
301 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
307 path
= udev_device_get_property_value(device
, "ID_PATH");
309 parent
= udev_device_get_parent(device
);
311 parent_driver
= udev_device_get_driver(parent
);
313 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
315 devtype
= udev_device_get_devtype(device
);
318 LIST_FOREACH(networks
, network
, manager
->networks
) {
319 if (net_match_config(network
->match_mac
, network
->match_path
,
320 network
->match_driver
, network
->match_type
,
321 network
->match_name
, network
->match_host
,
322 network
->match_virt
, network
->match_kernel
,
324 address
, path
, parent_driver
, driver
,
326 if (network
->match_name
&& device
) {
328 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
330 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
332 (void) safe_atou8(attr
, &name_assign_type
);
334 if (name_assign_type
== NET_NAME_ENUM
)
335 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
336 ifname
, network
->filename
);
338 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
340 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
352 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
359 link
->network
= network
;
361 if (network
->ipv4ll_route
) {
364 r
= route_new_static(network
, 0, &route
);
368 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst
.in
);
374 route
->family
= AF_INET
;
375 route
->dst_prefixlen
= 16;
376 route
->scope
= RT_SCOPE_LINK
;
377 route
->priority
= IPV4LL_ROUTE_METRIC
;
378 route
->protocol
= RTPROT_STATIC
;
381 if (network
->dns
|| network
->ntp
|| network
->domains
) {
382 manager_dirty(manager
);
389 int config_parse_netdev(const char *unit
,
390 const char *filename
,
393 unsigned section_line
,
399 Network
*network
= userdata
;
400 _cleanup_free_
char *kind_string
= NULL
;
411 kind_string
= strdup(lvalue
);
415 /* the keys are CamelCase versions of the kind */
416 for (p
= kind_string
; *p
; p
++)
419 kind
= netdev_kind_from_string(kind_string
);
420 if (kind
== _NETDEV_KIND_INVALID
) {
421 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid NetDev kind: %s", lvalue
);
425 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
427 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
431 if (netdev
->kind
!= kind
) {
432 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
437 case NETDEV_KIND_BRIDGE
:
438 network
->bridge
= netdev
;
441 case NETDEV_KIND_BOND
:
442 network
->bond
= netdev
;
445 case NETDEV_KIND_VLAN
:
446 case NETDEV_KIND_MACVLAN
:
447 case NETDEV_KIND_MACVTAP
:
448 case NETDEV_KIND_IPVLAN
:
449 case NETDEV_KIND_VXLAN
:
450 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
452 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Can not add VLAN '%s' to network: %m", rvalue
);
458 assert_not_reached("Can not parse NetDev");
466 int config_parse_domains(const char *unit
,
467 const char *filename
,
470 unsigned section_line
,
476 Network
*network
= userdata
;
477 char ***domains
= data
;
481 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
482 lvalue
, ltype
, rvalue
, domains
, userdata
);
487 network
->wildcard_domain
= !!strv_find(*domains
, "*");
489 STRV_FOREACH(domain
, *domains
) {
490 if (is_localhost(*domain
))
491 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
493 r
= dns_name_is_valid(*domain
);
494 if (r
<= 0 && !streq(*domain
, "*")) {
496 log_error_errno(r
, "Failed to validate domain name: %s: %m", *domain
);
498 log_warning("Domain name is not valid, ignoring assignment: %s", *domain
);
503 strv_remove(*domains
, *domain
);
505 /* We removed one entry, make sure we don't skip the next one */
512 int config_parse_tunnel(const char *unit
,
513 const char *filename
,
516 unsigned section_line
,
522 Network
*network
= userdata
;
531 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
533 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
537 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
538 netdev
->kind
!= NETDEV_KIND_SIT
&&
539 netdev
->kind
!= NETDEV_KIND_GRE
&&
540 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
541 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
542 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
543 netdev
->kind
!= NETDEV_KIND_VTI
&&
544 netdev
->kind
!= NETDEV_KIND_VTI6
&&
545 netdev
->kind
!= NETDEV_KIND_IP6TNL
547 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
548 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
552 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
554 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
563 int config_parse_ipv4ll(
565 const char *filename
,
568 unsigned section_line
,
575 AddressFamilyBoolean
*link_local
= data
;
582 /* Note that this is mostly like
583 * config_parse_address_family_boolean(), except that it
584 * applies only to IPv4 */
586 if (parse_boolean(rvalue
))
587 *link_local
|= ADDRESS_FAMILY_IPV4
;
589 *link_local
&= ~ADDRESS_FAMILY_IPV4
;
594 int config_parse_dhcp(
596 const char *filename
,
599 unsigned section_line
,
606 AddressFamilyBoolean
*dhcp
= data
, s
;
613 /* Note that this is mostly like
614 * config_parse_address_family_boolean(), except that it
615 * understands some old names for the enum values */
617 s
= address_family_boolean_from_string(rvalue
);
620 /* Previously, we had a slightly different enum here,
621 * support its values for compatbility. */
623 if (streq(rvalue
, "none"))
624 s
= ADDRESS_FAMILY_NO
;
625 else if (streq(rvalue
, "v4"))
626 s
= ADDRESS_FAMILY_IPV4
;
627 else if (streq(rvalue
, "v6"))
628 s
= ADDRESS_FAMILY_IPV6
;
629 else if (streq(rvalue
, "both"))
630 s
= ADDRESS_FAMILY_YES
;
632 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DHCP option, ignoring: %s", rvalue
);
641 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
642 [DHCP_CLIENT_ID_MAC
] = "mac",
643 [DHCP_CLIENT_ID_DUID
] = "duid"
646 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DCHPClientIdentifier
);
647 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DCHPClientIdentifier
, "Failed to parse client identifier type");
649 int config_parse_ipv6token(
651 const char *filename
,
654 unsigned section_line
,
661 union in_addr_union buffer
;
662 struct in6_addr
*token
= data
;
670 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
672 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
676 r
= in_addr_is_null(AF_INET6
, &buffer
);
678 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
682 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
683 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);
692 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
693 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
694 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
695 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
698 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
700 int config_parse_ipv6_privacy_extensions(
702 const char *filename
,
705 unsigned section_line
,
712 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
718 assert(ipv6_privacy_extensions
);
720 /* Our enum shall be a superset of booleans, hence first try
721 * to parse as boolean, and then as enum */
723 k
= parse_boolean(rvalue
);
725 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
727 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
729 IPv6PrivacyExtensions s
;
731 s
= ipv6_privacy_extensions_from_string(rvalue
);
734 if (streq(rvalue
, "kernel"))
735 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
737 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
742 *ipv6_privacy_extensions
= s
;
748 int config_parse_hostname(
750 const char *filename
,
753 unsigned section_line
,
760 char **hostname
= data
, *hn
= NULL
;
767 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
771 if (!hostname_is_valid(hn
, false)) {
772 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not valid, ignoring assignment: %s", rvalue
);
778 *hostname
= hostname_cleanup(hn
);
782 int config_parse_timezone(
784 const char *filename
,
787 unsigned section_line
,
794 char **datap
= data
, *tz
= NULL
;
801 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
805 if (!timezone_is_valid(tz
)) {
806 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Timezone is not valid, ignoring assignment: %s", rvalue
);
817 int config_parse_dhcp_server_dns(
819 const char *filename
,
822 unsigned section_line
,
830 const char *p
= rvalue
;
838 _cleanup_free_
char *w
= NULL
;
839 struct in_addr a
, *m
;
841 r
= extract_first_word(&p
, &w
, NULL
, 0);
843 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
850 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
851 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
855 m
= realloc(n
->dhcp_server_dns
, (n
->n_dhcp_server_dns
+ 1) * sizeof(struct in_addr
));
859 m
[n
->n_dhcp_server_dns
++] = a
;
860 n
->dhcp_server_dns
= m
;
864 int config_parse_dhcp_server_ntp(
866 const char *filename
,
869 unsigned section_line
,
877 const char *p
= rvalue
;
885 _cleanup_free_
char *w
= NULL
;
886 struct in_addr a
, *m
;
888 r
= extract_first_word(&p
, &w
, NULL
, 0);
890 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
897 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
898 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse NTP server address, ignoring: %s", w
);
902 m
= realloc(n
->dhcp_server_ntp
, (n
->n_dhcp_server_ntp
+ 1) * sizeof(struct in_addr
));
906 m
[n
->n_dhcp_server_ntp
++] = a
;
907 n
->dhcp_server_ntp
= m
;