2020-07-17 09:05:25 +08:00
|
|
|
package qqwry
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
2020-07-18 09:19:27 +08:00
|
|
|
"github.com/zu1k/nali/pkg/common"
|
2020-07-17 09:05:25 +08:00
|
|
|
"golang.org/x/text/encoding/simplifiedchinese"
|
|
|
|
)
|
|
|
|
|
|
|
|
type QQwry struct {
|
2020-07-18 09:19:27 +08:00
|
|
|
common.IPDB
|
2020-07-17 09:05:25 +08:00
|
|
|
}
|
|
|
|
|
2020-07-18 09:52:59 +08:00
|
|
|
// NewQQwry new db from path
|
|
|
|
func NewQQwry(filePath string) QQwry {
|
2020-07-18 10:48:41 +08:00
|
|
|
var fileData []byte
|
2020-07-18 09:19:27 +08:00
|
|
|
var fileInfo common.FileInfo
|
2020-07-17 09:05:25 +08:00
|
|
|
|
|
|
|
// 判断文件是否存在
|
|
|
|
_, err := os.Stat(filePath)
|
|
|
|
if err != nil && os.IsNotExist(err) {
|
|
|
|
log.Println("文件不存在,尝试从网络获取最新纯真 IP 库")
|
2020-07-18 10:48:41 +08:00
|
|
|
fileData, err = Download()
|
2020-07-17 09:05:25 +08:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
} else {
|
2020-07-18 10:48:41 +08:00
|
|
|
if err := ioutil.WriteFile(filePath, fileData, 0644); err == nil {
|
|
|
|
log.Printf("已将最新的 纯真IP库 保存到本地: %s ", filePath)
|
2020-07-17 09:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// 打开文件句柄
|
|
|
|
fileInfo.FileBase, err = os.OpenFile(filePath, os.O_RDONLY, 0400)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
defer fileInfo.FileBase.Close()
|
|
|
|
|
2020-07-18 10:48:41 +08:00
|
|
|
fileData, err = ioutil.ReadAll(fileInfo.FileBase)
|
2020-07-17 09:05:25 +08:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
2020-07-18 10:48:41 +08:00
|
|
|
fileInfo.Data = fileData
|
2020-07-17 09:05:25 +08:00
|
|
|
|
|
|
|
buf := fileInfo.Data[0:8]
|
|
|
|
start := binary.LittleEndian.Uint32(buf[:4])
|
|
|
|
end := binary.LittleEndian.Uint32(buf[4:])
|
|
|
|
|
2020-07-18 09:52:59 +08:00
|
|
|
return QQwry{
|
|
|
|
IPDB: common.IPDB{
|
|
|
|
Data: &fileInfo,
|
|
|
|
IndexLen: 7,
|
|
|
|
IPNum: (end-start)/7 + 1,
|
|
|
|
},
|
2020-07-17 09:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find ip地址查询对应归属地信息
|
2020-07-18 10:48:41 +08:00
|
|
|
func (db QQwry) Find(ip string) (res string) {
|
2020-07-17 09:05:25 +08:00
|
|
|
if strings.Count(ip, ".") != 3 {
|
|
|
|
return
|
|
|
|
}
|
2020-07-18 09:19:27 +08:00
|
|
|
|
|
|
|
ip4 := binary.BigEndian.Uint32(net.ParseIP(ip).To4())
|
|
|
|
|
2020-07-18 10:48:41 +08:00
|
|
|
offset := db.searchIndex(ip4)
|
2020-07-17 09:05:25 +08:00
|
|
|
if offset <= 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var gbkCountry []byte
|
|
|
|
var gbkArea []byte
|
|
|
|
|
2020-07-18 10:48:41 +08:00
|
|
|
mode := db.ReadMode(offset + 4)
|
2020-07-18 09:52:59 +08:00
|
|
|
// [IP][0x01][国家和地区信息的绝对偏移地址]
|
2020-07-18 09:19:27 +08:00
|
|
|
if mode == common.RedirectMode1 {
|
2020-07-18 10:48:41 +08:00
|
|
|
countryOffset := db.ReadUInt24()
|
|
|
|
mode = db.ReadMode(countryOffset)
|
2020-07-18 09:19:27 +08:00
|
|
|
if mode == common.RedirectMode2 {
|
2020-07-18 10:48:41 +08:00
|
|
|
c := db.ReadUInt24()
|
|
|
|
gbkCountry = db.ReadString(c)
|
2020-07-17 09:05:25 +08:00
|
|
|
countryOffset += 4
|
|
|
|
} else {
|
2020-07-18 10:48:41 +08:00
|
|
|
gbkCountry = db.ReadString(countryOffset)
|
2020-07-17 09:05:25 +08:00
|
|
|
countryOffset += uint32(len(gbkCountry) + 1)
|
|
|
|
}
|
2020-07-18 10:48:41 +08:00
|
|
|
gbkArea = db.ReadArea(countryOffset)
|
2020-07-18 09:19:27 +08:00
|
|
|
} else if mode == common.RedirectMode2 {
|
2020-07-18 10:48:41 +08:00
|
|
|
countryOffset := db.ReadUInt24()
|
|
|
|
gbkCountry = db.ReadString(countryOffset)
|
|
|
|
gbkArea = db.ReadArea(offset + 8)
|
2020-07-17 09:05:25 +08:00
|
|
|
} else {
|
2020-07-18 10:48:41 +08:00
|
|
|
gbkCountry = db.ReadString(offset + 4)
|
|
|
|
gbkArea = db.ReadArea(offset + uint32(5+len(gbkCountry)))
|
2020-07-17 09:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
enc := simplifiedchinese.GBK.NewDecoder()
|
|
|
|
country, _ := enc.String(string(gbkCountry))
|
|
|
|
area, _ := enc.String(string(gbkArea))
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s %s", country, area)
|
|
|
|
}
|
|
|
|
|
|
|
|
// searchIndex 查找索引位置
|
2020-07-18 10:48:41 +08:00
|
|
|
func (db *QQwry) searchIndex(ip uint32) uint32 {
|
|
|
|
header := db.ReadData(8, 0)
|
2020-07-17 09:05:25 +08:00
|
|
|
|
|
|
|
start := binary.LittleEndian.Uint32(header[:4])
|
|
|
|
end := binary.LittleEndian.Uint32(header[4:])
|
|
|
|
|
2020-07-18 10:48:41 +08:00
|
|
|
buf := make([]byte, db.IndexLen)
|
2020-07-17 09:05:25 +08:00
|
|
|
mid := uint32(0)
|
|
|
|
_ip := uint32(0)
|
|
|
|
|
|
|
|
for {
|
2020-07-18 10:48:41 +08:00
|
|
|
mid = db.GetMiddleOffset(start, end)
|
|
|
|
buf = db.ReadData(db.IndexLen, mid)
|
2020-07-17 09:05:25 +08:00
|
|
|
_ip = binary.LittleEndian.Uint32(buf[:4])
|
|
|
|
|
2020-07-18 10:48:41 +08:00
|
|
|
if end-start == db.IndexLen {
|
2020-07-18 09:19:27 +08:00
|
|
|
offset := common.ByteToUInt32(buf[4:])
|
2020-07-18 10:48:41 +08:00
|
|
|
buf = db.ReadData(db.IndexLen)
|
2020-07-17 09:05:25 +08:00
|
|
|
if ip < binary.LittleEndian.Uint32(buf[:4]) {
|
|
|
|
return offset
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// 找到的比较大,向前移
|
|
|
|
if _ip > ip {
|
|
|
|
end = mid
|
|
|
|
} else if _ip < ip { // 找到的比较小,向后移
|
|
|
|
start = mid
|
|
|
|
} else if _ip == ip {
|
2020-07-18 09:19:27 +08:00
|
|
|
return common.ByteToUInt32(buf[4:])
|
2020-07-17 09:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|