feat: Add Meta-geoip V0 database support
This commit is contained in:
parent
a82745f544
commit
b0e76ec791
5 changed files with 54 additions and 14 deletions
|
@ -20,6 +20,7 @@ type databaseType = uint8
|
||||||
const (
|
const (
|
||||||
typeMaxmind databaseType = iota
|
typeMaxmind databaseType = iota
|
||||||
typeSing
|
typeSing
|
||||||
|
typeMetaV0
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -34,9 +35,12 @@ func LoadFromBytes(buffer []byte) {
|
||||||
log.Fatalln("Can't load mmdb: %s", err.Error())
|
log.Fatalln("Can't load mmdb: %s", err.Error())
|
||||||
}
|
}
|
||||||
reader = Reader{Reader: mmdb}
|
reader = Reader{Reader: mmdb}
|
||||||
if mmdb.Metadata.DatabaseType == "sing-geoip" {
|
switch mmdb.Metadata.DatabaseType {
|
||||||
|
case "sing-geoip":
|
||||||
reader.databaseType = typeSing
|
reader.databaseType = typeSing
|
||||||
} else {
|
case "Meta-geoip0":
|
||||||
|
reader.databaseType = typeMetaV0
|
||||||
|
default:
|
||||||
reader.databaseType = typeMaxmind
|
reader.databaseType = typeMaxmind
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -52,14 +56,19 @@ func Verify() bool {
|
||||||
|
|
||||||
func Instance() Reader {
|
func Instance() Reader {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
mmdb, err := maxminddb.Open(C.Path.MMDB())
|
mmdbPath := C.Path.MMDB()
|
||||||
|
log.Debugln("Load MMDB file: %s", mmdbPath)
|
||||||
|
mmdb, err := maxminddb.Open(mmdbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Can't load mmdb: %s", err.Error())
|
log.Fatalln("Can't load MMDB: %s", err.Error())
|
||||||
}
|
}
|
||||||
reader = Reader{Reader: mmdb}
|
reader = Reader{Reader: mmdb}
|
||||||
if mmdb.Metadata.DatabaseType == "sing-geoip" {
|
switch mmdb.Metadata.DatabaseType {
|
||||||
|
case "sing-geoip":
|
||||||
reader.databaseType = typeSing
|
reader.databaseType = typeSing
|
||||||
} else {
|
case "Meta-geoip0":
|
||||||
|
reader.databaseType = typeMetaV0
|
||||||
|
default:
|
||||||
reader.databaseType = typeMaxmind
|
reader.databaseType = typeMaxmind
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/oschwald/maxminddb-golang"
|
"github.com/oschwald/maxminddb-golang"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type geoip2Country struct {
|
type geoip2Country struct {
|
||||||
|
@ -18,17 +19,36 @@ type Reader struct {
|
||||||
databaseType
|
databaseType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Reader) LookupCode(ipAddress net.IP) string {
|
func (r Reader) LookupCode(ipAddress net.IP) []string {
|
||||||
switch r.databaseType {
|
switch r.databaseType {
|
||||||
case typeMaxmind:
|
case typeMaxmind:
|
||||||
var country geoip2Country
|
var country geoip2Country
|
||||||
_ = r.Lookup(ipAddress, &country)
|
_ = r.Lookup(ipAddress, &country)
|
||||||
return country.Country.IsoCode
|
if country.Country.IsoCode == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
return []string{country.Country.IsoCode}
|
||||||
|
|
||||||
case typeSing:
|
case typeSing:
|
||||||
var code string
|
var code string
|
||||||
_ = r.Lookup(ipAddress, &code)
|
_ = r.Lookup(ipAddress, &code)
|
||||||
return code
|
if code == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
return []string{code}
|
||||||
|
|
||||||
|
case typeMetaV0:
|
||||||
|
var record any
|
||||||
|
_ = r.Lookup(ipAddress, &record)
|
||||||
|
switch record := record.(type) {
|
||||||
|
case string:
|
||||||
|
return []string{record}
|
||||||
|
case []any: // lookup returned type of slice is []any
|
||||||
|
return common.Map(record, func(it any) string {
|
||||||
|
return it.(string)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprint("unknown geoip database type:", r.databaseType))
|
panic(fmt.Sprint("unknown geoip database type:", r.databaseType))
|
||||||
|
|
|
@ -92,7 +92,8 @@ func (p *path) MMDB() string {
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
if strings.EqualFold(fi.Name(), "Country.mmdb") ||
|
if strings.EqualFold(fi.Name(), "Country.mmdb") ||
|
||||||
strings.EqualFold(fi.Name(), "geoip.db") {
|
strings.EqualFold(fi.Name(), "geoip.db") ||
|
||||||
|
strings.EqualFold(fi.Name(), "geoip.metadb") {
|
||||||
GeoipName = fi.Name()
|
GeoipName = fi.Name()
|
||||||
return P.Join(p.homeDir, fi.Name())
|
return P.Join(p.homeDir, fi.Name())
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,13 @@ var geoIPMatcher *router.GeoIPMatcher
|
||||||
|
|
||||||
func (gf *geoipFilter) Match(ip netip.Addr) bool {
|
func (gf *geoipFilter) Match(ip netip.Addr) bool {
|
||||||
if !C.GeodataMode {
|
if !C.GeodataMode {
|
||||||
code := mmdb.Instance().LookupCode(ip.AsSlice())
|
codes := mmdb.Instance().LookupCode(ip.AsSlice())
|
||||||
return !strings.EqualFold(code, gf.code) && !ip.IsPrivate()
|
for _, code := range codes {
|
||||||
|
if !strings.EqualFold(code, gf.code) && !ip.IsPrivate() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if geoIPMatcher == nil {
|
if geoIPMatcher == nil {
|
||||||
|
|
|
@ -40,8 +40,13 @@ func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) {
|
||||||
resolver.IsFakeBroadcastIP(ip), g.adapter
|
resolver.IsFakeBroadcastIP(ip), g.adapter
|
||||||
}
|
}
|
||||||
if !C.GeodataMode {
|
if !C.GeodataMode {
|
||||||
code := mmdb.Instance().LookupCode(ip.AsSlice())
|
codes := mmdb.Instance().LookupCode(ip.AsSlice())
|
||||||
return strings.EqualFold(code, g.country), g.adapter
|
for _, code := range codes {
|
||||||
|
if strings.EqualFold(code, g.country) {
|
||||||
|
return true, g.adapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, g.adapter
|
||||||
}
|
}
|
||||||
return g.geoIPMatcher.Match(ip.AsSlice()), g.adapter
|
return g.geoIPMatcher.Match(ip.AsSlice()), g.adapter
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue