diff options
Diffstat (limited to 'vendor/github.com/tomasen')
-rw-r--r-- | vendor/github.com/tomasen/realip/.travis.yml | 2 | ||||
-rw-r--r-- | vendor/github.com/tomasen/realip/README.md | 25 | ||||
-rw-r--r-- | vendor/github.com/tomasen/realip/realip.go | 100 | ||||
-rw-r--r-- | vendor/github.com/tomasen/realip/realip_test.go | 75 |
4 files changed, 121 insertions, 81 deletions
diff --git a/vendor/github.com/tomasen/realip/.travis.yml b/vendor/github.com/tomasen/realip/.travis.yml index 9c90009..fdfbf87 100644 --- a/vendor/github.com/tomasen/realip/.travis.yml +++ b/vendor/github.com/tomasen/realip/.travis.yml @@ -1,8 +1,6 @@ language: go go: - - 1.4 - - 1.5 - tip before_install: diff --git a/vendor/github.com/tomasen/realip/README.md b/vendor/github.com/tomasen/realip/README.md index 3eea89a..085f182 100644 --- a/vendor/github.com/tomasen/realip/README.md +++ b/vendor/github.com/tomasen/realip/README.md @@ -1,12 +1,27 @@ -a golang library that can get client's real public ip address from http request headers +# RealIP -[![Build Status](https://travis-ci.org/tomasen/realip.svg?branch=master)](https://travis-ci.org/Tomasen/realip) [![GoDoc](https://godoc.org/github.com/Tomasen/realip?status.svg)](http://godoc.org/github.com/Tomasen/realip) +Go package that can be used to get client's real public IP, which usually useful for logging HTTP server. -* follow the rule of X-FORWARDED-FOR/rfc7239 -* follow the rule of X-Real-Ip -* lan/intranet IP address filtered +### Feature + +* Follows the rule of X-Real-IP +* Follows the rule of X-Forwarded-For +* Exclude local or private address + +## Example + +```go +package main + +import "github.com/Tomasen/realip" + +func (h *Handler) ServeIndexPage(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + clientIP := realip.FromRequest(r) + log.Println("GET / from", clientIP) +} +``` ## Developing diff --git a/vendor/github.com/tomasen/realip/realip.go b/vendor/github.com/tomasen/realip/realip.go index 09ed74d..e2803a2 100644 --- a/vendor/github.com/tomasen/realip/realip.go +++ b/vendor/github.com/tomasen/realip/realip.go @@ -1,7 +1,7 @@ package realip import ( - "log" + "errors" "net" "net/http" "strings" @@ -10,62 +10,80 @@ import ( var cidrs []*net.IPNet func init() { - lancidrs := []string{ - "127.0.0.1/8", "10.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", + maxCidrBlocks := []string{ + "127.0.0.1/8", // localhost + "10.0.0.0/8", // 24-bit block + "172.16.0.0/12", // 20-bit block + "192.168.0.0/16", // 16-bit block + "169.254.0.0/16", // link local address + "::1/128", // localhost IPv6 + "fc00::/7", // unique local address IPv6 + "fe80::/10", // link local address IPv6 } - cidrs = make([]*net.IPNet, len(lancidrs)) - - for i, it := range lancidrs { - _, cidrnet, err := net.ParseCIDR(it) - if err != nil { - log.Fatalf("ParseCIDR error: %v", err) // assuming I did it right above - } - - cidrs[i] = cidrnet + cidrs = make([]*net.IPNet, len(maxCidrBlocks)) + for i, maxCidrBlock := range maxCidrBlocks { + _, cidr, _ := net.ParseCIDR(maxCidrBlock) + cidrs[i] = cidr } } -func isLocalAddress(addr string) bool { +// isLocalAddress works by checking if the address is under private CIDR blocks. +// List of private CIDR blocks can be seen on : +// +// https://en.wikipedia.org/wiki/Private_network +// +// https://en.wikipedia.org/wiki/Link-local_address +func isPrivateAddress(address string) (bool, error) { + ipAddress := net.ParseIP(address) + if ipAddress == nil { + return false, errors.New("address is not valid") + } + for i := range cidrs { - myaddr := net.ParseIP(addr) - if cidrs[i].Contains(myaddr) { - return true + if cidrs[i].Contains(ipAddress) { + return true, nil } } - return false + return false, nil } -// Request.RemoteAddress contains port, which we want to remove i.e.: -// "[::1]:58292" => "[::1]" -func ipAddrFromRemoteAddr(s string) string { - idx := strings.LastIndex(s, ":") - if idx == -1 { - return s - } - return s[:idx] -} +// FromRequest return client's real public IP address from http request headers. +func FromRequest(r *http.Request) string { + // Fetch header value + xRealIP := r.Header.Get("X-Real-Ip") + xForwardedFor := r.Header.Get("X-Forwarded-For") -// RealIP return client's real public IP address -// from http request headers. -func RealIP(r *http.Request) string { - hdr := r.Header - hdrRealIP := hdr.Get("X-Real-Ip") - hdrForwardedFor := hdr.Get("X-Forwarded-For") + // If both empty, return IP from remote address + if xRealIP == "" && xForwardedFor == "" { + var remoteIP string + + // If there are colon in remote address, remove the port number + // otherwise, return remote address as is + if strings.ContainsRune(r.RemoteAddr, ':') { + remoteIP, _, _ = net.SplitHostPort(r.RemoteAddr) + } else { + remoteIP = r.RemoteAddr + } - if len(hdrForwardedFor) == 0 && len(hdrRealIP) == 0 { - return ipAddrFromRemoteAddr(r.RemoteAddr) + return remoteIP } - // X-Forwarded-For is potentially a list of addresses separated with "," - for _, addr := range strings.Split(hdrForwardedFor, ",") { - // return first non-local address - addr = strings.TrimSpace(addr) - if len(addr) > 0 && !isLocalAddress(addr) { - return addr + // Check list of IP in X-Forwarded-For and return the first global address + for _, address := range strings.Split(xForwardedFor, ",") { + address = strings.TrimSpace(address) + isPrivate, err := isPrivateAddress(address) + if !isPrivate && err == nil { + return address } } - return hdrRealIP + // If nothing succeed, return X-Real-IP + return xRealIP +} + +// RealIP is depreciated, use FromRequest instead +func RealIP(r *http.Request) string { + return FromRequest(r) } diff --git a/vendor/github.com/tomasen/realip/realip_test.go b/vendor/github.com/tomasen/realip/realip_test.go index e301ee8..e80efe0 100644 --- a/vendor/github.com/tomasen/realip/realip_test.go +++ b/vendor/github.com/tomasen/realip/realip_test.go @@ -2,11 +2,10 @@ package realip import ( "net/http" - "strings" "testing" ) -func TestIsLocalAddr(t *testing.T) { +func TestIsPrivateAddr(t *testing.T) { testData := map[string]bool{ "127.0.0.0": true, "10.0.0.0": true, @@ -24,7 +23,12 @@ func TestIsLocalAddr(t *testing.T) { } for addr, isLocal := range testData { - if isLocalAddress(addr) != isLocal { + isPrivate, err := isPrivateAddress(addr) + if err != nil { + t.Errorf("fail processing %s: %v", addr, err) + } + + if isPrivate != isLocal { format := "%s should " if !isLocal { format += "not " @@ -36,51 +40,56 @@ func TestIsLocalAddr(t *testing.T) { } } -func TestIpAddrFromRemoteAddr(t *testing.T) { - testData := map[string]string{ - "127.0.0.1:8888": "127.0.0.1", - "ip:port": "ip", - "ip": "ip", - "12:34::0": "12:34:", +func TestRealIP(t *testing.T) { + // Create type and function for testing + type testIP struct { + name string + request *http.Request + expected string } - for remoteAddr, expectedAddr := range testData { - if actualAddr := ipAddrFromRemoteAddr(remoteAddr); actualAddr != expectedAddr { - t.Errorf("ipAddrFromRemoteAddr of %s should be %s but get %s", remoteAddr, expectedAddr, actualAddr) + newRequest := func(remoteAddr, xRealIP string, xForwardedFor ...string) *http.Request { + h := http.Header{} + h.Set("X-Real-IP", xRealIP) + for _, address := range xForwardedFor { + h.Set("X-Forwarded-For", address) } - } -} -func TestRealIP(t *testing.T) { - newRequest := func(remoteAddr, hdrRealIP, hdrForwardedFor string) *http.Request { - h := http.Header{} - h["X-Real-Ip"] = []string{hdrRealIP} - h["X-Forwarded-For"] = []string{hdrForwardedFor} return &http.Request{ RemoteAddr: remoteAddr, Header: h, } } - remoteAddr := "144.12.54.87" - anotherRemoteAddr := "119.14.55.11" + // Create test data + publicAddr1 := "144.12.54.87" + publicAddr2 := "119.14.55.11" localAddr := "127.0.0.0" - testData := []struct { - expected string - request *http.Request - }{ - {remoteAddr, newRequest(remoteAddr, "", "")}, // no header - {remoteAddr, newRequest("", "", remoteAddr)}, // X-Forwarded-For: remoteAddr - {remoteAddr, newRequest("", remoteAddr, "")}, // X-RealIP: remoteAddr - - // X-Forwarded-For: localAddr, remoteAddr, anotherRemoteAddr - {remoteAddr, newRequest("", "", strings.Join([]string{localAddr, remoteAddr, anotherRemoteAddr}, ", "))}, + testData := []testIP{ + { + name: "No header", + request: newRequest(publicAddr1, ""), + expected: publicAddr1, + }, { + name: "Has X-Forwarded-For", + request: newRequest("", "", publicAddr1), + expected: publicAddr1, + }, { + name: "Has multiple X-Forwarded-For", + request: newRequest("", "", localAddr, publicAddr1, publicAddr2), + expected: publicAddr2, + }, { + name: "Has X-Real-IP", + request: newRequest("", publicAddr1), + expected: publicAddr1, + }, } + // Run test for _, v := range testData { - if actual := RealIP(v.request); v.expected != actual { - t.Errorf("expected %s but get %s", v.expected, actual) + if actual := FromRequest(v.request); v.expected != actual { + t.Errorf("%s: expected %s but get %s", v.name, v.expected, actual) } } } |