diff --git a/internal/geoip/geoip.go b/internal/geoip/geoip.go index 9dd46ef..606db49 100644 --- a/internal/geoip/geoip.go +++ b/internal/geoip/geoip.go @@ -24,6 +24,9 @@ var ( reader *maxminddb.Reader loaded bool mmdbPath string + + dnsCacheMu sync.RWMutex + dnsCache = make(map[string][]net.IP) ) // countryNameCN maps ISO country codes to Chinese names. @@ -193,14 +196,35 @@ func Lookup(ipStr string) *GeoResult { } // LookupHost resolves a hostname to its first IP and then looks up geo info. +// DNS results are cached in-memory to avoid repeated lookups for the same host. func LookupHost(host string) *GeoResult { // If it's already an IP, lookup directly if ip := net.ParseIP(host); ip != nil { return Lookup(ip.String()) } - // Resolve domain - ips, err := net.LookupIP(host) - if err != nil || len(ips) == 0 { + + // Check DNS cache first + dnsCacheMu.RLock() + ips, ok := dnsCache[host] + dnsCacheMu.RUnlock() + + if !ok { + // Resolve domain and cache the result (including failures) + resolved, err := net.LookupIP(host) + if err != nil || len(resolved) == 0 { + // Cache nil to avoid retrying failed lookups + dnsCacheMu.Lock() + dnsCache[host] = nil + dnsCacheMu.Unlock() + return nil + } + ips = resolved + dnsCacheMu.Lock() + dnsCache[host] = ips + dnsCacheMu.Unlock() + } + + if len(ips) == 0 { return nil } return Lookup(ips[0].String()) diff --git a/internal/util/flag.go b/internal/util/flag.go index dddd781..d310226 100644 --- a/internal/util/flag.go +++ b/internal/util/flag.go @@ -164,10 +164,15 @@ func DetectGeo(name string) GeoInfo { return detectGeoFromName(name) } -// DetectGeoWithServer returns geographic info by looking up the proxy's -// server address via GeoIP first, falling back to name-based detection. +// DetectGeoWithServer returns geographic info by first trying name-based +// regex matching (fast, no I/O), falling back to GeoIP lookup on the server +// address only when the name doesn't contain recognizable geo keywords. func DetectGeoWithServer(name, server string) GeoInfo { - // Try GeoIP lookup first + // Try name-based detection first (fast, no I/O) + if geo := detectGeoFromName(name); geo.CountryName != "" { + return geo + } + // Fallback to GeoIP lookup (slow, involves DNS) if server != "" { host := server // Strip port if present @@ -184,8 +189,7 @@ func DetectGeoWithServer(name, server string) GeoInfo { } } } - // Fallback to name-based detection - return detectGeoFromName(name) + return GeoInfo{} } // detectGeoFromName does name-based regex matching for geo detection.