perf(security): reduce GeoIP lookups and deduplicate trusted proxy check

- Check(): single GeoIP LookupCountry call, result reused for both
  deny and allow checks. Removed goto label for structured flow.
- getClientIP(): single trusted proxy CIDR scan gates both
  X-Forwarded-For and X-Real-IP processing.
This commit is contained in:
xfy 2026-06-04 11:09:29 +08:00
parent e535b9062c
commit 197d0d2344

View File

@ -200,51 +200,41 @@ func (ac *AccessControl) Check(ip net.IP) bool {
ac.mu.RLock() ac.mu.RLock()
defer ac.mu.RUnlock() defer ac.mu.RUnlock()
// 1. 先检查 CIDR 拒绝列表(显式拒绝优先)
for _, network := range ac.denyList { for _, network := range ac.denyList {
if network.Contains(ip) { if network.Contains(ip) {
return false return false
} }
} }
// 2. 检查 GeoIP 国家拒绝(如果启用) var country string
var hasCountry bool
if ac.geoip != nil && ac.geoipConfig.Enabled { if ac.geoip != nil && ac.geoipConfig.Enabled {
country, err := ac.geoip.LookupCountry(ip) if c, err := ac.geoip.LookupCountry(ip); err == nil {
if err == nil { if c == geoPrivateDeny {
// 处理私有 IP 特殊标记
if country == geoPrivateAllow {
// 私有 IP 自动允许,跳过国家检查
goto checkAllow
}
if country == geoPrivateDeny {
return false return false
} }
if c != geoPrivateAllow {
if slices.Contains(ac.geoipConfig.DenyCountries, country) { country = c
return false hasCountry = true
if slices.Contains(ac.geoipConfig.DenyCountries, country) {
return false
}
} }
} }
} }
checkAllow:
// 3. 检查 CIDR 允许列表
for _, network := range ac.allowList { for _, network := range ac.allowList {
if network.Contains(ip) { if network.Contains(ip) {
return true return true
} }
} }
// 4. 检查 GeoIP 国家允许(如果启用) if hasCountry {
if ac.geoip != nil && ac.geoipConfig.Enabled { if slices.Contains(ac.geoipConfig.AllowCountries, country) {
country, err := ac.geoip.LookupCountry(ip) return true
if err == nil && country != geoPrivateDeny {
if slices.Contains(ac.geoipConfig.AllowCountries, country) {
return true
}
} }
} }
// 5. 返回默认操作
return ac.defaultAction == ActionAllow return ac.defaultAction == ActionAllow
} }
@ -360,56 +350,43 @@ func (ac *AccessControl) SetDefault(action string) error {
func (ac *AccessControl) getClientIP(ctx *fasthttp.RequestCtx) net.IP { func (ac *AccessControl) getClientIP(ctx *fasthttp.RequestCtx) net.IP {
remoteIP := netutil.GetRemoteAddrIP(ctx) remoteIP := netutil.GetRemoteAddrIP(ctx)
// 仅当配置了可信代理且请求来自可信代理时,才解析 X-Forwarded-For if len(ac.trustedProxies) == 0 || remoteIP == nil {
if len(ac.trustedProxies) > 0 && remoteIP != nil { return remoteIP
isTrusted := false }
for _, network := range ac.trustedProxies {
if network.Contains(remoteIP) {
isTrusted = true
break
}
}
if isTrusted { isTrusted := false
// 使用右侧(最接近客户端)的非可信 IP for _, network := range ac.trustedProxies {
if xff := ctx.Request.Header.Peek("X-Forwarded-For"); len(xff) > 0 { if network.Contains(remoteIP) {
ips := strings.Split(string(xff), ",") isTrusted = true
for _, v := range slices.Backward(ips) { break
ipStr := strings.TrimSpace(v) }
if ip := net.ParseIP(ipStr); ip != nil { }
// 检查该 IP 是否在可信代理列表中 if !isTrusted {
trusted := false return remoteIP
for _, network := range ac.trustedProxies { }
if network.Contains(ip) {
trusted = true if xff := ctx.Request.Header.Peek("X-Forwarded-For"); len(xff) > 0 {
break ips := strings.Split(string(xff), ",")
} for _, v := range slices.Backward(ips) {
} ipStr := strings.TrimSpace(v)
if !trusted { if ip := net.ParseIP(ipStr); ip != nil {
return ip trusted := false
} for _, network := range ac.trustedProxies {
if network.Contains(ip) {
trusted = true
break
} }
} }
if !trusted {
return ip
}
} }
} }
} }
// 检查 X-Real-IP 头部(仅来自可信代理时) if xri := ctx.Request.Header.Peek("X-Real-IP"); len(xri) > 0 {
if len(ac.trustedProxies) > 0 && remoteIP != nil { if ip := net.ParseIP(string(xri)); ip != nil {
isTrusted := false return ip
for _, network := range ac.trustedProxies {
if network.Contains(remoteIP) {
isTrusted = true
break
}
}
if isTrusted {
if xri := ctx.Request.Header.Peek("X-Real-IP"); len(xri) > 0 {
if ip := net.ParseIP(string(xri)); ip != nil {
return ip
}
}
} }
} }