Record the confirmed-live results of the group-ring debugging session
A group-owned personal DID is now working end to end against a real inbound call: it rings every authorized group member simultaneously, first to answer wins, and members whose own tier/allowed_numbers don't authorize the caller are correctly skipped. Updates the code comments that were written before that confirmation existed (the Busy(15) block's "NOT yet confirmed live", and the group-ring script's unverified-SHELL() note), and documents all four fixes plus the "Commit Changes" caveat in the Anveo setup guide's bugs-fixed section so the next person hitting one-ring-then-busy has the trail. Also clears the guide's "Still open" section: the 2-number account cap no longer applies, and the interactive walkthrough it described as unbuilt was built (_pstn_anveo_walkthrough).
This commit is contained in:
@@ -216,13 +216,56 @@ installer, not configuration mistakes — listed here for context on what
|
||||
under `setup.sh`'s `set -u` on `source`. Now guarded and falls back to
|
||||
safe defaults, erroring clearly only if genuinely required fields are
|
||||
missing.
|
||||
- **The inbound `[from-pstn-trunk]` context never loaded at all** — it used
|
||||
to share one `#include`'d file with the outbound dialplan, where the file
|
||||
continued `[intercom]` first and only declared `[from-pstn-trunk]`
|
||||
partway through. Asterisk silently failed to load the *entire* file
|
||||
(outbound patterns included) with no error anywhere, so every inbound
|
||||
call got "extension not found in context 'from-pstn-trunk'" and an
|
||||
immediate SIP rejection. Inbound now lives in its own file that starts
|
||||
with its context header, matching the structure of the messaging
|
||||
dialplan that always loaded correctly.
|
||||
- **Every inbound call's Caller-ID arrived as the DID itself**, not the
|
||||
real caller — the trunk endpoint pinned a static `callerid=<DID>` and
|
||||
didn't set `trust_id_inbound`, so Asterisk ignored the identity Anveo
|
||||
actually sends and fell back to that default. Every restricted-tier
|
||||
`allowed_numbers` check was therefore unwinnable regardless of config.
|
||||
Fixed by dropping the static default (redundant — the outbound dialplan
|
||||
sets `CALLERID(num)` on the channel itself) and adding
|
||||
`trust_id_inbound=yes`.
|
||||
- **A leading `+` broke whitelist matching** — once the fix above started
|
||||
surfacing real caller identity, Anveo delivers it `+E.164` style
|
||||
(`+15551234567`). The normalizer only added a leading `1` to 10-digit
|
||||
values and never stripped the `+`, so a 12-character value could never
|
||||
match an 11-digit, digits-only `allowed_numbers` entry no matter how
|
||||
correctly the number was whitelisted. The `+` is now stripped in the
|
||||
dialplan, the group-ring script, and the dashboard's admin-input side
|
||||
(so pasting a number straight from a call log works too).
|
||||
- **Bare `Hangup()` on inbound denials** instead of `Busy(15)` — three
|
||||
inbound denial paths didn't produce a proper "486 Busy Here", making a
|
||||
correct permission denial sound like a generic call failure and
|
||||
disguising config mismatches as dialplan bugs.
|
||||
|
||||
## Dashboard changes may need "Commit Changes"
|
||||
|
||||
Confirmed live: edits made in the Security Dashboard's PSTN Trunk tab
|
||||
(permission tiers, groups, personal-DID owners, limits) are written to disk
|
||||
immediately, but `AST_CONFIG()` in the dialplan has been observed still
|
||||
returning the *old* value until the Asterisk container is fully restarted —
|
||||
a `dialplan reload` / `module reload` is not enough. This contradicts the
|
||||
"reads fresh on every call, no restart needed" design premise these files
|
||||
otherwise rely on; root cause not established.
|
||||
|
||||
The PSTN Trunk tab has a **Commit Changes (Restart Asterisk)** button for
|
||||
this, which appears after any save on that tab and warns if you navigate
|
||||
away with changes uncommitted. Existing calls are unaffected by the
|
||||
restart. If a change doesn't seem to be taking effect on a test call, press
|
||||
it before assuming the config itself is wrong.
|
||||
|
||||
## Still open
|
||||
|
||||
- The 2-phone-number account cap (see step 1) blocks getting all 4
|
||||
planned numbers until either Anveo lifts it or a tax ID is provided —
|
||||
tabled for now.
|
||||
- The interactive CLI walkthrough (`pstn-trunk.sh` actually prompting
|
||||
through account setup step by step, not just this static doc) hasn't
|
||||
been built yet — this guide is the reference for building that once
|
||||
there's appetite for it.
|
||||
- Nothing blocking. The two items previously listed here are both resolved:
|
||||
the 2-phone-number account cap no longer applies (additional DIDs have
|
||||
since been obtained), and the interactive CLI walkthrough was built —
|
||||
see `_pstn_anveo_walkthrough` in `services/pstn-trunk.sh`, reachable from
|
||||
the provider quick-pick when you choose Anveo Direct.
|
||||
|
||||
+27
-23
@@ -583,30 +583,30 @@ __ALERT_KILLED_IN_LINE__
|
||||
; live config files and applies the identical tier/allowed_numbers logic
|
||||
; in a plain shell loop.
|
||||
;
|
||||
; Every OTHER denial path in this file (outbound tier/number/intl/killswitch,
|
||||
; the shared ring-group's pstn_in_denied, this owner's own denial just
|
||||
; above) plays a proper Busy(15) tone before Hangup() — pstn_in_denied and
|
||||
; the personal-DID denial paths were missing that Busy() and fell straight
|
||||
; to a bare Hangup() on an unanswered channel instead, which chan_pjsip
|
||||
; does NOT map to "486 Busy Here" the way Busy() does. NOT yet confirmed
|
||||
; live against a real call, but this is a real, reproducible inconsistency
|
||||
; (grep this file for "Hangup()" without a preceding Busy() and these three
|
||||
; exits were the only inbound ones missing it) and is a plausible cause of
|
||||
; a caller hearing one ring and then an ambiguous fast-busy/call-failed
|
||||
; tone on what looks like a correctly-authorized group member: if the
|
||||
; group/tier/allowed_numbers config has ANY mismatch against the test
|
||||
; caller ID, the call was always going to be denied here regardless of
|
||||
; this fix — the missing Busy() just made a config problem sound like a
|
||||
; dialplan problem. Fixed below (Busy(15) added to all three inbound
|
||||
; denial exits). If a group-assigned personal number still goes straight
|
||||
; to busy after this, the NoOp() logged right after the SHELL() call in
|
||||
; pstn_personal_group_ring prints the resolved group name, caller ID, and
|
||||
; PSTN_RING_LIST — check `asterisk -rx "core show channels verbose"` / the
|
||||
; full log for that line first; an empty list there means the config (not
|
||||
; the dialplan) is the next thing to check — confirm the calling number is
|
||||
; in allowed_numbers for at least one CURRENT group member whose tier is
|
||||
; Every denial path in this file (outbound tier/number/intl/killswitch, the
|
||||
; shared ring-group's pstn_in_denied, the personal-DID owner and group
|
||||
; denials) plays a proper Busy(15) tone before Hangup(). pstn_in_denied and
|
||||
; the two personal-DID denial paths used to fall straight to a bare
|
||||
; Hangup() on an unanswered channel instead, which chan_pjsip does NOT map
|
||||
; to "486 Busy Here" the way Busy() does — making a config mismatch sound
|
||||
; like a dialplan failure. Confirmed live (2026-07-24): a group-owned
|
||||
; personal DID is now fully working end to end, ringing every authorized
|
||||
; member simultaneously, after this plus three other fixes found in the
|
||||
; same session (see _pstn_write_inbound_dialplan_include's file-split
|
||||
; comment, and _pstn_write_pjsip_include's trust_id_inbound/callerid
|
||||
; comment).
|
||||
;
|
||||
; If a group-assigned personal number goes straight to busy, the NoOp()
|
||||
; logged right after the SHELL() call in pstn_personal_group_ring prints
|
||||
; the resolved group name, caller ID, and PSTN_RING_LIST — check the
|
||||
; Asterisk console/full log for that line first. An empty list there means
|
||||
; the config, not the dialplan: confirm the calling number is in
|
||||
; allowed_numbers for at least one CURRENT group member whose tier is
|
||||
; "restricted" or "full" in pstn-permissions.conf, and that the group's
|
||||
; members= line in pstn-groups.conf actually lists that extension.
|
||||
; members= line in pstn-groups.conf actually lists that extension. Note
|
||||
; that a dashboard edit may need the "Commit Changes" button (a container
|
||||
; restart — see restart_asterisk_container() in services/security-dashboard.sh)
|
||||
; before AST_CONFIG() actually returns the new value.
|
||||
exten => pstn_personal_inbound,1,GotoIf($["${PSTN_PERSONAL_OWNER:0:1}" = "@"]?pstn_personal_group_ring,1)
|
||||
same => n,Set(PSTN_OWNER_TIER=${AST_CONFIG(pstn-permissions.conf,${PSTN_PERSONAL_OWNER},tier)})
|
||||
same => n,GotoIf($["${PSTN_OWNER_TIER}" = "full"]?pstn_personal_ring,1)
|
||||
@@ -672,6 +672,10 @@ EOF
|
||||
# Safe REGEX direction: $allowed is admin-entered (pstn-permissions.conf),
|
||||
# $caller is the incoming Caller-ID — pattern is always the admin data,
|
||||
# string is always the caller-controlled data, never the reverse.
|
||||
# Confirmed live (2026-07-24): SHELL() invoking this script from the
|
||||
# dialplan works end to end against a real inbound call — the returned
|
||||
# &-joined list rings every authorized member simultaneously, first to
|
||||
# answer wins, and unauthorized members are correctly skipped.
|
||||
_pstn_write_personal_group_ring_script() {
|
||||
local FILE="$1"
|
||||
cat > "$FILE" << 'SCRIPT'
|
||||
|
||||
Reference in New Issue
Block a user