</listitem>
</varlistentry>
<varlistentry>
- <term><option>prefixstable[:<replaceable>ADDRESS</replaceable>]</option></term>
+ <term><option>prefixstable[:<replaceable>ADDRESS</replaceable>][,<replaceable>UUID</replaceable>]</option></term>
<listitem>
<para>
The algorithm specified in
then an interface identifier is generated only when a prefix received in an RA
message matches the supplied address.
</para>
+ <para>
+ This mode can also optionally take a non-null UUID in the format which
+ <function>sd_id128_from_string()</function> accepts, e.g.
+ <literal>86b123b969ba4b7eb8b3d8605123525a</literal> or
+ <literal>86b123b9-69ba-4b7e-b8b3-d8605123525a</literal>. If a UUID is specified, the
+ value is used as the secret key to generate interface identifiers. If not specified,
+ then an application specific ID generated with the system's machine-ID will be used
+ as the secret key. See
+ <citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_id128_from_string</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ and
+ <citerefentry><refentrytitle>sd_id128_get_machine</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ </para>
<para>
Note that the <literal>prefixstable</literal> algorithm uses both the interface
name and MAC address as input to the hash to compute the interface identifier, so
#include "sd-id128.h"
+#include "id128-util.h"
#include "memory-util.h"
#include "networkd-address-generation.h"
#include "networkd-link.h"
typedef struct IPv6Token {
AddressGenerationType type;
struct in6_addr address;
+ sd_id128_t secret_key;
} IPv6Token;
static void generate_eui64_address(const Link *link, const struct in6_addr *prefix, struct in6_addr *ret) {
static int generate_stable_private_address(
Link *link,
const sd_id128_t *app_id,
+ const sd_id128_t *secret_key,
const struct in6_addr *prefix,
struct in6_addr *ret) {
+ sd_id128_t secret_machine_key;
struct in6_addr addr;
- sd_id128_t secret_key;
uint8_t i;
int r;
assert(link);
assert(app_id);
+ assert(secret_key);
assert(prefix);
assert(ret);
- r = sd_id128_get_machine_app_specific(*app_id, &secret_key);
- if (r < 0)
- return log_link_debug_errno(link, r, "Failed to generate secret key for IPv6 stable private address: %m");
+ if (sd_id128_is_null(*secret_key)) {
+ r = sd_id128_get_machine_app_specific(*app_id, &secret_machine_key);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to generate secret key for IPv6 stable private address: %m");
+
+ secret_key = &secret_machine_key;
+ }
/* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop does
* not actually attempt Duplicate Address Detection; the counter will be incremented only when
* the address generation algorithm produces an invalid address, and the loop may exit with an
* address which ends up being unusable due to duplication on the link. */
for (i = 0; i < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; i++) {
- generate_stable_private_address_one(link, &secret_key, prefix, i, &addr);
+ generate_stable_private_address_one(link, secret_key, prefix, i, &addr);
if (stable_private_address_is_valid(&addr))
break;
if (in6_addr_is_set(&j->address) && !in6_addr_equal(&j->address, &masked))
continue;
- if (generate_stable_private_address(link, app_id, &masked, &addr) < 0)
+ if (generate_stable_private_address(link, app_id, &j->secret_key, &masked, &addr) < 0)
continue;
break;
static void ipv6_token_hash_func(const IPv6Token *p, struct siphash *state) {
siphash24_compress(&p->type, sizeof(p->type), state);
siphash24_compress(&p->address, sizeof(p->address), state);
+ id128_hash_func(&p->secret_key, state);
}
static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) {
if (r != 0)
return r;
- return memcmp(&a->address, &b->address, sizeof(struct in6_addr));
+ r = memcmp(&a->address, &b->address, sizeof(struct in6_addr));
+ if (r != 0)
+ return r;
+
+ return id128_compare_func(&a->secret_key, &b->secret_key);
}
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
ipv6_token_compare_func,
free);
-static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct in6_addr *addr) {
+static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct in6_addr *addr, const sd_id128_t *secret_key) {
IPv6Token *p;
assert(tokens);
assert(type >= 0 && type < _ADDRESS_GENERATION_TYPE_MAX);
assert(addr);
+ assert(secret_key);
p = new(IPv6Token, 1);
if (!p)
*p = (IPv6Token) {
.type = type,
.address = *addr,
+ .secret_key = *secret_key,
};
return set_ensure_consume(tokens, &ipv6_token_hash_ops, p);
void *data,
void *userdata) {
+ _cleanup_free_ char *addr_alloc = NULL;
+ sd_id128_t secret_key = SD_ID128_NULL;
union in_addr_union buffer = {};
AddressGenerationType type;
Set **tokens = data;
- const char *p;
+ const char *addr;
int r;
assert(filename);
return 0;
}
- if ((p = startswith(rvalue, "prefixstable"))) {
+ if ((addr = startswith(rvalue, "prefixstable"))) {
+ const char *comma;
+
type = ADDRESS_GENERATION_PREFIXSTABLE;
- if (*p == ':')
- p++;
- else if (*p == '\0')
- p = NULL;
- else {
+ if (*addr == ':') {
+ addr++;
+
+ comma = strchr(addr, ',');
+ if (comma) {
+ addr_alloc = strndup(addr, comma - addr);
+ if (!addr_alloc)
+ return log_oom();
+
+ addr = addr_alloc;
+ }
+ } else if (*addr == ',') {
+ comma = addr;
+ addr = NULL;
+ } else if (*addr == '\0') {
+ comma = NULL;
+ addr = NULL;
+ } else {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid IPv6 token mode in %s=, ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
+ if (comma) {
+ r = sd_id128_from_string(comma + 1, &secret_key);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse secret key in %s=, ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+ if (sd_id128_is_null(secret_key)) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Secret key in %s= cannot be null, ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+ }
+
} else if (streq(rvalue, "eui64")) {
type = ADDRESS_GENERATION_EUI64;
- p = NULL;
+ addr = NULL;
} else {
type = ADDRESS_GENERATION_STATIC;
- p = startswith(rvalue, "static:");
- if (!p)
- p = rvalue;
+ addr = startswith(rvalue, "static:");
+ if (!addr)
+ addr = rvalue;
}
- if (p) {
- r = in_addr_from_string(AF_INET6, p, &buffer);
+ if (addr) {
+ r = in_addr_from_string(AF_INET6, addr, &buffer);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse IP address in %s=, ignoring assignment: %s",
assert_not_reached();
}
- r = ipv6_token_add(tokens, type, &buffer.in6);
+ r = ipv6_token_add(tokens, type, &buffer.in6, &secret_key);
if (r < 0)
return log_oom();