diff --git a/pkg/common/const.go b/pkg/common/const.go new file mode 100644 index 0000000..9198703 --- /dev/null +++ b/pkg/common/const.go @@ -0,0 +1,6 @@ +package common + +const ( + RedirectMode1 = 0x01 // one mode + RedirectMode2 = 0x02 //another mode +) diff --git a/pkg/common/dbtool.go b/pkg/common/dbtool.go new file mode 100644 index 0000000..1a948b0 --- /dev/null +++ b/pkg/common/dbtool.go @@ -0,0 +1,9 @@ +package common + +// byteToUInt32 将 byte 转换为uint32 +func ByteToUInt32(data []byte) uint32 { + i := uint32(data[0]) & 0xff + i |= (uint32(data[1]) << 8) & 0xff00 + i |= (uint32(data[2]) << 16) & 0xff0000 + return i +} diff --git a/pkg/common/struct.go b/pkg/common/struct.go new file mode 100644 index 0000000..6cf5d9a --- /dev/null +++ b/pkg/common/struct.go @@ -0,0 +1,84 @@ +package common + +import "os" + +// FileInfo: info of db file +type FileInfo struct { + Data []byte + FilePath string + FileBase *os.File +} + +// IPDB common ip database +type IPDB struct { + Data *FileInfo + Offset uint32 + ItemLen uint32 + IndexLen uint32 + IPNum uint32 +} + +// setOffset 设置偏移量 +func (db *IPDB) SetOffset(offset uint32) { + db.Offset = offset +} + +// readString 获取字符串 +func (db *IPDB) ReadString(offset uint32) []byte { + db.SetOffset(offset) + data := make([]byte, 0, 30) + buf := make([]byte, 1) + for { + buf = db.ReadData(1) + if buf[0] == 0 { + break + } + data = append(data, buf[0]) + } + return data +} + +// readData 从文件中读取数据 +func (db *IPDB) ReadData(length int, offset ...uint32) (rs []byte) { + if len(offset) > 0 { + db.SetOffset(offset[0]) + } + readLength := uint32(length) + end := db.Offset + readLength + dataNum := uint32(len(db.Data.Data)) + if db.Offset > dataNum { + return nil + } + + if end > dataNum { + end = dataNum + } + rs = db.Data.Data[db.Offset:end] + db.Offset = end + return +} + +// readMode 获取偏移值类型 +func (db *IPDB) ReadMode(offset uint32) byte { + mode := db.ReadData(1, offset) + return mode[0] +} + +// ReadUInt24 +func (db *IPDB) ReadUInt24() uint32 { + buf := db.ReadData(3) + return ByteToUInt32(buf) +} + +// readArea 读取区域 +func (db *IPDB) ReadArea(offset uint32) []byte { + mode := db.ReadMode(offset) + if mode == RedirectMode1 || mode == RedirectMode2 { + areaOffset := db.ReadUInt24() + if areaOffset == 0 { + return []byte("") + } + return db.ReadString(areaOffset) + } + return db.ReadString(offset) +} diff --git a/pkg/qqwry/qqwry.go b/pkg/qqwry/qqwry.go index 12c3141..e72544f 100644 --- a/pkg/qqwry/qqwry.go +++ b/pkg/qqwry/qqwry.go @@ -9,33 +9,22 @@ import ( "os" "strings" + "github.com/zu1k/nali/pkg/common" "golang.org/x/text/encoding/simplifiedchinese" ) -// db file info with data -type FileInfo struct { - Data []byte - FilePath string - FileBase *os.File - IPNum int64 -} - -// qq ip db -type QQwry struct { - data *FileInfo - offset int64 -} - const ( - IndexLen = 7 // index length - RedirectMode1 = 0x01 // one mode - RedirectMode2 = 0x02 //another mode + IndexLen = 7 // index length ) +type QQwry struct { + common.IPDB +} + // new db from path -func NewQQwry(filePath string) QQwry { +func NewQQwry(filePath string) common.IPDB { var tmpData []byte - var fileInfo FileInfo + var fileInfo common.FileInfo // 判断文件是否存在 _, err := os.Stat(filePath) @@ -69,24 +58,21 @@ func NewQQwry(filePath string) QQwry { start := binary.LittleEndian.Uint32(buf[:4]) end := binary.LittleEndian.Uint32(buf[4:]) - fileInfo.IPNum = int64((end-start)/IndexLen + 1) - - return QQwry{ - data: &fileInfo, + return common.IPDB{ + Data: &fileInfo, + IPNum: uint32((end-start)/IndexLen + 1), } } -// setOffset 设置偏移量 -func (q *QQwry) setOffset(offset int64) { - q.offset = offset -} - // Find ip地址查询对应归属地信息 func (q QQwry) Find(ip string) (res string) { if strings.Count(ip, ".") != 3 { return } - offset := q.searchIndex(binary.BigEndian.Uint32(net.ParseIP(ip).To4())) + + ip4 := binary.BigEndian.Uint32(net.ParseIP(ip).To4()) + + offset := q.searchIndex(ip4) if offset <= 0 { return } @@ -94,26 +80,26 @@ func (q QQwry) Find(ip string) (res string) { var gbkCountry []byte var gbkArea []byte - mode := q.readMode(offset + 4) - if mode == RedirectMode1 { - countryOffset := q.readUInt24() - mode = q.readMode(countryOffset) - if mode == RedirectMode2 { - c := q.readUInt24() - gbkCountry = q.readString(c) + mode := q.ReadMode(offset + 4) + if mode == common.RedirectMode1 { + countryOffset := q.ReadUInt24() + mode = q.ReadMode(countryOffset) + if mode == common.RedirectMode2 { + c := q.ReadUInt24() + gbkCountry = q.ReadString(c) countryOffset += 4 } else { - gbkCountry = q.readString(countryOffset) + gbkCountry = q.ReadString(countryOffset) countryOffset += uint32(len(gbkCountry) + 1) } - gbkArea = q.readArea(countryOffset) - } else if mode == RedirectMode2 { - countryOffset := q.readUInt24() - gbkCountry = q.readString(countryOffset) - gbkArea = q.readArea(offset + 8) + gbkArea = q.ReadArea(countryOffset) + } else if mode == common.RedirectMode2 { + countryOffset := q.ReadUInt24() + gbkCountry = q.ReadString(countryOffset) + gbkArea = q.ReadArea(offset + 8) } else { - gbkCountry = q.readString(offset + 4) - gbkArea = q.readArea(offset + uint32(5+len(gbkCountry))) + gbkCountry = q.ReadString(offset + 4) + gbkArea = q.ReadArea(offset + uint32(5+len(gbkCountry))) } enc := simplifiedchinese.GBK.NewDecoder() @@ -123,43 +109,9 @@ func (q QQwry) Find(ip string) (res string) { return fmt.Sprintf("%s %s", country, area) } -// readMode 获取偏移值类型 -func (q *QQwry) readMode(offset uint32) byte { - mode := q.readData(1, int64(offset)) - return mode[0] -} - -// readArea 读取区域 -func (q *QQwry) readArea(offset uint32) []byte { - mode := q.readMode(offset) - if mode == RedirectMode1 || mode == RedirectMode2 { - areaOffset := q.readUInt24() - if areaOffset == 0 { - return []byte("") - } - return q.readString(areaOffset) - } - return q.readString(offset) -} - -// readString 获取字符串 -func (q *QQwry) readString(offset uint32) []byte { - q.setOffset(int64(offset)) - data := make([]byte, 0, 30) - buf := make([]byte, 1) - for { - buf = q.readData(1) - if buf[0] == 0 { - break - } - data = append(data, buf[0]) - } - return data -} - // searchIndex 查找索引位置 func (q *QQwry) searchIndex(ip uint32) uint32 { - header := q.readData(8, 0) + header := q.ReadData(8, 0) start := binary.LittleEndian.Uint32(header[:4]) end := binary.LittleEndian.Uint32(header[4:]) @@ -170,12 +122,12 @@ func (q *QQwry) searchIndex(ip uint32) uint32 { for { mid = q.getMiddleOffset(start, end) - buf = q.readData(IndexLen, int64(mid)) + buf = q.ReadData(IndexLen, mid) _ip = binary.LittleEndian.Uint32(buf[:4]) if end-start == IndexLen { - offset := byteToUInt32(buf[4:]) - buf = q.readData(IndexLen) + offset := common.ByteToUInt32(buf[4:]) + buf = q.ReadData(IndexLen) if ip < binary.LittleEndian.Uint32(buf[:4]) { return offset } @@ -188,47 +140,13 @@ func (q *QQwry) searchIndex(ip uint32) uint32 { } else if _ip < ip { // 找到的比较小,向后移 start = mid } else if _ip == ip { - return byteToUInt32(buf[4:]) + return common.ByteToUInt32(buf[4:]) } } } -// readUInt24 -func (q *QQwry) readUInt24() uint32 { - buf := q.readData(3) - return byteToUInt32(buf) -} - // getMiddleOffset func (q *QQwry) getMiddleOffset(start uint32, end uint32) uint32 { records := ((end - start) / IndexLen) >> 1 return start + records*IndexLen } - -// byteToUInt32 将 byte 转换为uint32 -func byteToUInt32(data []byte) uint32 { - i := uint32(data[0]) & 0xff - i |= (uint32(data[1]) << 8) & 0xff00 - i |= (uint32(data[2]) << 16) & 0xff0000 - return i -} - -// readData 从文件中读取数据 -func (q *QQwry) readData(num int, offset ...int64) (rs []byte) { - if len(offset) > 0 { - q.setOffset(offset[0]) - } - nums := int64(num) - end := q.offset + nums - dataNum := int64(len(q.data.Data)) - if q.offset > dataNum { - return nil - } - - if end > dataNum { - end = dataNum - } - rs = q.data.Data[q.offset:end] - q.offset = end - return -} diff --git a/pkg/zxipv6wry/zxipv6wry.go b/pkg/zxipv6wry/zxipv6wry.go new file mode 100644 index 0000000..7fb9d4c --- /dev/null +++ b/pkg/zxipv6wry/zxipv6wry.go @@ -0,0 +1,129 @@ +package zxipv6wry + +import ( + "encoding/binary" + "fmt" + "math/big" + "net" + + "github.com/zu1k/nali/pkg/common" +) + +var ( + header []byte + v6ip uint64 + offset uint32 + start uint32 + end uint32 +) + +type ZXwry struct { + common.IPDB +} + +func (q *ZXwry) Find(ip string) (result string) { + q.Offset = 0 + + tp := big.NewInt(0) + op := big.NewInt(0) + tp.SetBytes(net.ParseIP(ip).To16()) + op.SetString("18446744073709551616", 10) + op.Div(tp, op) + tp.SetString("FFFFFFFFFFFFFFFF", 16) + op.And(op, tp) + + v6ip = op.Uint64() + offset = q.searchIndexV6(v6ip) + + country, area := q.getAddr(offset) + + if area == "ZX" { + area = "" + } + + return fmt.Sprintf("%s %s", country, area) +} + +func (q *ZXwry) getAddr(offset uint32) (string, string) { + mode := q.ReadMode(offset) + if mode == 0x01 { + // [IP][0x01][国家和地区信息的绝对偏移地址] + offset = q.ReadUInt24() + return q.getAddr(offset) + } + // [IP][0x02][信息的绝对偏移][...] or [IP][国家][...] + _offset := q.Offset - 1 + c1 := q.ReadArea(_offset) + if mode == 0x02 { + q.Offset = 4 + _offset + } else { + q.Offset = _offset + uint32(1+len(c1)) + } + c2 := q.ReadArea(q.Offset) + return string(c1), string(c2) +} + +func (q *ZXwry) searchIndexV4(ip uint32) uint32 { + q.ItemLen = 4 + q.IndexLen = 7 + header = q.Data.Data[0:8] + start = binary.LittleEndian.Uint32(header[:4]) + end = binary.LittleEndian.Uint32(header[4:]) + + buf := make([]byte, q.IndexLen) + + for { + mid := start + q.IndexLen*(((end-start)/q.IndexLen)>>1) + buf = q.Data.Data[mid : mid+q.IndexLen] + _ip := binary.LittleEndian.Uint32(buf[:q.ItemLen]) + + if end-start == q.IndexLen { + if ip >= binary.LittleEndian.Uint32(q.Data.Data[end:end+q.ItemLen]) { + buf = q.Data.Data[end : end+q.IndexLen] + } + return common.ByteToUInt32(buf[q.ItemLen:]) + } + + if _ip > ip { + end = mid + } else if _ip < ip { + start = mid + } else if _ip == ip { + return common.ByteToUInt32(buf[q.ItemLen:]) + } + } +} + +func (q *ZXwry) searchIndexV6(ip uint64) uint32 { + + q.ItemLen = 8 + q.IndexLen = 11 + + header = q.Data.Data[8:24] + start = binary.LittleEndian.Uint32(header[8:]) + counts := binary.LittleEndian.Uint32(header[:8]) + end = start + counts*q.IndexLen + + buf := make([]byte, q.IndexLen) + + for { + mid := start + q.IndexLen*(((end-start)/q.IndexLen)>>1) + buf = q.Data.Data[mid : mid+q.IndexLen] + _ip := binary.LittleEndian.Uint64(buf[:q.ItemLen]) + + if end-start == q.IndexLen { + if ip >= binary.LittleEndian.Uint64(q.Data.Data[end:end+q.ItemLen]) { + buf = q.Data.Data[end : end+q.IndexLen] + } + return common.ByteToUInt32(buf[q.ItemLen:]) + } + + if _ip > ip { + end = mid + } else if _ip < ip { + start = mid + } else if _ip == ip { + return common.ByteToUInt32(buf[q.ItemLen:]) + } + } +}