0
Fork 0
mirror of https://github.com/caddyserver/caddy.git synced 2025-01-06 22:40:31 -05:00

caddyhttp: Support zone identifiers in remote_ip matcher (#4597)

* Update matchers.go

* Update matchers.go

* implementation of zone_id handling

* last changes in zone handling

* give return true values instead of bool

* Apply suggestions from code review

Co-authored-by: Francis Lavoie <lavofr@gmail.com>

* changes as suggested

* Apply suggestions from code review

Co-authored-by: Francis Lavoie <lavofr@gmail.com>

* Update matchers.go

* shortened the Match function

* changed mazcher handling

* Update matchers.go

* delete space

Co-authored-by: Francis Lavoie <lavofr@gmail.com>
This commit is contained in:
BitWuehler 2022-03-01 23:50:12 +01:00 committed by GitHub
parent 15c95e9d5b
commit ac14b64e08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -131,7 +131,10 @@ type (
// to spoof request headers. Default: false // to spoof request headers. Default: false
Forwarded bool `json:"forwarded,omitempty"` Forwarded bool `json:"forwarded,omitempty"`
// cidrs and zones vars should aligned always in the same
// length and indexes for matching later
cidrs []*net.IPNet cidrs []*net.IPNet
zones []string
logger *zap.Logger logger *zap.Logger
} }
@ -877,10 +880,19 @@ func (m *MatchRemoteIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
func (m *MatchRemoteIP) Provision(ctx caddy.Context) error { func (m *MatchRemoteIP) Provision(ctx caddy.Context) error {
m.logger = ctx.Logger(m) m.logger = ctx.Logger(m)
for _, str := range m.Ranges { for _, str := range m.Ranges {
// Exclude the zone_id from the IP
if strings.Contains(str, "%") {
split := strings.Split(str, "%")
str = split[0]
// write zone identifiers in m.zones for matching later
m.zones = append(m.zones, split[1])
} else {
m.zones = append(m.zones, "")
}
if strings.Contains(str, "/") { if strings.Contains(str, "/") {
_, ipNet, err := net.ParseCIDR(str) _, ipNet, err := net.ParseCIDR(str)
if err != nil { if err != nil {
return fmt.Errorf("parsing CIDR expression: %v", err) return fmt.Errorf("parsing CIDR expression '%s': %v", str, err)
} }
m.cidrs = append(m.cidrs, ipNet) m.cidrs = append(m.cidrs, ipNet)
} else { } else {
@ -898,8 +910,9 @@ func (m *MatchRemoteIP) Provision(ctx caddy.Context) error {
return nil return nil
} }
func (m MatchRemoteIP) getClientIP(r *http.Request) (net.IP, error) { func (m MatchRemoteIP) getClientIP(r *http.Request) (net.IP, string, error) {
remote := r.RemoteAddr remote := r.RemoteAddr
zoneID := ""
if m.Forwarded { if m.Forwarded {
if fwdFor := r.Header.Get("X-Forwarded-For"); fwdFor != "" { if fwdFor := r.Header.Get("X-Forwarded-For"); fwdFor != "" {
remote = strings.TrimSpace(strings.Split(fwdFor, ",")[0]) remote = strings.TrimSpace(strings.Split(fwdFor, ",")[0])
@ -909,25 +922,40 @@ func (m MatchRemoteIP) getClientIP(r *http.Request) (net.IP, error) {
if err != nil { if err != nil {
ipStr = remote // OK; probably didn't have a port ipStr = remote // OK; probably didn't have a port
} }
// Some IPv6-Adresses can contain zone identifiers at the end,
// which are separated with "%"
if strings.Contains(ipStr, "%") {
split := strings.Split(ipStr, "%")
ipStr = split[0]
zoneID = split[1]
}
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, zoneID, fmt.Errorf("invalid client IP address: %s", ipStr)
} }
return ip, nil return ip, zoneID, nil
} }
// Match returns true if r matches m. // Match returns true if r matches m.
func (m MatchRemoteIP) Match(r *http.Request) bool { func (m MatchRemoteIP) Match(r *http.Request) bool {
clientIP, err := m.getClientIP(r) clientIP, zoneID, err := m.getClientIP(r)
if err != nil { if err != nil {
m.logger.Error("getting client IP", zap.Error(err)) m.logger.Error("getting client IP", zap.Error(err))
return false return false
} }
for _, ipRange := range m.cidrs { zoneFilter := true
for i, ipRange := range m.cidrs {
if ipRange.Contains(clientIP) { if ipRange.Contains(clientIP) {
return true // Check if there are zone filters assigned and if they match.
if m.zones[i] == "" || zoneID == m.zones[i] {
return true
}
zoneFilter = false
} }
} }
if !zoneFilter {
m.logger.Debug("zone ID from remote did not match", zap.String("zone", zoneID))
}
return false return false
} }