aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules/caddyhttp/ip_matchers.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/caddyhttp/ip_matchers.go')
-rw-r--r--modules/caddyhttp/ip_matchers.go62
1 files changed, 45 insertions, 17 deletions
diff --git a/modules/caddyhttp/ip_matchers.go b/modules/caddyhttp/ip_matchers.go
index 99eb39dff..5e0b356e7 100644
--- a/modules/caddyhttp/ip_matchers.go
+++ b/modules/caddyhttp/ip_matchers.go
@@ -108,7 +108,7 @@ func (MatchRemoteIP) CELLibrary(ctx caddy.Context) (cel.Library, error) {
// internal data type of the MatchPath value.
[]*cel.Type{cel.ListType(cel.StringType)},
// function to convert a constant list of strings to a MatchPath instance.
- func(data ref.Val) (RequestMatcher, error) {
+ func(data ref.Val) (RequestMatcherWithError, error) {
refStringList := reflect.TypeOf([]string{})
strList, err := data.ConvertToNative(refStringList)
if err != nil {
@@ -145,9 +145,23 @@ func (m *MatchRemoteIP) Provision(ctx caddy.Context) error {
// Match returns true if r matches m.
func (m MatchRemoteIP) Match(r *http.Request) bool {
+ match, err := m.MatchWithError(r)
+ if err != nil {
+ SetVar(r.Context(), MatcherErrorVarKey, err)
+ }
+ return match
+}
+
+// MatchWithError returns true if r matches m.
+func (m MatchRemoteIP) MatchWithError(r *http.Request) (bool, error) {
+ // if handshake is not finished, we infer 0-RTT that has
+ // not verified remote IP; could be spoofed, so we throw
+ // HTTP 425 status to tell the client to try again after
+ // the handshake is complete
if r.TLS != nil && !r.TLS.HandshakeComplete {
- return false // if handshake is not finished, we infer 0-RTT that has not verified remote IP; could be spoofed
+ return false, Error(http.StatusTooEarly, fmt.Errorf("TLS handshake not complete, remote IP cannot be verified"))
}
+
address := r.RemoteAddr
clientIP, zoneID, err := parseIPZoneFromString(address)
if err != nil {
@@ -155,7 +169,7 @@ func (m MatchRemoteIP) Match(r *http.Request) bool {
c.Write(zap.Error(err))
}
- return false
+ return false, nil
}
matches, zoneFilter := matchIPByCidrZones(clientIP, zoneID, m.cidrs, m.zones)
if !matches && !zoneFilter {
@@ -163,7 +177,7 @@ func (m MatchRemoteIP) Match(r *http.Request) bool {
c.Write(zap.String("zone", zoneID))
}
}
- return matches
+ return matches, nil
}
// CaddyModule returns the Caddy module information.
@@ -207,7 +221,7 @@ func (MatchClientIP) CELLibrary(ctx caddy.Context) (cel.Library, error) {
// internal data type of the MatchPath value.
[]*cel.Type{cel.ListType(cel.StringType)},
// function to convert a constant list of strings to a MatchPath instance.
- func(data ref.Val) (RequestMatcher, error) {
+ func(data ref.Val) (RequestMatcherWithError, error) {
refStringList := reflect.TypeOf([]string{})
strList, err := data.ConvertToNative(refStringList)
if err != nil {
@@ -238,20 +252,34 @@ func (m *MatchClientIP) Provision(ctx caddy.Context) error {
// Match returns true if r matches m.
func (m MatchClientIP) Match(r *http.Request) bool {
+ match, err := m.MatchWithError(r)
+ if err != nil {
+ SetVar(r.Context(), MatcherErrorVarKey, err)
+ }
+ return match
+}
+
+// MatchWithError returns true if r matches m.
+func (m MatchClientIP) MatchWithError(r *http.Request) (bool, error) {
+ // if handshake is not finished, we infer 0-RTT that has
+ // not verified remote IP; could be spoofed, so we throw
+ // HTTP 425 status to tell the client to try again after
+ // the handshake is complete
if r.TLS != nil && !r.TLS.HandshakeComplete {
- return false // if handshake is not finished, we infer 0-RTT that has not verified remote IP; could be spoofed
+ return false, Error(http.StatusTooEarly, fmt.Errorf("TLS handshake not complete, remote IP cannot be verified"))
}
+
address := GetVar(r.Context(), ClientIPVarKey).(string)
clientIP, zoneID, err := parseIPZoneFromString(address)
if err != nil {
m.logger.Error("getting client IP", zap.Error(err))
- return false
+ return false, nil
}
matches, zoneFilter := matchIPByCidrZones(clientIP, zoneID, m.cidrs, m.zones)
if !matches && !zoneFilter {
m.logger.Debug("zone ID from client IP did not match", zap.String("zone", zoneID))
}
- return matches
+ return matches, nil
}
func provisionCidrsZonesFromRanges(ranges []string) ([]*netip.Prefix, []string, error) {
@@ -326,13 +354,13 @@ func matchIPByCidrZones(clientIP netip.Addr, zoneID string, cidrs []*netip.Prefi
// Interface guards
var (
- _ RequestMatcher = (*MatchRemoteIP)(nil)
- _ caddy.Provisioner = (*MatchRemoteIP)(nil)
- _ caddyfile.Unmarshaler = (*MatchRemoteIP)(nil)
- _ CELLibraryProducer = (*MatchRemoteIP)(nil)
-
- _ RequestMatcher = (*MatchClientIP)(nil)
- _ caddy.Provisioner = (*MatchClientIP)(nil)
- _ caddyfile.Unmarshaler = (*MatchClientIP)(nil)
- _ CELLibraryProducer = (*MatchClientIP)(nil)
+ _ RequestMatcherWithError = (*MatchRemoteIP)(nil)
+ _ caddy.Provisioner = (*MatchRemoteIP)(nil)
+ _ caddyfile.Unmarshaler = (*MatchRemoteIP)(nil)
+ _ CELLibraryProducer = (*MatchRemoteIP)(nil)
+
+ _ RequestMatcherWithError = (*MatchClientIP)(nil)
+ _ caddy.Provisioner = (*MatchClientIP)(nil)
+ _ caddyfile.Unmarshaler = (*MatchClientIP)(nil)
+ _ CELLibraryProducer = (*MatchClientIP)(nil)
)