feat: add IP-ASN rule

This commit is contained in:
xishang0128
2024-03-12 03:14:25 +08:00
parent 7ad37ca0e3
commit 44d8a14629
15 changed files with 248 additions and 33 deletions

View File

@@ -14,8 +14,11 @@ import (
"github.com/metacubex/mihomo/log"
)
var initGeoSite bool
var initGeoIP int
var (
initGeoSite bool
initGeoIP int
initASN bool
)
func InitGeoSite() error {
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
@@ -113,7 +116,7 @@ func InitGeoIP() error {
}
if initGeoIP != 2 {
if !mmdb.Verify() {
if !mmdb.Verify(C.Path.MMDB()) {
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())
@@ -126,3 +129,27 @@ func InitGeoIP() error {
}
return nil
}
func InitASN() error {
if _, err := os.Stat(C.Path.ASN()); os.IsNotExist(err) {
log.Infoln("Can't find ASN.mmdb, start download")
if err := mmdb.DownloadASN(C.Path.ASN()); err != nil {
return fmt.Errorf("can't download ASN.mmdb: %s", err.Error())
}
log.Infoln("Download ASN.mmdb finish")
initASN = false
}
if !initASN {
if !mmdb.Verify(C.Path.ASN()) {
log.Warnln("ASN invalid, remove and download")
if err := os.Remove(C.Path.ASN()); err != nil {
return fmt.Errorf("can't remove invalid ASN: %s", err.Error())
}
if err := mmdb.DownloadASN(C.Path.ASN()); err != nil {
return fmt.Errorf("can't download ASN: %s", err.Error())
}
}
initASN = true
}
return nil
}

View File

@@ -25,56 +25,58 @@ const (
)
var (
reader Reader
once sync.Once
IPreader IPReader
ASNreader ASNReader
IPonce sync.Once
ASNonce sync.Once
)
func LoadFromBytes(buffer []byte) {
once.Do(func() {
IPonce.Do(func() {
mmdb, err := maxminddb.FromBytes(buffer)
if err != nil {
log.Fatalln("Can't load mmdb: %s", err.Error())
}
reader = Reader{Reader: mmdb}
IPreader = IPReader{Reader: mmdb}
switch mmdb.Metadata.DatabaseType {
case "sing-geoip":
reader.databaseType = typeSing
IPreader.databaseType = typeSing
case "Meta-geoip0":
reader.databaseType = typeMetaV0
IPreader.databaseType = typeMetaV0
default:
reader.databaseType = typeMaxmind
IPreader.databaseType = typeMaxmind
}
})
}
func Verify() bool {
instance, err := maxminddb.Open(C.Path.MMDB())
func Verify(path string) bool {
instance, err := maxminddb.Open(path)
if err == nil {
instance.Close()
}
return err == nil
}
func Instance() Reader {
once.Do(func() {
func IPInstance() IPReader {
IPonce.Do(func() {
mmdbPath := C.Path.MMDB()
log.Infoln("Load MMDB file: %s", mmdbPath)
mmdb, err := maxminddb.Open(mmdbPath)
if err != nil {
log.Fatalln("Can't load MMDB: %s", err.Error())
}
reader = Reader{Reader: mmdb}
IPreader = IPReader{Reader: mmdb}
switch mmdb.Metadata.DatabaseType {
case "sing-geoip":
reader.databaseType = typeSing
IPreader.databaseType = typeSing
case "Meta-geoip0":
reader.databaseType = typeMetaV0
IPreader.databaseType = typeMetaV0
default:
reader.databaseType = typeMaxmind
IPreader.databaseType = typeMaxmind
}
})
return reader
return IPreader
}
func DownloadMMDB(path string) (err error) {
@@ -96,6 +98,43 @@ func DownloadMMDB(path string) (err error) {
return err
}
func Reload() {
mihomoOnce.Reset(&once)
func ASNInstance() ASNReader {
ASNonce.Do(func() {
ASNPath := C.Path.ASN()
log.Infoln("Load ASN file: %s", ASNPath)
asn, err := maxminddb.Open(ASNPath)
if err != nil {
log.Fatalln("Can't load ASN: %s", err.Error())
}
ASNreader = ASNReader{Reader: asn}
})
return ASNreader
}
func DownloadASN(path string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
resp, err := mihomoHttp.HttpRequest(ctx, C.ASNUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
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 ReloadIP() {
mihomoOnce.Reset(&IPonce)
}
func ReloadASN() {
mihomoOnce.Reset(&ASNonce)
}

View File

@@ -5,14 +5,14 @@ package mmdb
import "github.com/oschwald/maxminddb-golang"
func InstallOverride(override *maxminddb.Reader) {
newReader := Reader{Reader: override}
newReader := IPReader{Reader: override}
switch override.Metadata.DatabaseType {
case "sing-geoip":
reader.databaseType = typeSing
IPreader.databaseType = typeSing
case "Meta-geoip0":
reader.databaseType = typeMetaV0
IPreader.databaseType = typeMetaV0
default:
reader.databaseType = typeMaxmind
IPreader.databaseType = typeMaxmind
}
reader = newReader
IPreader = newReader
}

View File

@@ -14,12 +14,21 @@ type geoip2Country struct {
} `maxminddb:"country"`
}
type Reader struct {
type IPReader struct {
*maxminddb.Reader
databaseType
}
func (r Reader) LookupCode(ipAddress net.IP) []string {
type ASNReader struct {
*maxminddb.Reader
}
type ASNResult struct {
AutonomousSystemNumber uint32 `maxminddb:"autonomous_system_number"`
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
}
func (r IPReader) LookupCode(ipAddress net.IP) []string {
switch r.databaseType {
case typeMaxmind:
var country geoip2Country
@@ -56,3 +65,9 @@ func (r Reader) LookupCode(ipAddress net.IP) []string {
panic(fmt.Sprint("unknown geoip database type:", r.databaseType))
}
}
func (r ASNReader) LookupASN(ip net.IP) ASNResult {
var result ASNResult
r.Lookup(ip, &result)
return result
}