HTTP transports: Require trustedXForwardedFor for X-Forwarded-For

This commit is contained in:
Meo597
2026-06-11 01:42:20 +08:00
parent da21a8f77f
commit 1fb559f03b
9 changed files with 57 additions and 62 deletions
+23 -6
View File
@@ -1,19 +1,17 @@
package http
import (
"context"
gonet "net"
"net/http"
"strconv"
"strings"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
)
// ParseXForwardedFor parses X-Forwarded-For header in http headers, and return the IP list in it.
func ParseXForwardedFor(header http.Header) []net.Address {
xff := header.Get("X-Forwarded-For")
if xff == "" {
return nil
}
func parseXForwardedFor(xff string) []net.Address {
list := strings.Split(xff, ",")
addrs := make([]net.Address, 0, len(list))
for _, proxy := range list {
@@ -22,6 +20,25 @@ func ParseXForwardedFor(header http.Header) []net.Address {
return addrs
}
// ParseTrustedXForwardedFor parses X-Forwarded-For 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 == "" {
return nil
}
for _, key := range trusted {
if len(header.Values(key)) > 0 {
return parseXForwardedFor(xff)
}
}
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`)
} else {
errors.LogError(context.Background(), `ignored potentially forged "X-Forwarded-For" from `, clientAddr, `: `, xff)
}
return nil
}
// RemoveHopByHopHeaders removes hop by hop headers in http header list.
func RemoveHopByHopHeaders(header http.Header) {
// Strip hop-by-hop header based on RFC:
+10 -2
View File
@@ -2,6 +2,7 @@ package http_test
import (
"bufio"
gonet "net"
"net/http"
"strings"
"testing"
@@ -12,10 +13,17 @@ import (
. "github.com/xtls/xray-core/common/protocol/http"
)
func TestParseXForwardedFor(t *testing.T) {
func TestParseTrustedXForwardedFor(t *testing.T) {
header := http.Header{}
header.Add("X-Forwarded-For", "129.78.138.66, 129.78.64.103")
addrs := ParseXForwardedFor(header)
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)
}
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)
}