mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-27 12:25:55 +03:00
caddyhttp: Optionally use forwarded IP for remote_ip matcher
The remote_ip matcher was reading the X-Forwarded-For header by default, but this behavior was not documented in anything that was released. This is also a less secure default, as it is trivially easy to spoof request headers. Reading IPs from that header should be optional, and it should not be the default. This is technically a breaking change, but anyone relying on the undocumented behavior was just doing so by coincidence/luck up to this point since it was never in any released documentation. We'll still add a mention in the release notes about this.
This commit is contained in:
parent
63bda6a0dc
commit
deedf8abb0
1 changed files with 22 additions and 13 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue