network: introduce IPv6StableSecretAddress= setting

Previously, IPv6LinkLocalAddressGenerationMode= is not set, then we
define the address generation mode based on the result of reading
stable_secret sysctl value. This makes the mode is determined by whether
a secret address is specified in the new setting.

Closes #19622.
This commit is contained in:
Yu Watanabe 2021-06-08 06:21:57 +09:00
parent 7ff9d99e9e
commit 9e1432d5cc
7 changed files with 81 additions and 19 deletions

View file

@ -424,13 +424,27 @@
<listitem>
<para>Specifies how IPv6 link local address is generated. Takes one of
<literal>eui64</literal>, <literal>none</literal>, <literal>stable-privacy</literal> and
<literal>random</literal>. When unset, the kernel's default will be used. Note that if
<varname>LinkLocalAddressing=</varname> is <literal>no</literal> or
<literal>ipv4</literal>, then <varname>IPv6LinkLocalAddressGenerationMode=</varname> will
be ignored. Also, even if <varname>LinkLocalAddressing=</varname> is <literal>yes</literal>
or <literal>ipv6</literal>, setting
<varname>IPv6LinkLocalAddressGenerationMode=none</varname> disables to configure an IPv6
link-local address.</para>
<literal>random</literal>. When unset, <literal>stable-privacy</literal> is used if
<varname>IPv6StableSecretAddress=</varname> is specified, and if not,
<literal>eui64</literal> is used. Note that if <varname>LinkLocalAddressing=</varname> is
<literal>no</literal> or <literal>ipv4</literal>, then
<varname>IPv6LinkLocalAddressGenerationMode=</varname> will be ignored. Also, even if
<varname>LinkLocalAddressing=</varname> is <literal>yes</literal> or
<literal>ipv6</literal>, setting <varname>IPv6LinkLocalAddressGenerationMode=none</varname>
disables to configure an IPv6 link-local address.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>IPv6StableSecretAddress=</varname></term>
<listitem>
<para>Takes an IPv6 address. The specified address will be used as a stable secret for
generating IPv6 link-local address. If this setting is specified, and
<varname>IPv6LinkLocalAddressGenerationMode=</varname> is unset, then
<varname>IPv6LinkLocalAddressGenerationMode=stable-privacy</varname> is implied.
If this setting is not specified, and <literal>stable-privacy</literal> is set to
<varname>IPv6LinkLocalAddressGenerationMode=</varname>,
then a stable secret address will be generated from the local machine ID and the interface
name.</para>
</listitem>
</varlistentry>
<varlistentry>

View file

@ -97,6 +97,7 @@ Network.DHCP, config_parse_dhcp,
Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server)
Network.LinkLocalAddressing, config_parse_link_local_address_family, 0, offsetof(Network, link_local)
Network.IPv6LinkLocalAddressGenerationMode, config_parse_ipv6_link_local_address_gen_mode, 0, offsetof(Network, ipv6ll_address_gen_mode)
Network.IPv6StableSecretAddress, config_parse_in_addr_non_null, AF_INET6, offsetof(Network, ipv6ll_stable_secret)
Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
Network.DefaultRouteOnDevice, config_parse_bool, 0, offsetof(Network, default_route_on_device)
Network.IPv6Token, config_parse_address_generation_type, 0, 0

View file

@ -175,6 +175,10 @@ int network_verify(Network *network) {
if (network->ipv6ll_address_gen_mode == IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE)
SET_FLAG(network->link_local, ADDRESS_FAMILY_IPV6, false);
if (in6_addr_is_set(&network->ipv6ll_stable_secret) &&
network->ipv6ll_address_gen_mode < 0)
network->ipv6ll_address_gen_mode = IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY;
/* IPMasquerade implies IPForward */
network->ip_forward |= network->ip_masquerade;

View file

@ -209,6 +209,7 @@ struct Network {
/* link local addressing support */
AddressFamily link_local;
IPv6LinkLocalAddressGenMode ipv6ll_address_gen_mode;
struct in6_addr ipv6ll_stable_secret;
bool ipv4ll_route;
/* IPv6 RA support */

View file

@ -545,18 +545,10 @@ int link_request_to_set_addrgen_mode(Link *link) {
mode = IN6_ADDR_GEN_MODE_NONE;
else if (link->network->ipv6ll_address_gen_mode >= 0)
mode = link->network->ipv6ll_address_gen_mode;
else {
r = sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL);
if (r < 0) {
/* The file may not exist. And even if it exists, when stable_secret is unset,
* reading the file fails with ENOMEM when read_full_virtual_file(), which uses
* read() as the backend, and EIO when read_one_line_file() which uses fgetc(). */
log_link_debug_errno(link, r, "Failed to read sysctl property stable_secret, ignoring: %m");
mode = IN6_ADDR_GEN_MODE_EUI64;
} else
mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
}
else if (in6_addr_is_set(&link->network->ipv6ll_stable_secret))
mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
else
mode = IN6_ADDR_GEN_MODE_EUI64;
r = link_request_set_link(link, SET_LINK_ADDRESS_GENERATION_MODE, link_set_addrgen_mode_handler, &req);
if (r < 0)

View file

@ -11,6 +11,9 @@
#include "string-table.h"
#include "sysctl-util.h"
#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)
#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)
static int link_update_ipv6_sysctl(Link *link) {
assert(link);
@ -202,6 +205,48 @@ int link_set_ipv6_mtu(Link *link) {
return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu);
}
static int link_set_ipv6ll_stable_secret(Link *link) {
_cleanup_free_ char *str = NULL;
struct in6_addr a;
int r;
assert(link);
assert(link->network);
if (link->network->ipv6ll_address_gen_mode != IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY)
return 0;
if (in6_addr_is_set(&link->network->ipv6ll_stable_secret))
a = link->network->ipv6ll_stable_secret;
else {
sd_id128_t key;
le64_t v;
/* Generate a stable secret address from machine-ID and the interface name. */
r = sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_1, &key);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to generate key: %m");
v = htole64(siphash24_string(link->ifname, key.bytes));
memcpy(a.s6_addr, &v, sizeof(v));
r = sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_2, &key);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to generate key: %m");
v = htole64(siphash24_string(link->ifname, key.bytes));
assert_cc(sizeof(v) * 2 == sizeof(a.s6_addr));
memcpy(a.s6_addr + sizeof(v), &v, sizeof(v));
}
r = in6_addr_to_string(&a, &str);
if (r < 0)
return r;
return sysctl_write_ip_property(AF_INET6, link->ifname, "stable_secret", str);
}
static int link_set_ipv4_accept_local(Link *link) {
assert(link);
@ -273,6 +318,10 @@ int link_set_sysctl(Link *link) {
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv6 MTU, ignoring: %m");
r = link_set_ipv6ll_stable_secret(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot set stable secret address for IPv6 link local address: %m");
r = link_set_ipv4_accept_local(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");

View file

@ -222,6 +222,7 @@ L2TP=
MACsec=
LinkLocalAddressing=
IPv6LinkLocalAddressGenerationMode=
IPv6StableSecretAddress=
ConfigureWithoutCarrier=
NTP=
DHCP=