1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <linux/if.h>
4 #include <linux/if_arp.h>
5 
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"
14 #include "strv.h"
15 #include "sysctl-util.h"
16 
link_ipv6ll_enabled(Link * link)17 bool link_ipv6ll_enabled(Link *link) {
18         assert(link);
19 
20         if (!socket_ipv6_is_supported())
21                 return false;
22 
23         if (link->flags & IFF_LOOPBACK)
24                 return false;
25 
26         if (!link->network)
27                 return false;
28 
29         if (link->iftype == ARPHRD_CAN)
30                 return false;
31 
32         if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "nlmon"))
33                 return false;
34 
35         if (link->network->bond)
36                 return false;
37 
38         return link->network->link_local & ADDRESS_FAMILY_IPV6;
39 }
40 
link_may_have_ipv6ll(Link * link)41 bool link_may_have_ipv6ll(Link *link) {
42         assert(link);
43 
44         /*
45          * This is equivalent to link_ipv6ll_enabled() for non-WireGuard interfaces.
46          *
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.
50          *
51          * TODO: May be better to introduce GenerateIPv6LinkLocalAddress= setting, and use algorithms
52          *       used in networkd-address-generation.c
53          */
54 
55         if (link_ipv6ll_enabled(link))
56                 return true;
57 
58         /* IPv6LL address can be manually assigned on WireGuard interface. */
59         if (streq_ptr(link->kind, "wireguard")) {
60                 Address *a;
61 
62                 if (!link->network)
63                         return false;
64 
65                 ORDERED_HASHMAP_FOREACH(a, link->network->addresses_by_section) {
66                         if (a->family != AF_INET6)
67                                 continue;
68                         if (in6_addr_is_set(&a->in_addr_peer.in6))
69                                 continue;
70                         if (in6_addr_is_link_local(&a->in_addr.in6))
71                                 return true;
72                 }
73         }
74 
75         return false;
76 }
77 
link_get_ipv6ll_addrgen_mode(Link * link)78 IPv6LinkLocalAddressGenMode link_get_ipv6ll_addrgen_mode(Link *link) {
79         assert(link);
80 
81         if (!link_ipv6ll_enabled(link))
82                 return IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE;
83 
84         if (link->network->ipv6ll_address_gen_mode >= 0)
85                 return link->network->ipv6ll_address_gen_mode;
86 
87         if (in6_addr_is_set(&link->network->ipv6ll_stable_secret))
88                 return IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY;
89 
90         return IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64;
91 }
92 
ipv6ll_addrgen_mode_fill_message(sd_netlink_message * message,IPv6LinkLocalAddressGenMode mode)93 int ipv6ll_addrgen_mode_fill_message(sd_netlink_message *message, IPv6LinkLocalAddressGenMode mode) {
94         int r;
95 
96         assert(message);
97         assert(mode >= 0 && mode < _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX);
98 
99         r = sd_netlink_message_open_container(message, IFLA_AF_SPEC);
100         if (r < 0)
101                 return r;
102 
103         r = sd_netlink_message_open_container(message, AF_INET6);
104         if (r < 0)
105                 return r;
106 
107         r = sd_netlink_message_append_u8(message, IFLA_INET6_ADDR_GEN_MODE, mode);
108         if (r < 0)
109                 return r;
110 
111         r = sd_netlink_message_close_container(message);
112         if (r < 0)
113                 return r;
114 
115         r = sd_netlink_message_close_container(message);
116         if (r < 0)
117                 return r;
118 
119         return 0;
120 }
121 
link_update_ipv6ll_addrgen_mode(Link * link,sd_netlink_message * message)122 int link_update_ipv6ll_addrgen_mode(Link *link, sd_netlink_message *message) {
123         uint8_t mode;
124         int family, r;
125 
126         assert(link);
127         assert(message);
128 
129         r = sd_rtnl_message_get_family(message, &family);
130         if (r < 0)
131                 return r;
132 
133         if (family != AF_UNSPEC)
134                 return 0;
135 
136         r = sd_netlink_message_enter_container(message, IFLA_AF_SPEC);
137         if (r == -ENODATA)
138                 return 0;
139         if (r < 0)
140                 return r;
141 
142         r = sd_netlink_message_enter_container(message, AF_INET6);
143         if (r == -ENODATA)
144                 return sd_netlink_message_exit_container(message);
145         if (r < 0)
146                 return r;
147 
148         mode = (uint8_t) link->ipv6ll_address_gen_mode;
149         r = sd_netlink_message_read_u8(message, IFLA_INET6_ADDR_GEN_MODE, &mode);
150         if (r < 0 && r != -ENODATA)
151                 return r;
152 
153         r = sd_netlink_message_exit_container(message);
154         if (r < 0)
155                 return r;
156 
157         r = sd_netlink_message_exit_container(message);
158         if (r < 0)
159                 return r;
160 
161         if (mode == (uint8_t) link->ipv6ll_address_gen_mode)
162                 return 0;
163 
164         if (mode >= _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX) {
165                 log_link_debug(link, "Received invalid IPv6 link-local address generation mode (%u), ignoring.", mode);
166                 return 0;
167         }
168 
169         if (link->ipv6ll_address_gen_mode < 0)
170                 log_link_debug(link, "Saved IPv6 link-local address generation mode: %s",
171                                ipv6_link_local_address_gen_mode_to_string(mode));
172         else
173                 log_link_debug(link, "IPv6 link-local address generation mode is changed: %s -> %s",
174                                ipv6_link_local_address_gen_mode_to_string(link->ipv6ll_address_gen_mode),
175                                ipv6_link_local_address_gen_mode_to_string(mode));
176 
177         link->ipv6ll_address_gen_mode = mode;
178         return 0;
179 }
180 
181 #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)
182 #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)
183 
link_set_ipv6ll_stable_secret(Link * link)184 int link_set_ipv6ll_stable_secret(Link *link) {
185         _cleanup_free_ char *str = NULL;
186         struct in6_addr a;
187         int r;
188 
189         assert(link);
190         assert(link->network);
191 
192         if (link->network->ipv6ll_address_gen_mode != IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY)
193                 return 0;
194 
195         if (in6_addr_is_set(&link->network->ipv6ll_stable_secret))
196                 a = link->network->ipv6ll_stable_secret;
197         else {
198                 sd_id128_t key;
199                 le64_t v;
200 
201                 /* Generate a stable secret address from machine-ID and the interface name. */
202 
203                 r = sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_1, &key);
204                 if (r < 0)
205                         return log_link_debug_errno(link, r, "Failed to generate key: %m");
206 
207                 v = htole64(siphash24_string(link->ifname, key.bytes));
208                 memcpy(a.s6_addr, &v, sizeof(v));
209 
210                 r = sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_2, &key);
211                 if (r < 0)
212                         return log_link_debug_errno(link, r, "Failed to generate key: %m");
213 
214                 v = htole64(siphash24_string(link->ifname, key.bytes));
215                 assert_cc(sizeof(v) * 2 == sizeof(a.s6_addr));
216                 memcpy(a.s6_addr + sizeof(v), &v, sizeof(v));
217         }
218 
219         r = in6_addr_to_string(&a, &str);
220         if (r < 0)
221                 return r;
222 
223         return sysctl_write_ip_property(AF_INET6, link->ifname, "stable_secret", str);
224 }
225 
link_set_ipv6ll_addrgen_mode(Link * link,IPv6LinkLocalAddressGenMode mode)226 int link_set_ipv6ll_addrgen_mode(Link *link, IPv6LinkLocalAddressGenMode mode) {
227         assert(link);
228         assert(mode >= 0 && mode < _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX);
229 
230         if (mode == link->ipv6ll_address_gen_mode)
231                 return 0;
232 
233         return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "addr_gen_mode", mode);
234 }
235 
236 static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
237         [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64]          = "eui64",
238         [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE]           = "none",
239         [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
240         [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM]         = "random",
241 };
242 
243 DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
244 DEFINE_CONFIG_PARSE_ENUM(
245         config_parse_ipv6_link_local_address_gen_mode,
246         ipv6_link_local_address_gen_mode,
247         IPv6LinkLocalAddressGenMode,
248         "Failed to parse IPv6 link-local address generation mode");
249