-
Notifications
You must be signed in to change notification settings - Fork 563
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from alimy/master
优化查找IP地址信息的逻辑
- Loading branch information
Showing
6 changed files
with
157 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,8 @@ | ||
package util | ||
|
||
import ( | ||
"github.com/yinheli/qqwry" | ||
) | ||
import "github.com/rocboss/paopao-ce/pkg/util/iploc" | ||
|
||
func GetIPLoc(ip string) string { | ||
q := qqwry.NewQQwry("qqwry.dat") | ||
q.Find(ip) | ||
|
||
return q.Country | ||
country, _ := iploc.Find(ip) | ||
return country | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package iploc | ||
|
||
import ( | ||
_ "embed" | ||
"encoding/binary" | ||
"net" | ||
|
||
"github.com/yinheli/mahonia" | ||
) | ||
|
||
// Note: This file is a modified version of https://github.com/yinheli/qqwry. | ||
|
||
//go:embed qqwry.dat | ||
var qqwry []byte | ||
|
||
const ( | ||
cIndexLen = 7 | ||
cRedirectMode1 = 0x01 | ||
cRedirectMode2 = 0x02 | ||
) | ||
|
||
// Find get country and city base ip | ||
func Find(ip string) (string, string) { | ||
offset := searchIndex(binary.BigEndian.Uint32(net.ParseIP(ip).To4())) | ||
if offset <= 0 { | ||
return "", "" | ||
} | ||
var country, area []byte | ||
mode := readMode(offset + 4) | ||
if mode == cRedirectMode1 { | ||
countryOffset := readUInt24(offset + 5) | ||
mode = readMode(countryOffset) | ||
if mode == cRedirectMode2 { | ||
c := readUInt24(countryOffset + 1) | ||
country = readString(c) | ||
countryOffset += 4 | ||
} else { | ||
country = readString(countryOffset) | ||
countryOffset += uint32(len(country) + 1) | ||
} | ||
area = readArea(countryOffset) | ||
} else if mode == cRedirectMode2 { | ||
countryOffset := readUInt24(offset + 5) | ||
country = readString(countryOffset) | ||
area = readArea(offset + 8) | ||
} else { | ||
country = readString(offset + 4) | ||
area = readArea(offset + uint32(5+len(country))) | ||
} | ||
enc := mahonia.NewDecoder("gbk") | ||
Country := enc.ConvertString(string(country)) | ||
City := enc.ConvertString(string(area)) | ||
return Country, City | ||
} | ||
|
||
func readMode(offset uint32) byte { | ||
return qqwry[offset] | ||
} | ||
|
||
func readArea(offset uint32) []byte { | ||
mode := readMode(offset) | ||
if mode == cRedirectMode1 || mode == cRedirectMode2 { | ||
areaOffset := readUInt24(offset + 1) | ||
if areaOffset == 0 { | ||
return []byte("") | ||
} else { | ||
return readString(areaOffset) | ||
} | ||
} else { | ||
return readString(offset) | ||
} | ||
} | ||
|
||
func readString(offset uint32) []byte { | ||
data := make([]byte, 0, 30) | ||
for { | ||
if qqwry[offset] == 0 { | ||
break | ||
} | ||
data = append(data, qqwry[offset]) | ||
offset++ | ||
} | ||
return data | ||
} | ||
|
||
func searchIndex(ip uint32) uint32 { | ||
header := qqwry[:8] | ||
start := binary.LittleEndian.Uint32(header[:4]) | ||
end := binary.LittleEndian.Uint32(header[4:]) | ||
for { | ||
mid := getMiddleOffset(start, end) | ||
buf := qqwry[mid : mid+cIndexLen] | ||
ipaddr := binary.LittleEndian.Uint32(buf[:4]) | ||
if end-start == cIndexLen { | ||
offset := byte3ToUInt32(buf[4:]) | ||
// TODO: 这里可能有bug,需要优化 | ||
if ip < binary.LittleEndian.Uint32(qqwry[end:end+4]) { | ||
return offset | ||
} else { | ||
return 0 | ||
} | ||
} | ||
// 找到的比较大,向前移 | ||
if ipaddr > ip { | ||
end = mid | ||
} else if ipaddr < ip { // 找到的比较小,向后移 | ||
start = mid | ||
} else { | ||
return byte3ToUInt32(buf[4:]) | ||
} | ||
} | ||
} | ||
|
||
func readUInt24(offset uint32) uint32 { | ||
return byte3ToUInt32(qqwry[offset : offset+3]) | ||
} | ||
|
||
func getMiddleOffset(start uint32, end uint32) uint32 { | ||
records := ((end - start) / cIndexLen) >> 1 | ||
return start + records*cIndexLen | ||
} | ||
|
||
func byte3ToUInt32(data []byte) uint32 { | ||
i := uint32(data[0]) & 0xff | ||
i |= (uint32(data[1]) << 8) & 0xff00 | ||
i |= (uint32(data[2]) << 16) & 0xff0000 | ||
return i | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package iploc | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestFind(t *testing.T) { | ||
for _, data := range []struct { | ||
ip string | ||
country string | ||
city string | ||
}{ | ||
{ip: "127.0.0.1", country: "本机地址", city: " CZ88.NET"}, | ||
{ip: "180.89.94.9", country: "北京市", city: "鹏博士宽带"}, | ||
} { | ||
country, city := Find(data.ip) | ||
t.Logf("ip:%v, country:%v, city:%v", data.ip, country, city) | ||
if country != data.country { | ||
t.Errorf("find ip:%s expect country: %s got: %s", data.ip, data.country, country) | ||
} | ||
if city != data.city { | ||
t.Errorf("find ip:%s expect city: %s got: %s", data.ip, data.city, city) | ||
} | ||
} | ||
} |
File renamed without changes.