1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include <linux/if_arp.h>
6 #include "in-addr-util.h"
7 #include "networkd-address.h"
8 #include "networkd-ipv6ll.h"
9 #include "networkd-link.h"
10 #include "networkd-network.h"
11 #include "networkd-util.h"
12 #include "socket-util.h"
13 #include "string-table.h"
15 #include "sysctl-util.h"
17 bool link_ipv6ll_enabled(Link
*link
) {
20 if (!socket_ipv6_is_supported())
23 if (link
->flags
& IFF_LOOPBACK
)
29 if (link
->iftype
== ARPHRD_CAN
)
32 if (STRPTR_IN_SET(link
->kind
, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "nlmon"))
35 if (link
->network
->bond
)
38 return link
->network
->link_local
& ADDRESS_FAMILY_IPV6
;
41 bool link_may_have_ipv6ll(Link
*link
, bool check_multicast
) {
45 * This is equivalent to link_ipv6ll_enabled() for non-WireGuard interfaces.
47 * For WireGuard interface, the kernel does not assign any IPv6LL addresses, but we can assign
48 * it manually. It is necessary to set an IPv6LL address manually to run NDisc or RADV on
49 * WireGuard interface. Note, also Multicast=yes must be set. See #17380.
51 * TODO: May be better to introduce GenerateIPv6LinkLocalAddress= setting, and use algorithms
52 * used in networkd-address-generation.c
55 if (link_ipv6ll_enabled(link
))
58 /* IPv6LL address can be manually assigned on WireGuard interface. */
59 if (streq_ptr(link
->kind
, "wireguard")) {
65 if (check_multicast
&& !FLAGS_SET(link
->flags
, IFF_MULTICAST
) && link
->network
->multicast
<= 0)
68 ORDERED_HASHMAP_FOREACH(a
, link
->network
->addresses_by_section
) {
69 if (a
->family
!= AF_INET6
)
71 if (in6_addr_is_set(&a
->in_addr_peer
.in6
))
73 if (in6_addr_is_link_local(&a
->in_addr
.in6
))
81 IPv6LinkLocalAddressGenMode
link_get_ipv6ll_addrgen_mode(Link
*link
) {
84 if (!link_ipv6ll_enabled(link
))
85 return IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE
;
87 if (link
->network
->ipv6ll_address_gen_mode
>= 0)
88 return link
->network
->ipv6ll_address_gen_mode
;
90 if (in6_addr_is_set(&link
->network
->ipv6ll_stable_secret
))
91 return IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY
;
93 return IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64
;
96 int ipv6ll_addrgen_mode_fill_message(sd_netlink_message
*message
, IPv6LinkLocalAddressGenMode mode
) {
100 assert(mode
>= 0 && mode
< _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX
);
102 r
= sd_netlink_message_open_container(message
, IFLA_AF_SPEC
);
106 r
= sd_netlink_message_open_container(message
, AF_INET6
);
110 r
= sd_netlink_message_append_u8(message
, IFLA_INET6_ADDR_GEN_MODE
, mode
);
114 r
= sd_netlink_message_close_container(message
);
118 r
= sd_netlink_message_close_container(message
);
125 int link_update_ipv6ll_addrgen_mode(Link
*link
, sd_netlink_message
*message
) {
132 r
= sd_rtnl_message_get_family(message
, &family
);
136 if (family
!= AF_UNSPEC
)
139 r
= sd_netlink_message_enter_container(message
, IFLA_AF_SPEC
);
145 r
= sd_netlink_message_enter_container(message
, AF_INET6
);
147 return sd_netlink_message_exit_container(message
);
151 mode
= (uint8_t) link
->ipv6ll_address_gen_mode
;
152 r
= sd_netlink_message_read_u8(message
, IFLA_INET6_ADDR_GEN_MODE
, &mode
);
153 if (r
< 0 && r
!= -ENODATA
)
156 r
= sd_netlink_message_exit_container(message
);
160 r
= sd_netlink_message_exit_container(message
);
164 if (mode
== (uint8_t) link
->ipv6ll_address_gen_mode
)
167 if (mode
>= _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX
) {
168 log_link_debug(link
, "Received invalid IPv6 link-local address generation mode (%u), ignoring.", mode
);
172 if (link
->ipv6ll_address_gen_mode
< 0)
173 log_link_debug(link
, "Saved IPv6 link-local address generation mode: %s",
174 ipv6_link_local_address_gen_mode_to_string(mode
));
176 log_link_debug(link
, "IPv6 link-local address generation mode is changed: %s -> %s",
177 ipv6_link_local_address_gen_mode_to_string(link
->ipv6ll_address_gen_mode
),
178 ipv6_link_local_address_gen_mode_to_string(mode
));
180 link
->ipv6ll_address_gen_mode
= mode
;
184 #define STABLE_SECRET_APP_ID_1 SD_ID128_MAKE(aa,05,1d,94,43,68,45,07,b9,73,f1,e8,e4,b7,34,52)
185 #define STABLE_SECRET_APP_ID_2 SD_ID128_MAKE(52,c4,40,a0,9f,2f,48,58,a9,3a,f6,29,25,ba,7a,7d)
187 int link_set_ipv6ll_stable_secret(Link
*link
) {
192 assert(link
->network
);
194 if (link
->network
->ipv6ll_address_gen_mode
!= IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY
)
197 if (in6_addr_is_set(&link
->network
->ipv6ll_stable_secret
))
198 a
= link
->network
->ipv6ll_stable_secret
;
203 /* Generate a stable secret address from machine-ID and the interface name. */
205 r
= sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_1
, &key
);
207 return log_link_debug_errno(link
, r
, "Failed to generate key: %m");
209 v
= htole64(siphash24_string(link
->ifname
, key
.bytes
));
210 memcpy(a
.s6_addr
, &v
, sizeof(v
));
212 r
= sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_2
, &key
);
214 return log_link_debug_errno(link
, r
, "Failed to generate key: %m");
216 v
= htole64(siphash24_string(link
->ifname
, key
.bytes
));
217 assert_cc(sizeof(v
) * 2 == sizeof(a
.s6_addr
));
218 memcpy(a
.s6_addr
+ sizeof(v
), &v
, sizeof(v
));
221 return sysctl_write_ip_property(AF_INET6
, link
->ifname
, "stable_secret",
222 IN6_ADDR_TO_STRING(&a
));
225 int link_set_ipv6ll_addrgen_mode(Link
*link
, IPv6LinkLocalAddressGenMode mode
) {
227 assert(mode
>= 0 && mode
< _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX
);
229 if (mode
== link
->ipv6ll_address_gen_mode
)
232 return sysctl_write_ip_property_uint32(AF_INET6
, link
->ifname
, "addr_gen_mode", mode
);
235 static const char* const ipv6_link_local_address_gen_mode_table
[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX
] = {
236 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64
] = "eui64",
237 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE
] = "none",
238 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY
] = "stable-privacy",
239 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM
] = "random",
242 DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode
, IPv6LinkLocalAddressGenMode
);
243 DEFINE_CONFIG_PARSE_ENUM(
244 config_parse_ipv6_link_local_address_gen_mode
,
245 ipv6_link_local_address_gen_mode
,
246 IPv6LinkLocalAddressGenMode
,
247 "Failed to parse IPv6 link-local address generation mode");