]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
We don't support DHCPv6 Reconfigure messages.
authorAlan T. DeKok <aland@freeradius.org>
Thu, 9 Jul 2026 15:14:33 +0000 (11:14 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 9 Jul 2026 15:34:16 +0000 (11:34 -0400)
Because (a) most clients don't support it, and (b) we still need
to write the code to handle the Auth option.  Which includes a
bunch of additional requirements about storing keys and replay
counters.

src/protocols/dhcpv6/attrs.h
src/protocols/dhcpv6/base.c
src/protocols/dhcpv6/decode.c
src/protocols/dhcpv6/encode.c
src/tests/unit/protocols/dhcpv6/rfc8415.txt

index 49311f658a703bbc4250bc71667cc5f4b0b17ad1..6082b728b1b17e266a03dc97ed0728414a308d48 100644 (file)
@@ -36,6 +36,7 @@ extern HIDDEN fr_dict_attr_t const *attr_hop_count;
 extern HIDDEN fr_dict_attr_t const *attr_relay_link_address;
 extern HIDDEN fr_dict_attr_t const *attr_relay_peer_address;
 extern HIDDEN fr_dict_attr_t const *attr_relay_message;
+extern HIDDEN fr_dict_attr_t const *attr_auth;
 
 /*
  *     A private function that is used only in base.c and encode.c
index 9165b1c7fef56813e73bb0bad3de9c49c1e77cf5..ca7d83c1b6ce4935a7490e577fa665c2bf20eb9b 100644 (file)
@@ -53,6 +53,7 @@ fr_dict_attr_t const *attr_relay_link_address;
 fr_dict_attr_t const *attr_relay_peer_address;
 fr_dict_attr_t const *attr_relay_message;
 fr_dict_attr_t const *attr_option_request;
+fr_dict_attr_t const *attr_auth;
 
 extern fr_dict_attr_autoload_t libfreeradius_dhcpv6_dict_attr[];
 fr_dict_attr_autoload_t libfreeradius_dhcpv6_dict_attr[] = {
@@ -63,6 +64,7 @@ fr_dict_attr_autoload_t libfreeradius_dhcpv6_dict_attr[] = {
        { .out = &attr_relay_peer_address, .name = "Relay-Peer-Address", .type = FR_TYPE_IPV6_ADDR, .dict = &dict_dhcpv6 },
        { .out = &attr_relay_message, .name = "Relay-Message", .type = FR_TYPE_GROUP, .dict = &dict_dhcpv6 },
        { .out = &attr_option_request, .name = "Option-Request", .type = FR_TYPE_ATTR, .dict = &dict_dhcpv6 },
+       { .out = &attr_auth, .name = "Auth", .type = FR_TYPE_STRUCT, .dict = &dict_dhcpv6 },
        DICT_AUTOLOAD_TERMINATOR
 };
 
@@ -348,6 +350,47 @@ static bool verify_to_client(uint8_t const *packet, size_t packet_len, fr_dhcpv6
                goto check_duid;
 
        case FR_PACKET_TYPE_VALUE_RECONFIGURE:
+#if 1
+               /*
+                *      See RFC 8415 Section 18 (option format), and Section 20 (functionality).
+                *
+                *      In order to support sending Reconfigure messages, we have to support the Auth option.
+                *      Except that common clients don't support it:
+                *
+                *      https://www.cisco.com/c/en/us/td/docs/routers/asr920/configuration/guide/ipaddr-dhcp/17-1-1/b-dhcp-xe-17-1-asr920/b-dhcp-xe-17-1-asr920_chapter_0101.html
+                *
+                *      "DHCPv6 Reconfigure message type is not be supported on the Cisco ASR920 Series routers."
+                *
+                *      So we don't support it, either.  The rest of the comments here are notes about what we
+                *      would need to do in order to support Reconfigure, and the Auth option.
+                *
+                *      If auth.type == 1, the contents of the attribute are just a reconfigure key, which is
+                *      sent over the network in the clear.  The server has to get the key from somewhere, OR
+                *      create it from a CSRNG and then store it.  The client just stores it somewhere.
+                *      Except that the key is sent over the network in the clear, which make is pretty much
+                *      useless for security.
+                *
+                *      If auth.type == 2, then we need to check the encode/decode context for a key, and if
+                *      not fail.
+                *
+                *      For encode, encode the structure and remember in the encode context where we encoded
+                *      it.  Then when we are finished encoding the entire packet, go back and do an HMAC-MD5
+                *      over the packet and update the auth.value field.
+                *
+                *      We also have to ignore any supplied auth.rdm and auth.replay-detection field, and then
+                *      force auth.rdm=0, and set auth.reply-detection to the current 64-bit NTP time.  The
+                *      replay-detection field is a monotonically increasing 64-bit value which is saved
+                *      across server restarts.  So an NTP time is the easiest way to manage that.
+                *
+                *      For decode, we have to check the reply-detection field, and fail if it's smaller than
+                *      what we expect.  Then, remember where the Auth option is in the packet, go back and do
+                *      an HMAC-MD5 over the packet.
+                *
+                *      See also references to attr_auth in encode.c and decode.c.
+                */
+               fr_strerror_const("Sending Reconfigure to a client is not supported");
+               return false;
+#else
                if (!fr_dhcpv6_option_find(options, end, FR_SERVER_ID)) goto fail_sid;
 
                option = fr_dhcpv6_option_find(options, end, FR_CLIENT_ID);
@@ -378,11 +421,12 @@ static bool verify_to_client(uint8_t const *packet, size_t packet_len, fr_dhcpv6
                        fr_strerror_const("Invalid Reconf-Msg option value");
                        return false;
                }
+
                /*
-                *      @todo - check for authentication option and
-                *      verify it.
+                *      @todo - Do an HMAC-MD5 of the Auth option.
                 */
                break;
+#endif
 
        case FR_DHCPV6_RELAY_REPLY:
                if (packet_len < DHCPV6_RELAY_HDR_LEN) {
index 1153050cb7bc43b17a0da5d589eae477bde19e93..3f36d72a808f5c031b763b004466c2da2a23614f 100644 (file)
@@ -393,6 +393,22 @@ static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out,
        } else if (da->type == FR_TYPE_TLV) {
                slen = fr_pair_tlvs_from_network(ctx, out, da, data + 4, len, decode_ctx, decode_option, NULL, true);
 
+       } else if (da == attr_auth) {
+               /*
+                *      See RFC 8415 Section 18 (option format), and Section 20 (functionality).
+                *
+                *      The Auth option can be sent from a server to client in a Reply message, and contains a
+                *      128-bit secret key that is recorded somewhere on the server side.
+                *
+                *      The Auth option can be sent from a server to a client in a Reconfigure message, and
+                *      contains an HMAC-MD5 of the packet and the secret key.
+                *
+                *      We are not currently a DHCPv6 client, so we do not support the Auth option, or
+                *      Reconfigure messages.  See verify_to_client() in base.c.
+                */
+               fr_strerror_const("The 'Auth' option is not supported");
+               return -1;
+
        } else {
                slen = decode_value(ctx, out, da, data + 4, len, decode_ctx);
        }
index ce22e2a466d7692422abd15123bf1530c6dfd36f..247c2d08f8019aa1ce12a879404537354fca98d4 100644 (file)
@@ -715,6 +715,25 @@ ssize_t fr_dhcpv6_encode_option(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *
                slen = encode_rfc(&work_dbuff, &da_stack, depth, cursor, encode_ctx);
                break;
 
+       case FR_TYPE_STRUCT:
+               /*
+                *      See RFC 8415 Section 18 (option format), and Section 20 (functionality).
+                *
+                *      The Auth option can be sent from a server to client in a Reply message, and contains a
+                *      128-bit secret key that is recorded somewhere on the server side.
+                *
+                *      The Auth option can be sent from a server to a client in a Reconfigure message, and
+                *      contains an HMAC-MD5 of the packet and the secret key.
+                *
+                *      We are not currently a DHCPv6 client, so we do not support the Auth option, or
+                *      Reconfigure messages.  See verify_to_client() in base.c.
+                */
+               if (da_stack.da[depth] == attr_auth) {
+                       fr_strerror_const("The 'Auth' option is not supported");
+                       return -1;
+               }
+               FALL_THROUGH;
+
        default:
                slen = encode_child(&work_dbuff, &da_stack, depth, cursor, encode_ctx);
                break;
index 9a70fa053e895b844f699d38e0a6151bd5d4154f..70dd8278f5690ae9e364d4c92860e50c1a65f8b4 100644 (file)
@@ -453,10 +453,10 @@ match Elapsed-Time = 45887
 #                               option-len field).
 #
 encode-pair Auth.Protocol = Reconfigure-Key, Auth.Algorithm = HMAC-MD5, Auth.Replay-Detection-Method = Monotonicly-Increasing-Value, Auth.Replay-Detection = 1234567890, Auth.Information = 0x010203040506070809101112131415
-match 00 0b 00 1a 03 01 00 00 00 00 00 49 96 02 d2 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
+match ERROR: The 'Auth' option is not supported
 
-decode-pair -
-match Auth = { Protocol = ::Reconfigure-Key, Algorithm = ::HMAC-MD5, Replay-Detection-Method = ::Monotonicly-Increasing-Value, Replay-Detection = 1234567890, Information = 0x010203040506070809101112131415 }
+decode-pair 00 0b 00 1a 03 01 00 00 00 00 00 49 96 02 d2 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
+match ERROR: The 'Auth' option is not supported
 
 #
 #  21.12.  Server Unicast Option