in remoteip/parser.go [50:102]
func (p *RemoteIPParser) GetIP(r *http.Request) (string, error) {
// Get the direct remote address (equivalent to REMOTE_ADDR in Rails)
remoteAddr := p.parseIP(r.RemoteAddr)
// Get IPs from X-Forwarded-For header(s)
// In Go, r.Header.Get() returns joined values if there are multiple headers with the same name
forwardedIPs := p.parseIPsFromHeader(r.Header.Get("X-Forwarded-For"))
// Get IPs from Client-IP header(s)
clientIPs := p.parseIPsFromHeader(r.Header.Get("Client-Ip"))
// Check for potential IP spoofing if both headers are present
if p.CheckIPSpoofing && len(clientIPs) > 0 && len(forwardedIPs) > 0 {
// If the last client IP is not in the forwarded IPs list, it might be spoofing
lastClientIP := clientIPs[len(clientIPs)-1]
isInForwardedIPs := false
for _, ip := range forwardedIPs {
if ip == lastClientIP {
isInForwardedIPs = true
break
}
}
if !isInForwardedIPs {
return "", ErrIPSpoofAttack
}
}
// Following Rails logic:
// 1. Combine forwarded and client IPs (in original order)
// 2. Check for non-proxies in the combined list
// 3. If all IPs are proxies, use the furthest away IP (last in the list)
// Combine IPs from headers (in original order)
ips := make([]string, 0, len(forwardedIPs)+len(clientIPs))
ips = append(ips, forwardedIPs...)
ips = append(ips, clientIPs...)
// Filter out trusted proxies
filteredIPs := p.filterProxies(append(ips, remoteAddr))
if len(filteredIPs) > 0 {
return filteredIPs[0], nil
}
// If all IPs are trusted proxies, return the "furthest away" IP
// (which is the last IP in the list after filtering)
if len(ips) > 0 {
return ips[len(ips)-1], nil
}
// Final fallback is the remote address
return remoteAddr, nil
}