Files
waf-platform/EdgeCommon/pkg/iplibrary/default_ip_library.go

179 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
_ "embed"
"fmt"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/logs"
"net"
"os"
"sync"
)
//go:embed GeoLite2-City.mmdb
var maxMindCityDBData []byte
//go:embed GeoLite2-ASN.mmdb
var maxMindASNDBData []byte
var defaultLibrary *IPLibrary
var commonLibrary *IPLibrary
var libraryLocker = &sync.Mutex{} // 为了保持加载顺序性
// InitDefault 加载默认的IP库
// 优先使用后台上传的 MaxMind 文件,如果没有上传则使用代码中嵌入的 MaxMind 库
func InitDefault() error {
libraryLocker.Lock()
defer libraryLocker.Unlock()
// 1. 优先检查后台上传的 MaxMind 文件data/iplibrary/ 目录)
iplibDir := Tea.Root + "/data/iplibrary"
cityDBPath := iplibDir + "/maxmind-city.mmdb"
asnDBPath := iplibDir + "/maxmind-asn.mmdb"
// 检查上传的文件是否存在
uploadedFileExists := false
if _, err := os.Stat(cityDBPath); err == nil {
uploadedFileExists = true
}
// 如果 commonLibrary 已存在,需要检查是否应该重新加载
if commonLibrary != nil {
if commonLibrary.reader != nil {
// 检查是否是 MaxMindReader
_, isMaxMind := commonLibrary.reader.(*MaxMindReader)
if isMaxMind {
// 如果之前使用的是上传的文件,但现在文件不存在了,需要重新加载
// 如果之前使用的是嵌入的库,且现在也没有上传的文件,可以继续使用
// 这里通过检查文件是否存在来判断:如果文件存在,且库已加载,直接使用
if uploadedFileExists {
defaultLibrary = commonLibrary
return nil
}
// 文件不存在了,需要重新加载(使用嵌入的库)
commonLibrary.Destroy()
commonLibrary = nil
defaultLibrary = nil
} else {
// 不是 MaxMind 库,销毁并重新初始化
commonLibrary.Destroy()
commonLibrary = nil
defaultLibrary = nil
}
} else {
commonLibrary = nil
defaultLibrary = nil
}
}
if uploadedFileExists {
// 检查 ASN 文件是否存在
asnPath := ""
if _, err := os.Stat(asnDBPath); err == nil {
asnPath = asnDBPath
}
reader, err := NewMaxMindReader(cityDBPath, asnPath)
if err == nil {
defaultLibrary = NewIPLibraryWithReader(reader)
commonLibrary = defaultLibrary
logs.Println("[IP_LIBRARY]uploaded MaxMind database loaded successfully from: " + cityDBPath)
return nil
}
// 上传的文件加载失败,继续使用嵌入的库
logs.Println("[IP_LIBRARY]failed to load uploaded MaxMind database: " + err.Error() + ", will use embedded database")
}
// 2. 使用嵌入的 MaxMind 数据库作为默认
if len(maxMindCityDBData) == 0 {
return fmt.Errorf("embedded MaxMind database is empty (this should not happen if build is correct), please upload MaxMind database file or rebuild the application")
}
reader, err := NewMaxMindReaderFromBytes(maxMindCityDBData, maxMindASNDBData)
if err != nil {
return fmt.Errorf("failed to load embedded MaxMind database: %w", err)
}
defaultLibrary = NewIPLibraryWithReader(reader)
commonLibrary = defaultLibrary
logs.Println("[IP_LIBRARY]embedded MaxMind database loaded successfully (size: " + fmt.Sprintf("%d", len(maxMindCityDBData)) + " bytes)")
return nil
}
// Lookup 查询IP信息
func Lookup(ip net.IP) *QueryResult {
if defaultLibrary == nil {
// 如果 defaultLibrary 未初始化,尝试初始化
_ = InitDefault()
if defaultLibrary == nil {
return &QueryResult{}
}
}
return defaultLibrary.Lookup(ip)
}
// LookupIP 查询IP信息
func LookupIP(ip string) *QueryResult {
if defaultLibrary == nil {
// 如果 defaultLibrary 未初始化,尝试初始化
_ = InitDefault()
if defaultLibrary == nil {
return &QueryResult{}
}
}
return defaultLibrary.LookupIP(ip)
}
// LookupIPSummaries 查询一组IP对应的区域描述
func LookupIPSummaries(ipList []string) map[string]string /** ip => summary **/ {
var result = map[string]string{}
for _, ip := range ipList {
var region = LookupIP(ip)
if region != nil && region.IsOk() {
result[ip] = region.Summary()
}
}
return result
}
type IPLibrary struct {
reader ReaderInterface
}
func NewIPLibrary() *IPLibrary {
return &IPLibrary{}
}
func NewIPLibraryWithReader(reader ReaderInterface) *IPLibrary {
return &IPLibrary{reader: reader}
}
func (this *IPLibrary) Lookup(ip net.IP) *QueryResult {
if this.reader == nil {
return &QueryResult{}
}
var result = this.reader.Lookup(ip)
if result == nil {
result = &QueryResult{}
}
return result
}
func (this *IPLibrary) LookupIP(ip string) *QueryResult {
if this.reader == nil {
return &QueryResult{}
}
return this.Lookup(net.ParseIP(ip))
}
func (this *IPLibrary) Destroy() {
if this.reader != nil {
this.reader.Destroy()
this.reader = nil
}
}