Merge pull request #21346 from yuwata/network-token-prefixstable
network: extend Token=prefixstable setting
This commit is contained in:
+219
-185
@@ -2185,219 +2185,253 @@ Table=1234</programlisting></para>
|
||||
|
||||
<refsect1>
|
||||
<title>[IPv6AcceptRA] Section Options</title>
|
||||
<para>The [IPv6AcceptRA] section configures the IPv6 Router Advertisement (RA) client, if it is enabled
|
||||
with the <varname>IPv6AcceptRA=</varname> setting described above:</para>
|
||||
<para>The [IPv6AcceptRA] section configures the IPv6 Router Advertisement (RA) client, if it is enabled
|
||||
with the <varname>IPv6AcceptRA=</varname> setting described above:</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>Token=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies an optional address generation mode for the Stateless Address
|
||||
Autoconfiguration (SLAAC). Supported modes are <literal>eui64</literal>,
|
||||
<literal>static</literal>, and <literal>prefixstable</literal>.</para>
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>Token=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies an optional address generation mode for the Stateless Address
|
||||
Autoconfiguration (SLAAC). The following values are supported:</para>
|
||||
|
||||
<para>When the mode is set to <literal>eui64</literal>, then the EUI-64 algorithm will be
|
||||
used to generate an address for that prefix.</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>eui64</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The EUI-64 algorithm will be used to generate an address for that prefix.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>static:<replaceable>ADDRESS</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
An IPv6 address must be specified after a colon (<literal>:</literal>), and the
|
||||
lower bits of the supplied address are combined with the upper bits of a prefix
|
||||
received in a Router Advertisement (RA) message to form a complete address. Note
|
||||
that if multiple prefixes are received in an RA message, or in multiple RA messages,
|
||||
addresses will be formed from each of them using the supplied address. This mode
|
||||
implements SLAAC but uses a static interface identifier instead of an identifier
|
||||
generated by using the EUI-64 algorithm. Because the interface identifier is static,
|
||||
if Duplicate Address Detection detects that the computed address is a duplicate
|
||||
(in use by another node on the link), then this mode will fail to provide an address
|
||||
for that prefix. If an IPv6 address without mode is specified, then
|
||||
<literal>static</literal> mode is assumed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>prefixstable[:<replaceable>ADDRESS</replaceable>][,<replaceable>UUID</replaceable>]</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The algorithm specified in
|
||||
<ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink> will be used to
|
||||
generate interface identifiers. This mode can optionally take an IPv6 address
|
||||
separated with a colon (<literal>:</literal>). If an IPv6 address is specified,
|
||||
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
|
||||
if either of those are changed the resulting interface identifier (and address)
|
||||
will be changed, even if the prefix received in the RA message has not been
|
||||
changed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>When the mode is set to <literal>static</literal>, an IPv6 address must be
|
||||
specified after a colon (<literal>:</literal>), and the lower bits of the supplied
|
||||
address are combined with the upper bits of a prefix received in a Router Advertisement
|
||||
(RA) message to form a complete address. Note that if multiple prefixes are received in an
|
||||
RA message, or in multiple RA messages, addresses will be formed from each of them using
|
||||
the supplied address. This mode implements SLAAC but uses a static interface identifier
|
||||
instead of an identifier generated by using the EUI-64 algorithm. Because the interface
|
||||
identifier is static, if Duplicate Address Detection detects that the computed address is a
|
||||
duplicate (in use by another node on the link), then this mode will fail to provide an
|
||||
address for that prefix. If an IPv6 address without mode is specified, then
|
||||
<literal>static</literal> mode is assumed.</para>
|
||||
<para>If no address generation mode is specified (which is the default), or a received
|
||||
prefix does not match any of the addresses provided in <literal>prefixstable</literal>
|
||||
mode, then the EUI-64 algorithm will be used to form an interface identifier for that
|
||||
prefix.</para>
|
||||
|
||||
<para>When the mode is set to <literal>prefixstable</literal> the
|
||||
<ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink> algorithm for generating
|
||||
interface identifiers will be used. This mode can optionally take an IPv6 address separated
|
||||
with a colon (<literal>:</literal>). If an IPv6 address is specified, then an interface
|
||||
identifier is generated only when a prefix received in an RA message matches the supplied
|
||||
address.</para>
|
||||
<para>This setting can be specified multiple times. If an empty string is assigned, then
|
||||
the all previous assignments are cleared.</para>
|
||||
|
||||
<para>If no address generation mode is specified (which is the default), or a received
|
||||
prefix does not match any of the addresses provided in <literal>prefixstable</literal>
|
||||
mode, then the EUI-64 algorithm will be used to form an interface identifier for that
|
||||
prefix.</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 if either
|
||||
of those are changed the resulting interface identifier (and address) will be changed, even
|
||||
if the prefix received in the RA message has not been changed.</para>
|
||||
|
||||
<para>This setting can be specified multiple times. If an empty string is assigned, then
|
||||
the all previous assignments are cleared.</para>
|
||||
|
||||
<para>Examples:
|
||||
<programlisting>Token=eui64
|
||||
<para>Examples:
|
||||
<programlisting>Token=eui64
|
||||
Token=::1a:2b:3c:4d
|
||||
Token=static:::1a:2b:3c:4d
|
||||
Token=prefixstable
|
||||
Token=prefixstable:2002:da8:1::</programlisting></para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>UseDNS=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the DNS servers received in the Router Advertisement will be used.</para>
|
||||
<varlistentry>
|
||||
<term><varname>UseDNS=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the DNS servers received in the Router Advertisement will be used.</para>
|
||||
|
||||
<para>This corresponds to the <option>nameserver</option> option in <citerefentry
|
||||
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<para>This corresponds to the <option>nameserver</option> option in <citerefentry
|
||||
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>UseDomains=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean, or the special value <literal>route</literal>. When true, the domain name
|
||||
received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link, similar to
|
||||
the effect of the <option>Domains=</option> setting. If set to <literal>route</literal>, the domain name
|
||||
received via IPv6 RA will be used for routing DNS queries only, but not for searching, similar to the
|
||||
effect of the <option>Domains=</option> setting when the argument is prefixed with
|
||||
<literal>~</literal>. Defaults to false.</para>
|
||||
<varlistentry>
|
||||
<term><varname>UseDomains=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean, or the special value <literal>route</literal>. When true, the domain name
|
||||
received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link, similar to
|
||||
the effect of the <option>Domains=</option> setting. If set to <literal>route</literal>, the domain name
|
||||
received via IPv6 RA will be used for routing DNS queries only, but not for searching, similar to the
|
||||
effect of the <option>Domains=</option> setting when the argument is prefixed with
|
||||
<literal>~</literal>. Defaults to false.</para>
|
||||
|
||||
<para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
|
||||
of all hostnames, in particular of single-label names. It is generally safer to use the supplied domain
|
||||
only as routing domain, rather than as search domain, in order to not have it affect local resolution of
|
||||
single-label names.</para>
|
||||
<para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
|
||||
of all hostnames, in particular of single-label names. It is generally safer to use the supplied domain
|
||||
only as routing domain, rather than as search domain, in order to not have it affect local resolution of
|
||||
single-label names.</para>
|
||||
|
||||
<para>When set to true, this setting corresponds to the <option>domain</option> option in <citerefentry
|
||||
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<para>When set to true, this setting corresponds to the <option>domain</option> option in <citerefentry
|
||||
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RouteTable=<replaceable>num</replaceable></varname></term>
|
||||
<listitem>
|
||||
<para>The table identifier for the routes received in the Router Advertisement
|
||||
(a number between 1 and 4294967295, or 0 to unset).
|
||||
The table can be retrieved using <command>ip route show table <replaceable>num</replaceable></command>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>RouteTable=<replaceable>num</replaceable></varname></term>
|
||||
<listitem>
|
||||
<para>The table identifier for the routes received in the Router Advertisement
|
||||
(a number between 1 and 4294967295, or 0 to unset).
|
||||
The table can be retrieved using <command>ip route show table <replaceable>num</replaceable></command>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RouteMetric=</varname></term>
|
||||
<listitem>
|
||||
<para>Set the routing metric for the routes received in the Router Advertisement. Takes an
|
||||
unsigned integer in the range 0…4294967295. Defaults to 1024.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>RouteMetric=</varname></term>
|
||||
<listitem>
|
||||
<para>Set the routing metric for the routes received in the Router Advertisement. Takes an
|
||||
unsigned integer in the range 0…4294967295. Defaults to 1024.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>UseMTU=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean. When true, the MTU received in the Router Advertisement will be
|
||||
used. Defaults to true.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>UseMTU=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean. When true, the MTU received in the Router Advertisement will be
|
||||
used. Defaults to true.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>UseGateway=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the router address will be configured as the default gateway.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>UseGateway=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the router address will be configured as the default gateway.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>UseRoutePrefix=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the routes corresponding to the route prefixes received in
|
||||
the Router Advertisement will be configured.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>UseRoutePrefix=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the routes corresponding to the route prefixes received in
|
||||
the Router Advertisement will be configured.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>UseAutonomousPrefix=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the autonomous prefix received in the Router Advertisement will be used and take
|
||||
precedence over any statically configured ones.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>UseAutonomousPrefix=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the autonomous prefix received in the Router Advertisement will be used and take
|
||||
precedence over any statically configured ones.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>UseOnLinkPrefix=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the onlink prefix received in the Router Advertisement will be
|
||||
used and takes precedence over any statically configured ones.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>UseOnLinkPrefix=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the onlink prefix received in the Router Advertisement will be
|
||||
used and takes precedence over any statically configured ones.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RouterDenyList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
|
||||
take a prefix length after <literal>/</literal>. Any information advertised by the listed
|
||||
router is ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>RouterDenyList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
|
||||
take a prefix length after <literal>/</literal>. Any information advertised by the listed
|
||||
router is ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RouterAllowList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
|
||||
take a prefix length after <literal>/</literal>. Only information advertised by the listed
|
||||
router is accepted. Note that if <varname>RouterAllowList=</varname> is configured then
|
||||
<varname>RouterDenyList=</varname> is ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>RouterAllowList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
|
||||
take a prefix length after <literal>/</literal>. Only information advertised by the listed
|
||||
router is accepted. Note that if <varname>RouterAllowList=</varname> is configured then
|
||||
<varname>RouterDenyList=</varname> is ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>PrefixDenyList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
|
||||
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
|
||||
in the list are ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>PrefixDenyList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
|
||||
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
|
||||
in the list are ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>PrefixAllowList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
|
||||
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
|
||||
in the list are allowed. Note that if <varname>PrefixAllowList=</varname> is configured
|
||||
then <varname>PrefixDenyList=</varname> is ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>PrefixAllowList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
|
||||
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
|
||||
in the list are allowed. Note that if <varname>PrefixAllowList=</varname> is configured
|
||||
then <varname>PrefixDenyList=</varname> is ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RouteDenyList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
|
||||
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
|
||||
advertisements in the list are ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>RouteDenyList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
|
||||
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
|
||||
advertisements in the list are ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RouteAllowList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
|
||||
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
|
||||
advertisements in the list are allowed. Note that if <varname>RouteAllowList=</varname> is
|
||||
configured then <varname>RouteDenyList=</varname> is ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>RouteAllowList=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
|
||||
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
|
||||
advertisements in the list are allowed. Note that if <varname>RouteAllowList=</varname> is
|
||||
configured then <varname>RouteDenyList=</varname> is ignored.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>DHCPv6Client=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean, or the special value <literal>always</literal>. When true, the
|
||||
DHCPv6 client will be started when the RA has the managed or other information flag. If set
|
||||
to <literal>always</literal>, the DHCPv6 client will be started in managed mode when an RA
|
||||
is received, even if neither managed nor other information flag is set in the RA. This will
|
||||
be ignored when <varname>WithoutRA=</varname> in the [DHCPv6] section is enabled, or
|
||||
<varname>UplinkInterface=:self</varname> in the [DHCPv6PrefixDelegation] section is
|
||||
specified. Defaults to true.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<varlistentry>
|
||||
<term><varname>DHCPv6Client=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean, or the special value <literal>always</literal>. When true, the
|
||||
DHCPv6 client will be started when the RA has the managed or other information flag. If set
|
||||
to <literal>always</literal>, the DHCPv6 client will be started in managed mode when an RA
|
||||
is received, even if neither managed nor other information flag is set in the RA. This will
|
||||
be ignored when <varname>WithoutRA=</varname> in the [DHCPv6] section is enabled, or
|
||||
<varname>UplinkInterface=:self</varname> in the [DHCPv6PrefixDelegation] section is
|
||||
specified. Defaults to true.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "id128-util.h"
|
||||
#include "memory-util.h"
|
||||
#include "networkd-address-generation.h"
|
||||
#include "networkd-link.h"
|
||||
@@ -35,6 +36,7 @@ typedef enum AddressGenerationType {
|
||||
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) {
|
||||
@@ -117,29 +119,35 @@ static void generate_stable_private_address_one(
|
||||
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;
|
||||
@@ -192,7 +200,7 @@ static int generate_addresses(
|
||||
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;
|
||||
@@ -244,6 +252,7 @@ int radv_generate_addresses(Link *link, Set *tokens, const struct in6_addr *pref
|
||||
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) {
|
||||
@@ -253,7 +262,11 @@ 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(
|
||||
@@ -263,12 +276,13 @@ 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)
|
||||
@@ -277,6 +291,7 @@ static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct
|
||||
*p = (IPv6Token) {
|
||||
.type = type,
|
||||
.address = *addr,
|
||||
.secret_key = *secret_key,
|
||||
};
|
||||
|
||||
return set_ensure_consume(tokens, &ipv6_token_hash_ops, p);
|
||||
@@ -294,10 +309,12 @@ int config_parse_address_generation_type(
|
||||
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);
|
||||
@@ -310,33 +327,64 @@ int config_parse_address_generation_type(
|
||||
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",
|
||||
@@ -371,7 +419,7 @@ int config_parse_address_generation_type(
|
||||
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();
|
||||
|
||||
|
||||
@@ -7,3 +7,4 @@ IPv6AcceptRA=true
|
||||
|
||||
[IPv6AcceptRA]
|
||||
Token=prefixstable
|
||||
Token=prefixstable,86b123b969ba4b7eb8b3d8605123525a
|
||||
|
||||
@@ -7,7 +7,12 @@ IPv6AcceptRA=true
|
||||
|
||||
[IPv6AcceptRA]
|
||||
Token=prefixstable:2002:da8:1::
|
||||
Token=prefixstable:2002:da8:1::,86b123b969ba4b7eb8b3d8605123525a
|
||||
# invalid tokens
|
||||
Token=prefixstable:2002:da8:1::,00000000000000000000000000000000
|
||||
Token=prefixstable:2002:da8:1::,
|
||||
Token=prefixstable,00000000000000000000000000000000
|
||||
Token=prefixstable,
|
||||
Token=prefixstable@
|
||||
Token=static
|
||||
Token=static:
|
||||
|
||||
@@ -3951,8 +3951,8 @@ class NetworkdRATests(unittest.TestCase, Utilities):
|
||||
|
||||
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
|
||||
print(output)
|
||||
self.assertRegex(output, '2002:da8:1:0')
|
||||
self.assertRegex(output, '2002:da8:2:0.*78:9abc') # EUI
|
||||
self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
|
||||
self.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc', output) # EUI64
|
||||
|
||||
def test_ipv6_token_prefixstable_without_address(self):
|
||||
copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
|
||||
@@ -3961,8 +3961,8 @@ class NetworkdRATests(unittest.TestCase, Utilities):
|
||||
|
||||
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
|
||||
print(output)
|
||||
self.assertRegex(output, '2002:da8:1:0')
|
||||
self.assertRegex(output, '2002:da8:2:0')
|
||||
self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
|
||||
self.assertIn('2002:da8:2:0:f689:561a:8eda:7443', output)
|
||||
|
||||
class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
|
||||
links = [
|
||||
|
||||
Reference in New Issue
Block a user