mirror of
https://github.com/caddyserver/caddy.git
synced 2025-10-19 07:43:17 +00:00
caddyhttp: Add trusted_proxies_unix
for trusting unix socket X-Forwarded-*
headers (#7265)
This commit is contained in:
parent
7fb39ec1e5
commit
d7185fd002
4 changed files with 118 additions and 0 deletions
|
@ -51,6 +51,7 @@ type serverOptions struct {
|
||||||
StrictSNIHost *bool
|
StrictSNIHost *bool
|
||||||
TrustedProxiesRaw json.RawMessage
|
TrustedProxiesRaw json.RawMessage
|
||||||
TrustedProxiesStrict int
|
TrustedProxiesStrict int
|
||||||
|
TrustedProxiesUnix bool
|
||||||
ClientIPHeaders []string
|
ClientIPHeaders []string
|
||||||
ShouldLogCredentials bool
|
ShouldLogCredentials bool
|
||||||
Metrics *caddyhttp.Metrics
|
Metrics *caddyhttp.Metrics
|
||||||
|
@ -251,6 +252,12 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
|
||||||
}
|
}
|
||||||
serverOpts.TrustedProxiesStrict = 1
|
serverOpts.TrustedProxiesStrict = 1
|
||||||
|
|
||||||
|
case "trusted_proxies_unix":
|
||||||
|
if d.NextArg() {
|
||||||
|
return nil, d.ArgErr()
|
||||||
|
}
|
||||||
|
serverOpts.TrustedProxiesUnix = true
|
||||||
|
|
||||||
case "client_ip_headers":
|
case "client_ip_headers":
|
||||||
headers := d.RemainingArgs()
|
headers := d.RemainingArgs()
|
||||||
for _, header := range headers {
|
for _, header := range headers {
|
||||||
|
@ -342,6 +349,7 @@ func applyServerOptions(
|
||||||
server.TrustedProxiesRaw = opts.TrustedProxiesRaw
|
server.TrustedProxiesRaw = opts.TrustedProxiesRaw
|
||||||
server.ClientIPHeaders = opts.ClientIPHeaders
|
server.ClientIPHeaders = opts.ClientIPHeaders
|
||||||
server.TrustedProxiesStrict = opts.TrustedProxiesStrict
|
server.TrustedProxiesStrict = opts.TrustedProxiesStrict
|
||||||
|
server.TrustedProxiesUnix = opts.TrustedProxiesUnix
|
||||||
server.Metrics = opts.Metrics
|
server.Metrics = opts.Metrics
|
||||||
if opts.ShouldLogCredentials {
|
if opts.ShouldLogCredentials {
|
||||||
if server.Logs == nil {
|
if server.Logs == nil {
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
{
|
||||||
|
servers {
|
||||||
|
trusted_proxies_unix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
example.com {
|
||||||
|
reverse_proxy https://local:8080
|
||||||
|
}
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "subroute",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "reverse_proxy",
|
||||||
|
"transport": {
|
||||||
|
"protocol": "http",
|
||||||
|
"tls": {}
|
||||||
|
},
|
||||||
|
"upstreams": [
|
||||||
|
{
|
||||||
|
"dial": "local:8080"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trusted_proxies_unix": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -202,6 +202,13 @@ type Server struct {
|
||||||
// This option is disabled by default.
|
// This option is disabled by default.
|
||||||
TrustedProxiesStrict int `json:"trusted_proxies_strict,omitempty"`
|
TrustedProxiesStrict int `json:"trusted_proxies_strict,omitempty"`
|
||||||
|
|
||||||
|
// If greater than zero, enables trusting socket connections
|
||||||
|
// (e.g. Unix domain sockets) as coming from a trusted
|
||||||
|
// proxy.
|
||||||
|
//
|
||||||
|
// This option is disabled by default.
|
||||||
|
TrustedProxiesUnix bool `json:"trusted_proxies_unix,omitempty"`
|
||||||
|
|
||||||
// Enables access logging and configures how access logs are handled
|
// Enables access logging and configures how access logs are handled
|
||||||
// in this server. To minimally enable access logs, simply set this
|
// in this server. To minimally enable access logs, simply set this
|
||||||
// to a non-null, empty struct.
|
// to a non-null, empty struct.
|
||||||
|
@ -941,6 +948,17 @@ func determineTrustedProxy(r *http.Request, s *Server) (bool, string) {
|
||||||
return false, ""
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.TrustedProxiesUnix && r.RemoteAddr == "@" {
|
||||||
|
if s.TrustedProxiesStrict > 0 {
|
||||||
|
ipRanges := []netip.Prefix{}
|
||||||
|
if s.trustedProxies != nil {
|
||||||
|
ipRanges = s.trustedProxies.GetIPRanges(r)
|
||||||
|
}
|
||||||
|
return true, strictUntrustedClientIp(r, s.ClientIPHeaders, ipRanges, "@")
|
||||||
|
} else {
|
||||||
|
return true, trustedRealClientIP(r, s.ClientIPHeaders, "@")
|
||||||
|
}
|
||||||
|
}
|
||||||
// Parse the remote IP, ignore the error as non-fatal,
|
// Parse the remote IP, ignore the error as non-fatal,
|
||||||
// but the remote IP is required to continue, so we
|
// but the remote IP is required to continue, so we
|
||||||
// just return early. This should probably never happen
|
// just return early. This should probably never happen
|
||||||
|
|
|
@ -297,6 +297,39 @@ func TestServer_DetermineTrustedProxy_TrustedLoopback(t *testing.T) {
|
||||||
assert.Equal(t, clientIP, "31.40.0.10")
|
assert.Equal(t, clientIP, "31.40.0.10")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServer_DetermineTrustedProxy_UnixSocket(t *testing.T) {
|
||||||
|
server := &Server{
|
||||||
|
ClientIPHeaders: []string{"X-Forwarded-For"},
|
||||||
|
TrustedProxiesUnix: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
req := httptest.NewRequest("GET", "/", nil)
|
||||||
|
req.RemoteAddr = "@"
|
||||||
|
req.Header.Set("X-Forwarded-For", "2.2.2.2, 3.3.3.3")
|
||||||
|
|
||||||
|
trusted, clientIP := determineTrustedProxy(req, server)
|
||||||
|
|
||||||
|
assert.True(t, trusted)
|
||||||
|
assert.Equal(t, "2.2.2.2", clientIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServer_DetermineTrustedProxy_UnixSocketStrict(t *testing.T) {
|
||||||
|
server := &Server{
|
||||||
|
ClientIPHeaders: []string{"X-Forwarded-For"},
|
||||||
|
TrustedProxiesUnix: true,
|
||||||
|
TrustedProxiesStrict: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
req := httptest.NewRequest("GET", "/", nil)
|
||||||
|
req.RemoteAddr = "@"
|
||||||
|
req.Header.Set("X-Forwarded-For", "2.2.2.2, 3.3.3.3")
|
||||||
|
|
||||||
|
trusted, clientIP := determineTrustedProxy(req, server)
|
||||||
|
|
||||||
|
assert.True(t, trusted)
|
||||||
|
assert.Equal(t, "3.3.3.3", clientIP)
|
||||||
|
}
|
||||||
|
|
||||||
func TestServer_DetermineTrustedProxy_UntrustedPrefix(t *testing.T) {
|
func TestServer_DetermineTrustedProxy_UntrustedPrefix(t *testing.T) {
|
||||||
loopbackPrefix, _ := netip.ParsePrefix("127.0.0.1/8")
|
loopbackPrefix, _ := netip.ParsePrefix("127.0.0.1/8")
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue