54 lines
1.1 KiB
Go
54 lines
1.1 KiB
Go
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
|
|
}
|