diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go new file mode 100644 index 00000000..58f3fe00 --- /dev/null +++ b/component/mmdb/mmdb.go @@ -0,0 +1,44 @@ +package mmdb + +import ( + "github.com/oschwald/geoip2-golang" + "sync" + + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" +) + +var ( + mmdb *geoip2.Reader + once sync.Once +) + +func LoadFromBytes(buffer []byte) { + once.Do(func() { + var err error + mmdb, err = geoip2.FromBytes(buffer) + if err != nil { + log.Fatalln("Can't load mmdb: %s", err.Error()) + } + }) +} + +func Verify() bool { + instance, err := geoip2.Open(C.Path.MMDB()) + if err == nil { + instance.Close() + } + return err == nil +} + +func Instance() *geoip2.Reader { + once.Do(func() { + var err error + mmdb, err = geoip2.Open(C.Path.MMDB()) + if err != nil { + log.Fatalln("Can't load mmdb: %s", err.Error()) + } + }) + + return mmdb +} diff --git a/config/initial.go b/config/initial.go index 5363d3ba..b2acaa2a 100644 --- a/config/initial.go +++ b/config/initial.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "github.com/Dreamacro/clash/component/mmdb" "io" "net/http" "os" @@ -10,6 +11,23 @@ import ( "github.com/Dreamacro/clash/log" ) +func downloadMMDB(path string) (err error) { + resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb") + if err != nil { + return + } + defer resp.Body.Close() + + f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644) + if err != nil { + return err + } + defer f.Close() + _, err = io.Copy(f, resp.Body) + + return err +} + func downloadGeoIP(path string) (err error) { resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat") if err != nil { @@ -65,6 +83,24 @@ func initGeoIP() error { log.Infoln("Download GeoIP.dat finish") } + if _, err := os.Stat(C.Path.MMDB()); os.IsNotExist(err) { + log.Infoln("Can't find MMDB, start download") + if err := downloadMMDB(C.Path.MMDB()); err != nil { + return fmt.Errorf("can't download MMDB: %s", err.Error()) + } + } + + if !mmdb.Verify() { + log.Warnln("MMDB invalid, remove and download") + if err := os.Remove(C.Path.MMDB()); err != nil { + return fmt.Errorf("can't remove invalid MMDB: %s", err.Error()) + } + + if err := downloadMMDB(C.Path.MMDB()); err != nil { + return fmt.Errorf("can't download MMDB: %s", err.Error()) + } + } + return nil } diff --git a/constant/path.go b/constant/path.go index 4ace7ab0..31b1ef80 100644 --- a/constant/path.go +++ b/constant/path.go @@ -60,6 +60,21 @@ func (p *path) Resolve(path string) string { } func (p *path) MMDB() string { + files, err := ioutil.ReadDir(p.homeDir) + if err != nil { + return "" + } + for _, fi := range files { + if fi.IsDir() { + // 目录则直接跳过 + continue + } else { + if strings.EqualFold(fi.Name(), "Country.mmdb") { + GeoipName = fi.Name() + return P.Join(p.homeDir, fi.Name()) + } + } + } return P.Join(p.homeDir, "Country.mmdb") } diff --git a/go.mod b/go.mod index 0adc2ad5..4b6bbaf9 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99 github.com/lucas-clemente/quic-go v0.25.0 github.com/miekg/dns v1.1.45 + github.com/oschwald/geoip2-golang v1.6.1 github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 @@ -42,6 +43,7 @@ require ( github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/onsi/ginkgo v1.16.4 // indirect + github.com/oschwald/maxminddb-golang v1.8.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect golang.org/x/mod v0.4.2 // indirect diff --git a/go.sum b/go.sum index 3028c065..499fb380 100644 --- a/go.sum +++ b/go.sum @@ -367,6 +367,10 @@ github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2r github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20211123151946-c2389c3cb60a/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/oschwald/geoip2-golang v1.6.1 h1:GKxT3yaWWNXSb7vj6D7eoJBns+lGYgx08QO0UcNm0YY= +github.com/oschwald/geoip2-golang v1.6.1/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s= +github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk= +github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -654,6 +658,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=