caddyserver / caddy

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
https://caddyserver.com
Apache License 2.0
57.4k stars 4k forks source link

TLS does not work on NATed IPv4 literal #6344

Open ledlamp opened 4 months ago

ledlamp commented 4 months ago

caddy version v2.7.6

Host has private IP 10.0.0.79 and public IP 129.159.139.0 NAT forwarded (Oracle Cloud).

This works as expected:

10.0.0.79 {
        tls internal
        respond "ok"
}

curl --insecure https://10.0.0.79 -> "ok". curl -D - --insecure https://129.159.139.0 -> blank 200

But this does not:

129.159.139.0 {
        tls internal
        respond "ok"
}
# curl --insecure https://129.159.139.0
curl: (35) error:0A000438:SSL routines::tlsv1 alert internal error

Windows:

> curl.exe --insecure https://129.159.139.0
curl: (35) schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.

Google Chrome: ERR_SSL_PROTOCOL_ERROR

Firefox: SSL_ERROR_INTERNAL_ERROR_ALERT

However, having both sites make them both work:

129.159.139.0 {
        tls internal
        respond "foo"
}

10.0.0.79 {
        tls internal
        respond "bar"
}

curl --insecure https://129.159.139.0 -> "foo" curl --insecure https://10.0.0.79 -> "bar"

HOWEVER, if I explicitly specify my own cert files, it STILL uses the caddy local cert. With any of the following configs, the Caddy Local Authority cert is always used regardless.

129.159.139.0 {
        tls ssl/129.159.139.0/certificate.crt ssl/129.159.139.0/private.key
        # ...
}

10.0.0.79 {
        tls internal
        respond "test"
}
129.159.139.0 {
        tls ssl/129.159.139.0/certificate.crt ssl/129.159.139.0/private.key
        # ...
}

10.0.0.79 {
        tls ssl/129.159.139.0/certificate.crt ssl/129.159.139.0/private.key
        respond "test"
}
129.159.139.0 10.0.0.79 {
        tls ssl/129.159.139.0/certificate.crt ssl/129.159.139.0/private.key
        # ...
}
10.0.0.79 {
        tls ssl/129.159.139.0/certificate.crt ssl/129.159.139.0/private.key
        # ...
}

2024-05-27_03-23-57-583 129 159 139 0_-_Google_Chrome

So it seems it is not possible to use TLS on a raw NAT'ed IP address, with custom certs (from ZeroSSL for example). It fails to handshake, unless there is another non-NATed IP address anywhere in the caddyfile, but then internal tls is always used regardless.

I also reproduced this issue at my house where my public IP is forwarded to my server. And the VPS that has public IP directly, does not have this issue.

I thought I've done this before, so I tried caddy 2.6.4, 2.5.2, and 2.4.6, but it's the same. I must have used nginx last time.

I did try adding the public IP to the host's interface but it did not change it.

mholt commented 4 months ago

What's in the Caddy logs though? (Enable debug mode just in case.) That should reveal the reason.