]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: introduce IPv6StableSecretAddress= setting
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 7 Jun 2021 21:21:57 +0000 (06:21 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 8 Jun 2021 19:56:48 +0000 (04:56 +0900)
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.

man/systemd.network.xml
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-setlink.c
src/network/networkd-sysctl.c
test/fuzz/fuzz-network-parser/directives.network

index 020a5ffb721de4e833014ecfcc3aa663f088bed9..8a6211429df9846b53880af5ffc94e63ee38b1cb 100644 (file)
           <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>
index c1ee05a043c56b94c8398f10f5951a9d1ddb85a0..86010121236a73a98e1caa192ba57a6b16333683 100644 (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
index 4e4ae7b76be037afa2c9bc4dd7ffd08fc694756e..011cb944625ee9e4a076d1dbf773b5d1ba7d6de3 100644 (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;
 
index ce030d2661e51bbc08966decea6b0918b4c83988..341cf477ceccb82faaa2ec20923e6dd7bc9d2030 100644 (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 */
index e9269d36ef602acc644446a2fe32aac7a9c522de..1a16871b75d22c3236a1e75a305e4a5f9a08ead4 100644 (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)
index ee5fe5f93dbae642cf18a2291162882630852a4d..e3e2c0c7a15bb5938abe90e2cc266704c6972b68 100644 (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");
index 195ed8f0cc8d13591076436fafc571e8e298dfd6..f1305a04b2bdaeb2ab77831558afb2554f98be95 100644 (file)
@@ -222,6 +222,7 @@ L2TP=
 MACsec=
 LinkLocalAddressing=
 IPv6LinkLocalAddressGenerationMode=
+IPv6StableSecretAddress=
 ConfigureWithoutCarrier=
 NTP=
 DHCP=