Skip to content

Instantly share code, notes, and snippets.

@rmb122
Created January 15, 2022 14:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmb122/ec7f305679ae9921a79b571d56390a74 to your computer and use it in GitHub Desktop.
Save rmb122/ec7f305679ae9921a79b571d56390a74 to your computer and use it in GitHub Desktop.
ipv6wry go version
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"net"
"os"
)
type IPv6DB struct {
dbData []byte
recordStartOffset uint64
recordTotal uint64
locationPointerLength uint64
ipLength uint64
}
func IPv6DBOpen(path string) (IPv6DB, error) {
ipv6DB := IPv6DB{}
data, err := os.ReadFile(path)
if err == nil {
if ret := bytes.Compare(data[:4], []byte("IPDB")); ret == 0 {
ipv6DB.dbData = data
ipv6DB.recordStartOffset = binary.LittleEndian.Uint64(ipv6DB.dbData[16:24])
ipv6DB.recordTotal = binary.LittleEndian.Uint64(ipv6DB.dbData[8:16])
ipv6DB.locationPointerLength = uint64(ipv6DB.dbData[6])
ipv6DB.ipLength = uint64(ipv6DB.dbData[7])
if ipv6DB.locationPointerLength != 3 {
err = errors.New("location pointer length != 3")
}
} else {
err = errors.New("not a IPDB")
}
}
return ipv6DB, err
}
func (ipv6DB IPv6DB) findIPRecordIdx(ip uint64, start uint64, end uint64) uint64 {
if end-start <= 1 {
return start
}
mid := (start + end) / 2
tmpIPIdx := ipv6DB.recordStartOffset + mid*(ipv6DB.ipLength+ipv6DB.locationPointerLength)
tmpIP := binary.LittleEndian.Uint64(ipv6DB.dbData[tmpIPIdx : tmpIPIdx+ipv6DB.ipLength])
if ip < tmpIP {
return ipv6DB.findIPRecordIdx(ip, start, mid)
} else {
return ipv6DB.findIPRecordIdx(ip, mid, end)
}
}
func (ipv6DB IPv6DB) getLocationString(locationIdx uint64) string {
flag := ipv6DB.dbData[locationIdx]
if flag == 1 || flag == 2 {
return ipv6DB.getLocationString(ipv6DB.threeBytesToUint64(ipv6DB.dbData[locationIdx+1 : locationIdx+ipv6DB.locationPointerLength+1]))
} else {
currentIdx := locationIdx
for {
if ipv6DB.dbData[currentIdx] == 0 {
break
}
currentIdx += 1
}
return string(ipv6DB.dbData[locationIdx:currentIdx])
}
}
func (ipv6DB IPv6DB) findLocationRecord(locationIdx uint64) (string, string) {
flag := ipv6DB.dbData[locationIdx]
if flag == 1 {
return ipv6DB.findLocationRecord(ipv6DB.threeBytesToUint64(ipv6DB.dbData[locationIdx+1 : locationIdx+ipv6DB.locationPointerLength+1]))
} else {
cArea := ipv6DB.getLocationString(locationIdx)
if flag == 2 {
locationIdx += 1 + ipv6DB.locationPointerLength
} else {
for {
if ipv6DB.dbData[locationIdx] == 0 {
break
}
locationIdx += 1
}
}
aArea := ipv6DB.getLocationString(locationIdx)
return cArea, aArea
}
}
func (ipv6DB IPv6DB) threeBytesToUint64(b []byte) uint64 {
return uint64(b[0]) + uint64(b[1])*256 + uint64(b[2])*256*256
}
func (ipv6DB IPv6DB) GetIPLocation(addr string) (string, string) {
ipBytes := net.ParseIP(addr)
ip := binary.BigEndian.Uint64(ipBytes[:8])
ipRecordIdx := ipv6DB.findIPRecordIdx(ip, 0, ipv6DB.recordTotal)
ipIdx := ipv6DB.recordStartOffset + ipRecordIdx*(ipv6DB.ipLength+ipv6DB.locationPointerLength)
locationRecordIdxBytes := ipv6DB.dbData[ipIdx+ipv6DB.ipLength : ipIdx+ipv6DB.ipLength+ipv6DB.locationPointerLength]
locationRecordIdx := ipv6DB.threeBytesToUint64(locationRecordIdxBytes)
cArea, aArea := ipv6DB.findLocationRecord(locationRecordIdx)
return cArea, aArea
}
func main() {
ipv6DB, _ := IPv6DBOpen("./ipv6wry.db")
c, a := ipv6DB.GetIPLocation("2606:4700:4700::1001")
fmt.Println(c)
fmt.Println(a)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment