mirror of
				https://github.com/TeaOSLab/EdgeNode.git
				synced 2025-11-04 07:40:56 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			131 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 源码改自:https://github.com/lionsoul2014/ip2region/blob/master/binding/golang/ip2region/ip2Region.go
 | 
						||
 | 
						||
package iplibrary
 | 
						||
 | 
						||
import (
 | 
						||
	"errors"
 | 
						||
	"os"
 | 
						||
	"strconv"
 | 
						||
	"strings"
 | 
						||
)
 | 
						||
 | 
						||
const (
 | 
						||
	IndexBlockLength = 12
 | 
						||
)
 | 
						||
 | 
						||
var err error
 | 
						||
 | 
						||
type IP2Region struct {
 | 
						||
	headerSip []int64
 | 
						||
	headerPtr []int64
 | 
						||
	headerLen int64
 | 
						||
 | 
						||
	// super block index info
 | 
						||
	firstIndexPtr int64
 | 
						||
	lastIndexPtr  int64
 | 
						||
	totalBlocks   int64
 | 
						||
 | 
						||
	dbData []byte
 | 
						||
}
 | 
						||
 | 
						||
type IpInfo struct {
 | 
						||
	CityId   int64
 | 
						||
	Country  string
 | 
						||
	Region   string
 | 
						||
	Province string
 | 
						||
	City     string
 | 
						||
	ISP      string
 | 
						||
}
 | 
						||
 | 
						||
func (ip IpInfo) String() string {
 | 
						||
	return strconv.FormatInt(ip.CityId, 10) + "|" + ip.Country + "|" + ip.Region + "|" + ip.Province + "|" + ip.City + "|" + ip.ISP
 | 
						||
}
 | 
						||
 | 
						||
func getIpInfo(cityId int64, line []byte) *IpInfo {
 | 
						||
	lineSlice := strings.Split(string(line), "|")
 | 
						||
	ipInfo := &IpInfo{}
 | 
						||
	length := len(lineSlice)
 | 
						||
	ipInfo.CityId = cityId
 | 
						||
	if length < 5 {
 | 
						||
		for i := 0; i <= 5-length; i++ {
 | 
						||
			lineSlice = append(lineSlice, "")
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	ipInfo.Country = lineSlice[0]
 | 
						||
	ipInfo.Region = lineSlice[1]
 | 
						||
	ipInfo.Province = lineSlice[2]
 | 
						||
	ipInfo.City = lineSlice[3]
 | 
						||
	ipInfo.ISP = lineSlice[4]
 | 
						||
	return ipInfo
 | 
						||
}
 | 
						||
 | 
						||
func NewIP2Region(path string) (*IP2Region, error) {
 | 
						||
	var region = &IP2Region{}
 | 
						||
	region.dbData, err = os.ReadFile(path)
 | 
						||
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	region.firstIndexPtr = region.ipLongAtOffset(0)
 | 
						||
	region.lastIndexPtr = region.ipLongAtOffset(4)
 | 
						||
	region.totalBlocks = (region.lastIndexPtr-region.firstIndexPtr)/IndexBlockLength + 1
 | 
						||
	return region, nil
 | 
						||
}
 | 
						||
 | 
						||
func (this *IP2Region) MemorySearch(ipStr string) (ipInfo *IpInfo, err error) {
 | 
						||
	ip, err := ip2long(ipStr)
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	h := this.totalBlocks
 | 
						||
	var dataPtr, l int64
 | 
						||
	for l <= h {
 | 
						||
		m := (l + h) >> 1
 | 
						||
		p := this.firstIndexPtr + m*IndexBlockLength
 | 
						||
		sip := this.ipLongAtOffset(p)
 | 
						||
		if ip < sip {
 | 
						||
			h = m - 1
 | 
						||
		} else {
 | 
						||
			eip := this.ipLongAtOffset(p + 4)
 | 
						||
			if ip > eip {
 | 
						||
				l = m + 1
 | 
						||
			} else {
 | 
						||
				dataPtr = this.ipLongAtOffset(p + 8)
 | 
						||
				break
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	if dataPtr == 0 {
 | 
						||
		return nil, nil
 | 
						||
	}
 | 
						||
 | 
						||
	dataLen := (dataPtr >> 24) & 0xFF
 | 
						||
	dataPtr = dataPtr & 0x00FFFFFF
 | 
						||
	return getIpInfo(this.ipLongAtOffset(dataPtr), this.dbData[(dataPtr)+4:dataPtr+dataLen]), nil
 | 
						||
}
 | 
						||
 | 
						||
func (this *IP2Region) ipLongAtOffset(offset int64) int64 {
 | 
						||
	return int64(this.dbData[offset]) |
 | 
						||
		int64(this.dbData[offset+1])<<8 |
 | 
						||
		int64(this.dbData[offset+2])<<16 |
 | 
						||
		int64(this.dbData[offset+3])<<24
 | 
						||
}
 | 
						||
 | 
						||
func ip2long(IpStr string) (int64, error) {
 | 
						||
	bits := strings.Split(IpStr, ".")
 | 
						||
	if len(bits) != 4 {
 | 
						||
		return 0, errors.New("ip format error")
 | 
						||
	}
 | 
						||
 | 
						||
	var sum int64
 | 
						||
	for i, n := range bits {
 | 
						||
		bit, _ := strconv.ParseInt(n, 10, 64)
 | 
						||
		sum += bit << uint(24-8*i)
 | 
						||
	}
 | 
						||
 | 
						||
	return sum, nil
 | 
						||
}
 |