mirror of
https://github.com/bolucat/Archive.git
synced 2026-04-23 00:17:16 +08:00
289 lines
8.3 KiB
Go
289 lines
8.3 KiB
Go
package maxmind
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/Loyalsoldier/geoip/lib"
|
|
"github.com/oschwald/geoip2-golang/v2"
|
|
"github.com/oschwald/maxminddb-golang/v2"
|
|
)
|
|
|
|
var (
|
|
defaultGeoLite2CountryMMDBOutputName = "Country.mmdb"
|
|
|
|
defaultMaxmindOutputDir = filepath.Join("./", "output", "maxmind")
|
|
defaultDBIPOutputDir = filepath.Join("./", "output", "db-ip")
|
|
defaultIPInfoOutputDir = filepath.Join("./", "output", "ipinfo")
|
|
)
|
|
|
|
// Reference: https://github.com/oschwald/geoip2-golang/blob/HEAD/models.go
|
|
var (
|
|
zeroDBIPLanguageNames dbipLanguageNames
|
|
zeroDBIPContinent dbipContinent
|
|
zeroDBIPCountryRecord dbipCountryRecord
|
|
zeroDBIPRepresentedCountry dbipRepresentedCountry
|
|
zeroDBIPCountry dbipCountry
|
|
)
|
|
|
|
// Reference: https://ipinfo.io/lite
|
|
type ipInfoLite struct {
|
|
ASN string `maxminddb:"asn"`
|
|
ASName string `maxminddb:"as_name"`
|
|
ASDomain string `maxminddb:"as_domain"`
|
|
Continent string `maxminddb:"continent"`
|
|
ContinentCode string `maxminddb:"continent_code"`
|
|
Country string `maxminddb:"country"`
|
|
CountryCode string `maxminddb:"country_code"`
|
|
}
|
|
|
|
// Reference: https://github.com/oschwald/geoip2-golang/blob/HEAD/models.go
|
|
type dbipLanguageNames struct {
|
|
geoip2.Names
|
|
|
|
// Persian localized name
|
|
Persian string `json:"fa,omitzero" maxminddb:"fa"`
|
|
// Korean localized name
|
|
Korean string `json:"ko,omitzero" maxminddb:"ko"`
|
|
}
|
|
|
|
func (d dbipLanguageNames) HasData() bool {
|
|
return d != zeroDBIPLanguageNames
|
|
}
|
|
|
|
// Reference: https://github.com/oschwald/geoip2-golang/blob/HEAD/models.go
|
|
type dbipContinent struct {
|
|
geoip2.Continent
|
|
|
|
Names dbipLanguageNames `json:"names,omitzero" maxminddb:"names"`
|
|
}
|
|
|
|
func (d dbipContinent) HasData() bool {
|
|
return d != zeroDBIPContinent
|
|
}
|
|
|
|
// Reference: https://github.com/oschwald/geoip2-golang/blob/HEAD/models.go
|
|
type dbipCountryRecord struct {
|
|
geoip2.CountryRecord
|
|
|
|
Names dbipLanguageNames `json:"names,omitzero" maxminddb:"names"`
|
|
}
|
|
|
|
func (d dbipCountryRecord) HasData() bool {
|
|
return d != zeroDBIPCountryRecord
|
|
}
|
|
|
|
// Reference: https://github.com/oschwald/geoip2-golang/blob/HEAD/models.go
|
|
type dbipRepresentedCountry struct {
|
|
geoip2.RepresentedCountry
|
|
|
|
Names dbipLanguageNames `json:"names,omitzero" maxminddb:"names"`
|
|
}
|
|
|
|
func (d dbipRepresentedCountry) HasData() bool {
|
|
return d != zeroDBIPRepresentedCountry
|
|
}
|
|
|
|
// Reference: https://github.com/oschwald/geoip2-golang/blob/HEAD/models.go
|
|
type dbipCountry struct {
|
|
Traits geoip2.CountryTraits `json:"traits,omitzero" maxminddb:"traits"`
|
|
Continent dbipContinent `json:"continent,omitzero" maxminddb:"continent"`
|
|
RepresentedCountry dbipRepresentedCountry `json:"represented_country,omitzero" maxminddb:"represented_country"`
|
|
Country dbipCountryRecord `json:"country,omitzero" maxminddb:"country"`
|
|
RegisteredCountry dbipCountryRecord `json:"registered_country,omitzero" maxminddb:"registered_country"`
|
|
}
|
|
|
|
func (d dbipCountry) HasData() bool {
|
|
return d != zeroDBIPCountry
|
|
}
|
|
|
|
func newGeoLite2CountryMMDBOut(iType string, iDesc string, action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
|
|
var tmp struct {
|
|
OutputName string `json:"outputName"`
|
|
OutputDir string `json:"outputDir"`
|
|
Want []string `json:"wantedList"`
|
|
Overwrite []string `json:"overwriteList"`
|
|
Exclude []string `json:"excludedList"`
|
|
OnlyIPType lib.IPType `json:"onlyIPType"`
|
|
|
|
SourceMMDBURI string `json:"sourceMMDBURI"`
|
|
}
|
|
|
|
if len(data) > 0 {
|
|
if err := json.Unmarshal(data, &tmp); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if tmp.OutputName == "" {
|
|
tmp.OutputName = defaultGeoLite2CountryMMDBOutputName
|
|
}
|
|
|
|
if tmp.OutputDir == "" {
|
|
switch iType {
|
|
case TypeGeoLite2CountryMMDBOut:
|
|
tmp.OutputDir = defaultMaxmindOutputDir
|
|
|
|
case TypeDBIPCountryMMDBOut:
|
|
tmp.OutputDir = defaultDBIPOutputDir
|
|
|
|
case TypeIPInfoCountryMMDBOut:
|
|
tmp.OutputDir = defaultIPInfoOutputDir
|
|
}
|
|
}
|
|
|
|
return &GeoLite2CountryMMDBOut{
|
|
Type: iType,
|
|
Action: action,
|
|
Description: iDesc,
|
|
OutputName: tmp.OutputName,
|
|
OutputDir: tmp.OutputDir,
|
|
Want: tmp.Want,
|
|
Overwrite: tmp.Overwrite,
|
|
Exclude: tmp.Exclude,
|
|
OnlyIPType: tmp.OnlyIPType,
|
|
|
|
SourceMMDBURI: tmp.SourceMMDBURI,
|
|
}, nil
|
|
}
|
|
|
|
func (g *GeoLite2CountryMMDBOut) GetExtraInfo() (map[string]any, error) {
|
|
if strings.TrimSpace(g.SourceMMDBURI) == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
var content []byte
|
|
var err error
|
|
switch {
|
|
case strings.HasPrefix(strings.ToLower(g.SourceMMDBURI), "http://"), strings.HasPrefix(strings.ToLower(g.SourceMMDBURI), "https://"):
|
|
content, err = lib.GetRemoteURLContent(g.SourceMMDBURI)
|
|
default:
|
|
content, err = os.ReadFile(g.SourceMMDBURI)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
db, err := maxminddb.OpenBytes(content)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer db.Close()
|
|
|
|
infoList := make(map[string]any)
|
|
for network := range db.Networks() {
|
|
switch g.Type {
|
|
case TypeGeoLite2CountryMMDBOut:
|
|
var record geoip2.Country
|
|
err := network.Decode(&record)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
switch {
|
|
case strings.TrimSpace(record.Country.ISOCode) != "":
|
|
countryCode := strings.ToUpper(strings.TrimSpace(record.Country.ISOCode))
|
|
if _, found := infoList[countryCode]; !found {
|
|
infoList[countryCode] = geoip2.Country{
|
|
Continent: record.Continent,
|
|
Country: record.Country,
|
|
}
|
|
}
|
|
|
|
case strings.TrimSpace(record.RegisteredCountry.ISOCode) != "":
|
|
countryCode := strings.ToUpper(strings.TrimSpace(record.RegisteredCountry.ISOCode))
|
|
if _, found := infoList[countryCode]; !found {
|
|
infoList[countryCode] = geoip2.Country{
|
|
Continent: record.Continent,
|
|
Country: record.RegisteredCountry,
|
|
}
|
|
}
|
|
|
|
case strings.TrimSpace(record.RepresentedCountry.ISOCode) != "":
|
|
countryCode := strings.ToUpper(strings.TrimSpace(record.RepresentedCountry.ISOCode))
|
|
if _, found := infoList[countryCode]; !found {
|
|
infoList[countryCode] = geoip2.Country{
|
|
Continent: record.Continent,
|
|
Country: geoip2.CountryRecord{
|
|
Names: record.RepresentedCountry.Names,
|
|
ISOCode: record.RepresentedCountry.ISOCode,
|
|
GeoNameID: record.RepresentedCountry.GeoNameID,
|
|
IsInEuropeanUnion: record.RepresentedCountry.IsInEuropeanUnion,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
case TypeDBIPCountryMMDBOut:
|
|
var record dbipCountry
|
|
err := network.Decode(&record)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
switch {
|
|
case strings.TrimSpace(record.Country.ISOCode) != "":
|
|
countryCode := strings.ToUpper(strings.TrimSpace(record.Country.ISOCode))
|
|
if _, found := infoList[countryCode]; !found {
|
|
infoList[countryCode] = dbipCountry{
|
|
Continent: record.Continent,
|
|
Country: record.Country,
|
|
}
|
|
}
|
|
|
|
case strings.TrimSpace(record.RegisteredCountry.ISOCode) != "":
|
|
countryCode := strings.ToUpper(strings.TrimSpace(record.RegisteredCountry.ISOCode))
|
|
if _, found := infoList[countryCode]; !found {
|
|
infoList[countryCode] = dbipCountry{
|
|
Continent: record.Continent,
|
|
Country: record.RegisteredCountry,
|
|
}
|
|
}
|
|
|
|
case strings.TrimSpace(record.RepresentedCountry.ISOCode) != "":
|
|
countryCode := strings.ToUpper(strings.TrimSpace(record.RepresentedCountry.ISOCode))
|
|
if _, found := infoList[countryCode]; !found {
|
|
infoList[countryCode] = dbipCountry{
|
|
Continent: record.Continent,
|
|
Country: dbipCountryRecord{
|
|
CountryRecord: geoip2.CountryRecord{
|
|
ISOCode: record.RepresentedCountry.ISOCode,
|
|
GeoNameID: record.RepresentedCountry.GeoNameID,
|
|
IsInEuropeanUnion: record.RepresentedCountry.IsInEuropeanUnion,
|
|
},
|
|
Names: record.RepresentedCountry.Names,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
case TypeIPInfoCountryMMDBOut:
|
|
var record ipInfoLite
|
|
err := network.Decode(&record)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
countryCode := strings.ToUpper(strings.TrimSpace(record.CountryCode))
|
|
if _, found := infoList[countryCode]; !found {
|
|
record.ASN = ""
|
|
record.ASName = ""
|
|
record.ASDomain = ""
|
|
infoList[countryCode] = record
|
|
}
|
|
|
|
default:
|
|
return nil, lib.ErrNotSupportedFormat
|
|
}
|
|
|
|
}
|
|
|
|
if len(infoList) == 0 {
|
|
return nil, fmt.Errorf("❌ [type %s | action %s] no extra info found in the source MMDB file: %s", g.Type, g.Action, g.SourceMMDBURI)
|
|
}
|
|
|
|
return infoList, nil
|
|
}
|