]> git.proxmox.com Git - systemd.git/blob - src/network/networkd-address-generation.c
New upstream version 250.4
[systemd.git] / src / network / networkd-address-generation.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <net/if_arp.h>
4
5 #include "sd-id128.h"
6
7 #include "arphrd-util.h"
8 #include "id128-util.h"
9 #include "memory-util.h"
10 #include "networkd-address-generation.h"
11 #include "networkd-link.h"
12 #include "networkd-network.h"
13 #include "string-util.h"
14
15 #define DAD_CONFLICTS_IDGEN_RETRIES_RFC7217 3
16
17 /* https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xml */
18 #define SUBNET_ROUTER_ANYCAST_ADDRESS ((const struct in6_addr) { .s6_addr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } })
19 #define SUBNET_ROUTER_ANYCAST_PREFIXLEN 64
20 #define RESERVED_INTERFACE_IDENTIFIERS_ADDRESS ((const struct in6_addr) { .s6_addr = { 0x02, 0x00, 0x5E, 0xFF, 0xFE } })
21 #define RESERVED_INTERFACE_IDENTIFIERS_PREFIXLEN 40
22 #define RESERVED_SUBNET_ANYCAST_ADDRESSES ((const struct in6_addr) { .s6_addr = { 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80 } })
23 #define RESERVED_SUBNET_ANYCAST_PREFIXLEN 57
24
25 #define DHCP_PD_APP_ID SD_ID128_MAKE(fb,b9,37,ca,4a,ed,4a,4d,b0,70,7f,aa,71,c0,c9,85)
26 #define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
27 #define RADV_APP_ID SD_ID128_MAKE(1f,1e,90,c8,5c,78,4f,dc,8e,61,2d,59,0d,53,c1,25)
28
29 typedef enum AddressGenerationType {
30 ADDRESS_GENERATION_EUI64,
31 ADDRESS_GENERATION_STATIC,
32 ADDRESS_GENERATION_PREFIXSTABLE,
33 _ADDRESS_GENERATION_TYPE_MAX,
34 _ADDRESS_GENERATION_TYPE_INVALID = -EINVAL,
35 } AddressGenerationType;
36
37 typedef struct IPv6Token {
38 AddressGenerationType type;
39 struct in6_addr address;
40 sd_id128_t secret_key;
41 } IPv6Token;
42
43 static int generate_eui64_address(const Link *link, const struct in6_addr *prefix, struct in6_addr *ret) {
44 assert(link);
45 assert(prefix);
46 assert(ret);
47
48 memcpy(ret->s6_addr, prefix, 8);
49
50 switch (link->iftype) {
51 case ARPHRD_INFINIBAND:
52 /* Use last 8 byte. See RFC4391 section 8 */
53 memcpy(&ret->s6_addr[8], &link->hw_addr.infiniband[INFINIBAND_ALEN - 8], 8);
54 break;
55 case ARPHRD_ETHER:
56 /* see RFC4291 section 2.5.1 */
57 ret->s6_addr[8] = link->hw_addr.ether.ether_addr_octet[0];
58 ret->s6_addr[9] = link->hw_addr.ether.ether_addr_octet[1];
59 ret->s6_addr[10] = link->hw_addr.ether.ether_addr_octet[2];
60 ret->s6_addr[11] = 0xff;
61 ret->s6_addr[12] = 0xfe;
62 ret->s6_addr[13] = link->hw_addr.ether.ether_addr_octet[3];
63 ret->s6_addr[14] = link->hw_addr.ether.ether_addr_octet[4];
64 ret->s6_addr[15] = link->hw_addr.ether.ether_addr_octet[5];
65 break;
66 default:
67 return log_link_debug_errno(link, SYNTHETIC_ERRNO(EINVAL),
68 "Token=eui64 is not supported for interface type %s, ignoring.",
69 strna(arphrd_to_name(link->iftype)));
70 }
71
72 ret->s6_addr[8] ^= 1 << 1;
73 return 0;
74 }
75
76 static bool stable_private_address_is_valid(const struct in6_addr *addr) {
77 assert(addr);
78
79 /* According to rfc4291, generated address should not be in the following ranges. */
80
81 if (in6_addr_prefix_covers(&SUBNET_ROUTER_ANYCAST_ADDRESS, SUBNET_ROUTER_ANYCAST_PREFIXLEN, addr))
82 return false;
83
84 if (in6_addr_prefix_covers(&RESERVED_INTERFACE_IDENTIFIERS_ADDRESS, RESERVED_INTERFACE_IDENTIFIERS_PREFIXLEN, addr))
85 return false;
86
87 if (in6_addr_prefix_covers(&RESERVED_SUBNET_ANYCAST_ADDRESSES, RESERVED_SUBNET_ANYCAST_PREFIXLEN, addr))
88 return false;
89
90 return true;
91 }
92
93 static void generate_stable_private_address_one(
94 Link *link,
95 const sd_id128_t *secret_key,
96 const struct in6_addr *prefix,
97 uint8_t dad_counter,
98 struct in6_addr *ret) {
99
100 struct siphash state;
101 uint64_t rid;
102
103 assert(link);
104 assert(secret_key);
105 assert(prefix);
106 assert(ret);
107
108 /* According to RFC7217 section 5.1
109 * RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) */
110
111 siphash24_init(&state, secret_key->bytes);
112
113 siphash24_compress(prefix, 8, &state);
114 siphash24_compress_string(link->ifname, &state);
115 if (link->iftype == ARPHRD_INFINIBAND)
116 /* Only last 8 bytes of IB MAC are stable */
117 siphash24_compress(&link->hw_addr.infiniband[INFINIBAND_ALEN - 8], 8, &state);
118 else
119 siphash24_compress(link->hw_addr.bytes, link->hw_addr.length, &state);
120 siphash24_compress(&dad_counter, sizeof(uint8_t), &state);
121
122 rid = htole64(siphash24_finalize(&state));
123
124 memcpy(ret->s6_addr, prefix->s6_addr, 8);
125 memcpy(ret->s6_addr + 8, &rid, 8);
126 }
127
128 static int generate_stable_private_address(
129 Link *link,
130 const sd_id128_t *app_id,
131 const sd_id128_t *secret_key,
132 const struct in6_addr *prefix,
133 struct in6_addr *ret) {
134
135 sd_id128_t secret_machine_key;
136 struct in6_addr addr;
137 uint8_t i;
138 int r;
139
140 assert(link);
141 assert(app_id);
142 assert(secret_key);
143 assert(prefix);
144 assert(ret);
145
146 if (sd_id128_is_null(*secret_key)) {
147 r = sd_id128_get_machine_app_specific(*app_id, &secret_machine_key);
148 if (r < 0)
149 return log_link_debug_errno(link, r, "Failed to generate secret key for IPv6 stable private address: %m");
150
151 secret_key = &secret_machine_key;
152 }
153
154 /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop does
155 * not actually attempt Duplicate Address Detection; the counter will be incremented only when
156 * the address generation algorithm produces an invalid address, and the loop may exit with an
157 * address which ends up being unusable due to duplication on the link. */
158 for (i = 0; i < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; i++) {
159 generate_stable_private_address_one(link, secret_key, prefix, i, &addr);
160
161 if (stable_private_address_is_valid(&addr))
162 break;
163 }
164 if (i >= DAD_CONFLICTS_IDGEN_RETRIES_RFC7217)
165 /* propagate recognizable errors. */
166 return log_link_debug_errno(link, SYNTHETIC_ERRNO(ENOANO),
167 "Failed to generate stable private address.");
168
169 *ret = addr;
170 return 0;
171 }
172
173 static int generate_addresses(
174 Link *link,
175 Set *tokens,
176 const sd_id128_t *app_id,
177 const struct in6_addr *prefix,
178 uint8_t prefixlen,
179 Set **ret) {
180
181 _cleanup_set_free_ Set *addresses = NULL;
182 struct in6_addr masked;
183 IPv6Token *j;
184 int r;
185
186 assert(link);
187 assert(app_id);
188 assert(prefix);
189 assert(prefixlen > 0 && prefixlen <= 64);
190 assert(ret);
191
192 masked = *prefix;
193 in6_addr_mask(&masked, prefixlen);
194
195 SET_FOREACH(j, tokens) {
196 struct in6_addr addr, *copy;
197
198 switch (j->type) {
199 case ADDRESS_GENERATION_EUI64:
200 if (generate_eui64_address(link, &masked, &addr) < 0)
201 continue;
202 break;
203
204 case ADDRESS_GENERATION_STATIC:
205 memcpy(addr.s6_addr, masked.s6_addr, 8);
206 memcpy(addr.s6_addr + 8, j->address.s6_addr + 8, 8);
207 break;
208
209 case ADDRESS_GENERATION_PREFIXSTABLE:
210 if (in6_addr_is_set(&j->address) && !in6_addr_equal(&j->address, &masked))
211 continue;
212
213 if (generate_stable_private_address(link, app_id, &j->secret_key, &masked, &addr) < 0)
214 continue;
215
216 break;
217
218 default:
219 assert_not_reached();
220 }
221
222 copy = newdup(struct in6_addr, &addr, 1);
223 if (!copy)
224 return -ENOMEM;
225
226 r = set_ensure_consume(&addresses, &in6_addr_hash_ops_free, copy);
227 if (r < 0)
228 return r;
229 }
230
231 /* fall back to EUI-64 if no token is provided */
232 if (set_isempty(addresses)) {
233 _cleanup_free_ struct in6_addr *addr = NULL;
234
235 addr = new(struct in6_addr, 1);
236 if (!addr)
237 return -ENOMEM;
238
239 if (IN_SET(link->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
240 r = generate_eui64_address(link, &masked, addr);
241 else
242 r = generate_stable_private_address(link, app_id, &SD_ID128_NULL, &masked, addr);
243 if (r < 0)
244 return r;
245
246 r = set_ensure_consume(&addresses, &in6_addr_hash_ops_free, TAKE_PTR(addr));
247 if (r < 0)
248 return r;
249 }
250
251 *ret = TAKE_PTR(addresses);
252 return 0;
253 }
254
255 int dhcp_pd_generate_addresses(Link *link, const struct in6_addr *prefix, Set **ret) {
256 return generate_addresses(link, link->network->dhcp_pd_tokens, &DHCP_PD_APP_ID, prefix, 64, ret);
257 }
258
259 int ndisc_generate_addresses(Link *link, const struct in6_addr *prefix, uint8_t prefixlen, Set **ret) {
260 return generate_addresses(link, link->network->ndisc_tokens, &NDISC_APP_ID, prefix, prefixlen, ret);
261 }
262
263 int radv_generate_addresses(Link *link, Set *tokens, const struct in6_addr *prefix, uint8_t prefixlen, Set **ret) {
264 return generate_addresses(link, tokens, &RADV_APP_ID, prefix, prefixlen, ret);
265 }
266
267 static void ipv6_token_hash_func(const IPv6Token *p, struct siphash *state) {
268 siphash24_compress(&p->type, sizeof(p->type), state);
269 siphash24_compress(&p->address, sizeof(p->address), state);
270 id128_hash_func(&p->secret_key, state);
271 }
272
273 static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) {
274 int r;
275
276 r = CMP(a->type, b->type);
277 if (r != 0)
278 return r;
279
280 r = memcmp(&a->address, &b->address, sizeof(struct in6_addr));
281 if (r != 0)
282 return r;
283
284 return id128_compare_func(&a->secret_key, &b->secret_key);
285 }
286
287 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
288 ipv6_token_hash_ops,
289 IPv6Token,
290 ipv6_token_hash_func,
291 ipv6_token_compare_func,
292 free);
293
294 static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct in6_addr *addr, const sd_id128_t *secret_key) {
295 IPv6Token *p;
296
297 assert(tokens);
298 assert(type >= 0 && type < _ADDRESS_GENERATION_TYPE_MAX);
299 assert(addr);
300 assert(secret_key);
301
302 p = new(IPv6Token, 1);
303 if (!p)
304 return -ENOMEM;
305
306 *p = (IPv6Token) {
307 .type = type,
308 .address = *addr,
309 .secret_key = *secret_key,
310 };
311
312 return set_ensure_consume(tokens, &ipv6_token_hash_ops, p);
313 }
314
315 int config_parse_address_generation_type(
316 const char *unit,
317 const char *filename,
318 unsigned line,
319 const char *section,
320 unsigned section_line,
321 const char *lvalue,
322 int ltype,
323 const char *rvalue,
324 void *data,
325 void *userdata) {
326
327 _cleanup_free_ char *addr_alloc = NULL;
328 sd_id128_t secret_key = SD_ID128_NULL;
329 union in_addr_union buffer = {};
330 AddressGenerationType type;
331 Set **tokens = data;
332 const char *addr;
333 int r;
334
335 assert(filename);
336 assert(lvalue);
337 assert(rvalue);
338 assert(data);
339
340 if (isempty(rvalue)) {
341 *tokens = set_free(*tokens);
342 return 0;
343 }
344
345 if ((addr = startswith(rvalue, "prefixstable"))) {
346 const char *comma;
347
348 type = ADDRESS_GENERATION_PREFIXSTABLE;
349
350 if (*addr == ':') {
351 addr++;
352
353 comma = strchr(addr, ',');
354 if (comma) {
355 addr_alloc = strndup(addr, comma - addr);
356 if (!addr_alloc)
357 return log_oom();
358
359 addr = addr_alloc;
360 }
361 } else if (*addr == ',')
362 comma = TAKE_PTR(addr);
363 else if (*addr == '\0') {
364 comma = NULL;
365 addr = NULL;
366 } else {
367 log_syntax(unit, LOG_WARNING, filename, line, 0,
368 "Invalid IPv6 token mode in %s=, ignoring assignment: %s",
369 lvalue, rvalue);
370 return 0;
371 }
372
373 if (comma) {
374 r = sd_id128_from_string(comma + 1, &secret_key);
375 if (r < 0) {
376 log_syntax(unit, LOG_WARNING, filename, line, r,
377 "Failed to parse secret key in %s=, ignoring assignment: %s",
378 lvalue, rvalue);
379 return 0;
380 }
381 if (sd_id128_is_null(secret_key)) {
382 log_syntax(unit, LOG_WARNING, filename, line, 0,
383 "Secret key in %s= cannot be null, ignoring assignment: %s",
384 lvalue, rvalue);
385 return 0;
386 }
387 }
388
389 } else if (streq(rvalue, "eui64")) {
390 type = ADDRESS_GENERATION_EUI64;
391 addr = NULL;
392 } else {
393 type = ADDRESS_GENERATION_STATIC;
394
395 addr = startswith(rvalue, "static:");
396 if (!addr)
397 addr = rvalue;
398 }
399
400 if (addr) {
401 r = in_addr_from_string(AF_INET6, addr, &buffer);
402 if (r < 0) {
403 log_syntax(unit, LOG_WARNING, filename, line, r,
404 "Failed to parse IP address in %s=, ignoring assignment: %s",
405 lvalue, rvalue);
406 return 0;
407 }
408 }
409
410 switch (type) {
411 case ADDRESS_GENERATION_EUI64:
412 assert(in6_addr_is_null(&buffer.in6));
413 break;
414
415 case ADDRESS_GENERATION_STATIC:
416 /* Only last 64 bits are used. */
417 memzero(buffer.in6.s6_addr, 8);
418
419 if (in6_addr_is_null(&buffer.in6)) {
420 log_syntax(unit, LOG_WARNING, filename, line, 0,
421 "IPv6 address in %s= cannot be the ANY address, ignoring assignment: %s",
422 lvalue, rvalue);
423 return 0;
424 }
425 break;
426
427 case ADDRESS_GENERATION_PREFIXSTABLE:
428 /* At most, the initial 64 bits are used. */
429 (void) in6_addr_mask(&buffer.in6, 64);
430 break;
431
432 default:
433 assert_not_reached();
434 }
435
436 r = ipv6_token_add(tokens, type, &buffer.in6, &secret_key);
437 if (r < 0)
438 return log_oom();
439
440 return 0;
441 }