xfy 5a6f4d351f feat(resolver): 新增 DNS 解析器支持
新增 internal/resolver 包,提供动态 DNS 解析功能:
- Resolver 类型支持配置多个 DNS 服务器
- 内置缓存支持 TTL 和最大条目数限制
- 统计信息追踪查询次数和缓存命中率

配置层面:
- ResolverConfig 支持 addresses/valid/timeout/ipv4/ipv6/cache_size
- 添加配置验证逻辑

Target 增强:
- 新增 hostname/resolvedIPs 字段支持 IP 缓存
- NeedsResolve 方法判断是否需要重新解析
- NewTargetFromConfig 工厂函数

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 11:36:49 +08:00

95 lines
2.1 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.

// Package resolver 提供 DNS 解析功能,支持缓存和后台刷新。
//
// 该文件包含 DNS 缓存相关的实现。
//
// 作者xfy
package resolver
import (
"sync"
"time"
)
// CacheStats 返回缓存统计信息。
type CacheStats struct {
Hits int64 // 缓存命中次数
Misses int64 // 缓存未命中次数
Entries int // 当前缓存条目数
Expired int // 过期条目数
}
// GetCacheStats 返回当前缓存统计信息。
// 这是一个辅助函数,用于测试和监控。
func (r *DNSResolver) GetCacheStats() CacheStats {
hits := r.hits.Load()
misses := r.misses.Load()
// 统计缓存条目
var entries, expired int
now := time.Now()
r.cache.Range(func(key, value interface{}) bool {
entries++
entry := value.(*dnsCacheEntry)
entry.mu.RLock()
if now.After(entry.ExpiresAt) {
expired++
}
entry.mu.RUnlock()
return true
})
return CacheStats{
Hits: hits,
Misses: misses,
Entries: entries,
Expired: expired,
}
}
// GetCacheEntry 获取指定主机的缓存条目(用于测试)。
func (r *DNSResolver) GetCacheEntry(host string) (*dnsCacheEntry, bool) {
if entry, ok := r.cache.Load(host); ok {
return entry.(*dnsCacheEntry), true
}
return nil, false
}
// DeleteCacheEntry 删除指定主机的缓存条目。
func (r *DNSResolver) DeleteCacheEntry(host string) {
r.cache.Delete(host)
r.mu.Lock()
delete(r.refreshHosts, host)
r.mu.Unlock()
}
// ClearCache 清空所有缓存。
func (r *DNSResolver) ClearCache() {
r.cache = sync.Map{}
r.mu.Lock()
r.refreshHosts = make(map[string]struct{})
r.mu.Unlock()
}
// GetHitRate 返回缓存命中率。
func (r *DNSResolver) GetHitRate() float64 {
hits := r.hits.Load()
misses := r.misses.Load()
total := hits + misses
if total == 0 {
return 0
}
return float64(hits) / float64(total)
}
// IsCached 检查指定主机是否在缓存中且未过期。
func (r *DNSResolver) IsCached(host string) bool {
if entry, ok := r.cache.Load(host); ok {
cacheEntry := entry.(*dnsCacheEntry)
cacheEntry.mu.RLock()
expiresAt := cacheEntry.ExpiresAt
cacheEntry.mu.RUnlock()
return time.Now().Before(expiresAt)
}
return false
}