Permalink
Cannot retrieve contributors at this time
235 lines (228 sloc)
9.27 KB
| package echo | |
| import ( | |
| "net" | |
| "net/http" | |
| "strings" | |
| "testing" | |
| testify "github.com/stretchr/testify/assert" | |
| ) | |
| const ( | |
| // For RemoteAddr | |
| ipForRemoteAddrLoopback = "127.0.0.1" // From 127.0.0.0/8 | |
| sampleRemoteAddrLoopback = ipForRemoteAddrLoopback + ":8080" | |
| ipForRemoteAddrExternal = "203.0.113.1" | |
| sampleRemoteAddrExternal = ipForRemoteAddrExternal + ":8080" | |
| // For x-real-ip | |
| ipForRealIP = "203.0.113.10" | |
| // For XFF | |
| ipForXFF1LinkLocal = "169.254.0.101" // From 169.254.0.0/16 | |
| ipForXFF2Private = "192.168.0.102" // From 192.168.0.0/16 | |
| ipForXFF3External = "2001:db8::103" | |
| ipForXFF4Private = "fc00::104" // From fc00::/7 | |
| ipForXFF5External = "198.51.100.105" | |
| ipForXFF6External = "192.0.2.106" | |
| ipForXFFBroken = "this.is.broken.lol" | |
| // keys for test cases | |
| ipTestReqKeyNoHeader = "no header" | |
| ipTestReqKeyRealIPExternal = "x-real-ip; remote addr external" | |
| ipTestReqKeyRealIPInternal = "x-real-ip; remote addr internal" | |
| ipTestReqKeyRealIPAndXFFExternal = "x-real-ip and xff; remote addr external" | |
| ipTestReqKeyRealIPAndXFFInternal = "x-real-ip and xff; remote addr internal" | |
| ipTestReqKeyXFFExternal = "xff; remote addr external" | |
| ipTestReqKeyXFFInternal = "xff; remote addr internal" | |
| ipTestReqKeyBrokenXFF = "broken xff" | |
| ) | |
| var ( | |
| sampleXFF = strings.Join([]string{ | |
| ipForXFF6External, ipForXFF5External, ipForXFF4Private, ipForXFF3External, ipForXFF2Private, ipForXFF1LinkLocal, | |
| }, ", ") | |
| requests = map[string]*http.Request{ | |
| ipTestReqKeyNoHeader: &http.Request{ | |
| RemoteAddr: sampleRemoteAddrExternal, | |
| }, | |
| ipTestReqKeyRealIPExternal: &http.Request{ | |
| Header: http.Header{ | |
| "X-Real-Ip": []string{ipForRealIP}, | |
| }, | |
| RemoteAddr: sampleRemoteAddrExternal, | |
| }, | |
| ipTestReqKeyRealIPInternal: &http.Request{ | |
| Header: http.Header{ | |
| "X-Real-Ip": []string{ipForRealIP}, | |
| }, | |
| RemoteAddr: sampleRemoteAddrLoopback, | |
| }, | |
| ipTestReqKeyRealIPAndXFFExternal: &http.Request{ | |
| Header: http.Header{ | |
| "X-Real-Ip": []string{ipForRealIP}, | |
| HeaderXForwardedFor: []string{sampleXFF}, | |
| }, | |
| RemoteAddr: sampleRemoteAddrExternal, | |
| }, | |
| ipTestReqKeyRealIPAndXFFInternal: &http.Request{ | |
| Header: http.Header{ | |
| "X-Real-Ip": []string{ipForRealIP}, | |
| HeaderXForwardedFor: []string{sampleXFF}, | |
| }, | |
| RemoteAddr: sampleRemoteAddrLoopback, | |
| }, | |
| ipTestReqKeyXFFExternal: &http.Request{ | |
| Header: http.Header{ | |
| HeaderXForwardedFor: []string{sampleXFF}, | |
| }, | |
| RemoteAddr: sampleRemoteAddrExternal, | |
| }, | |
| ipTestReqKeyXFFInternal: &http.Request{ | |
| Header: http.Header{ | |
| HeaderXForwardedFor: []string{sampleXFF}, | |
| }, | |
| RemoteAddr: sampleRemoteAddrLoopback, | |
| }, | |
| ipTestReqKeyBrokenXFF: &http.Request{ | |
| Header: http.Header{ | |
| HeaderXForwardedFor: []string{ipForXFFBroken + ", " + ipForXFF1LinkLocal}, | |
| }, | |
| RemoteAddr: sampleRemoteAddrLoopback, | |
| }, | |
| } | |
| ) | |
| func TestExtractIP(t *testing.T) { | |
| _, ipv4AllRange, _ := net.ParseCIDR("0.0.0.0/0") | |
| _, ipv6AllRange, _ := net.ParseCIDR("::/0") | |
| _, ipForXFF3ExternalRange, _ := net.ParseCIDR(ipForXFF3External + "/48") | |
| _, ipForRemoteAddrExternalRange, _ := net.ParseCIDR(ipForRemoteAddrExternal + "/24") | |
| tests := map[string]*struct { | |
| extractor IPExtractor | |
| expectedIPs map[string]string | |
| }{ | |
| "ExtractIPDirect": { | |
| ExtractIPDirect(), | |
| map[string]string{ | |
| ipTestReqKeyNoHeader: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyRealIPAndXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPAndXFFInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyXFFInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyBrokenXFF: ipForRemoteAddrLoopback, | |
| }, | |
| }, | |
| "ExtractIPFromRealIPHeader(default)": { | |
| ExtractIPFromRealIPHeader(), | |
| map[string]string{ | |
| ipTestReqKeyNoHeader: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPInternal: ipForRealIP, | |
| ipTestReqKeyRealIPAndXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPAndXFFInternal: ipForRealIP, | |
| ipTestReqKeyXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyXFFInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyBrokenXFF: ipForRemoteAddrLoopback, | |
| }, | |
| }, | |
| "ExtractIPFromRealIPHeader(trust only direct-facing proxy)": { | |
| ExtractIPFromRealIPHeader(TrustLoopback(false), TrustLinkLocal(false), TrustPrivateNet(false), TrustIPRange(ipForRemoteAddrExternalRange)), | |
| map[string]string{ | |
| ipTestReqKeyNoHeader: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPExternal: ipForRealIP, | |
| ipTestReqKeyRealIPInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyRealIPAndXFFExternal: ipForRealIP, | |
| ipTestReqKeyRealIPAndXFFInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyXFFInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyBrokenXFF: ipForRemoteAddrLoopback, | |
| }, | |
| }, | |
| "ExtractIPFromRealIPHeader(trust direct-facing proxy)": { | |
| ExtractIPFromRealIPHeader(TrustIPRange(ipForRemoteAddrExternalRange)), | |
| map[string]string{ | |
| ipTestReqKeyNoHeader: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPExternal: ipForRealIP, | |
| ipTestReqKeyRealIPInternal: ipForRealIP, | |
| ipTestReqKeyRealIPAndXFFExternal: ipForRealIP, | |
| ipTestReqKeyRealIPAndXFFInternal: ipForRealIP, | |
| ipTestReqKeyXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyXFFInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyBrokenXFF: ipForRemoteAddrLoopback, | |
| }, | |
| }, | |
| "ExtractIPFromXFFHeader(default)": { | |
| ExtractIPFromXFFHeader(), | |
| map[string]string{ | |
| ipTestReqKeyNoHeader: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyRealIPAndXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPAndXFFInternal: ipForXFF3External, | |
| ipTestReqKeyXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyXFFInternal: ipForXFF3External, | |
| ipTestReqKeyBrokenXFF: ipForRemoteAddrLoopback, | |
| }, | |
| }, | |
| "ExtractIPFromXFFHeader(trust only direct-facing proxy)": { | |
| ExtractIPFromXFFHeader(TrustLoopback(false), TrustLinkLocal(false), TrustPrivateNet(false), TrustIPRange(ipForRemoteAddrExternalRange)), | |
| map[string]string{ | |
| ipTestReqKeyNoHeader: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyRealIPAndXFFExternal: ipForXFF1LinkLocal, | |
| ipTestReqKeyRealIPAndXFFInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyXFFExternal: ipForXFF1LinkLocal, | |
| ipTestReqKeyXFFInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyBrokenXFF: ipForRemoteAddrLoopback, | |
| }, | |
| }, | |
| "ExtractIPFromXFFHeader(trust direct-facing proxy)": { | |
| ExtractIPFromXFFHeader(TrustIPRange(ipForRemoteAddrExternalRange)), | |
| map[string]string{ | |
| ipTestReqKeyNoHeader: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyRealIPAndXFFExternal: ipForXFF3External, | |
| ipTestReqKeyRealIPAndXFFInternal: ipForXFF3External, | |
| ipTestReqKeyXFFExternal: ipForXFF3External, | |
| ipTestReqKeyXFFInternal: ipForXFF3External, | |
| ipTestReqKeyBrokenXFF: ipForRemoteAddrLoopback, | |
| }, | |
| }, | |
| "ExtractIPFromXFFHeader(trust everything)": { | |
| // This is similar to legacy behavior, but ignores x-real-ip header. | |
| ExtractIPFromXFFHeader(TrustIPRange(ipv4AllRange), TrustIPRange(ipv6AllRange)), | |
| map[string]string{ | |
| ipTestReqKeyNoHeader: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyRealIPAndXFFExternal: ipForXFF6External, | |
| ipTestReqKeyRealIPAndXFFInternal: ipForXFF6External, | |
| ipTestReqKeyXFFExternal: ipForXFF6External, | |
| ipTestReqKeyXFFInternal: ipForXFF6External, | |
| ipTestReqKeyBrokenXFF: ipForRemoteAddrLoopback, | |
| }, | |
| }, | |
| "ExtractIPFromXFFHeader(trust ipForXFF3External)": { | |
| // This trusts private network also after "additional" trust ranges unlike `TrustNProxies(1)` doesn't | |
| ExtractIPFromXFFHeader(TrustIPRange(ipForXFF3ExternalRange)), | |
| map[string]string{ | |
| ipTestReqKeyNoHeader: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPInternal: ipForRemoteAddrLoopback, | |
| ipTestReqKeyRealIPAndXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyRealIPAndXFFInternal: ipForXFF5External, | |
| ipTestReqKeyXFFExternal: ipForRemoteAddrExternal, | |
| ipTestReqKeyXFFInternal: ipForXFF5External, | |
| ipTestReqKeyBrokenXFF: ipForRemoteAddrLoopback, | |
| }, | |
| }, | |
| } | |
| for name, test := range tests { | |
| t.Run(name, func(t *testing.T) { | |
| assert := testify.New(t) | |
| for key, req := range requests { | |
| actual := test.extractor(req) | |
| expected := test.expectedIPs[key] | |
| assert.Equal(expected, actual, "Request: %s", key) | |
| } | |
| }) | |
| } | |
| } |