mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-06-19 22:58:03 +03:00
Refactor: GeoSite & GeoIP
This commit is contained in:
90
common/matcher/geoip/conf.go
Normal file
90
common/matcher/geoip/conf.go
Normal file
@ -0,0 +1,90 @@
|
||||
package geoip
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
)
|
||||
|
||||
var (
|
||||
FileCache = make(map[string][]byte)
|
||||
IPCache = make(map[string]*GeoIP)
|
||||
)
|
||||
|
||||
func LoadGeoIP(code string) ([]*CIDR, error) {
|
||||
return LoadIPFile("geoip.dat", code)
|
||||
}
|
||||
|
||||
func LoadIPFile(file, code string) ([]*CIDR, error) {
|
||||
index := file + ":" + code
|
||||
if IPCache[index] == nil {
|
||||
bs, err := loadFile(file)
|
||||
if err != nil {
|
||||
return nil, newError("failed to load file: ", file).Base(err)
|
||||
}
|
||||
bs = find(bs, []byte(code))
|
||||
if bs == nil {
|
||||
return nil, newError("code not found in ", file, ": ", code)
|
||||
}
|
||||
var geoipdat GeoIP
|
||||
if err := proto.Unmarshal(bs, &geoipdat); err != nil {
|
||||
return nil, newError("error unmarshal IP in ", file, ": ", code).Base(err)
|
||||
}
|
||||
defer runtime.GC() // or debug.FreeOSMemory()
|
||||
return geoipdat.Cidr, nil // do not cache geoip
|
||||
IPCache[index] = &geoipdat
|
||||
}
|
||||
return IPCache[index].Cidr, nil
|
||||
}
|
||||
|
||||
func loadFile(file string) ([]byte, error) {
|
||||
if FileCache[file] == nil {
|
||||
bs, err := filesystem.ReadAsset(file)
|
||||
if err != nil {
|
||||
return nil, newError("failed to open file: ", file).Base(err)
|
||||
}
|
||||
if len(bs) == 0 {
|
||||
return nil, newError("empty file: ", file)
|
||||
}
|
||||
// Do not cache file, may save RAM when there
|
||||
// are many files, but consume CPU each time.
|
||||
return bs, nil
|
||||
FileCache[file] = bs
|
||||
}
|
||||
return FileCache[file], nil
|
||||
}
|
||||
|
||||
func find(data, code []byte) []byte {
|
||||
codeL := len(code)
|
||||
if codeL == 0 {
|
||||
return nil
|
||||
}
|
||||
for {
|
||||
dataL := len(data)
|
||||
if dataL < 2 {
|
||||
return nil
|
||||
}
|
||||
x, y := proto.DecodeVarint(data[1:])
|
||||
if x == 0 && y == 0 {
|
||||
return nil
|
||||
}
|
||||
headL, bodyL := 1+y, int(x)
|
||||
dataL -= headL
|
||||
if dataL < bodyL {
|
||||
return nil
|
||||
}
|
||||
data = data[headL:]
|
||||
if int(data[1]) == codeL {
|
||||
for i := 0; i < codeL && data[2+i] == code[i]; i++ {
|
||||
if i+1 == codeL {
|
||||
return data[:bodyL]
|
||||
}
|
||||
}
|
||||
}
|
||||
if dataL == bodyL {
|
||||
return nil
|
||||
}
|
||||
data = data[bodyL:]
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user