mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-31 10:19:44 +08:00 
			
		
		
		
	caddyhttp: Add trusted_proxies_unix for trusting unix socket X-Forwarded-* headers (#7265)
				
					
				
			This commit is contained in:
		| @ -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") | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Chris Seufert
					Chris Seufert