[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <7a400e64-1170-4995-8989-138a01e4e294@uliege.be>
Date: Sat, 22 Nov 2025 11:07:25 +0100
From: Justin Iurman <justin.iurman@...ege.be>
To: Tom Herbert <tom@...bertland.com>
Cc: davem@...emloft.net, kuba@...nel.org, netdev@...r.kernel.org,
justin.iurman@...ege.be
Subject: Re: [RFC net-next 2/3] ipv6: Disable IPv6 Destination Options RX
processing by default
On 11/22/25 10:53, Justin Iurman wrote:
> On 11/21/25 22:23, Tom Herbert wrote:
>> On Thu, Nov 13, 2025 at 5:17 AM Justin Iurman
>> <justin.iurman@...ege.be> wrote:
>>>
>>> On 11/12/25 01:16, Tom Herbert wrote:
>>>> Set IP6_DEFAULT_MAX_HBH_OPTS_CNT to zero. This disables
>>>
>>> s/IP6_DEFAULT_MAX_HBH_OPTS_CNT/IP6_DEFAULT_MAX_DST_OPTS_CNT
>>>
>>>> processing of Destinations Options extension headers by default.
>>>> Processing can be enabled by setting the net.ipv6.max_dst_opts_number
>>>> to a non-zero value.
>>>>
>>>> The rationale for this is that Destination Options pose a serious risk
>>>> of Denial off Service attack. The problem is that even if the
>>>> default limit is set to a small number (previously it was eight) there
>>>> is still the possibility of a DoS attack. All an attacker needs to do
>>>> is create and MTU size packet filled with 8 bytes Destination Options
>>>> Extension Headers. Each Destination EH simply contains a single
>>>> padding option with six bytes of zeroes.
>>>>
>>>> In a 1500 byte MTU size packet, 182 of these dummy Destination
>>>> Options headers can be placed in a packet. Per RFC8200, a host must
>>>> accept and process a packet with any number of Destination Options
>>>> extension headers. So when the stack processes such a packet it is
>>>> a lot of work and CPU cycles that provide zero benefit. The packet
>>>> can be designed such that every byte after the IP header requires
>>>> a conditional check and branch prediction can be rendered useless
>>>> for that. This also may mean over twenty cache misses per packet.
>>>> In other words, these packets filled with dummy Destination Options
>>>> extension headers are the basis for what would be an effective DoS
>>>> attack.
>>>
>>> How about a new document to update RFC8200 Sec. 4.1.? Maybe we can get
>>> 6man consensus to enforce only one occurrence (vs. 2 for the Dest) for
>>> each extension header. Let alone the recommended order (without
>>> normative language), we could...
>>
>> Hi Justin,
>
> Hi Tom,
>
>> It's a nice idea, but given the turnaround times for the IETF process
>
> Indeed, but I think we'll need that at some point. I'll craft something
> and send it to 6man to get feedback.
>
>> it would take years. Also to implement that in the stack isn't
>
> I don't think it would be difficult thanks to struct inet6_skb_parm that
> is stored in the control buffer of skb's. We already have some flags
> that are set, and offsets defined.
>
>> particularly trivial. Avoiding the potential DoS attack is the higher
>> priority problem IMO, and disabling DestOpts by default will have
>> little impact since almost no one is using them..
>
> Agree, but both issues are linked. If we don't explicitly limit (funny,
> in this case, I'd be OK to use that term ;-) the number of Destination
> Options header to 2 (as it should be), then the attack surface increases.
>
>>>
>>> OLD:
>>> Each extension header should occur at most once, except for the
>>> Destination Options header, which should occur at most twice (once
>>> before a Routing header and once before the upper-layer header).
>>>
>>> NEW:
>>> Each extension header MUST occur at most once, except for the
>>> Destination Options header, which MUST occur at most twice (once
>>> before a Routing header and once before the upper-layer header).
>>>
>>> ...and...
>>>
>>> OLD:
>>> IPv6 nodes must accept and attempt to process extension headers in
>>> any order and occurring any number of times in the same packet,
>>> except for the Hop-by-Hop Options header, which is restricted to
>>> appear immediately after an IPv6 header only. Nonetheless, it is
>>> strongly advised that sources of IPv6 packets adhere to the above
>>> recommended order until and unless subsequent specifications revise
>>> that recommendation.
>>>
>>> NEW:
>>> IPv6 nodes must accept and attempt to process extension headers in
>>> any order in the same packet,
>>> except for the Hop-by-Hop Options header, which is restricted to
>>> appear immediately after an IPv6 header only. Nonetheless, it is
>>> strongly advised that sources of IPv6 packets adhere to the above
>>> recommended order until and unless subsequent specifications revise
>>> that recommendation.
>>>
>>>> Disabling Destination Options is not a major issue for the following
>>>> reasons:
>>>>
>>>> * Linux kernel only supports one Destination Option (Home Address
>>>> Option). There is no evidence this has seen any real world use
>>>
>>> IMO, this is precisely the one designed for such real world end-to-end
>>> use cases (e.g., PDM [RFC8250] and PDMv2 [draft-ietf-ippm-encrypted-
>>> pdmv2]).
>>
>> Sure, but where is the Linux implementation? Deployment?
>
> Maybe they'll send it upstream one day, who knows.
>
>>>
>>>> * On the Internet packets with Destination Options are dropped with
>>>> a high enough rate such that use of Destination Options is not
>>>> feasible
>>>
>>> I wouldn't say that a 10-20% drop is *that* bad (i.e., "not feasible")
>>> for sizes < 64 bytes. But anyway...
>>
>> The drop rates for Destination Options vary by size of the extension
>> header. AP NIC data shows that 32 bytes options have about a 30% drop
>> rate, 64 byte options have about a 40% drop rate, but 128 byte options
>> have over 80% drop rate. The drops are coming from routers and not
>> hosts, Linux has no problem with different sizes. As you know from the
>> 6man list discussions, I proposed a minimum level of support that
>> routers must forward packets with up to 64 bytes of extension headers,
>> but that draft was rejected because of concerns that it would ossify
>> an already ossified protocol :-(. Even if a 40% drop rate isn't "that
>> bad" the 80% drop rate of 128 bytes EH would seem to qualify as "bad".
>> In any case, no one in IETF has offered an alternative plan to address
>> the high loss rates and without a solution I believe it's fair to say
>> that use of Destination Options is not feasible.
>
> The difference with APNIC's measurements lies in the fact that they
> reach end-users located behind ISPs, where EHs are heavily filtered. So
> their measurements are worst case scenarios (not saying they are not
> representative, just that it's a different location in networks). This
> becomes "less" problematic (don't get me wrong, there are still EH
> filters) if you remain at the core/edge (e.g., cloud providers, etc).
>
>>>
>>>> * It is unknown however quite possible that no one anywhere is using
>>>> Destination Options for anything but experiments, class projects,
>>>> or DoS. If someone is using them in their private network
>>>> thenthatit
>>>> it's easy enough to configure a non-zero limit for their use case
>>>> ---
>>>> include/net/ipv6.h | 7 +++++--
>>>> 1 file changed, 5 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
>>>> index 74fbf1ad8065..723a254c0b90 100644
>>>> --- a/include/net/ipv6.h
>>>> +++ b/include/net/ipv6.h
>>>> @@ -86,8 +86,11 @@ struct ip_tunnel_info;
>>>> * silently discarded.
>>>> */
>>>>
>>>> -/* Default limits for Hop-by-Hop and Destination options */
>>>> -#define IP6_DEFAULT_MAX_DST_OPTS_CNT 8
>>>> +/* Default limits for Hop-by-Hop and Destination options. By default
>>>> + * packets received with Destination Options headers are dropped to
>>>> thwart
>>>> + * Denial of Service attacks (see sysctl documention)
>>>> + */
>>>> +#define IP6_DEFAULT_MAX_DST_OPTS_CNT 0
>>>> #define IP6_DEFAULT_MAX_HBH_OPTS_CNT 8
>>>> #define IP6_DEFAULT_MAX_DST_OPTS_LEN INT_MAX /* No limit */
>>>> #define IP6_DEFAULT_MAX_HBH_OPTS_LEN INT_MAX /* No limit */
>>>
>>> I'd rather prefer to update RFC8200 and enforce a maximum of 2
>>> occurrences for the Dest, and keep the default limit of 8 options.
>>>
>>> Also, regardless of what we do here (and this remark also applies to the
>>> Hop-by-Hop), I think it's reasonable for a *host* to drop packets with a
>>> number of Hbh or Dest options that exceeds the configured limit.
>>> However, for a router (i.e., forwarding mode), I'd prefer to skip the EH
>>> chain rather than drop packets (for obvious reasons).
>>
>> I considered that, but there is a problem in that when we process HBH
>> options we don't know if we're a host (i.e. the final destination) or
>> a router (i.e. the packet will be forwarded). I would prefer to keep
>
> Correct. We may consider calling ip6_route_input() earlier (this is what
> IOAM does already), for example before calling ipv6_parse_hopopts() in
> ip6_rcv_core(), instead of doing it in ip6_rcv_finish_core(). Otherwise,
> we'd need to rely on ipv6_chk_addr_ret(). Maybe something like (not
> tested):
>
> diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
> index a23eb8734e15..0351b7fc58ee 100644
> --- a/net/ipv6/exthdrs.c
> +++ b/net/ipv6/exthdrs.c
> @@ -119,6 +119,7 @@ static bool ip6_parse_tlv(bool hopbyhop,
> const unsigned char *nh = skb_network_header(skb);
> int off = skb_network_header_len(skb);
> bool disallow_unknowns = false;
> + int ipv6_chk_addr_ret = -1;
> int tlv_count = 0;
> int padlen = 0;
>
> @@ -166,8 +167,30 @@ static bool ip6_parse_tlv(bool hopbyhop,
> }
> } else {
> tlv_count++;
> - if (tlv_count > max_count)
> - goto bad;
> + if (tlv_count > max_count) {
> + /* Drop a Destination Options header when its
> + * number of options exceeds the configured
> + * limit.
> + */
> + if (!hopbyhop)
> + goto bad;
> +
> + /* Drop a Hop-by-Hop Options header when its
> + * number of options exceeds the configured
> + * limit IF we're the destination. Otherwise,
> + * just skip it.
> + */
> + if (ipv6_chk_addr_ret == -1)
> + ipv6_chk_addr_ret = ipv6_chk_addr(
> + dev_net(skb->dev),
> + &ipv6_hdr(skb)->daddr,
> + skb->dev, 0);
> +
> + if (ipv6_chk_addr_ret)
> + goto bad;
> +
> + goto skip;
> + }
>
> if (hopbyhop) {
> switch (nh[off]) {
> @@ -210,6 +233,7 @@ static bool ip6_parse_tlv(bool hopbyhop,
> break;
> }
> }
> +skip:
> padlen = 0;
> }
> off += optlen;
Of course, this would also require an early check in patch #1 of this
series (for a Hbh), in order to handle the case: limit==0.
>> it simple and drop whenever a limit is exceeded. RFC9673 does allow a
>> host to skip over HBH options, but IMO it's too risky to blindly
>> accept a packet without verifying all the headers.
>
> For a host, I agree. But as a router, I really don't think we should
> drop packets if the limit is exceeded. In that case, we just don't care,
> we're routers, it's not our job to decide if we drop a packet because of
> EHs. Otherwise, we'd be doing the same as operators' policies and
> hardware limitation in transit ASs, and we'd be exacerbating the
> ossification.
>
> Justin
>
>> Tom
>
Powered by blists - more mailing lists