IPv6, realip and ipfilter middlewares (troubleshooting)

Hi people,

This has been driving me crazy for the last few hours. I’m using Caddy with realip and ipfilter middlewares.

This issue is related to IPv6 and is somehow coding-related. Suppose the following Caddyfile:
log log.log
errors error.log
ipfilter / {
    rule block
realip {

If you run Caddy with this configuration, the realip middleware will replace the visitor’s IP address with the one contained in the X-Forwarded-For header. With IPv4, everything works fine. However, when IPv6 comes to play, ipfilter (I believe) throws the following error:
[ERROR 500 /] too many colons in address 2001:1620:28:1:b6f:8bca:93:a116:36061

The “too many colons in address” string leads to the function SplitHostPort:

Both middlewares make use of the SplitHostPort.

The funny thing is, if I remove the realip middleware and remove the “strict” flag from ipfilter (so ipfilter can read the X-Forwarded-For header by itself without relying on realip), everything works fine. The realip middleware alone (without ipfilter) also doesn’t throw any error. It’s just the combination of realip, ipfilter and IPv6 that throws.

I’ve been trying to troubleshoot the source of the bug by looking at both middleware source-codes, but as I’m not a Go developer I can’t really do much. Therefore, I’m looking for a good samaritan to take a quick look on this matter.

If I’m thinking right, realip middleware is called first, and only then ipfilter. Am I correct?

req.RemoteAddr should look like this for IPv6 addresses, I believe:
(remember the square brackets for IPv6)

I’m going to throw a bet. I bet the source of the problem is on the realip middleware, at the following lines:

Look at the following line:
req.RemoteAddr = leftMost + ":" + port
I guess it doesn’t include the square brackets, and then that variable goes to the next middleware (ipfilter). The result? That error (“too many colons in address”) when ipfilter throws the req.RemoteAddr variable to the function SplitHostPort.

But like I said, this is just a bet. I need a Go person to take a look at this and say if I’m right or wrong, and what’s the source of the problem if possible.

GitHub ipfilter (maybe you want to check it as well?)

For anyone wanting to replicate this situation, you can execute the following curl command:
curl "" -H "X-Forwarded-For: 2001:1620:28:1:b6f:8bca:93:a116"

Replace with your machine’s IPv4 address (if you try with IPv6 it will fail to an unrelated reason/bug with realip, apparently the CIDR range doesn’t apply to IPv6, so realip will ignore your X-Forwarded-For).

That curl command will trigger a 500 Internal Server Error when Caddy has the realip+ipfilter middleware and is running the Caddyfile specified on this topic. Trying X-Forwarded-For with a IPv4 address will not trigger any error, everything will work as expected:
curl "" -H "X-Forwarded-For:"

Thank you!

Yes, this need to be net.JoinHostPort, seeing ports being concatenated like this is almost always a bug. You can just make this change yourself, recompile and test.

You’re right, problem solved & pull request on the way. Thanks! :slight_smile:

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.