From 40d1f709ec28979f155c54f3fded357a986757a9 Mon Sep 17 00:00:00 2001 From: Vladimir Buyanov Date: Mon, 27 Nov 2023 17:41:01 +0200 Subject: [PATCH 1/2] Fix realIP logic --- ip.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ip.go b/ip.go index 1bcd756ae..497c6a78a 100644 --- a/ip.go +++ b/ip.go @@ -225,15 +225,16 @@ func extractIP(req *http.Request) string { func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor { checker := newIPChecker(options) return func(req *http.Request) string { + remoteIP := extractIP(req) realIP := req.Header.Get(HeaderXRealIP) - if realIP != "" { - realIP = strings.TrimPrefix(realIP, "[") - realIP = strings.TrimSuffix(realIP, "]") - if ip := net.ParseIP(realIP); ip != nil && checker.trust(ip) { + realIP = strings.TrimPrefix(realIP, "[") + realIP = strings.TrimSuffix(realIP, "]") + if checker.trust(remoteIP) && realIP != "" { + if ip := net.ParseIP(realIP); ip != nil { return realIP } } - return extractIP(req) + return remoteIP } } From 92a8221fb691f79815e9308f3588f0528a212db1 Mon Sep 17 00:00:00 2001 From: Vladimir Buyanov Date: Tue, 5 Dec 2023 22:32:52 +0200 Subject: [PATCH 2/2] Update code and tests --- ip.go | 17 +++++++++++------ ip_test.go | 45 ++++++++++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/ip.go b/ip.go index 497c6a78a..b1a5a7abb 100644 --- a/ip.go +++ b/ip.go @@ -225,16 +225,21 @@ func extractIP(req *http.Request) string { func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor { checker := newIPChecker(options) return func(req *http.Request) string { - remoteIP := extractIP(req) + directIP := extractIP(req) realIP := req.Header.Get(HeaderXRealIP) - realIP = strings.TrimPrefix(realIP, "[") - realIP = strings.TrimSuffix(realIP, "]") - if checker.trust(remoteIP) && realIP != "" { - if ip := net.ParseIP(realIP); ip != nil { + if realIP == "" { + return directIP + } + + if checker.trust(net.ParseIP(directIP)) { + realIP = strings.TrimPrefix(realIP, "[") + realIP = strings.TrimSuffix(realIP, "]") + if rIP := net.ParseIP(realIP); rIP != nil { return realIP } } - return remoteIP + + return directIP } } diff --git a/ip_test.go b/ip_test.go index 38c4a1cac..bc0c69c03 100644 --- a/ip_test.go +++ b/ip_test.go @@ -1,10 +1,11 @@ package echo import ( - "github.com/stretchr/testify/assert" "net" "net/http" "testing" + + "github.com/stretchr/testify/assert" ) func mustParseCIDR(s string) *net.IPNet { @@ -458,7 +459,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 { @@ -486,36 +487,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", @@ -524,11 +531,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", @@ -537,12 +544,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", @@ -551,12 +558,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", }, }