2020-07-18 09:19:27 +08:00
|
|
|
|
package zxipv6wry
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/binary"
|
2021-08-02 12:01:25 +08:00
|
|
|
|
"errors"
|
2020-07-18 09:19:27 +08:00
|
|
|
|
"fmt"
|
2022-10-20 15:54:20 +08:00
|
|
|
|
"io"
|
2020-07-18 09:52:59 +08:00
|
|
|
|
"log"
|
2020-07-18 09:19:27 +08:00
|
|
|
|
"net"
|
2020-07-18 09:52:59 +08:00
|
|
|
|
"os"
|
2020-07-18 09:19:27 +08:00
|
|
|
|
|
2022-10-20 15:54:20 +08:00
|
|
|
|
"github.com/zu1k/nali/pkg/wry"
|
2020-07-18 09:19:27 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type ZXwry struct {
|
2022-10-20 15:54:20 +08:00
|
|
|
|
wry.IPDB[uint64]
|
2020-07-18 09:19:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-02 12:34:11 +08:00
|
|
|
|
func NewZXwry(filePath string) (*ZXwry, error) {
|
2020-07-20 20:31:12 +08:00
|
|
|
|
var fileData []byte
|
2020-07-18 09:52:59 +08:00
|
|
|
|
|
|
|
|
|
_, err := os.Stat(filePath)
|
|
|
|
|
if err != nil && os.IsNotExist(err) {
|
2020-07-20 20:31:12 +08:00
|
|
|
|
log.Println("文件不存在,尝试从网络获取最新ZX IPv6数据库")
|
|
|
|
|
fileData, err = Download(filePath)
|
|
|
|
|
if err != nil {
|
2022-03-02 12:34:11 +08:00
|
|
|
|
return nil, err
|
2020-07-20 20:31:12 +08:00
|
|
|
|
}
|
2020-07-18 09:52:59 +08:00
|
|
|
|
} else {
|
2022-10-20 15:54:20 +08:00
|
|
|
|
fileBase, err := os.OpenFile(filePath, os.O_RDONLY, 0400)
|
2020-07-18 09:52:59 +08:00
|
|
|
|
if err != nil {
|
2022-03-02 12:34:11 +08:00
|
|
|
|
return nil, err
|
2020-07-18 09:52:59 +08:00
|
|
|
|
}
|
2022-10-20 15:54:20 +08:00
|
|
|
|
defer fileBase.Close()
|
2020-07-18 09:52:59 +08:00
|
|
|
|
|
2022-10-20 15:54:20 +08:00
|
|
|
|
fileData, err = io.ReadAll(fileBase)
|
2020-07-18 09:52:59 +08:00
|
|
|
|
if err != nil {
|
2022-03-02 12:34:11 +08:00
|
|
|
|
return nil, err
|
2020-07-18 09:52:59 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-24 09:51:19 +08:00
|
|
|
|
if !CheckFile(fileData) {
|
2022-10-20 16:05:02 +08:00
|
|
|
|
log.Fatalln("ZX IPv6数据库存在错误,请重新下载")
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-20 15:54:20 +08:00
|
|
|
|
header := fileData[:24]
|
|
|
|
|
offLen := header[6]
|
|
|
|
|
ipLen := header[7]
|
|
|
|
|
|
|
|
|
|
start := binary.LittleEndian.Uint64(header[16:24])
|
|
|
|
|
counts := binary.LittleEndian.Uint64(header[8:16])
|
|
|
|
|
end := start + counts*11
|
2020-07-18 09:52:59 +08:00
|
|
|
|
|
2022-03-02 12:34:11 +08:00
|
|
|
|
return &ZXwry{
|
2022-10-20 15:54:20 +08:00
|
|
|
|
IPDB: wry.IPDB[uint64]{
|
|
|
|
|
Data: fileData,
|
|
|
|
|
|
|
|
|
|
OffLen: offLen,
|
|
|
|
|
IPLen: ipLen,
|
|
|
|
|
IPCnt: counts,
|
|
|
|
|
IdxStart: start,
|
|
|
|
|
IdxEnd: end,
|
2020-07-18 09:52:59 +08:00
|
|
|
|
},
|
2022-03-02 12:34:11 +08:00
|
|
|
|
}, nil
|
2020-07-18 09:52:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-20 15:54:20 +08:00
|
|
|
|
func (db *ZXwry) Find(query string, _ ...string) (result fmt.Stringer, err error) {
|
2021-08-02 12:01:25 +08:00
|
|
|
|
ip := net.ParseIP(query)
|
|
|
|
|
if ip == nil {
|
2022-10-20 15:54:20 +08:00
|
|
|
|
return nil, errors.New("query should be IPv6")
|
2021-08-02 12:01:25 +08:00
|
|
|
|
}
|
|
|
|
|
ip6 := ip.To16()
|
|
|
|
|
if ip6 == nil {
|
2022-10-20 15:54:20 +08:00
|
|
|
|
return nil, errors.New("query should be IPv6")
|
2020-07-18 09:19:27 +08:00
|
|
|
|
}
|
2022-10-20 15:54:20 +08:00
|
|
|
|
ip6 = ip6[:8]
|
|
|
|
|
ipu64 := binary.BigEndian.Uint64(ip6)
|
2020-07-18 09:19:27 +08:00
|
|
|
|
|
2022-10-20 15:54:20 +08:00
|
|
|
|
offset := db.SearchIndexV6(ipu64)
|
|
|
|
|
reader := wry.NewReader(db.Data)
|
|
|
|
|
reader.Parse(offset)
|
|
|
|
|
return reader.Result, nil
|
2020-07-18 09:19:27 +08:00
|
|
|
|
}
|
2022-10-24 09:51:19 +08:00
|
|
|
|
|
2023-05-20 17:53:43 +08:00
|
|
|
|
func (db *ZXwry) Name() string {
|
2023-05-21 14:41:21 +08:00
|
|
|
|
return "zxipv6wry"
|
2023-05-20 17:53:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-24 09:51:19 +08:00
|
|
|
|
func CheckFile(data []byte) bool {
|
|
|
|
|
if len(data) < 4 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if string(data[:4]) != "IPDB" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(data) < 24 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
header := data[:24]
|
|
|
|
|
start := binary.LittleEndian.Uint64(header[16:24])
|
|
|
|
|
counts := binary.LittleEndian.Uint64(header[8:16])
|
|
|
|
|
end := start + counts*11
|
|
|
|
|
if start >= end || uint64(len(data)) < end {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|