diff --git a/fileutil/file_test.go b/fileutil/file_test.go index 8bb351d..607fce4 100644 --- a/fileutil/file_test.go +++ b/fileutil/file_test.go @@ -25,6 +25,7 @@ func TestCreateFile(t *testing.T) { f := "./text.txt" if CreateFile(f) { file, err := os.Open(f) + defer file.Close() assert.IsNil(err) assert.Equal(f, file.Name()) } else { @@ -111,6 +112,7 @@ func TestReadFileToString(t *testing.T) { CreateFile(path) f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777) + defer f.Close() f.WriteString("hello world") content, _ := ReadFileToString(path) @@ -218,6 +220,7 @@ func TestMiMeType(t *testing.T) { assert := internal.NewAssert(t, "TestMiMeType") f, _ := os.Open("./file.go") + defer f.Close() assert.Equal("text/plain; charset=utf-8", MiMeType(f)) assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go")) } diff --git a/netutil/net.go b/netutil/net.go index fc735f3..c685ab3 100644 --- a/netutil/net.go +++ b/netutil/net.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "net" "net/http" + "strings" ) // GetInternalIp return internal ipv4 @@ -24,6 +25,26 @@ func GetInternalIp() string { return "" } +// GetRequestPublicIp return the requested public ip +func GetRequestPublicIp(req *http.Request) string { + var ip string + for _, ip = range strings.Split(req.Header.Get("X-Forwarded-For"), ",") { + if ip = strings.TrimSpace(ip); ip != "" && !IsInternalIP(net.ParseIP(ip)) { + return ip + } + } + + if ip = strings.TrimSpace(req.Header.Get("X-Real-Ip")); ip != "" && !IsInternalIP(net.ParseIP(ip)) { + return ip + } + + if ip, _, _ = net.SplitHostPort(req.RemoteAddr); !IsInternalIP(net.ParseIP(ip)) { + return ip + } + + return ip +} + // GetPublicIpInfo return public ip information // return the PublicIpInfo struct func GetPublicIpInfo() (*PublicIpInfo, error) { @@ -122,3 +143,17 @@ func IsPublicIP(IP net.IP) bool { } return false } + +// IsInternalIP verify an ip is intranet or not +func IsInternalIP(IP net.IP) bool { + if IP.IsLoopback() { + return true + } + if ip4 := IP.To4(); ip4 != nil { + return ip4[0] == 10 || + (ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || + (ip4[0] == 169 && ip4[1] == 254) || + (ip4[0] == 192 && ip4[1] == 168) + } + return false +} diff --git a/netutil/net_test.go b/netutil/net_test.go index 9458459..f4fa146 100644 --- a/netutil/net_test.go +++ b/netutil/net_test.go @@ -2,6 +2,7 @@ package netutil import ( "net" + "net/http" "testing" "github.com/duke-git/lancet/v2/internal" @@ -15,6 +16,30 @@ func TestGetInternalIp(t *testing.T) { assert.IsNotNil(ip) } +func TestGetRequestPublicIp(t *testing.T) { + assert := internal.NewAssert(t, "TestGetPublicIpInfo") + + ip := "36.112.24.10" + + request := http.Request{ + Method: "GET", + Header: http.Header{ + "X-Forwarded-For": {ip}, + }, + } + publicIp := GetRequestPublicIp(&request) + assert.Equal(publicIp, ip) + + request = http.Request{ + Method: "GET", + Header: http.Header{ + "X-Real-Ip": {ip}, + }, + } + publicIp = GetRequestPublicIp(&request) + assert.Equal(publicIp, ip) +} + func TestGetPublicIpInfo(t *testing.T) { assert := internal.NewAssert(t, "TestGetPublicIpInfo") @@ -43,6 +68,25 @@ func TestIsPublicIP(t *testing.T) { } } +func TestIsInternalIP(t *testing.T) { + assert := internal.NewAssert(t, "TestIsInternalIP") + + ips := []net.IP{ + net.ParseIP("127.0.0.1"), + net.ParseIP("192.168.0.1"), + net.ParseIP("10.91.210.131"), + net.ParseIP("172.20.16.1"), + net.ParseIP("36.112.24.10"), + } + + expected := []bool{true, true, true, true, false} + + for i := 0; i < len(ips); i++ { + actual := IsInternalIP(ips[i]) + assert.Equal(expected[i], actual) + } +} + func TestGetIps(t *testing.T) { ips := GetIps() t.Log(ips)