# Caddy SIP Guardian [![Go Version](https://img.shields.io/badge/Go-1.25+-00ADD8?style=flat&logo=go)](https://go.dev/) [![Caddy](https://img.shields.io/badge/Caddy-2.10+-22b638?style=flat&logo=caddy)](https://caddyserver.com/) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Tests](https://img.shields.io/badge/Tests-196%20passing-success)](https://git.supported.systems/rsp2k/caddy-sip-guardian) > **A comprehensive Caddy module providing SIP-aware security at Layer 4.** > Protects your VoIP infrastructure with intelligent rate limiting, attack detection, message validation, and topology hiding. --- ## Why SIP Guardian? Traditional SIP security (like fail2ban) parses logs *after* attacks reach your PBX. SIP Guardian operates at **Layer 4**, blocking threats *before* they touch your infrastructure: | Traditional Approach | SIP Guardian | |---------------------|--------------| | Log parsing delay | Real-time blocking | | Regex-based detection | Protocol-aware analysis | | Separate fail2ban config | Single Caddyfile | | No topology protection | Full B2BUA-lite hiding | | Manual IP management | Auto-ban with API control | --- ## Features ### 🛡️ Core Protection - **Layer 4 SIP Proxying** — Handle SIP traffic (UDP/TCP/TLS) before it reaches your PBX - **Intelligent Rate Limiting** — Per-method token bucket rate limiting with burst support - **Automatic Banning** — Ban IPs that exceed failure thresholds - **Attack Detection** — Detect common SIP scanning tools (SIPVicious, friendly-scanner, etc.) - **CIDR Whitelisting** — Whitelist trusted networks by IP range - **DNS-aware Whitelisting** — Whitelist SIP trunks by hostname or SRV record with auto-refresh - **GeoIP Blocking** — Block traffic by country using MaxMind databases ### 🔍 Extension Enumeration Detection - **Count-based Detection** — Block IPs probing too many unique extensions - **Sequential Pattern Detection** — Detect numeric extension scanning (100, 101, 102...) - **Rapid-fire Detection** — Catch high-speed enumeration attempts - **Configurable Exemptions** — Whitelist common extensions like voicemail ### ✅ SIP Message Validation - **RFC 3261 Compliance** — Enforce required headers and message structure - **Injection Prevention** — Block NULL bytes and binary injection attacks - **Content-Length Validation** — Detect body/header mismatches - **Multiple Modes** — Permissive, strict, or paranoid validation ### 🔒 Topology Hiding (B2BUA-lite) - **Via Header Rewriting** — Hide internal proxy chain - **Contact Header Rewriting** — Mask internal IP addresses - **Sensitive Header Stripping** — Remove P-Asserted-Identity, Server, etc. - **Call-ID Anonymization** — Prevent dialog correlation attacks - **Private IP Masking** — Automatically hide RFC 1918 addresses ### 📊 Observability - **Prometheus Metrics** — Comprehensive metrics for monitoring - **Webhook Notifications** — Real-time alerts for security events - **SQLite Persistence** — Durable ban storage across restarts - **Admin API** — RESTful API for management and stats --- ## Architecture ``` Internet │ ▼ ┌──────────────────────────────────────────────────────────────────┐ │ Caddy SIP Guardian (Layer 4) │ │ ┌────────────────────────────────────────────────────────────┐ │ │ │ 1. SIP Matcher ─ Identifies SIP traffic │ │ │ │ 2. Ban Check ─ Reject banned IPs │ │ │ │ 3. Whitelist Check ─ Skip checks for trusted IPs │ │ │ │ 4. GeoIP Check ─ Block by country │ │ │ │ 5. Validation ─ RFC 3261 compliance │ │ │ │ 6. Pattern Detection ─ Scanner fingerprinting │ │ │ │ 7. Enumeration Check ─ Extension scanning detection │ │ │ │ 8. Rate Limiting ─ Per-method token buckets │ │ │ │ 9. Topology Hiding ─ Header rewriting (optional) │ │ │ └────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────┐ │ FreePBX / Asterisk / Kamailio │ │ (Protected from scanners, enumeration, topology leaks) │ └──────────────────────────────────────────────────────────────────┘ ``` --- ## Quick Start ```bash # Clone the repository git clone https://git.supported.systems/rsp2k/caddy-sip-guardian.git cd caddy-sip-guardian # Build the custom Caddy image make build # Start the stack make run # View logs make logs # Run tests (60 tests) make test ``` --- ## Configuration ### Minimal Configuration ```caddyfile { layer4 { udp/:5060 { @sip sip route @sip { sip_guardian { max_failures 5 ban_time 1h whitelist 10.0.0.0/8 192.168.0.0/16 } proxy udp/asterisk:5060 } } } } ``` ### Full Configuration
Click to expand complete Caddyfile example ```caddyfile { layer4 { # UDP SIP (standard port) udp/:5060 { @sip sip { methods REGISTER INVITE OPTIONS ACK BYE CANCEL INFO NOTIFY SUBSCRIBE MESSAGE } route @sip { sip_guardian { # Core settings max_failures 5 find_time 10m ban_time 1h whitelist 10.0.0.0/8 192.168.0.0/16 # GeoIP blocking (optional) geoip_db /etc/caddy/GeoLite2-Country.mmdb blocked_countries CN RU # Per-method rate limiting rate_limit { register 10/s burst 20 invite 5/s burst 10 options 20/s burst 50 } # Extension enumeration detection enumeration { max_extensions 20 extension_window 5m sequential_threshold 5 rapid_fire_count 10 rapid_fire_window 30s ban_time 2h exempt_extensions 100 200 9999 } # SIP message validation validation { enabled true mode strict max_message_size 65535 ban_on_null_bytes true ban_on_binary_injection true } # Prometheus metrics metrics { enabled true } # Webhook notifications webhooks { url https://hooks.example.com/sip-alerts events ban unban attack enumeration } # SQLite persistence storage { path /var/lib/caddy/sip_guardian.db } } # Optional: Topology hiding sip_topology_hider { proxy_host 203.0.113.1 proxy_port 5060 upstream udp/192.168.1.100:5060 rewrite_via rewrite_contact strip_headers P-Preferred-Identity P-Asserted-Identity Server User-Agent hide_private_ips # anonymize_call_id # Optional: randomize Call-IDs } proxy udp/freepbx:5060 } } # TCP SIP tcp/:5060 { @sip sip route @sip { sip_guardian { ... } proxy tcp/freepbx:5060 } } # SIP over TLS tcp/:5061 { @sip tls sni sip.example.com route @sip { sip_guardian { ... } tls proxy tcp/freepbx:5060 } } } } # Admin API :2020 { handle /api/sip-guardian/* { sip_guardian_admin } # Prometheus metrics endpoint handle /metrics { metrics } } ```
### Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `SIP_UPSTREAM_HOST` | `freepbx` | Upstream SIP server hostname | | `SIP_UPSTREAM_PORT` | `5060` | Upstream SIP port | | `SIP_GUARDIAN_MAX_FAILURES` | `5` | Failures before ban | | `SIP_GUARDIAN_FIND_TIME` | `10m` | Time window for counting failures | | `SIP_GUARDIAN_BAN_TIME` | `1h` | Ban duration | --- ## Feature Details ### Extension Enumeration Detection Protects against tools like SIPVicious `svwar` that scan for valid extensions: ```caddyfile enumeration { max_extensions 20 # Ban after 20 unique extensions probed extension_window 5m # Within this time window sequential_threshold 5 # Ban if 5+ consecutive extensions (100,101,102...) rapid_fire_count 10 # Ban if 10+ extensions in rapid_fire_window rapid_fire_window 30s ban_time 2h # Enumeration bans last longer exempt_extensions 100 200 9999 # Don't count these (voicemail, etc.) } ``` **Detection Methods:** | Method | Trigger | Use Case | |--------|---------|----------| | **Count Threshold** | 20+ unique extensions | Catches slow scanners | | **Sequential Pattern** | 5+ consecutive numbers | Detects `svwar` immediately | | **Rapid Fire** | 10+ in 30 seconds | Catches fast automated scans | --- ### DNS-aware Whitelisting Whitelist SIP trunks and providers by hostname or SRV record. IPs are automatically resolved and refreshed: ```caddyfile sip_guardian { # Static CIDR whitelist (always available) whitelist 10.0.0.0/8 192.168.0.0/16 # DNS-aware whitelist - resolved to IPs automatically whitelist_hosts pbx.example.com trunk.sipcarrier.net whitelist_srv _sip._udp.provider.com _sip._tcp.carrier.net dns_refresh 5m # How often to refresh DNS lookups (default: 5m) } ``` **Why DNS-aware whitelisting?** | Static IP Whitelisting | DNS-aware Whitelisting | |------------------------|------------------------| | Breaks when provider changes IPs | Auto-updates when IPs change | | Must manually track carrier IPs | Just use their SRV record | | Fails silently on changes | Logs refresh events | **SRV Record Support:** SIP trunks commonly use SRV records for load balancing and failover. SIP Guardian resolves the full chain: ``` _sip._udp.carrier.com → sip1.carrier.com, sip2.carrier.com → 203.0.113.10, 203.0.113.11 ``` **Admin API Endpoints:** | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/api/sip-guardian/dns-whitelist` | List all resolved DNS entries | | `POST` | `/api/sip-guardian/dns-whitelist/refresh` | Force immediate DNS refresh | --- ### SIP Message Validation Enforces RFC 3261 compliance and blocks malformed/malicious packets: ```caddyfile validation { enabled true mode strict # permissive, strict, or paranoid max_message_size 65535 # Reject oversized messages ban_on_null_bytes true # Immediate ban for NULL byte injection ban_on_binary_injection true disabled_rules via_invalid_branch # Skip specific rules } ``` **Validation Modes:** | Mode | Behavior | |------|----------| | **Permissive** | Log violations, only block critical attacks | | **Strict** | Enforce RFC 3261 required headers | | **Paranoid** | Additional heuristics for edge cases | **Validation Rules:** | Rule | Severity | Action | |------|----------|--------| | `null_bytes` | 🔴 CRITICAL | Immediate ban | | `binary_injection` | 🔴 CRITICAL | Immediate ban | | `missing_via` | 🟠 HIGH | Count toward ban | | `missing_from` | 🟠 HIGH | Count toward ban | | `missing_to` | 🟠 HIGH | Count toward ban | | `missing_call_id` | 🟠 HIGH | Count toward ban | | `missing_cseq` | 🟠 HIGH | Count toward ban | | `content_length_mismatch` | 🟠 HIGH | Count toward ban | | `oversized_message` | 🟠 HIGH | Count toward ban | | `invalid_request_uri` | 🟡 MEDIUM | Reject only | --- ### Topology Hiding Hide your internal infrastructure from external attackers: ```caddyfile sip_topology_hider { # Your public-facing address proxy_host 203.0.113.1 proxy_port 5060 # Internal PBX (never exposed) upstream udp/192.168.1.100:5060 rewrite_via # Add proxy Via, remove on response rewrite_contact # Replace internal Contact URIs strip_headers P-Preferred-Identity P-Asserted-Identity Server User-Agent hide_private_ips # Replace RFC 1918 addresses # anonymize_call_id # Optional: randomize Call-IDs } ``` **What It Hides:** | Header/Field | Before | After | |--------------|--------|-------| | Via | `192.168.1.100:5060` | `proxy.example.com:5060` | | Contact | `` | `` | | Server | `Asterisk PBX 18.x` | *(removed)* | | P-Asserted-Identity | `` | *(removed)* | **Request Flow:** ``` External UA ──────► Caddy ──────► Asterisk │ ├─ Adds Via: SIP/2.0/UDP proxy.example.com;branch=z9hG4bK... ├─ Rewrites Contact: └─ Strips: Server, P-Asserted-Identity ``` **Response Flow:** ``` Asterisk ──────► Caddy ──────► External UA │ ├─ Removes top Via (proxy's) └─ Dialog state routes response correctly ``` --- ## Admin API ### Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/api/sip-guardian/bans` | List all banned IPs | | `GET` | `/api/sip-guardian/stats` | View statistics | | `POST` | `/api/sip-guardian/ban/{ip}` | Manually ban an IP | | `DELETE` | `/api/sip-guardian/unban/{ip}` | Remove IP from ban list | | `GET` | `/api/sip-guardian/enumeration/stats` | Enumeration statistics | | `GET` | `/api/sip-guardian/validation/stats` | Validation statistics | ### Examples
List Banned IPs ```bash curl http://localhost:2020/api/sip-guardian/bans ``` ```json { "bans": [ { "ip": "185.224.128.0", "reason": "scanner_detected", "banned_at": "2024-01-15T10:30:00Z", "expires_at": "2024-01-15T11:30:00Z" } ], "total": 1 } ```
View Stats ```bash curl http://localhost:2020/api/sip-guardian/stats ``` ```json { "total_requests": 15234, "blocked_requests": 423, "active_bans": 12, "enumeration_detections": 5, "validation_failures": 89, "rate_limited": 156 } ```
Manually Ban IP ```bash curl -X POST http://localhost:2020/api/sip-guardian/ban/192.168.1.100 \ -H "Content-Type: application/json" \ -d '{"reason": "manual_ban", "duration": "24h"}' ```
Unban IP ```bash curl -X DELETE http://localhost:2020/api/sip-guardian/unban/192.168.1.100 ```
--- ## Prometheus Metrics ```prometheus # Core metrics sip_guardian_requests_total{method="REGISTER"} sip_guardian_blocked_total{reason="banned"} sip_guardian_active_bans # Rate limiting sip_guardian_rate_limited_total{method="INVITE"} # Enumeration detection sip_guardian_enumeration_detections_total{reason="sequential_pattern"} sip_guardian_enumeration_tracked_ips # Validation sip_guardian_validation_violations_total{rule="missing_via"} sip_guardian_validation_results_total{result="valid"} sip_guardian_message_size_bytes # GeoIP sip_guardian_geoip_blocked_total{country="CN"} ``` --- ## Integration Examples
FreePBX / Asterisk ```caddyfile { layer4 { udp/:5060 { @sip sip route @sip { sip_guardian { max_failures 3 ban_time 24h whitelist 10.0.0.0/8 } proxy udp/freepbx:5060 } } } } ```
Kamailio (as SBC) ```caddyfile { layer4 { udp/:5060 { @sip sip route @sip { sip_guardian { max_failures 5 ban_time 1h } sip_topology_hider { proxy_host sbc.example.com proxy_port 5060 upstream udp/kamailio:5060 rewrite_via rewrite_contact } proxy udp/kamailio:5060 } } } } ```
High Availability Setup ```caddyfile { layer4 { udp/:5060 { @sip sip route @sip { sip_guardian { storage { # Shared storage for HA path /shared/sip_guardian.db } } # Load balance across PBX cluster proxy udp/pbx1:5060 udp/pbx2:5060 udp/pbx3:5060 { lb_policy round_robin health_check interval=30s } } } } } ```
--- ## Troubleshooting ### Common Issues
Legitimate users getting banned **Symptoms:** Users report being unable to connect; they appear in ban list. **Solutions:** 1. Add their network to the whitelist: ```caddyfile whitelist 10.0.0.0/8 192.168.0.0/16 YOUR.NETWORK.0.0/16 ``` 2. Increase `max_failures` threshold 3. Check if their client sends malformed packets (validation logs) 4. Temporarily unban: `curl -X DELETE http://localhost:2020/api/sip-guardian/unban/IP`
SIP traffic not being matched **Symptoms:** Traffic passes through but SIP Guardian doesn't process it. **Solutions:** 1. Verify the matcher syntax: ```caddyfile @sip sip { methods REGISTER INVITE OPTIONS } ``` 2. Check Caddy logs for matcher errors 3. Ensure traffic is arriving on the correct port (UDP vs TCP) 4. Test with `tcpdump -i any port 5060` to verify traffic flow
Topology hiding breaks calls **Symptoms:** Calls connect but audio is one-way or missing. **Solutions:** 1. This is usually an RTP/media issue, not SIP signaling 2. Ensure RTP ports are forwarded through your firewall 3. Check if `hide_private_ips` is replacing IPs in SDP body 4. Verify NAT traversal settings on your PBX
High memory usage **Symptoms:** Caddy process memory grows over time. **Solutions:** 1. Dialog/transaction state cleanup runs automatically, but check TTL settings 2. Reduce `extension_window` to clean up enumeration tracking faster 3. Check for memory leaks with `go tool pprof` 4. Ensure cleanup goroutines are running (check logs)
GeoIP database not loading **Symptoms:** Country blocking not working; errors about mmdb file. **Solutions:** 1. Download the database: ```bash wget https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&suffix=tar.gz ``` 2. Verify path in config matches actual file location 3. Check file permissions (Caddy needs read access) 4. Ensure you're using GeoLite2-Country, not City database
### Debug Mode Enable verbose logging: ```caddyfile { debug layer4 { # ... your config } } ``` Check logs: ```bash docker logs caddy-sip-guardian 2>&1 | grep -E "(sip_guardian|topology)" ``` --- ## Building from Source ```bash # Using xcaddy xcaddy build \ --with github.com/mholt/caddy-l4 \ --with git.supported.systems/rsp2k/caddy-sip-guardian # Or with local development xcaddy build \ --with github.com/mholt/caddy-l4 \ --with git.supported.systems/rsp2k/caddy-sip-guardian=/path/to/local/module ``` ### Running Tests ```bash # Run all unit tests (60 tests) make test # Run with verbose output docker run --rm -v $(pwd):/app -w /app golang:1.25 go test -v ./... # Test specific feature go test -v -run TestEnumeration ./... go test -v -run TestValidation ./... go test -v -run TestTopology ./... ``` --- ## Changelog ### v0.3.0 (2024-12) - ✨ **Topology Hiding** — B2BUA-lite functionality for hiding internal infrastructure - ✨ **SIP Message Parsing** — Full RFC 3261 compliant parser with header manipulation - ✨ **Dialog State Management** — Stateful response routing for topology hiding - 🐛 Fixed PRNG overflow in branch generation ### v0.2.0 (2024-12) - ✨ **SIP Message Validation** — RFC 3261 compliance checking - ✨ **Injection Detection** — NULL byte and binary injection blocking - ✨ **Validation Modes** — Permissive, strict, and paranoid modes ### v0.1.0 (2024-12) - ✨ **Extension Enumeration Detection** — Sequential pattern and rapid-fire detection - ✨ **Per-method Rate Limiting** — Token bucket with configurable burst - ✨ **GeoIP Blocking** — Country-based blocking with MaxMind - ✨ **Prometheus Metrics** — Comprehensive observability - ✨ **Webhook Notifications** — Real-time security alerts - ✨ **SQLite Persistence** — Durable ban storage --- ## Security Considerations | Consideration | Recommendation | |---------------|----------------| | **Whitelist internal networks** | Always add your LAN to prevent self-blocking | | **Start permissive** | Begin with permissive validation, tighten after monitoring | | **Monitor false positives** | Watch metrics for legitimate traffic being blocked | | **Keep GeoIP updated** | Refresh MaxMind databases monthly | | **Use webhooks** | Configure alerts for immediate security notification | | **Protect admin API** | Don't expose `:2020` to the internet | --- ## Detected Attack Patterns SIP Guardian automatically detects: | Pattern | Detection Method | |---------|------------------| | **SIPVicious** | User-Agent fingerprinting | | **friendly-scanner** | User-Agent fingerprinting | | **sipcli / sip-scan** | User-Agent fingerprinting | | **Sequential scanning** | Extension pattern analysis | | **NULL byte injection** | Binary content inspection | | **Malformed packets** | RFC 3261 validation | --- ## License MIT — see [LICENSE](LICENSE) for details. ## Contributing Contributions welcome! Please: 1. Fork the repository 2. Create a feature branch 3. Add tests for new functionality 4. Submit a pull request ## Related Projects - [caddy-l4](https://github.com/mholt/caddy-l4) — Layer 4 proxy for Caddy - [Caddy](https://caddyserver.com/) — The HTTP/2 web server with automatic HTTPS - [SIPVicious](https://github.com/EnableSecurity/sipvicious) — SIP security testing tools (for testing your setup)