caddy-sip-guardian/sandbox/docker-compose.yml
Ryan Malloy c73fa9d3d1 Add extension enumeration detection and comprehensive SIP protection
Major features:
- Extension enumeration detection with 3 detection algorithms:
  - Max unique extensions threshold (default: 20 in 5 min)
  - Sequential pattern detection (e.g., 100,101,102...)
  - Rapid-fire detection (many extensions in short window)
- Prometheus metrics for all SIP Guardian operations
- SQLite persistent storage for bans and attack history
- Webhook notifications for ban/unban/suspicious events
- GeoIP-based country blocking with continent shortcuts
- Per-method rate limiting with token bucket algorithm

Bug fixes:
- Fix whitelist count always reporting zero in stats
- Fix whitelisted connections metric never incrementing
- Fix Caddyfile config not being applied to shared guardian

New files:
- enumeration.go: Extension enumeration detector
- enumeration_test.go: 14 comprehensive unit tests
- metrics.go: Prometheus metrics handler
- storage.go: SQLite persistence layer
- webhooks.go: Webhook notification system
- geoip.go: MaxMind GeoIP integration
- ratelimit.go: Per-method rate limiting

Testing:
- sandbox/ contains complete Docker Compose test environment
- All 14 enumeration tests pass
2025-12-07 15:22:28 -07:00

220 lines
5.4 KiB
YAML

# SIP Guardian Testing Sandbox
#
# This provides a complete testing environment with:
# - FreePBX (real PBX for testing)
# - Caddy with SIP Guardian (the proxy under test)
# - Attack containers (sipvicious, custom scripts)
# - Valid client containers (pjsip for legitimate traffic)
#
# Usage:
# docker compose up -d
# docker compose logs -f caddy
# docker compose run --rm attacker sipvicious_svwar -e100-200 caddy
# docker compose run --rm client pjsua --registrar=sip:caddy
services:
# ============================================
# FreePBX - The Protected PBX
# ============================================
freepbx:
image: tiredofit/freepbx:latest
container_name: sandbox-freepbx
hostname: freepbx
restart: unless-stopped
privileged: true
environment:
- VIRTUAL_HOST=pbx.sandbox.local
- VIRTUAL_NETWORK=sandbox
- HTTP_PORT=80
- HTTPS_PORT=443
- UCP_FIRST_RUN=true
- DB_HOST=mariadb
- DB_PORT=3306
- DB_NAME=asterisk
- DB_USER=asterisk
- DB_PASS=asteriskpass
- ENABLE_FAIL2BAN=FALSE # We're replacing this!
- TZ=UTC
volumes:
- freepbx_data:/data
- freepbx_logs:/var/log
- freepbx_www:/var/www/html
depends_on:
- mariadb
networks:
sandbox:
ipv4_address: 10.55.0.10
mariadb:
image: mariadb:10.11
container_name: sandbox-mariadb
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=rootpass
- MYSQL_DATABASE=asterisk
- MYSQL_USER=asterisk
- MYSQL_PASSWORD=asteriskpass
volumes:
- mariadb_data:/var/lib/mysql
networks:
sandbox:
ipv4_address: 10.55.0.11
# ============================================
# Caddy with SIP Guardian - The Proxy
# ============================================
caddy:
build:
context: ..
dockerfile: Dockerfile
container_name: sandbox-caddy
hostname: caddy
restart: unless-stopped
# Override default command to use explicit Caddyfile (ENTRYPOINT is "caddy")
command: ["run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
ports:
# Expose SIP ports to host for external testing
- "5060:5060/udp"
- "5060:5060/tcp"
- "5061:5061/tcp"
# Admin API
- "2020:2020"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
environment:
- SIP_UPSTREAM_HOST=freepbx
- SIP_UPSTREAM_PORT=5060
- SIP_UPSTREAM_TLS_PORT=5061
networks:
sandbox:
ipv4_address: 10.55.0.2
depends_on:
- freepbx
# ============================================
# Attack Simulation Containers
# ============================================
# SIPVicious scanner - for testing scanner detection
attacker:
image: python:3.11-slim
container_name: sandbox-attacker
hostname: attacker
profiles:
- testing
command: >
bash -c "
pip install sipvicious pysip3 &&
echo 'SIPVicious and tools installed. Use: sipvicious_svwar, sipvicious_svcrack, sipvicious_svmap' &&
tail -f /dev/null
"
networks:
sandbox:
ipv4_address: 10.55.0.100
depends_on:
- caddy
# Brute force simulation
bruteforcer:
image: python:3.11-slim
container_name: sandbox-bruteforcer
hostname: bruteforcer
profiles:
- testing
volumes:
- ./scripts:/scripts:ro
command: >
bash -c "
pip install sipsimple requests &&
echo 'Brute force tools ready. Run: python /scripts/bruteforce.py' &&
tail -f /dev/null
"
networks:
sandbox:
ipv4_address: 10.55.0.101
depends_on:
- caddy
# ============================================
# Legitimate Client Containers
# ============================================
# PJSIP-based SIP client
client:
image: alpine:latest
container_name: sandbox-client
hostname: client
profiles:
- testing
command: >
sh -c "
apk add --no-cache pjsua netcat-openbsd curl jq &&
echo 'PJSIP client ready. Use pjsua for SIP registration.' &&
tail -f /dev/null
"
networks:
sandbox:
ipv4_address: 10.55.0.50
depends_on:
- caddy
# Linphone CLI client
linphone:
image: alpine:latest
container_name: sandbox-linphone
hostname: linphone
profiles:
- testing
command: >
sh -c "
apk add --no-cache linphone netcat-openbsd curl &&
echo 'Linphone ready.' &&
tail -f /dev/null
"
networks:
sandbox:
ipv4_address: 10.55.0.51
depends_on:
- caddy
# ============================================
# Monitoring & Debugging
# ============================================
# Network sniffer for SIP traffic analysis
tcpdump:
image: alpine:latest
container_name: sandbox-tcpdump
hostname: tcpdump
profiles:
- debug
cap_add:
- NET_ADMIN
- NET_RAW
network_mode: "service:caddy"
command: >
sh -c "
apk add --no-cache tcpdump &&
tcpdump -i any -n 'udp port 5060 or tcp port 5060 or tcp port 5061' -vvv
"
depends_on:
- caddy
volumes:
freepbx_data:
freepbx_logs:
freepbx_www:
mariadb_data:
caddy_data:
caddy_config:
networks:
sandbox:
driver: bridge
ipam:
config:
- subnet: 10.55.0.0/24
gateway: 10.55.0.1