Skip to content

Commit a90ace4

Browse files
authored
Merge pull request #193 from Nextra/fix-ipv6
2 parents 22ad092 + fa0811e commit a90ace4

2 files changed

Lines changed: 46 additions & 17 deletions

File tree

http/http.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,19 @@ func ipFromRequest(headers []string, r *http.Request, customIP bool) (net.IP, er
101101
if remoteIP == "" {
102102
remoteIP = r.RemoteAddr
103103
}
104-
sep := strings.Index(remoteIP, ":")
105-
if sep != -1 {
106-
host, _, err := net.SplitHostPort(remoteIP)
107-
if err != nil {
108-
return nil, err
109-
}
110-
remoteIP = host
111-
}
112104
ip := net.ParseIP(remoteIP)
113105
if ip == nil {
114-
return nil, fmt.Errorf("could not parse IP: %s", remoteIP)
106+
if strings.Contains(remoteIP, ":") {
107+
host, _, err := net.SplitHostPort(remoteIP)
108+
if err != nil {
109+
return nil, err
110+
}
111+
remoteIP = host
112+
ip = net.ParseIP(remoteIP)
113+
}
114+
if ip == nil {
115+
return nil, fmt.Errorf("could not parse IP: %s", remoteIP)
116+
}
115117
}
116118
return ip, nil
117119
}

http/http_test.go

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ func lookupAddr(net.IP) (string, error) { return "localhost", nil }
1717
func lookupPort(net.IP, uint64) error { return nil }
1818

1919
type testDb struct{}
20+
type ipTestCase struct {
21+
remoteAddr string
22+
headerKey string
23+
headerValue string
24+
trustedHeaders []string
25+
out string
26+
}
2027

2128
func (t *testDb) Country(net.IP) (geo.Country, error) {
2229
return geo.Country{Name: "Elbonia", ISO: "EB", IsEU: new(bool)}, nil
@@ -209,14 +216,8 @@ func TestCacheResizeHandler(t *testing.T) {
209216
}
210217
}
211218

212-
func TestIPFromRequest(t *testing.T) {
213-
var tests = []struct {
214-
remoteAddr string
215-
headerKey string
216-
headerValue string
217-
trustedHeaders []string
218-
out string
219-
}{
219+
func TestIPv4FromRequest(t *testing.T) {
220+
var tests = []ipTestCase{
220221
{"127.0.0.1:9999", "", "", nil, "127.0.0.1"}, // No header given
221222
{"127.0.0.1:9999", "X-Real-IP", "1.3.3.7", nil, "127.0.0.1"}, // Trusted header is empty
222223
{"127.0.0.1:9999", "X-Real-IP", "1.3.3.7", []string{"X-Foo-Bar"}, "127.0.0.1"}, // Trusted header does not match
@@ -235,6 +236,32 @@ func TestIPFromRequest(t *testing.T) {
235236
{"127.0.0.1:9999?ip=1.2.3.4:1234", "", "", nil, "1.2.3.4"}, // passed in "ip" parameter (with port)
236237
{"127.0.0.1:9999?ip=1.2.3.4:1234", "X-Forwarded-For", "1.3.3.7:1337,4.2.4.2:4242", []string{"X-Forwarded-For"}, "1.2.3.4"}, // ip parameter wins over X-Forwarded-For with multiple entries (with port)
237238
}
239+
testIpFromRequest(t, tests)
240+
}
241+
func TestIPv6FromRequest(t *testing.T) {
242+
var tests = []ipTestCase{
243+
{"[::1]:9999", "", "", nil, "::1"}, // No header given
244+
{"[::1]:9999", "X-Real-IP", "::ffff:103:307", nil, "::1"}, // Trusted header is empty
245+
{"[::1]:9999", "X-Real-IP", "::ffff:103:307", []string{"X-Foo-Bar"}, "::1"}, // Trusted header does not match
246+
{"[::1]:9999", "X-Real-IP", "::ffff:103:307", []string{"X-Real-IP", "X-Forwarded-For"}, "::ffff:103:307"}, // Trusted header matches
247+
{"[::1]:9999", "X-Forwarded-For", "::ffff:103:307", []string{"X-Real-IP", "X-Forwarded-For"}, "::ffff:103:307"}, // Second trusted header matches
248+
{"[::1]:9999", "X-Forwarded-For", "::ffff:103:307,::ffff:402:402", []string{"X-Forwarded-For"}, "::ffff:103:307"}, // X-Forwarded-For with multiple entries (commas separator)
249+
{"[::1]:9999", "X-Forwarded-For", "::ffff:103:307, ::ffff:402:402", []string{"X-Forwarded-For"}, "::ffff:103:307"}, // X-Forwarded-For with multiple entries (space+comma separator)
250+
{"[::1]:9999", "X-Forwarded-For", "", []string{"X-Forwarded-For"}, "::1"}, // Empty header
251+
{"[::1]:9999?ip=::ffff:102:304", "", "", nil, "::ffff:102:304"}, // passed in "ip" parameter
252+
{"[::1]:9999?ip=::ffff:102:304", "X-Forwarded-For", "::ffff:103:307,::ffff:402:402", []string{"X-Forwarded-For"}, "::ffff:102:304"}, // ip parameter wins over X-Forwarded-For with multiple entries
253+
254+
{"[::1]:9999", "X-Real-IP", "[::ffff:103:307]:1337", []string{"X-Real-IP", "X-Forwarded-For"}, "::ffff:103:307"}, // Trusted header matches (with port)
255+
{"[::1]:9999", "X-Forwarded-For", "[::ffff:103:307]:1337", []string{"X-Real-IP", "X-Forwarded-For"}, "::ffff:103:307"}, // Second trusted header matches (with port)
256+
{"[::1]:9999", "X-Forwarded-For", "[::ffff:103:307]:1337,[::ffff:402:402]:4242", []string{"X-Forwarded-For"}, "::ffff:103:307"}, // X-Forwarded-For with multiple entries (commas separator, with port)
257+
{"[::1]:9999", "X-Forwarded-For", "[::ffff:103:307]:1337, [::ffff:402:402]:4242", []string{"X-Forwarded-For"}, "::ffff:103:307"}, // X-Forwarded-For with multiple entries (space+comma separator, with port)
258+
{"[::1]:9999?ip=[::ffff:102:304]:1234", "", "", nil, "::ffff:102:304"}, // passed in "ip" parameter (with port)
259+
{"[::1]:9999?ip=[::ffff:102:304]:1234", "X-Forwarded-For", "[::ffff:103:307]:1337,[::ffff:402:402]:4242", []string{"X-Forwarded-For"}, "::ffff:102:304"}, // ip parameter wins over X-Forwarded-For with multiple entries (with port)
260+
}
261+
testIpFromRequest(t, tests)
262+
}
263+
264+
func testIpFromRequest(t *testing.T, tests []ipTestCase) {
238265
for _, tt := range tests {
239266
u, err := url.Parse("http://" + tt.remoteAddr)
240267
if err != nil {

0 commit comments

Comments
 (0)