| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- package qqwry
- import (
- "encoding/binary"
- "io"
- "net"
- "os"
- "strings"
- "bet24.com/log"
- "golang.org/x/text/encoding/simplifiedchinese"
- )
- // IPData IP库的数据
- var IPData fileData
- // InitIPData 初始化ip库数据到内存中
- func (f *fileData) InitIPData() (rs interface{}) {
- var tmpData []byte
- // 判断文件是否存在
- _, err := os.Stat(f.FilePath)
- if err != nil && os.IsNotExist(err) {
- log.Release("文件不存在,尝试从网络获取最新纯真 IP 库")
- } else {
- // 打开文件句柄
- log.Debug("从本地数据库文件 %s 打开\n", f.FilePath)
- f.Path, err = os.OpenFile(f.FilePath, os.O_RDONLY, 0400)
- if err != nil {
- rs = err
- return
- }
- defer f.Path.Close()
- tmpData, err = io.ReadAll(f.Path)
- if err != nil {
- log.Error("%v", err)
- rs = err
- return
- }
- }
- f.Data = tmpData
- buf := f.Data[0:8]
- start := binary.LittleEndian.Uint32(buf[:4])
- end := binary.LittleEndian.Uint32(buf[4:])
- f.IPNum = int64((end-start)/IndexLen + 1)
- return true
- }
- // NewQQwry 新建 qqwry 类型
- func NewQQwry() QQwry {
- return QQwry{
- Data: &IPData,
- }
- }
- // 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
- }
- // SetOffset 设置偏移量
- func (q *QQwry) SetOffset(offset int64) {
- q.Offset = offset
- }
- // Find ip地址查询对应归属地信息
- func (q *QQwry) Find(ip string) (res ResultQQwry) {
- res = ResultQQwry{}
- res.IP = ip
- if strings.Count(ip, ".") != 3 {
- return res
- }
- offset := q.searchIndex(binary.BigEndian.Uint32(net.ParseIP(ip).To4()))
- if offset <= 0 {
- return
- }
- var country []byte
- var area []byte
- mode := q.readMode(offset + 4)
- if mode == RedirectMode1 {
- countryOffset := q.readUInt24()
- mode = q.readMode(countryOffset)
- if mode == RedirectMode2 {
- c := q.readUInt24()
- country = q.readString(c)
- countryOffset += 4
- } else {
- country = q.readString(countryOffset)
- countryOffset += uint32(len(country) + 1)
- }
- area = q.readArea(countryOffset)
- } else if mode == RedirectMode2 {
- countryOffset := q.readUInt24()
- country = q.readString(countryOffset)
- area = q.readArea(offset + 8)
- } else {
- country = q.readString(offset + 4)
- area = q.readArea(offset + uint32(5+len(country)))
- }
- enc := simplifiedchinese.GBK.NewDecoder()
- res.Country, _ = enc.String(string(country))
- res.Area, _ = enc.String(string(area))
- return
- }
- // 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)
- start := binary.LittleEndian.Uint32(header[:4])
- end := binary.LittleEndian.Uint32(header[4:])
- buf := make([]byte, IndexLen)
- mid := uint32(0)
- _ip := uint32(0)
- for {
- mid = q.getMiddleOffset(start, end)
- buf = q.ReadData(IndexLen, int64(mid))
- _ip = binary.LittleEndian.Uint32(buf[:4])
- if end-start == IndexLen {
- offset := byteToUInt32(buf[4:])
- buf = q.ReadData(IndexLen)
- 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 {
- return 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
- }
|