HTTP transports: X-Real-IP

This commit is contained in:
Meo597
2026-06-11 05:35:27 +08:00
parent 2589a52d48
commit ce3b4fd175
2 changed files with 57 additions and 18 deletions
+16 -8
View File
@@ -20,21 +20,29 @@ func parseXForwardedFor(xff string) []net.Address {
return addrs
}
// ParseTrustedXForwardedFor parses X-Forwarded-For only when a configured trusted header is present.
// ParseTrustedXForwardedFor parses forwarding headers only when a configured trusted header is present.
func ParseTrustedXForwardedFor(header http.Header, trusted []string, clientAddr gonet.Addr) []net.Address {
xff := header.Get("X-Forwarded-For")
if xff == "" {
key := "X-Real-IP"
value := header.Get(key)
if value == "" {
key = "X-Forwarded-For"
value = header.Get(key)
}
if value == "" {
return nil
}
for _, key := range trusted {
if len(header.Values(key)) > 0 {
return parseXForwardedFor(xff)
for _, t := range trusted {
if len(header.Values(t)) > 0 {
if key == "X-Real-IP" {
return []net.Address{net.ParseAddress(value)}
}
return parseXForwardedFor(value)
}
}
if len(trusted) == 0 {
errors.LogWarning(context.Background(), `received "X-Forwarded-For" from `, clientAddr, ` but "sockopt.trustedXForwardedFor" is not configured; ignoring it and using the real remote address`)
errors.LogWarning(context.Background(), `received "`, key, `" from `, clientAddr, ` but "sockopt.trustedXForwardedFor" is not configured; ignoring it and using the real remote address`)
} else {
errors.LogError(context.Background(), `ignored potentially forged "X-Forwarded-For" from `, clientAddr, `: `, xff)
errors.LogError(context.Background(), `ignored potentially forged "`, key, `" from `, clientAddr, `: `, value)
}
return nil
}
+41 -10
View File
@@ -14,19 +14,50 @@ import (
)
func TestParseTrustedXForwardedFor(t *testing.T) {
header := http.Header{}
header.Add("X-Forwarded-For", "129.78.138.66, 129.78.64.103")
clientAddr := &gonet.TCPAddr{IP: gonet.ParseIP("127.0.0.1"), Port: 12345}
if addrs := ParseTrustedXForwardedFor(header, nil, clientAddr); addrs != nil {
t.Fatalf("unexpected trusted X-Forwarded-For: %v", addrs)
}
t.Run("ignore X-Forwarded-For without trusted header", func(t *testing.T) {
header := http.Header{}
header.Add("X-Forwarded-For", "129.78.138.66, 129.78.64.103")
header.Add("X-Trusted-CDN", "")
addrs := ParseTrustedXForwardedFor(header, []string{"X-Trusted-CDN"}, clientAddr)
if r := cmp.Diff(addrs, []net.Address{net.ParseAddress("129.78.138.66"), net.ParseAddress("129.78.64.103")}); r != "" {
t.Error(r)
}
if addrs := ParseTrustedXForwardedFor(header, nil, clientAddr); addrs != nil {
t.Fatalf("unexpected trusted X-Forwarded-For: %v", addrs)
}
})
t.Run("trust X-Forwarded-For", func(t *testing.T) {
header := http.Header{}
header.Add("X-Forwarded-For", "129.78.138.66, 129.78.64.103")
header.Add("X-Trusted-CDN", "")
addrs := ParseTrustedXForwardedFor(header, []string{"X-Trusted-CDN"}, clientAddr)
if r := cmp.Diff(addrs, []net.Address{net.ParseAddress("129.78.138.66"), net.ParseAddress("129.78.64.103")}); r != "" {
t.Error(r)
}
})
t.Run("prefer X-Real-IP over X-Forwarded-For", func(t *testing.T) {
header := http.Header{}
header.Add("X-Real-IP", "10.0.0.1")
header.Add("X-Forwarded-For", "129.78.138.66, 129.78.64.103")
header.Add("X-Trusted-CDN", "")
addrs := ParseTrustedXForwardedFor(header, []string{"X-Trusted-CDN"}, clientAddr)
if r := cmp.Diff(addrs, []net.Address{net.ParseAddress("10.0.0.1")}); r != "" {
t.Error(r)
}
})
t.Run("do not parse X-Real-IP as a list", func(t *testing.T) {
header := http.Header{}
header.Add("X-Real-IP", "8.8.8.8, 9.9.9.9")
header.Add("X-Trusted-CDN", "")
addrs := ParseTrustedXForwardedFor(header, []string{"X-Trusted-CDN"}, clientAddr)
if r := cmp.Diff(addrs, []net.Address{net.ParseAddress("8.8.8.8, 9.9.9.9")}); r != "" {
t.Error(r)
}
})
}
func TestHopByHopHeadersRemoving(t *testing.T) {