I have originally submitted the issue to spring-cloud-gateway, so pardon the reproducer name.

In RFC for handling Forwarded and X-Forwarded compatibility [1] and there is an issue when X-Forwarded-For contains an IPv6 as first entry. I could reproduce this only via Cloudfare with an ISP that offers dual IP stack.

The X-Forwarded-For header that is received from Cloudfare when source IP is a real IPv6 is shown below (fully anonymized, of course).

Consider the following

   Note that IPv6 addresses may not be quoted in
   X-Forwarded-For and may not be enclosed by square brackets, but they
   are quoted and enclosed in square brackets in "Forwarded".

       X-Forwarded-For: 192.0.2.43, 2001:db8:cafe::17

   becomes:

       Forwarded: for=192.0.2.43, for="[2001:db8:cafe::17]"

When using X-Forwarded-For header such as

X-Forwarded-For: fd00:fefe:1::4, 192.168.0.1

The org.springframework.web.util.ForwardedHeaderUtils produces an InetHostAddress without square brackets "[]"

{66F73C95-BAB3-496E-832D-AA29E6978B5F}

When using an equivalent Forwarded header, the InetHostAddress is present WITH square brackets "[]"

Forwarded: for="[fd00:fefe:1::4]", for=192.168.0.1

{C54059F1-3CAD-41C3-AC4E-B6CA817AA6E0}

It would be nice if both would return the same format.

Reproducer https://github.com/ZIRAKrezovic/gateway-reproducer

Simply run ./mvnw clean verify

Adjust DemoApplicationSimpleTests to switch between X-Forwarded-For and Forwarded as shown above.

[1] https://datatracker.ietf.org/doc/html/rfc7239#section-7.4

Comment From: rstoyanchev

We can add the square brackets in the x-forwarded-for case to match the RFC forwarded header syntax.

Comment From: krezovic

Hi @rstoyanchev - I believe only IPv6 should be enclosed within square brackets. This is true for "Forwarded" handling. If you enclose IPv4 within square brackets then it's again inconsistent.

Comment From: rstoyanchev

Good point. In that case, we might not be able to do this. I'm not sure there is an easy way to tell them apart.

Comment From: krezovic

The obvious difference is that IPv6 blocks are separated by colon : rather than dot .

Comment From: rstoyanchev

I was thinking of an address with a port, but "X-Forwarded-For" is just a host, so it should be an easy check indeed.

Comment From: ZIRAKrezovic

Even with port, IPv6 will always contain more than one :, and may even contain two ::. But you don't need to validate an IPv6 only to detect it