Add Caddyfile unmarshaler support for SIPMatcher and SIPHandler

The layer4 matchers and handlers must implement caddyfile.Unmarshaler
to be usable in Caddyfile syntax. This enables proper parsing of:
- @sip sip { methods ... } matchers
- sip_guardian { ... } handlers
This commit is contained in:
Ryan Malloy 2025-12-07 10:23:38 -07:00
parent 2315989ca7
commit b5fa007d6e

View File

@ -8,6 +8,7 @@ import (
"strings" "strings"
"github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/mholt/caddy-l4/layer4" "github.com/mholt/caddy-l4/layer4"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -177,10 +178,75 @@ func min(a, b int) int {
return b return b
} }
// UnmarshalCaddyfile implements caddyfile.Unmarshaler for SIPMatcher.
// Usage in Caddyfile:
//
// @sip sip {
// methods REGISTER INVITE OPTIONS
// }
//
// Or simply: @sip sip
func (m *SIPMatcher) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// Move past "sip" token
d.Next()
// Check for block
for nesting := d.Nesting(); d.NextBlock(nesting); {
switch d.Val() {
case "methods":
m.Methods = d.RemainingArgs()
if len(m.Methods) == 0 {
return d.ArgErr()
}
default:
return d.Errf("unknown sip matcher directive: %s", d.Val())
}
}
return nil
}
// UnmarshalCaddyfile implements caddyfile.Unmarshaler for SIPHandler.
// Usage in Caddyfile:
//
// sip_guardian {
// max_failures 5
// find_time 10m
// ban_time 1h
// whitelist 10.0.0.0/8 172.16.0.0/12
// }
//
// Or simply: sip_guardian (uses defaults)
func (h *SIPHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// Move past "sip_guardian" token
d.Next()
// The handler doesn't have its own configuration - it uses the shared SIPGuardian
// But we need to parse any configuration blocks that might be present
// Check for inline args or block
for nesting := d.Nesting(); d.NextBlock(nesting); {
// For now, SIPHandler delegates to SIPGuardian
// In future, handler-specific config could go here
switch d.Val() {
case "max_failures", "find_time", "ban_time", "whitelist":
// These are handled by the embedded SIPGuardian
// Skip to allow flexibility in config placement
d.RemainingArgs()
default:
return d.Errf("unknown sip_guardian directive: %s", d.Val())
}
}
return nil
}
// Interface guards // Interface guards
var ( var (
_ layer4.ConnMatcher = (*SIPMatcher)(nil) _ layer4.ConnMatcher = (*SIPMatcher)(nil)
_ layer4.NextHandler = (*SIPHandler)(nil) _ layer4.NextHandler = (*SIPHandler)(nil)
_ caddy.Provisioner = (*SIPMatcher)(nil) _ caddy.Provisioner = (*SIPMatcher)(nil)
_ caddy.Provisioner = (*SIPHandler)(nil) _ caddy.Provisioner = (*SIPHandler)(nil)
_ caddyfile.Unmarshaler = (*SIPMatcher)(nil)
_ caddyfile.Unmarshaler = (*SIPHandler)(nil)
) )