diff --git a/.gitignore b/.gitignore index f953780..396af34 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .vscode/ .devcontainer/ assets/qqwry.dat +assets/qqwry.ipdb \ No newline at end of file diff --git a/README.md b/README.md index 3bad693..14033e7 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,8 @@ func main() { # IP数据库 -- [https://aite.xyz/share-file/qqwry/qqwry.dat](https://aite.xyz/share-file/qqwry/qqwry.dat) +- DAT格式:[https://aite.xyz/share-file/qqwry/qqwry.dat](https://aite.xyz/share-file/qqwry/qqwry.dat) +- IPDB格式:[https://aite.xyz/share-file/qqwry/qqwry.ipdb](https://aite.xyz/share-file/qqwry/qqwry.ipdb) # 编译说明 @@ -47,6 +48,11 @@ func main() { 2. client和server需要go1.16的内嵌资源特性。 3. 作为库使用,请直接引包,并不需要go1.16+才能编译。 +# 数据更新 + +- 由于qqwry.dat缺乏更新,官方czdb格式又难以获得和分发,建议使用ipdb格式。 +- 这里的ipdb格式指metowolf提供的官方czdb格式转换而来的ipdb格式(纯真格式原版)。 + # 服务接口 1. 自行根据需要调整server下源码。 @@ -57,6 +63,7 @@ func main() { - 感谢[纯真IP库](https://www.cz88.net/)一直坚持为大家提供免费IP数据库。 - 感谢[yinheli](https://github.com/yinheli)的[qqwry](https://github.com/yinheli/qqwry)项目,为我提供纯真ip库解析算法参考。 +- 感谢[metowolf](https://github.com/metowolf)的[qqwry.ipdb](https://github.com/metowolf/qqwry.ipdb)项目,提供纯真czdb转ipdb数据库。 # 授权说明 diff --git a/assets/assets.go b/assets/assets.go index 0c022de..1beb4bd 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -4,3 +4,6 @@ import _ "embed" //go:embed qqwry.dat var QQWryDat []byte + +//go:embed qqwry.ipdb +var QQWryIpdb []byte diff --git a/client/client.go b/client/client.go index 9d995af..aac7ea7 100644 --- a/client/client.go +++ b/client/client.go @@ -8,7 +8,7 @@ import ( ) func init() { - qqwry.LoadData(assets.QQWryDat) + qqwry.LoadData(assets.QQWryIpdb) } func main() { diff --git a/go.mod b/go.mod index 3d06870..a3150f1 100644 --- a/go.mod +++ b/go.mod @@ -3,3 +3,5 @@ module github.com/xiaoqidun/qqwry go 1.20 require golang.org/x/text v0.21.0 + +require github.com/ipipdotnet/ipdb-go v1.3.3 diff --git a/go.sum b/go.sum index 0d8f5b2..099ed79 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ +github.com/ipipdotnet/ipdb-go v1.3.3 h1:GLSAW9ypLUd6EF9QNK2Uhxew9Jzs4XMJ9gOZEFnJm7U= +github.com/ipipdotnet/ipdb-go v1.3.3/go.mod h1:yZ+8puwe3R37a/3qRftXo40nZVQbxYDLqls9o5foexs= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= diff --git a/qqwry.go b/qqwry.go index a487b07..e800a35 100644 --- a/qqwry.go +++ b/qqwry.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "errors" + "github.com/ipipdotnet/ipdb-go" "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" "io" @@ -16,9 +17,16 @@ import ( var ( data []byte dataLen uint32 + ipdbCity *ipdb.City + dataType = dataTypeDat locationCache = &sync.Map{} ) +const ( + dataTypeDat = 0 + dataTypeIpdb = 1 +) + const ( indexLen = 7 redirectMode1 = 0x01 @@ -49,10 +57,22 @@ func gb18030Decode(src []byte) string { } // QueryIP 从内存或缓存查询IP -func QueryIP(ipv4 string) (location *Location, err error) { - if v, ok := locationCache.Load(ipv4); ok { +func QueryIP(ip string) (location *Location, err error) { + if v, ok := locationCache.Load(ip); ok { return v.(*Location), nil } + switch dataType { + case dataTypeDat: + return QueryIPDat(ip) + case dataTypeIpdb: + return QueryIPIpdb(ip) + default: + return nil, errors.New("data type not support") + } +} + +// QueryIPDat 从dat查询IP,仅加载dat格式数据库时使用 +func QueryIPDat(ipv4 string) (location *Location, err error) { ip := net.ParseIP(ipv4).To4() if ip == nil { return nil, errors.New("ip is not ipv4") @@ -156,19 +176,39 @@ func QueryIP(ipv4 string) (location *Location, err error) { return location, nil } +// QueryIPIpdb 从ipdb查询IP,仅加载ipdb格式数据库时使用 +func QueryIPIpdb(ip string) (location *Location, err error) { + ret, err := ipdbCity.Find(ip, "CN") + if err != nil { + return + } + location = SplitResult(ret[0], ret[1], ip) + locationCache.Store(ip, location) + return location, nil +} + // LoadData 从内存加载IP数据库 func LoadData(database []byte) { + if string(database[6:11]) == "build" { + dataType = dataTypeIpdb + loadCity, err := ipdb.NewCityFromBytes(database) + if err != nil { + panic(err) + } + ipdbCity = loadCity + return + } data = database dataLen = uint32(len(data)) } // LoadFile 从文件加载IP数据库 func LoadFile(filepath string) (err error) { - data, err = os.ReadFile(filepath) + body, err := os.ReadFile(filepath) if err != nil { return } - dataLen = uint32(len(data)) + LoadData(body) return } diff --git a/qqwry_test.go b/qqwry_test.go index 5b7d7ed..365e042 100644 --- a/qqwry_test.go +++ b/qqwry_test.go @@ -5,7 +5,7 @@ import ( ) func init() { - if err := LoadFile("assets/qqwry.dat"); err != nil { + if err := LoadFile("assets/qqwry.ipdb"); err != nil { panic(err) } } diff --git a/server/server.go b/server/server.go index 0a30a75..6be73df 100644 --- a/server/server.go +++ b/server/server.go @@ -16,7 +16,7 @@ type resp struct { } func init() { - qqwry.LoadData(assets.QQWryDat) + qqwry.LoadData(assets.QQWryIpdb) } func main() {