2018-08-24 16:20:03 +02:00
package ip
import (
2019-08-26 12:20:06 +02:00
"net"
2018-08-24 16:20:03 +02:00
"net/http"
"strings"
)
const (
xForwardedFor = "X-Forwarded-For"
)
2020-05-11 12:06:07 +02:00
// Strategy a strategy for IP selection.
2018-08-24 16:20:03 +02:00
type Strategy interface {
GetIP ( req * http . Request ) string
}
2020-05-11 12:06:07 +02:00
// RemoteAddrStrategy a strategy that always return the remote address.
2018-08-24 16:20:03 +02:00
type RemoteAddrStrategy struct { }
2020-05-11 12:06:07 +02:00
// GetIP returns the selected IP.
2018-08-24 16:20:03 +02:00
func ( s * RemoteAddrStrategy ) GetIP ( req * http . Request ) string {
2019-08-26 12:20:06 +02:00
ip , _ , err := net . SplitHostPort ( req . RemoteAddr )
if err != nil {
return req . RemoteAddr
}
return ip
2018-08-24 16:20:03 +02:00
}
2020-05-11 12:06:07 +02:00
// DepthStrategy a strategy based on the depth inside the X-Forwarded-For from right to left.
2018-08-24 16:20:03 +02:00
type DepthStrategy struct {
Depth int
}
2020-05-11 12:06:07 +02:00
// GetIP return the selected IP.
2018-08-24 16:20:03 +02:00
func ( s * DepthStrategy ) GetIP ( req * http . Request ) string {
xff := req . Header . Get ( xForwardedFor )
xffs := strings . Split ( xff , "," )
if len ( xffs ) < s . Depth {
return ""
}
2018-10-05 12:43:17 +02:00
return strings . TrimSpace ( xffs [ len ( xffs ) - s . Depth ] )
2018-08-24 16:20:03 +02:00
}
2021-06-07 17:46:14 +02:00
// PoolStrategy is a strategy based on an IP Checker.
// It allows to check whether addresses are in a given pool of IPs.
type PoolStrategy struct {
2018-08-24 16:20:03 +02:00
Checker * Checker
}
2021-06-07 17:46:14 +02:00
// GetIP checks the list of Forwarded IPs (most recent first) against the
// Checker pool of IPs. It returns the first IP that is not in the pool, or the
// empty string otherwise.
func ( s * PoolStrategy ) GetIP ( req * http . Request ) string {
2018-08-24 16:20:03 +02:00
if s . Checker == nil {
return ""
}
xff := req . Header . Get ( xForwardedFor )
xffs := strings . Split ( xff , "," )
for i := len ( xffs ) - 1 ; i >= 0 ; i -- {
2018-10-05 12:43:17 +02:00
xffTrimmed := strings . TrimSpace ( xffs [ i ] )
2021-06-07 17:46:14 +02:00
if len ( xffTrimmed ) == 0 {
continue
}
2018-10-05 12:43:17 +02:00
if contain , _ := s . Checker . Contains ( xffTrimmed ) ; ! contain {
return xffTrimmed
2018-08-24 16:20:03 +02:00
}
}
2021-06-07 17:46:14 +02:00
2018-08-24 16:20:03 +02:00
return ""
}