diff --git a/docs/pstn-calling-voipms-plan.md b/docs/pstn-calling-voipms-plan.md index dddd7d9..2cf04fd 100644 --- a/docs/pstn-calling-voipms-plan.md +++ b/docs/pstn-calling-voipms-plan.md @@ -174,7 +174,7 @@ separately from that hourly check. server hostname, and DID are all prompted at install time (VoIP.ms is only the suggested default), so any provider supporting IP auth works. - An outbound dialplan route matching US numbers only — **implemented**: - `_1NXXNXXXXX` (11-digit NANP with leading 1) and `_NXXNXXXXX` (10-digit, + `_1NXXNXXXXXX` (11-digit NANP with leading 1) and `_NXXNXXXXXX` (10-digit, auto-prefixed with 1), both routed to the trunk. No catch-all `_X.` pattern. **Also implemented**: an explicit block on the 27 NANP area codes that aren't actually US (Caribbean/Atlantic nations + US @@ -331,10 +331,20 @@ generator output. Fixed by quoting every value in that heredoc. 1. ~~Decide: new `services/pstn-trunk.sh`...~~ Done — separate service file, generalized to any IP-auth SIP provider (VoIP.ms is just the default). 2. ~~IP auth vs. registration~~ Done — IP authentication, no password stored. -3. ~~Exact NANP dial pattern(s)~~ Done — `_1NXXNXXXXX` / `_NXXNXXXXX`. ~~NANP +3. ~~Exact NANP dial pattern(s)~~ Done — `_1NXXNXXXXXX` / `_NXXNXXXXXX`. ~~NANP ≠ US gap~~ Done — 27 Caribbean/territory area codes explicitly blocked (see toll-fraud nuance above); this was a real, live gap in the design for a while, not a hypothetical. + **Real bug, confirmed live (2026-07-23):** both patterns shipped one + digit short (`_1NXXNXXXXX` / `_NXXNXXXXX` — 10/9 characters instead of + the correct 11/10), so Asterisk's exact-length pattern matching never + matched a real NANP number at all. Every outbound test call failed with + "extension not found in context 'intercom'" — looked exactly like a + config-loading problem (and several genuinely were, along the way: a + stale settings file, the #include never reaching the live config) but + the actual root cause underneath all of that was this one missing `X`. + Found by dumping `dialplan show intercom` and counting characters by + hand against a real dialed number, not by inspection alone. 4. ~~Inbound~~ Done — rings a configurable list of extensions (ring-group supported), each checked live per-call against its own tier. ~~Permission model~~ Done — superseded the original flat allow-list with a 3-tier diff --git a/services/pstn-trunk.sh b/services/pstn-trunk.sh index 136ba56..9f604a5 100644 --- a/services/pstn-trunk.sh +++ b/services/pstn-trunk.sh @@ -276,7 +276,7 @@ _pstn_write_dialplan_include() { ; reachable" rule, not something even a "full" tier extension can override, ; since "full" means "any US number," not "any NANP-shaped number." -exten => _1NXXNXXXXX,1,NoOp(PSTN outbound call attempt from ${CHANNEL(peername)} to ${EXTEN}) +exten => _1NXXNXXXXXX,1,NoOp(PSTN outbound call attempt from ${CHANNEL(peername)} to ${EXTEN}) same => n,Set(PSTN_KILLED=${AST_CONFIG(pstn-trunk-killswitch.conf,state,tripped)}) same => n,GotoIf($["${PSTN_KILLED}" = "1"]?pstn_killed,1) same => n,Set(PSTN_AREA_CODE=${EXTEN:1:3}) @@ -290,7 +290,7 @@ __ALERT_DENY_TIER_LINE__ same => n,Busy(15) same => n,Hangup() -exten => _NXXNXXXXX,1,NoOp(Assuming NANP - adding leading 1) +exten => _NXXNXXXXXX,1,NoOp(Assuming NANP - adding leading 1) same => n,Goto(1${EXTEN},1) exten => pstn_intl_blocked,1,NoOp(PSTN outbound call to ${EXTEN} blocked - non-US/premium NANP area code ${PSTN_AREA_CODE}) @@ -1651,7 +1651,7 @@ background, cost estimate, and toll-fraud reasoning. | Provider | ${PROVIDER_NAME} | | Server/POP | ${TRUNK_SERVER} (inbound match IPs: ${TRUNK_SERVER_IPS}) | | DID | ${TRUNK_DID} | -| Outbound scope | US/NANP only — \`_1NXXNXXXXX\` / \`_NXXNXXXXX\` patterns, no catch-all, minus 27 non-US/premium NANP area codes (see below) | +| Outbound scope | US/NANP only — \`_1NXXNXXXXXX\` / \`_NXXNXXXXXX\` patterns, no catch-all, minus 27 non-US/premium NANP area codes (see below) | | Permission tiers, messaging, personal numbers | Managed live via the Security Dashboard's PSTN Trunk tab — not set at install, so not shown here (this file isn't regenerated when you change them there). Everyone starts at \`internal\` (no PSTN, no messaging) until granted. | | Concurrency caps | ${MAX_OUTBOUND} outbound / ${MAX_INBOUND} inbound simultaneous calls (live — see \`pstn-limits.conf\` below) | | Inbound ring-group | ${RING_EXTS} | @@ -1682,7 +1682,7 @@ American Samoa (684), Sint Maarten (721), Saint Lucia (758), Dominica If you have a legitimate reason to call one of these (e.g. family in Puerto Rico), remove that entry from the `REGEX()` pattern in -`pstn-trunk-dialplan.conf`'s `_1NXXNXXXXX` extension — it'll be +`pstn-trunk-dialplan.conf`'s `_1NXXNXXXXXX` extension — it'll be regenerated exactly the same way on the next reinstall/update, so note the change somewhere you'll remember it, or keep a local diff.