filedata.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package qqwry
  2. import (
  3. "encoding/binary"
  4. "io"
  5. "net"
  6. "os"
  7. "strings"
  8. "bet24.com/log"
  9. "golang.org/x/text/encoding/simplifiedchinese"
  10. )
  11. // IPData IP库的数据
  12. var IPData fileData
  13. // InitIPData 初始化ip库数据到内存中
  14. func (f *fileData) InitIPData() (rs interface{}) {
  15. var tmpData []byte
  16. // 判断文件是否存在
  17. _, err := os.Stat(f.FilePath)
  18. if err != nil && os.IsNotExist(err) {
  19. log.Release("文件不存在,尝试从网络获取最新纯真 IP 库")
  20. } else {
  21. // 打开文件句柄
  22. log.Debug("从本地数据库文件 %s 打开\n", f.FilePath)
  23. f.Path, err = os.OpenFile(f.FilePath, os.O_RDONLY, 0400)
  24. if err != nil {
  25. rs = err
  26. return
  27. }
  28. defer f.Path.Close()
  29. tmpData, err = io.ReadAll(f.Path)
  30. if err != nil {
  31. log.Error("%v", err)
  32. rs = err
  33. return
  34. }
  35. }
  36. f.Data = tmpData
  37. buf := f.Data[0:8]
  38. start := binary.LittleEndian.Uint32(buf[:4])
  39. end := binary.LittleEndian.Uint32(buf[4:])
  40. f.IPNum = int64((end-start)/IndexLen + 1)
  41. return true
  42. }
  43. // NewQQwry 新建 qqwry 类型
  44. func NewQQwry() QQwry {
  45. return QQwry{
  46. Data: &IPData,
  47. }
  48. }
  49. // ReadData 从文件中读取数据
  50. func (q *QQwry) ReadData(num int, offset ...int64) (rs []byte) {
  51. if len(offset) > 0 {
  52. q.SetOffset(offset[0])
  53. }
  54. nums := int64(num)
  55. end := q.Offset + nums
  56. dataNum := int64(len(q.Data.Data))
  57. if q.Offset > dataNum {
  58. return nil
  59. }
  60. if end > dataNum {
  61. end = dataNum
  62. }
  63. rs = q.Data.Data[q.Offset:end]
  64. q.Offset = end
  65. return
  66. }
  67. // SetOffset 设置偏移量
  68. func (q *QQwry) SetOffset(offset int64) {
  69. q.Offset = offset
  70. }
  71. // Find ip地址查询对应归属地信息
  72. func (q *QQwry) Find(ip string) (res ResultQQwry) {
  73. res = ResultQQwry{}
  74. res.IP = ip
  75. if strings.Count(ip, ".") != 3 {
  76. return res
  77. }
  78. offset := q.searchIndex(binary.BigEndian.Uint32(net.ParseIP(ip).To4()))
  79. if offset <= 0 {
  80. return
  81. }
  82. var country []byte
  83. var area []byte
  84. mode := q.readMode(offset + 4)
  85. if mode == RedirectMode1 {
  86. countryOffset := q.readUInt24()
  87. mode = q.readMode(countryOffset)
  88. if mode == RedirectMode2 {
  89. c := q.readUInt24()
  90. country = q.readString(c)
  91. countryOffset += 4
  92. } else {
  93. country = q.readString(countryOffset)
  94. countryOffset += uint32(len(country) + 1)
  95. }
  96. area = q.readArea(countryOffset)
  97. } else if mode == RedirectMode2 {
  98. countryOffset := q.readUInt24()
  99. country = q.readString(countryOffset)
  100. area = q.readArea(offset + 8)
  101. } else {
  102. country = q.readString(offset + 4)
  103. area = q.readArea(offset + uint32(5+len(country)))
  104. }
  105. enc := simplifiedchinese.GBK.NewDecoder()
  106. res.Country, _ = enc.String(string(country))
  107. res.Area, _ = enc.String(string(area))
  108. return
  109. }
  110. // readMode 获取偏移值类型
  111. func (q *QQwry) readMode(offset uint32) byte {
  112. mode := q.ReadData(1, int64(offset))
  113. return mode[0]
  114. }
  115. // readArea 读取区域
  116. func (q *QQwry) readArea(offset uint32) []byte {
  117. mode := q.readMode(offset)
  118. if mode == RedirectMode1 || mode == RedirectMode2 {
  119. areaOffset := q.readUInt24()
  120. if areaOffset == 0 {
  121. return []byte("")
  122. }
  123. return q.readString(areaOffset)
  124. }
  125. return q.readString(offset)
  126. }
  127. // readString 获取字符串
  128. func (q *QQwry) readString(offset uint32) []byte {
  129. q.SetOffset(int64(offset))
  130. data := make([]byte, 0, 30)
  131. buf := make([]byte, 1)
  132. for {
  133. buf = q.ReadData(1)
  134. if buf[0] == 0 {
  135. break
  136. }
  137. data = append(data, buf[0])
  138. }
  139. return data
  140. }
  141. // searchIndex 查找索引位置
  142. func (q *QQwry) searchIndex(ip uint32) uint32 {
  143. header := q.ReadData(8, 0)
  144. start := binary.LittleEndian.Uint32(header[:4])
  145. end := binary.LittleEndian.Uint32(header[4:])
  146. buf := make([]byte, IndexLen)
  147. mid := uint32(0)
  148. _ip := uint32(0)
  149. for {
  150. mid = q.getMiddleOffset(start, end)
  151. buf = q.ReadData(IndexLen, int64(mid))
  152. _ip = binary.LittleEndian.Uint32(buf[:4])
  153. if end-start == IndexLen {
  154. offset := byteToUInt32(buf[4:])
  155. buf = q.ReadData(IndexLen)
  156. if ip < binary.LittleEndian.Uint32(buf[:4]) {
  157. return offset
  158. }
  159. return 0
  160. }
  161. // 找到的比较大,向前移
  162. if _ip > ip {
  163. end = mid
  164. } else if _ip < ip { // 找到的比较小,向后移
  165. start = mid
  166. } else if _ip == ip {
  167. return byteToUInt32(buf[4:])
  168. }
  169. }
  170. }
  171. // readUInt24
  172. func (q *QQwry) readUInt24() uint32 {
  173. buf := q.ReadData(3)
  174. return byteToUInt32(buf)
  175. }
  176. // getMiddleOffset
  177. func (q *QQwry) getMiddleOffset(start uint32, end uint32) uint32 {
  178. records := ((end - start) / IndexLen) >> 1
  179. return start + records*IndexLen
  180. }
  181. // byteToUInt32 将 byte 转换为uint32
  182. func byteToUInt32(data []byte) uint32 {
  183. i := uint32(data[0]) & 0xff
  184. i |= (uint32(data[1]) << 8) & 0xff00
  185. i |= (uint32(data[2]) << 16) & 0xff0000
  186. return i
  187. }