diff --git a/TODO.md b/TODO.md index bfeedfe..1a25e55 100644 --- a/TODO.md +++ b/TODO.md @@ -34,6 +34,22 @@ by the migration: file-read ACLs (new inodes from the extraction never had them) — now documented and the restore script prints a reminder to re-run `sudo ./setup.sh security-dashboard` afterward. +- All outbound (and ring-group inbound) PSTN calls silently denied, every + time, with zero errors or warnings anywhere in the logs. Took an + extended live debugging session working through firewalls (IONOS's + separate Cloud Panel network firewall — a real, separate issue, but not + this one), Anveo's IP allowlists, and IONOS-vs-DigitalOcean network + theories before finding it: `asterisk.conf` needs `live_dangerously = + yes` under `[options]` for `AST_CONFIG()` to actually work — without it, + every `AST_CONFIG()` read (pstn-permissions.conf tiers, the PSTN + kill-switch) silently returns an empty string instead of erroring, so a + perfectly correct `tier_out = full` in pstn-permissions.conf still + evaluates as no permission. Not IONOS-specific at all — Easy Asterisk's + vendor default just ships without it, and the old DigitalOcean box + apparently had it set by hand at some point with no record of why. Now + fixed at the source: `_asterisk_ensure_live_dangerously()` in + `services/asterisk.sh`, called after every fresh install and every + "update" rebuild. Loose end: no code fix pending, just keep an eye out in case the registration bounce recurs (would point back at Sipnetic/coturn rather diff --git a/services/asterisk.sh b/services/asterisk.sh index 862fe3a..b9628c9 100644 --- a/services/asterisk.sh +++ b/services/asterisk.sh @@ -1155,6 +1155,58 @@ _asterisk_patch_voicemail_vendor_files() { log_success "Vendor generator functions patched for voicemail access codes." } +# ── asterisk.conf: live_dangerously ───────────────────────────────────────── +# pstn-trunk.sh's dialplan leans on AST_CONFIG() for everything permission- +# related (pstn-permissions.conf tiers, pstn-trunk-killswitch.conf) — see +# [intercom]'s outbound extension. AST_CONFIG() silently returns an empty +# string, with no warning or error anywhere in the logs, unless asterisk.conf +# has live_dangerously = yes under [options]. Easy Asterisk's own vendor +# default ships without it, so every outbound (and inbound ring-group) call +# gets denied with tier_out reading as blank — looking exactly like a +# permissions problem even when pstn-permissions.conf is correct. Confirmed +# live: this cost a multi-hour debugging session chasing firewalls, Anveo's +# IP allowlists, and IONOS-vs-DigitalOcean theories before landing here — the +# box had simply never had this one line set, on either provider by luck of +# whatever manual setup happened before this repo tracked it. +# +# Idempotent and safe to call on every install/update: no-ops if already set, +# only restarts the container if the file actually changed. +_asterisk_ensure_live_dangerously() { + local EA_DIR="$1" CONTAINER_NAME="$2" + local CONF="$EA_DIR/config/asterisk/asterisk.conf" + + # asterisk.conf is written by the container's own entrypoint on its + # first boot, not by this repo — give it a few seconds to appear right + # after a fresh `docker compose up` before giving up. + local _tries=0 + while [[ ! -f "$CONF" && $_tries -lt 10 ]]; do + sleep 1 + _tries=$((_tries + 1)) + done + if [[ ! -f "$CONF" ]]; then + log_warning "asterisk.conf not found yet — couldn't check live_dangerously. Re-run this" + log_warning "installer (update mode) once the container has started, or set it by hand:" + log_warning " docker exec $CONTAINER_NAME sh -c \"echo 'live_dangerously = yes' >> /etc/asterisk/asterisk.conf\" && docker restart $CONTAINER_NAME" + return 0 + fi + + grep -q '^live_dangerously[[:space:]]*=[[:space:]]*yes' "$CONF" && return 0 + + if grep -q '^live_dangerously' "$CONF"; then + sed -i 's/^live_dangerously.*/live_dangerously = yes/' "$CONF" + elif grep -q '^\[options\]' "$CONF"; then + sed -i '/^\[options\]/a live_dangerously = yes' "$CONF" + else + printf '\n[options]\nlive_dangerously = yes\n' >> "$CONF" + fi + log_success "Set live_dangerously = yes in asterisk.conf (required for PSTN permission/kill-switch checks to actually work)." + + log_info "Restarting Asterisk to apply (this is a startup-time option, a reload won't pick it up)..." + docker restart "$CONTAINER_NAME" &>/dev/null \ + && log_success "Restarted." \ + || log_warning "Restart failed — check: docker logs $CONTAINER_NAME" +} + # Live-file counterpart to the vendor-template patch above, same reasoning # as _asterisk_ensure_live_messaging_include (Easy Asterisk's entrypoint # only regenerates extensions.conf if it's missing, so a box with existing @@ -2095,6 +2147,7 @@ install_asterisk() { log_info "Rebuilding and restarting containers..." if docker compose up -d --build --force-recreate; then log_success "Update complete — vendor files and docker-compose.yml refreshed." + _asterisk_ensure_live_dangerously "$EA_DIR" "$CONTAINER" else log_warning "docker compose up failed — check: docker compose -f $EA_DIR/docker-compose.yml logs" fi @@ -2439,9 +2492,12 @@ ENV local START_NOW="" prompt_yn "Build and start Asterisk now? (y/n):" "y" START_NOW if [ "$START_NOW" = "y" ] || [ "$START_NOW" = "Y" ]; then - docker compose up -d --build \ - && log_success "Easy Asterisk started" \ - || log_warning "Start failed — check: docker compose logs" + if docker compose up -d --build; then + log_success "Easy Asterisk started" + _asterisk_ensure_live_dangerously "$EA_DIR" "$CONTAINER" + else + log_warning "Start failed — check: docker compose logs" + fi fi _asterisk_offer_dashboard_and_trunk "$EA_DIR"