reader.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. package ipdb
  2. import (
  3. "os"
  4. "encoding/binary"
  5. "errors"
  6. "encoding/json"
  7. "io/ioutil"
  8. "net"
  9. "strings"
  10. "reflect"
  11. "unsafe"
  12. "time"
  13. )
  14. const IPv4 = 0x01
  15. const IPv6 = 0x02
  16. var (
  17. ErrFileSize = errors.New("IP Database file size error.")
  18. ErrMetaData = errors.New("IP Database metadata error.")
  19. ErrReadFull = errors.New("IP Database ReadFull error.")
  20. ErrDatabaseError = errors.New("database error")
  21. ErrIPFormat = errors.New("Query IP Format error.")
  22. ErrNoSupportLanguage = errors.New("language not support")
  23. ErrNoSupportIPv4 = errors.New("IPv4 not support")
  24. ErrNoSupportIPv6 = errors.New("IPv6 not support")
  25. ErrDataNotExists = errors.New("data is not exists")
  26. )
  27. type MetaData struct {
  28. Build int64 `json:"build"`
  29. IPVersion uint16 `json:"ip_version"`
  30. Languages map[string]int `json:"languages"`
  31. NodeCount int `json:"node_count"`
  32. TotalSize int `json:"total_size"`
  33. Fields []string `json:"fields"`
  34. }
  35. type reader struct {
  36. fileSize int
  37. nodeCount int
  38. v4offset int
  39. meta MetaData
  40. data []byte
  41. refType map[string]string
  42. }
  43. func newReader(name string, obj interface{}) (*reader, error) {
  44. var err error
  45. var fileInfo os.FileInfo
  46. fileInfo, err = os.Stat(name)
  47. if err != nil {
  48. return nil, err
  49. }
  50. fileSize := int(fileInfo.Size())
  51. body, err := ioutil.ReadFile(name)
  52. if err != nil {
  53. return nil, ErrReadFull
  54. }
  55. var meta MetaData
  56. metaLength := int(binary.BigEndian.Uint32(body[0:4]))
  57. if err := json.Unmarshal(body[4:4+metaLength], &meta); err != nil {
  58. return nil, err
  59. }
  60. if len(meta.Languages) == 0 || len(meta.Fields) == 0 {
  61. return nil, ErrMetaData
  62. }
  63. if fileSize != (4+metaLength+meta.TotalSize) {
  64. return nil, ErrFileSize
  65. }
  66. var dm map[string]string
  67. if obj != nil {
  68. t := reflect.TypeOf(obj).Elem()
  69. dm = make(map[string]string, t.NumField())
  70. for i := 0; i < t.NumField(); i++ {
  71. k := t.Field(i).Tag.Get("json")
  72. dm[k] = t.Field(i).Name
  73. }
  74. }
  75. db := &reader{
  76. fileSize: fileSize,
  77. nodeCount: meta.NodeCount,
  78. meta:meta,
  79. refType: dm,
  80. data: body[4+metaLength:],
  81. }
  82. if db.v4offset == 0 {
  83. node := 0
  84. for i := 0; i < 96 && node < db.nodeCount; i++ {
  85. if i >= 80 {
  86. node = db.readNode(node, 1)
  87. } else {
  88. node = db.readNode(node, 0)
  89. }
  90. }
  91. db.v4offset = node
  92. }
  93. return db, nil
  94. }
  95. func (db *reader) Find(addr, language string) ([]string, error) {
  96. return db.find1(addr, language)
  97. }
  98. func (db *reader) FindMap(addr, language string) (map[string]string, error) {
  99. data, err := db.find1(addr, language)
  100. if err != nil {
  101. return nil, err
  102. }
  103. info := make(map[string]string, len(db.meta.Fields))
  104. for k, v := range data {
  105. info[db.meta.Fields[k]] = v
  106. }
  107. return info, nil
  108. }
  109. func (db *reader) find0(addr string) ([]byte, error) {
  110. var err error
  111. var node int
  112. ipv := net.ParseIP(addr)
  113. if ip := ipv.To4(); ip != nil {
  114. if !db.IsIPv4Support() {
  115. return nil, ErrNoSupportIPv4
  116. }
  117. node, err = db.search(ip, 32)
  118. } else if ip := ipv.To16(); ip != nil {
  119. if !db.IsIPv6Support() {
  120. return nil, ErrNoSupportIPv6
  121. }
  122. node, err = db.search(ip, 128)
  123. } else {
  124. return nil, ErrIPFormat
  125. }
  126. if err != nil || node < 0 {
  127. return nil, err
  128. }
  129. body, err := db.resolve(node)
  130. if err != nil {
  131. return nil, err
  132. }
  133. return body, nil
  134. }
  135. func (db *reader) find1(addr, language string) ([]string, error) {
  136. off, ok := db.meta.Languages[language]
  137. if !ok {
  138. return nil, ErrNoSupportLanguage
  139. }
  140. body, err := db.find0(addr)
  141. if err != nil {
  142. return nil, err
  143. }
  144. str := (*string)(unsafe.Pointer(&body))
  145. tmp := strings.Split(*str, "\t")
  146. if (off + len(db.meta.Fields)) > len(tmp) {
  147. return nil, ErrDatabaseError
  148. }
  149. return tmp[off:off+len(db.meta.Fields)], nil
  150. }
  151. func (db *reader) search(ip net.IP, bitCount int) (int, error) {
  152. var node int
  153. if bitCount == 32 {
  154. node = db.v4offset
  155. } else {
  156. node = 0;
  157. }
  158. for i := 0; i < bitCount; i++ {
  159. if node > db.nodeCount {
  160. break
  161. }
  162. node = db.readNode(node, ((0xFF & int(ip[i >> 3])) >> uint(7 - (i % 8))) & 1)
  163. }
  164. if node > db.nodeCount {
  165. return node, nil
  166. }
  167. return -1, ErrDataNotExists
  168. }
  169. func (db *reader) readNode(node, index int) int {
  170. off := node * 8 + index * 4
  171. return int(binary.BigEndian.Uint32(db.data[off:off+4]))
  172. }
  173. func (db *reader) resolve(node int) ([]byte, error) {
  174. resolved := node - db.nodeCount + db.nodeCount * 8
  175. if resolved >= db.fileSize {
  176. return nil, ErrDatabaseError
  177. }
  178. size := int(binary.BigEndian.Uint16(db.data[resolved:resolved+2]))
  179. if (resolved+2+size) > len(db.data) {
  180. return nil, ErrDatabaseError
  181. }
  182. bytes := db.data[resolved+2:resolved+2+size]
  183. return bytes, nil
  184. }
  185. func (db *reader) IsIPv4Support() bool {
  186. return (int(db.meta.IPVersion) & IPv4) == IPv4
  187. }
  188. func (db *reader) IsIPv6Support() bool {
  189. return (int(db.meta.IPVersion) & IPv6) == IPv6
  190. }
  191. func (db *reader) Build() time.Time {
  192. return time.Unix(db.meta.Build, 0).In(time.UTC)
  193. }
  194. func (db *reader) Languages() []string {
  195. ls := make([]string, 0, len(db.meta.Languages))
  196. for k := range db.meta.Languages {
  197. ls = append(ls, k)
  198. }
  199. return ls
  200. }