feat: Add sing-geoip database support

This commit is contained in:
H1JK 2023-07-14 22:28:24 +08:00
parent 5dd57bab67
commit 081e94c738
7 changed files with 73 additions and 19 deletions

View file

@ -12,42 +12,59 @@ import (
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/oschwald/geoip2-golang"
"github.com/oschwald/maxminddb-golang"
)
type databaseType = uint8
const (
typeMaxmind databaseType = iota
typeSing
)
var (
mmdb *geoip2.Reader
once sync.Once
reader Reader
once sync.Once
)
func LoadFromBytes(buffer []byte) {
once.Do(func() {
var err error
mmdb, err = geoip2.FromBytes(buffer)
mmdb, err := maxminddb.FromBytes(buffer)
if err != nil {
log.Fatalln("Can't load mmdb: %s", err.Error())
}
reader = Reader{Reader: mmdb}
if mmdb.Metadata.DatabaseType == "sing-geoip" {
reader.databaseType = typeSing
} else {
reader.databaseType = typeMaxmind
}
})
}
func Verify() bool {
instance, err := geoip2.Open(C.Path.MMDB())
instance, err := maxminddb.Open(C.Path.MMDB())
if err == nil {
instance.Close()
}
return err == nil
}
func Instance() *geoip2.Reader {
func Instance() Reader {
once.Do(func() {
var err error
mmdb, err = geoip2.Open(C.Path.MMDB())
mmdb, err := maxminddb.Open(C.Path.MMDB())
if err != nil {
log.Fatalln("Can't load mmdb: %s", err.Error())
}
reader = Reader{Reader: mmdb}
if mmdb.Metadata.DatabaseType == "sing-geoip" {
reader.databaseType = typeSing
} else {
reader.databaseType = typeMaxmind
}
})
return mmdb
return reader
}
func DownloadMMDB(path string) (err error) {

36
component/mmdb/reader.go Normal file
View file

@ -0,0 +1,36 @@
package mmdb
import (
"fmt"
"net"
"github.com/oschwald/maxminddb-golang"
)
type geoip2Country struct {
Country struct {
IsoCode string `maxminddb:"iso_code"`
} `maxminddb:"country"`
}
type Reader struct {
*maxminddb.Reader
databaseType
}
func (r Reader) LookupCode(ipAddress net.IP) string {
switch r.databaseType {
case typeMaxmind:
var country geoip2Country
_ = r.Lookup(ipAddress, &country)
return country.Country.IsoCode
case typeSing:
var code string
_ = r.Lookup(ipAddress, &code)
return code
default:
panic(fmt.Sprint("unknown geoip database type:", r.databaseType))
}
}

View file

@ -14,7 +14,7 @@ import (
clashHttp "github.com/Dreamacro/clash/component/http"
C "github.com/Dreamacro/clash/constant"
"github.com/oschwald/geoip2-golang"
"github.com/oschwald/maxminddb-golang"
)
func UpdateGeoDatabases() error {
@ -44,7 +44,7 @@ func UpdateGeoDatabases() error {
return fmt.Errorf("can't download MMDB database file: %w", err)
}
instance, err := geoip2.FromBytes(data)
instance, err := maxminddb.FromBytes(data)
if err != nil {
return fmt.Errorf("invalid MMDB database file: %s", err)
}

View file

@ -91,7 +91,8 @@ func (p *path) MMDB() string {
// 目录则直接跳过
continue
} else {
if strings.EqualFold(fi.Name(), "Country.mmdb") {
if strings.EqualFold(fi.Name(), "Country.mmdb") ||
strings.EqualFold(fi.Name(), "geoip.db") {
GeoipName = fi.Name()
return P.Join(p.homeDir, fi.Name())
}

View file

@ -2,6 +2,7 @@ package dns
import (
"net/netip"
"strings"
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/geodata/router"
@ -9,7 +10,6 @@ import (
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"strings"
)
type fallbackIPFilter interface {
@ -24,8 +24,8 @@ var geoIPMatcher *router.GeoIPMatcher
func (gf *geoipFilter) Match(ip netip.Addr) bool {
if !C.GeodataMode {
record, _ := mmdb.Instance().Country(ip.AsSlice())
return !strings.EqualFold(record.Country.IsoCode, gf.code) && !ip.IsPrivate()
code := mmdb.Instance().LookupCode(ip.AsSlice())
return !strings.EqualFold(code, gf.code) && !ip.IsPrivate()
}
if geoIPMatcher == nil {

2
go.mod
View file

@ -30,6 +30,7 @@ require (
github.com/mroth/weightedrand/v2 v2.0.1
github.com/openacid/low v0.1.21
github.com/oschwald/geoip2-golang v1.9.0
github.com/oschwald/maxminddb-golang v1.11.0
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97
github.com/sagernet/sing v0.2.8-0.20230703002104-c68251b6d059
github.com/sagernet/sing-mux v0.1.1-0.20230703132253-2cedde0fbc90
@ -80,7 +81,6 @@ require (
github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 // indirect
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
github.com/oschwald/maxminddb-golang v1.11.0 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect

View file

@ -40,8 +40,8 @@ func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) {
resolver.IsFakeBroadcastIP(ip), g.adapter
}
if !C.GeodataMode {
record, _ := mmdb.Instance().Country(ip.AsSlice())
return strings.EqualFold(record.Country.IsoCode, g.country), g.adapter
code := mmdb.Instance().LookupCode(ip.AsSlice())
return strings.EqualFold(code, g.country), g.adapter
}
return g.geoIPMatcher.Match(ip.AsSlice()), g.adapter
}