Intermediate 10 min SIP 486

486 Busy Here — Call Routing Loop Misdiagnosis

อาการ

- Calls to a specific extension receive 486 Busy Here immediately (within milliseconds) even though the recipient's phone is on-hook and not in any active call
- The recipient's phone never rings — the rejection happens at the PBX level before the phone is even alerted
- SIP trace shows the INVITE being forwarded between two SIP proxies repeatedly, with Max-Forwards decrementing toward zero before the loop is terminated and 486 returned
- Calls to the same extension from within the PBX work correctly but fail when routed via an external SIP trunk or remote proxy
- The problem appeared after a dial plan change, a new forwarding rule was added, or a secondary SIP server was brought online

สาเหตุหลัก

  • PBX dial plan routes the call in a loop between two servers — Server A forwards to Server B which forwards back to Server A, consuming Max-Forwards until the INVITE is dropped
  • Call forwarding rule on the extension points back to itself or to a number that resolves back to the original extension through the dial plan, creating an infinite forwarding chain
  • A SIP proxy detects the loop via Max-Forwards reaching 0 or Via header loop detection (RFC 3261 Section 16.3) and returns 486 instead of the more accurate 482 Loop Detected
  • DND (Do Not Disturb) is silently enabled on the endpoint — the phone immediately sends 486 without alerting the user, and the caller has no indication that DND is active
  • Multiple registrations exist for the same SIP AOR (Address of Record) and one of the registered contacts is busy or stale, causing the proxy to fork and receive a 486 from the busy contact

การวินิจฉัย

**Step 1: Trace the INVITE path through the dial plan**
```bash
# Enable verbose SIP logging in Asterisk
asterisk -rx 'sip set debug on'
asterisk -rx 'core set verbose 5'
# Make the failing call and observe the log
tail -f /var/log/asterisk/full | grep -E '(INVITE|486|Max-Forwards)'
```

**Step 2: Check Max-Forwards value in the failing INVITE**
```bash
sngrep -d eth0 port 5060
# In the INVITE details, look for:
# Max-Forwards: 5 (or any low value — started at 70, decremented per hop)
# Count the Via headers — each hop adds one
# More than 3-4 Vias on an internal call → routing loop
```

**Step 3: Inspect call forwarding rules on the extension**
```bash
# Asterisk — check database for call forwarding (CF) entries
asterisk -rx 'database show CF'
# Or in FreePBX web UI: Applications > Call Flow Control
# Look for circular: ext 1001 forwards to 1002, and 1002 forwards to 1001
```

**Step 4: Verify DND status on the target extension**
```bash
asterisk -rx 'database show DND'
# If 'DND/1001' = 'YES', the phone is in Do Not Disturb mode
# Clear it:
asterisk -rx 'database del DND 1001'
```

**Step 5: Check active registrations for the extension**
```bash
asterisk -rx 'sip show registry'
asterisk -rx 'sip show peers | grep 1001'
# Multiple entries for the same extension indicate forking
```

การแก้ไข

**Fix 1: Break the dial plan loop**
```ini
# Asterisk extensions.conf — add loop protection
; Before routing to another server, check we haven't already visited it
exten => _X.,1,GotoIf($["${SIPDOMAIN}" = "sip.example.com"]?local)
same => n,Dial(SIP/${EXTEN}@remote-server)
same => n(local),Dial(SIP/${EXTEN})
```

**Fix 2: Remove circular call forwarding rules**
```bash
# Delete a forwarding entry in Asterisk AstDB
asterisk -rx 'database del CF 1001'
# Or via FreePBX UI: Users > Extension 1001 > Call Forwarding > Disable
```

**Fix 3: Clear DND for an extension**
```bash
asterisk -rx 'database del DND 1001'
# Confirm it's cleared
asterisk -rx 'database get DND 1001'
# Expected: Database entry not found.
```

**Fix 4: Use Max-Forwards to limit loop depth**
```ini
# Asterisk sip.conf — lower max forwards to detect loops faster
[general]
maxforwards=20
# Each hop decrements; reaching 0 triggers 483 Too Many Hops
# rather than looping indefinitely
```

**Fix 5: Purge stale registrations**
```bash
# Force re-registration by clearing the registration database
asterisk -rx 'sip prune realtime all'
# Or restart just the SIP stack (not the whole process)
asterisk -rx 'module reload chan_sip.so'
```

การป้องกัน

- **Validate dial plan changes** in a staging environment before applying to production — a simple call flow diagram helps spot potential loops visually before they reach SIP trace analysis
- **Set an appropriate Max-Forwards value** (default 70 is often too high for internal routing — 20 catches loops faster without affecting legitimate call paths)
- **Audit call forwarding rules periodically** using a management script that detects circular references in the forwarding table
- **Log 486 responses centrally** — a spike in 486 responses to idle extensions is a leading indicator of a routing misconfiguration
- **Use 482 Loop Detected correctly** — if your SIP proxy detects a loop via Via header inspection (RFC 3261 §16.3), return 482 rather than 486 so the caller gets an accurate error signal

รหัสสถานะที่เกี่ยวข้อง

คำศัพท์ที่เกี่ยวข้อง