feat(适配特性): 适配纯真IP库社区版更新(2024-06-19)地理位置格式

This commit is contained in:
2024-06-20 00:38:19 +08:00
parent 26b587798e
commit 25daf60573
5 changed files with 98 additions and 45 deletions

View File

@@ -5,7 +5,6 @@ Golang QQWry高性能纯真IP查询库。
# 使用须知 # 使用须知
1. 仅支持ipv4查询。 1. 仅支持ipv4查询。
2. city也可能是国家。
# 使用说明 # 使用说明
@@ -13,8 +12,8 @@ Golang QQWry高性能纯真IP查询库。
package main package main
import ( import (
"fmt"
"github.com/xiaoqidun/qqwry" "github.com/xiaoqidun/qqwry"
"log"
) )
func main() { func main() {
@@ -23,8 +22,18 @@ func main() {
panic(err) panic(err)
} }
// 从内存或缓存查询IP // 从内存或缓存查询IP
city, isp, err := qqwry.QueryIP("1.1.1.1") location, err := qqwry.QueryIP("119.29.29.29")
log.Printf("城市:%s运营商%s错误%v", city, isp, err) if err != nil {
fmt.Printf("错误:%v\n", err)
return
}
fmt.Printf("国家:%s省份%s城市%s区县%s运营商%s\n",
location.Country,
location.Province,
location.City,
location.District,
location.ISP,
)
} }
``` ```
@@ -42,7 +51,7 @@ func main() {
1. 自行根据需要调整server下源码。 1. 自行根据需要调整server下源码。
2. 可以通过-listen参数指定http服务地址。 2. 可以通过-listen参数指定http服务地址。
3. json apicurl http://127.0.0.1/ip/1.1.1.1 3. json apicurl http://127.0.0.1/ip/119.29.29.29
# 特别感谢 # 特别感谢

View File

@@ -16,10 +16,22 @@ func main() {
return return
} }
queryIp := os.Args[1] queryIp := os.Args[1]
city, isp, err := qqwry.QueryIP(queryIp) location, err := qqwry.QueryIP(queryIp)
if err != nil { if err != nil {
fmt.Printf("错误:%v\n", err) fmt.Printf("错误:%v\n", err)
return return
} }
fmt.Printf("城市:%s运营商%s\n", city, isp) emptyVal := func(val string) string {
if val != "" {
return val
}
return "未知"
}
fmt.Printf("国家:%s省份%s城市%s区县%s运营商%s\n",
emptyVal(location.Country),
emptyVal(location.Province),
emptyVal(location.City),
emptyVal(location.District),
emptyVal(location.ISP),
)
} }

View File

@@ -16,7 +16,7 @@ import (
var ( var (
data []byte data []byte
dataLen uint32 dataLen uint32
ipCache = &sync.Map{} locationCache = &sync.Map{}
) )
const ( const (
@@ -25,9 +25,13 @@ const (
redirectMode2 = 0x02 redirectMode2 = 0x02
) )
type cache struct { type Location struct {
City string Country string // 国家
Isp string Province string // 省份
City string // 城市
District string // 区县
ISP string // 运营商
IP string // IP地址
} }
func byte3ToUInt32(data []byte) uint32 { func byte3ToUInt32(data []byte) uint32 {
@@ -45,16 +49,13 @@ func gb18030Decode(src []byte) string {
} }
// QueryIP 从内存或缓存查询IP // QueryIP 从内存或缓存查询IP
func QueryIP(queryIp string) (city string, isp string, err error) { func QueryIP(ipv4 string) (location *Location, err error) {
if v, ok := ipCache.Load(queryIp); ok { if v, ok := locationCache.Load(ipv4); ok {
city = v.(cache).City return v.(*Location), nil
isp = v.(cache).Isp
return
} }
ip := net.ParseIP(queryIp).To4() ip := net.ParseIP(ipv4).To4()
if ip == nil { if ip == nil {
err = errors.New("ip is not ipv4") return nil, errors.New("ip is not ipv4")
return
} }
ip32 := binary.BigEndian.Uint32(ip) ip32 := binary.BigEndian.Uint32(ip)
posA := binary.LittleEndian.Uint32(data[:4]) posA := binary.LittleEndian.Uint32(data[:4])
@@ -84,12 +85,12 @@ func QueryIP(queryIp string) (city string, isp string, err error) {
} }
} }
if offset <= 0 { if offset <= 0 {
err = errors.New("ip not found") return nil, errors.New("ip not found")
return
} }
posM := offset + 4 posM := offset + 4
mode := data[posM] mode := data[posM]
var ispPos uint32 var ispPos uint32
var addr, isp string
switch mode { switch mode {
case redirectMode1: case redirectMode1:
posC := byte3ToUInt32(data[posM+1 : posM+4]) posC := byte3ToUInt32(data[posM+1 : posM+4])
@@ -101,19 +102,19 @@ func QueryIP(queryIp string) (city string, isp string, err error) {
} }
for i := posCA; i < dataLen; i++ { for i := posCA; i < dataLen; i++ {
if data[i] == 0 { if data[i] == 0 {
city = string(data[posCA:i]) addr = string(data[posCA:i])
break break
} }
} }
if mode != redirectMode2 { if mode != redirectMode2 {
posC += uint32(len(city) + 1) posC += uint32(len(addr) + 1)
} }
ispPos = posC ispPos = posC
case redirectMode2: case redirectMode2:
posCA := byte3ToUInt32(data[posM+1 : posM+4]) posCA := byte3ToUInt32(data[posM+1 : posM+4])
for i := posCA; i < dataLen; i++ { for i := posCA; i < dataLen; i++ {
if data[i] == 0 { if data[i] == 0 {
city = string(data[posCA:i]) addr = string(data[posCA:i])
break break
} }
} }
@@ -122,14 +123,14 @@ func QueryIP(queryIp string) (city string, isp string, err error) {
posCA := offset + 4 posCA := offset + 4
for i := posCA; i < dataLen; i++ { for i := posCA; i < dataLen; i++ {
if data[i] == 0 { if data[i] == 0 {
city = string(data[posCA:i]) addr = string(data[posCA:i])
break break
} }
} }
ispPos = offset + uint32(5+len(city)) ispPos = offset + uint32(5+len(addr))
} }
if city != "" { if addr != "" {
city = strings.TrimSpace(gb18030Decode([]byte(city))) addr = strings.TrimSpace(gb18030Decode([]byte(addr)))
} }
ispMode := data[ispPos] ispMode := data[ispPos]
if ispMode == redirectMode1 || ispMode == redirectMode2 { if ispMode == redirectMode1 || ispMode == redirectMode2 {
@@ -150,8 +151,9 @@ func QueryIP(queryIp string) (city string, isp string, err error) {
} }
} }
} }
ipCache.Store(queryIp, cache{City: city, Isp: isp}) location = SplitResult(addr, isp, ipv4)
return locationCache.Store(ipv4, location)
return location, nil
} }
// LoadData 从内存加载IP数据库 // LoadData 从内存加载IP数据库
@@ -169,3 +171,22 @@ func LoadFile(filepath string) (err error) {
dataLen = uint32(len(data)) dataLen = uint32(len(data))
return return
} }
// SplitResult 按照调整后的纯真社区版IP库地理位置格式返回结果
func SplitResult(addr string, isp string, ipv4 string) (location *Location) {
location = &Location{ISP: isp, IP: ipv4}
splitList := strings.Split(addr, "")
for i := 0; i < len(splitList); i++ {
switch i {
case 0:
location.Country = splitList[i]
case 1:
location.Province = splitList[i]
case 2:
location.City = splitList[i]
case 3:
location.District = splitList[i]
}
}
return
}

View File

@@ -11,10 +11,22 @@ func init() {
} }
func TestQueryIP(t *testing.T) { func TestQueryIP(t *testing.T) {
queryIp := "1.1.1.1" queryIp := "119.29.29.29"
city, isp, err := QueryIP(queryIp) location, err := QueryIP(queryIp)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Logf("城市:%s运营商%s", city, isp) emptyVal := func(val string) string {
if val != "" {
return val
}
return "未知"
}
t.Logf("国家:%s省份%s城市%s区县%s运营商%s",
emptyVal(location.Country),
emptyVal(location.Province),
emptyVal(location.City),
emptyVal(location.District),
emptyVal(location.ISP),
)
} }

View File

@@ -10,10 +10,9 @@ import (
) )
type resp struct { type resp struct {
IP string `json:"ip"` Data *qqwry.Location `json:"data"`
Err string `json:"err"` Success bool `json:"success"`
City string `json:"city"` Message string `json:"message"`
Isp string `json:"isp"`
} }
func init() { func init() {
@@ -34,14 +33,14 @@ func IpAPI(writer http.ResponseWriter, request *http.Request) {
if ip == "" { if ip == "" {
ip, _, _ = net.SplitHostPort(request.RemoteAddr) ip, _, _ = net.SplitHostPort(request.RemoteAddr)
} }
rw := &resp{IP: ip} write := &resp{}
city, isp, err := qqwry.QueryIP(ip) location, err := qqwry.QueryIP(ip)
if err != nil { if err != nil {
rw.Err = err.Error() write.Message = err.Error()
} else { } else {
rw.City = city write.Data = location
rw.Isp = isp write.Success = true
} }
b, _ := json.MarshalIndent(rw, "", " ") b, _ := json.MarshalIndent(write, "", " ")
_, _ = writer.Write(b) _, _ = writer.Write(b)
} }