Skip to content

Commit 63d597c

Browse files
caddyhttp: Accept XFF header values with ports, when parsing client IP (#6183)
1 parent e65b97f commit 63d597c

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

modules/caddyhttp/server.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -902,9 +902,18 @@ func trustedRealClientIP(r *http.Request, headers []string, clientIP string) str
902902
allValues := strings.Split(strings.Join(values, ","), ",")
903903

904904
// Get first valid left-most IP address
905-
for _, ip := range allValues {
906-
ip, _, _ = strings.Cut(strings.TrimSpace(ip), "%")
907-
ipAddr, err := netip.ParseAddr(ip)
905+
for _, part := range allValues {
906+
// Some proxies may retain the port number, so split if possible
907+
host, _, err := net.SplitHostPort(part)
908+
if err != nil {
909+
host = part
910+
}
911+
912+
// Remove any zone identifier from the IP address
913+
host, _, _ = strings.Cut(strings.TrimSpace(host), "%")
914+
915+
// Parse the IP address
916+
ipAddr, err := netip.ParseAddr(host)
908917
if err != nil {
909918
continue
910919
}
@@ -921,11 +930,20 @@ func trustedRealClientIP(r *http.Request, headers []string, clientIP string) str
921930
// remote address is returned.
922931
func strictUntrustedClientIp(r *http.Request, headers []string, trusted []netip.Prefix, clientIP string) string {
923932
for _, headerName := range headers {
924-
ips := strings.Split(strings.Join(r.Header.Values(headerName), ","), ",")
933+
parts := strings.Split(strings.Join(r.Header.Values(headerName), ","), ",")
934+
935+
for i := len(parts) - 1; i >= 0; i-- {
936+
// Some proxies may retain the port number, so split if possible
937+
host, _, err := net.SplitHostPort(parts[i])
938+
if err != nil {
939+
host = parts[i]
940+
}
941+
942+
// Remove any zone identifier from the IP address
943+
host, _, _ = strings.Cut(strings.TrimSpace(host), "%")
925944

926-
for i := len(ips) - 1; i >= 0; i-- {
927-
ip, _, _ := strings.Cut(strings.TrimSpace(ips[i]), "%")
928-
ipAddr, err := netip.ParseAddr(ip)
945+
// Parse the IP address
946+
ipAddr, err := netip.ParseAddr(host)
929947
if err != nil {
930948
continue
931949
}

modules/caddyhttp/server_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,15 @@ func TestServer_TrustedRealClientIP_OneTrustedHeaderValidArray(t *testing.T) {
188188
assert.Equal(t, ip, "1.1.1.1")
189189
}
190190

191+
func TestServer_TrustedRealClientIP_IncludesPort(t *testing.T) {
192+
req := httptest.NewRequest("GET", "/", nil)
193+
req.RemoteAddr = "192.0.2.1:12345"
194+
req.Header.Set("X-Forwarded-For", "1.1.1.1:1234")
195+
ip := trustedRealClientIP(req, []string{"X-Forwarded-For"}, "192.0.2.1")
196+
197+
assert.Equal(t, ip, "1.1.1.1")
198+
}
199+
191200
func TestServer_TrustedRealClientIP_SkipsInvalidIps(t *testing.T) {
192201
req := httptest.NewRequest("GET", "/", nil)
193202
req.RemoteAddr = "192.0.2.1:12345"

0 commit comments

Comments
 (0)