From a3b0ba24d3596de3bc2dde618125ac3acb1c774c Mon Sep 17 00:00:00 2001 From: Vladimir Buyanov <81759784+cl-bvl@users.noreply.github.com> Date: Sun, 10 Mar 2024 19:04:54 +0200 Subject: [PATCH] Fix Real IP logic (#2550) * Fix realIP logic --- ip.go | 12 +++++++++--- ip_test.go | 45 ++++++++++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/ip.go b/ip.go index 5374dc018..6aed8d606 100644 --- a/ip.go +++ b/ip.go @@ -228,15 +228,21 @@ func extractIP(req *http.Request) string { func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor { checker := newIPChecker(options) return func(req *http.Request) string { + directIP := extractIP(req) realIP := req.Header.Get(HeaderXRealIP) - if realIP != "" { + if realIP == "" { + return directIP + } + + if checker.trust(net.ParseIP(directIP)) { realIP = strings.TrimPrefix(realIP, "[") realIP = strings.TrimSuffix(realIP, "]") - if ip := net.ParseIP(realIP); ip != nil && checker.trust(ip) { + if rIP := net.ParseIP(realIP); rIP != nil { return realIP } } - return extractIP(req) + + return directIP } } diff --git a/ip_test.go b/ip_test.go index 20e3127a8..cf26e04e8 100644 --- a/ip_test.go +++ b/ip_test.go @@ -4,10 +4,11 @@ package echo import ( - "github.com/stretchr/testify/assert" "net" "net/http" "testing" + + "github.com/stretchr/testify/assert" ) func mustParseCIDR(s string) *net.IPNet { @@ -461,7 +462,7 @@ func TestExtractIPDirect(t *testing.T) { } func TestExtractIPFromRealIPHeader(t *testing.T) { - _, ipForRemoteAddrExternalRange, _ := net.ParseCIDR("203.0.113.199/24") + _, ipForRemoteAddrExternalRange, _ := net.ParseCIDR("203.0.113.0/24") _, ipv6ForRemoteAddrExternalRange, _ := net.ParseCIDR("2001:db8::/64") var testCases = []struct { @@ -489,36 +490,42 @@ func TestExtractIPFromRealIPHeader(t *testing.T) { }, { name: "request is from external IP has valid + UNTRUSTED external X-Real-Ip header, extract IP from remote addr", + givenTrustOptions: []TrustOption{ // case for "trust direct-facing proxy" + TrustIPRange(ipForRemoteAddrExternalRange), // we trust external IP range "203.0.113.199/24" + }, whenRequest: http.Request{ Header: http.Header{ - HeaderXRealIP: []string{"203.0.113.199"}, // <-- this is untrusted + HeaderXRealIP: []string{"203.0.113.199"}, }, - RemoteAddr: "203.0.113.1:8080", + RemoteAddr: "8.8.8.8:8080", // <-- this is untrusted }, - expectIP: "203.0.113.1", + expectIP: "8.8.8.8", }, { name: "request is from external IP has valid + UNTRUSTED external X-Real-Ip header, extract IP from remote addr", + givenTrustOptions: []TrustOption{ // case for "trust direct-facing proxy" + TrustIPRange(ipv6ForRemoteAddrExternalRange), // we trust external IP range "203.0.113.199/24" + }, whenRequest: http.Request{ Header: http.Header{ - HeaderXRealIP: []string{"[2001:db8::113:199]"}, // <-- this is untrusted + HeaderXRealIP: []string{"[bc01:1010::9090:1888]"}, }, - RemoteAddr: "[2001:db8::113:1]:8080", + RemoteAddr: "[fe64:aa10::1]:8080", // <-- this is untrusted }, - expectIP: "2001:db8::113:1", + expectIP: "fe64:aa10::1", }, { name: "request is from external IP has valid + TRUSTED X-Real-Ip header, extract IP from X-Real-Ip header", givenTrustOptions: []TrustOption{ // case for "trust direct-facing proxy" - TrustIPRange(ipForRemoteAddrExternalRange), // we trust external IP range "203.0.113.199/24" + TrustIPRange(ipForRemoteAddrExternalRange), // we trust external IP range "203.0.113.0/24" }, whenRequest: http.Request{ Header: http.Header{ - HeaderXRealIP: []string{"203.0.113.199"}, + HeaderXRealIP: []string{"8.8.8.8"}, }, RemoteAddr: "203.0.113.1:8080", }, - expectIP: "203.0.113.199", + expectIP: "8.8.8.8", }, { name: "request is from external IP has valid + TRUSTED X-Real-Ip header, extract IP from X-Real-Ip header", @@ -527,11 +534,11 @@ func TestExtractIPFromRealIPHeader(t *testing.T) { }, whenRequest: http.Request{ Header: http.Header{ - HeaderXRealIP: []string{"[2001:db8::113:199]"}, + HeaderXRealIP: []string{"[fe64:db8::113:199]"}, }, RemoteAddr: "[2001:db8::113:1]:8080", }, - expectIP: "2001:db8::113:199", + expectIP: "fe64:db8::113:199", }, { name: "request is from external IP has XFF and valid + TRUSTED X-Real-Ip header, extract IP from X-Real-Ip header", @@ -540,12 +547,12 @@ func TestExtractIPFromRealIPHeader(t *testing.T) { }, whenRequest: http.Request{ Header: http.Header{ - HeaderXRealIP: []string{"203.0.113.199"}, - HeaderXForwardedFor: []string{"203.0.113.198, 203.0.113.197"}, // <-- should not affect anything + HeaderXRealIP: []string{"8.8.8.8"}, + HeaderXForwardedFor: []string{"1.1.1.1 ,8.8.8.8"}, // <-- should not affect anything }, RemoteAddr: "203.0.113.1:8080", }, - expectIP: "203.0.113.199", + expectIP: "8.8.8.8", }, { name: "request is from external IP has XFF and valid + TRUSTED X-Real-Ip header, extract IP from X-Real-Ip header", @@ -554,12 +561,12 @@ func TestExtractIPFromRealIPHeader(t *testing.T) { }, whenRequest: http.Request{ Header: http.Header{ - HeaderXRealIP: []string{"[2001:db8::113:199]"}, - HeaderXForwardedFor: []string{"[2001:db8::113:198], [2001:db8::113:197]"}, // <-- should not affect anything + HeaderXRealIP: []string{"[fe64:db8::113:199]"}, + HeaderXForwardedFor: []string{"[feab:cde9::113:198], [fe64:db8::113:199]"}, // <-- should not affect anything }, RemoteAddr: "[2001:db8::113:1]:8080", }, - expectIP: "2001:db8::113:199", + expectIP: "fe64:db8::113:199", }, }