mirror of
https://github.com/caddyserver/caddy.git
synced 2025-10-19 07:43:17 +00:00
Merge branch 'master' into per-host-cardinality
This commit is contained in:
commit
198534d47f
9 changed files with 293 additions and 16 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
129
caddytest/integration/h2listener_test.go
Normal file
129
caddytest/integration/h2listener_test.go
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/v2/caddytest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newH2ListenerWithVersionsWithTLSTester(t *testing.T, serverVersions []string, clientVersions []string) *caddytest.Tester {
|
||||||
|
const baseConfig = `
|
||||||
|
{
|
||||||
|
skip_install_trust
|
||||||
|
admin localhost:2999
|
||||||
|
http_port 9080
|
||||||
|
https_port 9443
|
||||||
|
servers :9443 {
|
||||||
|
protocols %s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localhost {
|
||||||
|
respond "{http.request.tls.proto} {http.request.proto}"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
tester := caddytest.NewTester(t)
|
||||||
|
tester.InitServer(fmt.Sprintf(baseConfig, strings.Join(serverVersions, " ")), "caddyfile")
|
||||||
|
|
||||||
|
tr := tester.Client.Transport.(*http.Transport)
|
||||||
|
tr.TLSClientConfig.NextProtos = clientVersions
|
||||||
|
tr.Protocols = new(http.Protocols)
|
||||||
|
if slices.Contains(clientVersions, "h2") {
|
||||||
|
tr.ForceAttemptHTTP2 = true
|
||||||
|
tr.Protocols.SetHTTP2(true)
|
||||||
|
}
|
||||||
|
if !slices.Contains(clientVersions, "http/1.1") {
|
||||||
|
tr.Protocols.SetHTTP1(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tester
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestH2ListenerWithTLS(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
serverVersions []string
|
||||||
|
clientVersions []string
|
||||||
|
expectedBody string
|
||||||
|
failed bool
|
||||||
|
}{
|
||||||
|
{[]string{"h2"}, []string{"h2"}, "h2 HTTP/2.0", false},
|
||||||
|
{[]string{"h2"}, []string{"http/1.1"}, "", true},
|
||||||
|
{[]string{"h1"}, []string{"http/1.1"}, "http/1.1 HTTP/1.1", false},
|
||||||
|
{[]string{"h1"}, []string{"h2"}, "", true},
|
||||||
|
{[]string{"h2", "h1"}, []string{"h2"}, "h2 HTTP/2.0", false},
|
||||||
|
{[]string{"h2", "h1"}, []string{"http/1.1"}, "http/1.1 HTTP/1.1", false},
|
||||||
|
}
|
||||||
|
for _, tc := range tests {
|
||||||
|
tester := newH2ListenerWithVersionsWithTLSTester(t, tc.serverVersions, tc.clientVersions)
|
||||||
|
t.Logf("running with server versions %v and client versions %v:", tc.serverVersions, tc.clientVersions)
|
||||||
|
if tc.failed {
|
||||||
|
resp, err := tester.Client.Get("https://localhost:9443")
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("unexpected response: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tester.AssertGetResponse("https://localhost:9443", 200, tc.expectedBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newH2ListenerWithVersionsWithoutTLSTester(t *testing.T, serverVersions []string, clientVersions []string) *caddytest.Tester {
|
||||||
|
const baseConfig = `
|
||||||
|
{
|
||||||
|
skip_install_trust
|
||||||
|
admin localhost:2999
|
||||||
|
http_port 9080
|
||||||
|
servers :9080 {
|
||||||
|
protocols %s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
http://localhost {
|
||||||
|
respond "{http.request.proto}"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
tester := caddytest.NewTester(t)
|
||||||
|
tester.InitServer(fmt.Sprintf(baseConfig, strings.Join(serverVersions, " ")), "caddyfile")
|
||||||
|
|
||||||
|
tr := tester.Client.Transport.(*http.Transport)
|
||||||
|
tr.Protocols = new(http.Protocols)
|
||||||
|
if slices.Contains(clientVersions, "h2c") {
|
||||||
|
tr.Protocols.SetHTTP1(false)
|
||||||
|
tr.Protocols.SetUnencryptedHTTP2(true)
|
||||||
|
} else if slices.Contains(clientVersions, "http/1.1") {
|
||||||
|
tr.Protocols.SetHTTP1(true)
|
||||||
|
tr.Protocols.SetUnencryptedHTTP2(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tester
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestH2ListenerWithoutTLS(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
serverVersions []string
|
||||||
|
clientVersions []string
|
||||||
|
expectedBody string
|
||||||
|
failed bool
|
||||||
|
}{
|
||||||
|
{[]string{"h2c"}, []string{"h2c"}, "HTTP/2.0", false},
|
||||||
|
{[]string{"h2c"}, []string{"http/1.1"}, "", true},
|
||||||
|
{[]string{"h1"}, []string{"http/1.1"}, "HTTP/1.1", false},
|
||||||
|
{[]string{"h1"}, []string{"h2c"}, "", true},
|
||||||
|
{[]string{"h2c", "h1"}, []string{"h2c"}, "HTTP/2.0", false},
|
||||||
|
{[]string{"h2c", "h1"}, []string{"http/1.1"}, "HTTP/1.1", false},
|
||||||
|
}
|
||||||
|
for _, tc := range tests {
|
||||||
|
tester := newH2ListenerWithVersionsWithoutTLSTester(t, tc.serverVersions, tc.clientVersions)
|
||||||
|
t.Logf("running with server versions %v and client versions %v:", tc.serverVersions, tc.clientVersions)
|
||||||
|
if tc.failed {
|
||||||
|
resp, err := tester.Client.Get("http://localhost:9080")
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("unexpected response: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tester.AssertGetResponse("http://localhost:9080", 200, tc.expectedBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -468,7 +468,14 @@ func (app *App) Start() error {
|
||||||
ErrorLog: serverLogger,
|
ErrorLog: serverLogger,
|
||||||
Protocols: new(http.Protocols),
|
Protocols: new(http.Protocols),
|
||||||
ConnContext: func(ctx context.Context, c net.Conn) context.Context {
|
ConnContext: func(ctx context.Context, c net.Conn) context.Context {
|
||||||
return context.WithValue(ctx, ConnCtxKey, c)
|
if nc, ok := c.(interface{ tlsNetConn() net.Conn }); ok {
|
||||||
|
getTlsConStateFunc := sync.OnceValue(func() *tls.ConnectionState {
|
||||||
|
tlsConnState := nc.tlsNetConn().(connectionStater).ConnectionState()
|
||||||
|
return &tlsConnState
|
||||||
|
})
|
||||||
|
ctx = context.WithValue(ctx, tlsConnectionStateFuncCtxKey, getTlsConStateFunc)
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,12 @@ func (h *http2Listener) Accept() (net.Conn, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// *tls.Conn doesn't need to be wrapped because we already removed unwanted alpns
|
||||||
|
// and handshake won't succeed without mutually supported alpns
|
||||||
|
if tlsConn, ok := conn.(*tls.Conn); ok {
|
||||||
|
return tlsConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
_, isConnectionStater := conn.(connectionStater)
|
_, isConnectionStater := conn.(connectionStater)
|
||||||
// emit a warning
|
// emit a warning
|
||||||
if h.useTLS && !isConnectionStater {
|
if h.useTLS && !isConnectionStater {
|
||||||
|
@ -46,6 +52,9 @@ func (h *http2Listener) Accept() (net.Conn, error) {
|
||||||
|
|
||||||
// if both h1 and h2 are enabled, we don't need to check the preface
|
// if both h1 and h2 are enabled, we don't need to check the preface
|
||||||
if h.useH1 && h.useH2 {
|
if h.useH1 && h.useH2 {
|
||||||
|
if isConnectionStater {
|
||||||
|
return tlsStateConn{conn}, nil
|
||||||
|
}
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,14 +62,26 @@ func (h *http2Listener) Accept() (net.Conn, error) {
|
||||||
// or else the listener wouldn't be created
|
// or else the listener wouldn't be created
|
||||||
h2Conn := &http2Conn{
|
h2Conn := &http2Conn{
|
||||||
h2Expected: h.useH2,
|
h2Expected: h.useH2,
|
||||||
|
logger: h.logger,
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
if isConnectionStater {
|
if isConnectionStater {
|
||||||
return http2StateConn{h2Conn}, nil
|
return tlsStateConn{http2StateConn{h2Conn}}, nil
|
||||||
}
|
}
|
||||||
return h2Conn, nil
|
return h2Conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tlsStateConn wraps a net.Conn that implements connectionStater to hide that method
|
||||||
|
// we can call netConn to get the original net.Conn and get the tls connection state
|
||||||
|
// golang 1.25 will call that method, and it breaks h2 with connections other than *tls.Conn
|
||||||
|
type tlsStateConn struct {
|
||||||
|
net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn tlsStateConn) tlsNetConn() net.Conn {
|
||||||
|
return conn.Conn
|
||||||
|
}
|
||||||
|
|
||||||
type http2StateConn struct {
|
type http2StateConn struct {
|
||||||
*http2Conn
|
*http2Conn
|
||||||
}
|
}
|
||||||
|
|
|
@ -409,12 +409,16 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
|
||||||
return caddyhttp.Error(http.StatusInternalServerError,
|
return caddyhttp.Error(http.StatusInternalServerError,
|
||||||
fmt.Errorf("preparing request for upstream round-trip: %v", err))
|
fmt.Errorf("preparing request for upstream round-trip: %v", err))
|
||||||
}
|
}
|
||||||
// websocket over http2, assuming backend doesn't support this, the request will be modified to http1.1 upgrade
|
|
||||||
|
// websocket over http2 or http3 if extended connect is enabled, assuming backend doesn't support this, the request will be modified to http1.1 upgrade
|
||||||
|
// Both use the same upgrade mechanism: server advertizes extended connect support, and client sends the pseudo header :protocol in a CONNECT request
|
||||||
|
// The quic-go http3 implementation also puts :protocol in r.Proto for CONNECT requests (quic-go/http3/headers.go@70-72,185,203)
|
||||||
// TODO: once we can reliably detect backend support this, it can be removed for those backends
|
// TODO: once we can reliably detect backend support this, it can be removed for those backends
|
||||||
if r.ProtoMajor == 2 && r.Method == http.MethodConnect && r.Header.Get(":protocol") == "websocket" {
|
if (r.ProtoMajor == 2 && r.Method == http.MethodConnect && r.Header.Get(":protocol") == "websocket") ||
|
||||||
|
(r.ProtoMajor == 3 && r.Method == http.MethodConnect && r.Proto == "websocket") {
|
||||||
clonedReq.Header.Del(":protocol")
|
clonedReq.Header.Del(":protocol")
|
||||||
// keep the body for later use. http1.1 upgrade uses http.NoBody
|
// keep the body for later use. http1.1 upgrade uses http.NoBody
|
||||||
caddyhttp.SetVar(clonedReq.Context(), "h2_websocket_body", clonedReq.Body)
|
caddyhttp.SetVar(clonedReq.Context(), "extended_connect_websocket_body", clonedReq.Body)
|
||||||
clonedReq.Body = http.NoBody
|
clonedReq.Body = http.NoBody
|
||||||
clonedReq.Method = http.MethodGet
|
clonedReq.Method = http.MethodGet
|
||||||
clonedReq.Header.Set("Upgrade", "websocket")
|
clonedReq.Header.Set("Upgrade", "websocket")
|
||||||
|
|
|
@ -94,9 +94,9 @@ func (h *Handler) handleUpgradeResponse(logger *zap.Logger, wg *sync.WaitGroup,
|
||||||
conn io.ReadWriteCloser
|
conn io.ReadWriteCloser
|
||||||
brw *bufio.ReadWriter
|
brw *bufio.ReadWriter
|
||||||
)
|
)
|
||||||
// websocket over http2, assuming backend doesn't support this, the request will be modified to http1.1 upgrade
|
// websocket over http2 or http3 if extended connect is enabled, assuming backend doesn't support this, the request will be modified to http1.1 upgrade
|
||||||
// TODO: once we can reliably detect backend support this, it can be removed for those backends
|
// TODO: once we can reliably detect backend support this, it can be removed for those backends
|
||||||
if body, ok := caddyhttp.GetVar(req.Context(), "h2_websocket_body").(io.ReadCloser); ok {
|
if body, ok := caddyhttp.GetVar(req.Context(), "extended_connect_websocket_body").(io.ReadCloser); ok {
|
||||||
req.Body = body
|
req.Body = body
|
||||||
rw.Header().Del("Upgrade")
|
rw.Header().Del("Upgrade")
|
||||||
rw.Header().Del("Connection")
|
rw.Header().Del("Connection")
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -281,14 +288,9 @@ type Server struct {
|
||||||
// ServeHTTP is the entry point for all HTTP requests.
|
// ServeHTTP is the entry point for all HTTP requests.
|
||||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
// If there are listener wrappers that process tls connections but don't return a *tls.Conn, this field will be nil.
|
// If there are listener wrappers that process tls connections but don't return a *tls.Conn, this field will be nil.
|
||||||
// TODO: Scheduled to be removed later because https://github.com/golang/go/pull/56110 has been merged.
|
|
||||||
if r.TLS == nil {
|
if r.TLS == nil {
|
||||||
// not all requests have a conn (like virtual requests) - see #5698
|
if tlsConnStateFunc, ok := r.Context().Value(tlsConnectionStateFuncCtxKey).(func() *tls.ConnectionState); ok {
|
||||||
if conn, ok := r.Context().Value(ConnCtxKey).(net.Conn); ok {
|
r.TLS = tlsConnStateFunc()
|
||||||
if csc, ok := conn.(connectionStater); ok {
|
|
||||||
r.TLS = new(tls.ConnectionState)
|
|
||||||
*r.TLS = csc.ConnectionState()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,6 +943,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
|
||||||
|
@ -1097,11 +1110,14 @@ const (
|
||||||
// originally came into the server's entry handler
|
// originally came into the server's entry handler
|
||||||
OriginalRequestCtxKey caddy.CtxKey = "original_request"
|
OriginalRequestCtxKey caddy.CtxKey = "original_request"
|
||||||
|
|
||||||
// For referencing underlying net.Conn
|
// DEPRECATED: not used anymore.
|
||||||
// This will eventually be deprecated and not used. To refer to the underlying connection, implement a middleware plugin
|
// To refer to the underlying connection, implement a middleware plugin
|
||||||
// that RegisterConnContext during provisioning.
|
// that RegisterConnContext during provisioning.
|
||||||
ConnCtxKey caddy.CtxKey = "conn"
|
ConnCtxKey caddy.CtxKey = "conn"
|
||||||
|
|
||||||
|
// used to get the tls connection state in the context, if available
|
||||||
|
tlsConnectionStateFuncCtxKey caddy.CtxKey = "tls_connection_state_func"
|
||||||
|
|
||||||
// For tracking whether the client is a trusted proxy
|
// For tracking whether the client is a trusted proxy
|
||||||
TrustedProxyVarKey string = "trusted_proxy"
|
TrustedProxyVarKey string = "trusted_proxy"
|
||||||
|
|
||||||
|
|
|
@ -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