1
0
mirror of https://github.com/zu1k/nali.git synced 2025-01-22 21:29:02 +08:00
nali/pkg/qqwry/qqwry.go

151 lines
3.3 KiB
Go
Raw Normal View History

2020-07-17 09:05:25 +08:00
package qqwry
import (
"encoding/binary"
2021-08-02 12:01:25 +08:00
"errors"
2020-07-17 09:05:25 +08:00
"fmt"
"io/ioutil"
"log"
"net"
"os"
"strings"
2020-07-18 09:19:27 +08:00
"github.com/zu1k/nali/pkg/common"
"github.com/zu1k/nali/pkg/download"
2020-07-17 09:05:25 +08:00
"golang.org/x/text/encoding/simplifiedchinese"
)
var DownloadUrls = []string{
"https://99wry.cf/qqwry.dat",
}
2020-07-17 09:05:25 +08:00
type QQwry struct {
2020-07-18 09:19:27 +08:00
common.IPDB
2020-07-17 09:05:25 +08:00
}
2021-08-02 12:01:25 +08:00
// NewQQwry new database from path
func NewQQwry(filePath string) (*QQwry, error) {
2020-07-18 10:48:41 +08:00
var fileData []byte
2020-07-18 14:18:54 +08:00
var fileInfo common.FileData
2020-07-17 09:05:25 +08:00
_, err := os.Stat(filePath)
if err != nil && os.IsNotExist(err) {
log.Println("文件不存在,尝试从网络获取最新纯真 IP 库")
fileData, err = download.Download(filePath, DownloadUrls...)
2020-07-17 09:05:25 +08:00
if err != nil {
return nil, err
2020-07-17 09:05:25 +08:00
}
} else {
fileInfo.FileBase, err = os.OpenFile(filePath, os.O_RDONLY, 0400)
if err != nil {
return nil, err
2020-07-17 09:05:25 +08:00
}
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 {
return nil, err
2020-07-17 09:05:25 +08:00
}
}
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:])
return &QQwry{
2020-07-18 09:52:59 +08:00
IPDB: common.IPDB{
2020-07-22 06:45:58 +08:00
Data: &fileInfo,
IPNum: (end-start)/7 + 1,
2020-07-18 09:52:59 +08:00
},
}, nil
2020-07-17 09:05:25 +08:00
}
2021-08-02 12:01:25 +08:00
func (db QQwry) Find(query string, params ...string) (result fmt.Stringer, err error) {
ip := net.ParseIP(query)
if ip == nil {
return nil, errors.New("Query should be IPv4")
2020-07-17 09:05:25 +08:00
}
2021-08-02 12:01:25 +08:00
ip4 := ip.To4()
if ip4 == nil {
return nil, errors.New("Query should be IPv4")
}
ip4uint := binary.BigEndian.Uint32(ip4)
2020-07-18 09:19:27 +08:00
2021-08-02 12:01:25 +08:00
offset := db.searchIndex(ip4uint)
2020-07-17 09:05:25 +08:00
if offset <= 0 {
2021-08-02 12:01:25 +08:00
return nil, errors.New("Query not valid")
2020-07-17 09:05:25 +08:00
}
var gbkCountry []byte
var gbkArea []byte
2020-07-18 10:48:41 +08:00
mode := db.ReadMode(offset + 4)
2021-08-02 12:01:25 +08:00
switch mode {
case common.RedirectMode1: // [IP][0x01][国家和地区信息的绝对偏移地址]
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)
2021-08-02 12:01:25 +08:00
case common.RedirectMode2:
2020-07-18 10:48:41 +08:00
countryOffset := db.ReadUInt24()
gbkCountry = db.ReadString(countryOffset)
gbkArea = db.ReadArea(offset + 8)
2021-08-02 12:01:25 +08:00
default:
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))
2021-08-02 12:01:25 +08:00
result = common.Result{
Country: strings.ReplaceAll(country, " CZ88.NET", ""),
Area: strings.ReplaceAll(area, " CZ88.NET", ""),
2020-07-21 17:23:38 +08:00
}
2021-08-02 12:01:25 +08:00
return result, nil
2020-07-17 09:05:25 +08:00
}
// 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-22 06:45:58 +08:00
buf := make([]byte, 7)
2020-07-17 09:05:25 +08:00
mid := uint32(0)
2020-07-30 07:23:52 +08:00
ipUint := uint32(0)
2020-07-17 09:05:25 +08:00
for {
2020-07-22 06:45:58 +08:00
mid = common.GetMiddleOffset(start, end, 7)
buf = db.ReadData(7, mid)
2020-07-30 07:23:52 +08:00
ipUint = binary.LittleEndian.Uint32(buf[:4])
2020-07-17 09:05:25 +08:00
2020-07-22 06:45:58 +08:00
if end-start == 7 {
2020-07-18 09:19:27 +08:00
offset := common.ByteToUInt32(buf[4:])
2020-07-22 06:45:58 +08:00
buf = db.ReadData(7)
2020-07-17 09:05:25 +08:00
if ip < binary.LittleEndian.Uint32(buf[:4]) {
return offset
}
return 0
}
2020-07-30 07:23:52 +08:00
if ipUint > ip {
2020-07-17 09:05:25 +08:00
end = mid
2020-07-30 07:23:52 +08:00
} else if ipUint < ip {
2020-07-17 09:05:25 +08:00
start = mid
2020-07-30 07:23:52 +08:00
} else if ipUint == ip {
2020-07-18 09:19:27 +08:00
return common.ByteToUInt32(buf[4:])
2020-07-17 09:05:25 +08:00
}
}
}