From 05fd83bd6fe68ff0f5491cead091501cf5848e58 Mon Sep 17 00:00:00 2001 From: y0ast Date: Sun, 7 Feb 2021 21:50:06 +0000 Subject: [PATCH] add support for ipv6 with zone index --- http/request/client_ip.go | 16 ++++++++++++---- http/request/client_ip_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/http/request/client_ip.go b/http/request/client_ip.go index 27fb64e2..22086081 100644 --- a/http/request/client_ip.go +++ b/http/request/client_ip.go @@ -10,6 +10,14 @@ import ( "strings" ) +func dropIPv6zone(address string) string { + i := strings.IndexByte(address, '%') + if i != -1 { + address = address[:i] + } + return address +} + // FindClientIP returns client real IP address. func FindClientIP(r *http.Request) string { headers := []string{"X-Forwarded-For", "X-Real-Ip"} @@ -19,6 +27,7 @@ func FindClientIP(r *http.Request) string { if value != "" { addresses := strings.Split(value, ",") address := strings.TrimSpace(addresses[0]) + address = dropIPv6zone(address) if net.ParseIP(address) != nil { return address @@ -27,12 +36,11 @@ func FindClientIP(r *http.Request) string { } // Fallback to TCP/IP source IP address. - var remoteIP string - if strings.ContainsRune(r.RemoteAddr, ':') { - remoteIP, _, _ = net.SplitHostPort(r.RemoteAddr) - } else { + remoteIP, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { remoteIP = r.RemoteAddr } + remoteIP = dropIPv6zone(remoteIP) // When listening on a Unix socket, RemoteAddr is empty. if remoteIP == "" { diff --git a/http/request/client_ip_test.go b/http/request/client_ip_test.go index 82f7dd63..714b0dcd 100644 --- a/http/request/client_ip_test.go +++ b/http/request/client_ip_test.go @@ -19,6 +19,21 @@ func TestFindClientIPWithoutHeaders(t *testing.T) { if ip := FindClientIP(r); ip != "192.168.0.1" { t.Fatalf(`Unexpected result, got: %q`, ip) } + + r = &http.Request{RemoteAddr: "fe80::14c2:f039:edc7:edc7"} + if ip := FindClientIP(r); ip != "fe80::14c2:f039:edc7:edc7" { + t.Fatalf(`Unexpected result, got: %q`, ip) + } + + r = &http.Request{RemoteAddr: "fe80::14c2:f039:edc7:edc7%eth0"} + if ip := FindClientIP(r); ip != "fe80::14c2:f039:edc7:edc7" { + t.Fatalf(`Unexpected result, got: %q`, ip) + } + + r = &http.Request{RemoteAddr: "[fe80::14c2:f039:edc7:edc7%eth0]:4242"} + if ip := FindClientIP(r); ip != "fe80::14c2:f039:edc7:edc7" { + t.Fatalf(`Unexpected result, got: %q`, ip) + } } func TestFindClientIPWithXFFHeader(t *testing.T) { @@ -40,6 +55,15 @@ func TestFindClientIPWithXFFHeader(t *testing.T) { t.Fatalf(`Unexpected result, got: %q`, ip) } + // Test with single IPv6 address with zone + headers = http.Header{} + headers.Set("X-Forwarded-For", "fe80::14c2:f039:edc7:edc7%eth0") + r = &http.Request{RemoteAddr: "192.168.0.1:4242", Header: headers} + + if ip := FindClientIP(r); ip != "fe80::14c2:f039:edc7:edc7" { + t.Fatalf(`Unexpected result, got: %q`, ip) + } + // Test with single IPv4 address. headers = http.Header{} headers.Set("X-Forwarded-For", "70.41.3.18")