package security import ( "net" "net/http" "strings" ) type RealIPConfig struct { TrustedProxies []*net.IPNet } func (c RealIPConfig) IsTrusted(remoteAddr string) bool { host, _, err := net.SplitHostPort(remoteAddr) if err != nil { host = remoteAddr } ip := net.ParseIP(host) if ip == nil { return false } for _, n := range c.TrustedProxies { if n.Contains(ip) { return true } } return false } // RealIP returns the best-effort client IP. // It only honors X-Forwarded-For when the direct peer is in TrustedProxies. func RealIP(r *http.Request, cfg RealIPConfig) string { if cfg.IsTrusted(r.RemoteAddr) { if xff := r.Header.Get("X-Forwarded-For"); xff != "" { // First IP is original client parts := strings.Split(xff, ",") if len(parts) > 0 { ip := strings.TrimSpace(parts[0]) if net.ParseIP(ip) != nil { return ip } } } if xrip := strings.TrimSpace(r.Header.Get("X-Real-IP")); xrip != "" && net.ParseIP(xrip) != nil { return xrip } } host, _, err := net.SplitHostPort(r.RemoteAddr) if err == nil && net.ParseIP(host) != nil { return host } return r.RemoteAddr }