Skip to content

Commit

Permalink
feat: Add Meta-geoip V0 database support
Browse files Browse the repository at this point in the history
  • Loading branch information
H1JK committed Jul 17, 2023
1 parent a82745f commit b0e76ec
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 14 deletions.
21 changes: 15 additions & 6 deletions component/mmdb/mmdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type databaseType = uint8
const (
typeMaxmind databaseType = iota
typeSing
typeMetaV0
)

var (
Expand All @@ -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
}
})
Expand All @@ -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
}
})
Expand Down
26 changes: 23 additions & 3 deletions component/mmdb/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net"

"github.com/oschwald/maxminddb-golang"
"github.com/sagernet/sing/common"
)

type geoip2Country struct {
Expand All @@ -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))
Expand Down
3 changes: 2 additions & 1 deletion constant/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
Expand Down
9 changes: 7 additions & 2 deletions dns/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 7 additions & 2 deletions rules/common/geoip.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down

0 comments on commit b0e76ec

Please sign in to comment.