Fix ACK loss: bypass all security checks for mid-dialog ACKs

Resolves production issue where ACK messages triggered rate-limiting
and enumeration detection, causing calls to die at ~64s (Timer H expiry).

### Root Cause (refined via agent-thread debugging):
ACKs lack dialog-aware fast-path. Initial diagnosis pointed to enumeration
detection, but flextel agent's runtime config dump revealed enumeration was
disabled. **Rate-limiting** was the actual culprit - ACK retransmissions
(responding to Asterisk's 200 OK retransmits) hit rate limits and connections
were closed.

### The Fix (l4handler.go:231-246):
ACKs now fast-path through ALL security checks:
-  Bypass rate-limiting (ACK retransmissions don't trigger limits)
-  Bypass enumeration detection (no false-positive rapid-fire bans)
-  Bypass validation/pattern matching (unnecessary for mid-dialog)
-  Debug logging for troubleshooting
-  Metrics tracking (ACKs count as "allowed")

### Agent-Thread Debugging Protocol:
Cross-project debugging via immutable message threads:
- 001: flextel reports calls dying at 64s, hypothesizes ACK loss
- 002: Our diagnosis - ACK → enumeration false-positives
- 003: flextel deploys temporary Caddyfile bypass, requests Option B
- 004: flextel refines diagnosis - rate-limiting, not enumeration
- 005: Our reply - ACK fast-path shipped, bypasses ALL checks

### Security Documentation:
Added README warning about SIP trunk whitelisting security:
- ⚠️ Don't whitelist entire carrier ranges (bypasses protection for ANY customer)
-  Use narrow trunk-specific IPs only (54.172.60.0/30, 54.244.51.0/30)
- Documents Twilio-specific example with security rationale

### Impact:
- **Production fix**: Calls no longer die at 64s
- **Architecture**: Proper mid-dialog handling for all ACKs
- **Security**: Narrow whitelist guidance prevents bypass abuse
- **Future**: Dialog-aware fast-path (Option A) for all in-dialog messages

### Test Results:
All 196 tests passing  (1.213s)

See: docs/agent-threads/ack-loss-from-twilio-trunk/ for full debugging trail
This commit is contained in:
Ryan Malloy 2026-06-22 00:37:48 -06:00
parent f295c19e06
commit 4050b3f7c5
6 changed files with 392 additions and 5 deletions

View file

@ -403,6 +403,37 @@ _sip._udp.carrier.com → sip1.carrier.com, sip2.carrier.com → 203.0.113.10, 2
| `GET` | `/api/sip-guardian/dns-whitelist` | List all resolved DNS entries |
| `POST` | `/api/sip-guardian/dns-whitelist/refresh` | Force immediate DNS refresh |
**⚠️ Security Warning: SIP Trunk Whitelisting**
**DO NOT whitelist entire carrier IP ranges** - this bypasses protection for ANY customer of that carrier:
```caddyfile
# ❌ INSECURE - Whitelists ALL Twilio customers
whitelist 54.172.60.0/23 54.244.51.0/24 177.71.206.0/24
# ✅ SECURE - Only YOUR specific trunk IPs
sip_guardian {
# Twilio Elastic SIP Trunk - YOUR assigned ranges only
# These are the specific IPs assigned to your trunk, not Twilio's full infrastructure
whitelist 54.172.60.0/30 54.244.51.0/30 # /30 = 4 IPs each
}
```
**Why narrow ranges matter:**
- A malicious actor with a Twilio account could route attacks through Twilio's infrastructure
- Wide whitelisting bypasses enumeration detection, rate limiting, and validation for ANY Twilio customer
- Narrow to your trunk's assigned IPs only
- If carrier changes your IPs, calls will fail until whitelist is updated (monitor for this)
**How to find your trunk IPs:**
```bash
# Capture real traffic to see source IPs
tcpdump -i any -n 'udp port 5060' | grep 'INVITE'
# Check carrier documentation for assigned IP ranges
# Twilio: Account Settings → Elastic SIP Trunking → Origination IPs
```
---
### SIP Message Validation