@ -105,12 +105,16 @@ type (
MatchProtocol string
MatchProtocol string
// MatchRemoteIP matches requests by client IP (or CIDR range).
// MatchRemoteIP matches requests by client IP (or CIDR range).
// If the X-Forwarded-For header is set, the first IP in that list
// is used as the reference IP; otherwise, the remote IP of the
// connection is the reference.
MatchRemoteIP struct {
MatchRemoteIP struct {
// The IPs or CIDR ranges to match.
Ranges [ ] string ` json:"ranges,omitempty" `
Ranges [ ] string ` json:"ranges,omitempty" `
// If true, prefer the first IP in the request's X-Forwarded-For
// header, if present, rather than the immediate peer's IP, as
// the reference IP against which to match. Note that it is easy
// to spoof request headers. Default: false
Forwarded bool ` json:"forwarded,omitempty" `
cidrs [ ] * net . IPNet
cidrs [ ] * net . IPNet
logger * zap . Logger
logger * zap . Logger
}
}
@ -795,7 +799,16 @@ func (MatchRemoteIP) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func ( m * MatchRemoteIP ) UnmarshalCaddyfile ( d * caddyfile . Dispenser ) error {
func ( m * MatchRemoteIP ) UnmarshalCaddyfile ( d * caddyfile . Dispenser ) error {
for d . Next ( ) {
for d . Next ( ) {
m . Ranges = append ( m . Ranges , d . RemainingArgs ( ) ... )
for d . NextArg ( ) {
if d . Val ( ) == "forwarded" {
if len ( m . Ranges ) > 0 {
return d . Err ( "if used, 'forwarded' must be first argument" )
}
m . Forwarded = true
continue
}
m . Ranges = append ( m . Ranges , d . Val ( ) )
}
if d . NextBlock ( 0 ) {
if d . NextBlock ( 0 ) {
return d . Err ( "malformed remote_ip matcher: blocks are not supported" )
return d . Err ( "malformed remote_ip matcher: blocks are not supported" )
}
}
@ -829,24 +842,20 @@ func (m *MatchRemoteIP) Provision(ctx caddy.Context) error {
}
}
func ( m MatchRemoteIP ) getClientIP ( r * http . Request ) ( net . IP , error ) {
func ( m MatchRemoteIP ) getClientIP ( r * http . Request ) ( net . IP , error ) {
var remote string
remote := r . RemoteAddr
if fwdFor := r . Header . Get ( "X-Forwarded-For" ) ; fwdFor != "" {
if m . Forwarded {
remote = strings . TrimSpace ( strings . Split ( fwdFor , "," ) [ 0 ] )
if fwdFor := r . Header . Get ( "X-Forwarded-For" ) ; fwdFor != "" {
}
remote = strings . TrimSpace ( strings . Split ( fwdFor , "," ) [ 0 ] )
if remote == "" {
}
remote = r . RemoteAddr
}
}
ipStr , _ , err := net . SplitHostPort ( remote )
ipStr , _ , err := net . SplitHostPort ( remote )
if err != nil {
if err != nil {
ipStr = remote // OK; probably didn't have a port
ipStr = remote // OK; probably didn't have a port
}
}
ip := net . ParseIP ( ipStr )
ip := net . ParseIP ( ipStr )
if ip == nil {
if ip == nil {
return nil , fmt . Errorf ( "invalid client IP address: %s" , ipStr )
return nil , fmt . Errorf ( "invalid client IP address: %s" , ipStr )
}
}
return ip , nil
return ip , nil
}
}