feat: Add Meta-geoip V0 database support

This commit is contained in:
H1JK 2023-07-17 10:33:20 +08:00
parent a82745f544
commit b0e76ec791
5 changed files with 54 additions and 14 deletions

View file

@ -20,6 +20,7 @@ type databaseType = uint8
const (
typeMaxmind databaseType = iota
typeSing
typeMetaV0
)
var (
@ -34,9 +35,12 @@ func LoadFromBytes(buffer []byte) {
log.Fatalln("Can't load mmdb: %s", err.Error())
}
reader = Reader{Reader: mmdb}
if mmdb.Metadata.DatabaseType == "sing-geoip" {
switch mmdb.Metadata.DatabaseType {
case "sing-geoip":
reader.databaseType = typeSing
} else {
case "Meta-geoip0":
reader.databaseType = typeMetaV0
default:
reader.databaseType = typeMaxmind
}
})
@ -52,14 +56,19 @@ func Verify() bool {
func Instance() Reader {
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 {
log.Fatalln("Can't load mmdb: %s", err.Error())
log.Fatalln("Can't load MMDB: %s", err.Error())
}
reader = Reader{Reader: mmdb}
if mmdb.Metadata.DatabaseType == "sing-geoip" {
switch mmdb.Metadata.DatabaseType {
case "sing-geoip":
reader.databaseType = typeSing
} else {
case "Meta-geoip0":
reader.databaseType = typeMetaV0
default:
reader.databaseType = typeMaxmind
}
})

View file

@ -5,6 +5,7 @@ import (
"net"
"github.com/oschwald/maxminddb-golang"
"github.com/sagernet/sing/common"
)
type geoip2Country struct {
@ -18,17 +19,36 @@ type Reader struct {
databaseType
}
func (r Reader) LookupCode(ipAddress net.IP) string {
func (r Reader) LookupCode(ipAddress net.IP) []string {
switch r.databaseType {
case typeMaxmind:
var country geoip2Country
_ = r.Lookup(ipAddress, &country)
return country.Country.IsoCode
if country.Country.IsoCode == "" {
return []string{}
}
return []string{country.Country.IsoCode}
case typeSing:
var code string
_ = 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:
panic(fmt.Sprint("unknown geoip database type:", r.databaseType))

View file

@ -92,7 +92,8 @@ func (p *path) MMDB() string {
continue
} else {
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()
return P.Join(p.homeDir, fi.Name())
}

View file

@ -24,8 +24,13 @@ var geoIPMatcher *router.GeoIPMatcher
func (gf *geoipFilter) Match(ip netip.Addr) bool {
if !C.GeodataMode {
code := mmdb.Instance().LookupCode(ip.AsSlice())
return !strings.EqualFold(code, gf.code) && !ip.IsPrivate()
codes := mmdb.Instance().LookupCode(ip.AsSlice())
for _, code := range codes {
if !strings.EqualFold(code, gf.code) && !ip.IsPrivate() {
return true
}
}
return false
}
if geoIPMatcher == nil {

View file

@ -40,8 +40,13 @@ func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) {
resolver.IsFakeBroadcastIP(ip), g.adapter
}
if !C.GeodataMode {
code := mmdb.Instance().LookupCode(ip.AsSlice())
return strings.EqualFold(code, g.country), g.adapter
codes := mmdb.Instance().LookupCode(ip.AsSlice())
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
}