forked from NiceLabs/geoip-seeker
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathip_seeker.go
95 lines (85 loc) · 1.9 KB
/
ip_seeker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package qqwry
import (
"encoding/binary"
"net"
"strings"
. "github.com/OpenIPDB/geoip-seeker/shared"
)
type Seeker struct {
data []byte
indexes []*indexRecord
}
func New(data []byte) (*Seeker, error) {
if len(data) == 0 {
return nil, ErrFileSize
}
seeker := &Seeker{data: data}
seeker.expandIndexes()
return seeker, nil
}
func (s *Seeker) LookupByIP(address net.IP) (record *Record, err error) {
if address = address.To4(); address == nil {
err = ErrInvalidIPv4
return
}
ip := uint(binary.BigEndian.Uint32(address))
head := 0
tail := len(s.indexes) - 1
var index int
for (head + 1) < tail {
index = (head + tail) / 2
if s.indexes[index].ip <= ip {
head = index
} else {
tail = index
}
}
record = s.index(s.indexes[head])
record.IP = address
return
}
func (s *Seeker) Records() (records []*Record) {
records = make([]*Record, len(s.indexes))
for index, record := range s.indexes {
records[index] = s.index(record)
}
return
}
func (s *Seeker) index(index *indexRecord) *Record {
country, area := s.readRecord(index.offset)
if area == " CZ88.NET" {
area = ""
}
return &Record{
BeginIP: index.begin,
EndIP: index.end,
CountryName: strings.TrimSpace(country),
RegionName: strings.TrimSpace(area),
}
}
func (s *Seeker) readRecord(offset uint) (country, area string) {
switch mode := s.data[offset]; mode {
case 1:
return s.readRecord(s.readUInt24LE(offset + 1))
case 2:
country = s.readCString(s.readUInt24LE(offset + 1))
area = s.readArea(offset + 4)
default:
country = s.readCString(offset)
area = s.readArea(offset + 1 + uint(len(country)))
}
return
}
func (s *Seeker) readArea(offset uint) string {
if s.data[offset] == 2 {
offset = s.readUInt24LE(offset + 1)
}
return s.readCString(offset)
}
func (s *Seeker) readCString(offset uint) string {
index := offset
for s.data[index] != 0 {
index++
}
return string(s.data[offset:index])
}