Fix keep_alive_interval placement: [global], not [transport-tls]
keep_alive_interval is a type=global pjsip.conf option, not a
type=transport option -- it never existed on [transport-tls] on any
Asterisk version. The IONOS TLS-keepalive mitigation was inserting it
there, which made sorcery reject the whole transport-tls object
("Could not find option suitable for category 'transport-tls' named
'keep_alive_interval'"), silently killing TLS SIP entirely instead of
just adding a keepalive.
Both _asterisk_patch_keepalive_vendor_files (deployed vendor copies)
and _asterisk_ensure_live_keepalive (live pjsip.conf) now target
[global]/type=global, and both self-heal a box that already picked up
the bad placement by removing it from [transport-tls] first.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SpKTLpwAgZNooTacWeQLuc
This commit is contained in:
+55
-19
@@ -1284,7 +1284,7 @@ _asterisk_ensure_live_voicemail_include() {
|
||||
docker exec "$CONTAINER_NAME" asterisk -rx "dialplan reload" &>/dev/null || true
|
||||
}
|
||||
|
||||
# ── pjsip.conf: [transport-tls] keep_alive_interval ─────────────────────────
|
||||
# ── pjsip.conf: [global] keep_alive_interval ─────────────────────────────────
|
||||
# Mitigation for WiFi/LAN SIP clients (e.g. Sipnetic on Android) dropping
|
||||
# their TLS registration every few seconds on some hosts but not others —
|
||||
# confirmed live on an IONOS VPS (never reproduced on a DigitalOcean droplet
|
||||
@@ -1293,15 +1293,28 @@ _asterisk_ensure_live_voicemail_include() {
|
||||
# live disconnect and CrowdSec/packet-loss both ruled out first. Leading
|
||||
# theory: an idle-connection timeout somewhere in IONOS's own network
|
||||
# virtualization layer, below anything client-side tools can see. PJSIP's
|
||||
# `keep_alive_interval` sends a lightweight double-CRLF over the transport's
|
||||
# TLS connection on a timer, which is the standard fix for exactly this
|
||||
# `keep_alive_interval` sends a lightweight double-CRLF over connection-oriented
|
||||
# transports (TCP/TLS) on a timer, which is the standard fix for exactly this
|
||||
# class of "idle SIP/TLS connection gets silently dropped" symptom.
|
||||
#
|
||||
# This is a *transport* option, not an endpoint/AOR option — `qualify_frequency`
|
||||
# (already set globally) is an endpoint-level OPTIONS ping that re-establishes
|
||||
# a dropped connection, it doesn't stop the drop from happening in the first
|
||||
# place. `rtp_keepalive` (mobile devices) is unrelated: RTP media keepalive
|
||||
# during an active call, not SIP signaling connection keepalive while idle.
|
||||
# **This is a `type=global` option, not a `type=transport` option** — it does
|
||||
# not exist on `[transport-tls]`/`[transport-tcp]` objects at all, on any
|
||||
# Asterisk version. An earlier version of this patch inserted it into
|
||||
# `[transport-tls]` (right after `protocol=tls`), which sorcery always
|
||||
# rejects: "Could not find option suitable for category 'transport-tls'
|
||||
# named 'keep_alive_interval'" — and rejecting the option means the whole
|
||||
# `type=transport` object fails to be created, so `transport-tls` never
|
||||
# binds at all. Confirmed live: this silently took down TLS SIP entirely on
|
||||
# a box that had picked up the patch, reproducing the exact same "network
|
||||
# error on all calls" symptom the rest of this file's health check exists to
|
||||
# catch. The anchor below targets `type=global` inside `[global]` instead.
|
||||
#
|
||||
# This is a *transport-behavior* option, not an endpoint/AOR option —
|
||||
# `qualify_frequency` (already set globally) is an endpoint-level OPTIONS
|
||||
# ping that re-establishes a dropped connection, it doesn't stop the drop
|
||||
# from happening in the first place. `rtp_keepalive` (mobile devices) is
|
||||
# unrelated: RTP media keepalive during an active call, not SIP signaling
|
||||
# connection keepalive while idle.
|
||||
_asterisk_patch_keepalive_vendor_files() {
|
||||
local EA_DIR="$1"
|
||||
local ENTRYPOINT="$EA_DIR/docker/entrypoint.sh"
|
||||
@@ -1313,15 +1326,20 @@ _asterisk_patch_keepalive_vendor_files() {
|
||||
|
||||
for f in "$ENTRYPOINT" "$EASY1" "$EASY2"; do
|
||||
[[ -f "$f" ]] || continue
|
||||
if ! grep -q '^protocol=tls$' "$f"; then
|
||||
log_warning "$(basename "$f"): '[transport-tls]' anchor not found — vendor template changed upstream."
|
||||
log_warning " Add 'keep_alive_interval=15' manually inside [transport-tls] in this file's pjsip.conf heredoc."
|
||||
# Undo the old, incorrect [transport-tls] placement if an earlier
|
||||
# run of this function already patched it there.
|
||||
if grep -q '^protocol=tls$' "$f" && grep -A2 '^protocol=tls$' "$f" | grep -q '^keep_alive_interval='; then
|
||||
sed -i '/^protocol=tls$/{n;/^keep_alive_interval=/d}' "$f"
|
||||
fi
|
||||
if ! grep -q '^type=global$' "$f"; then
|
||||
log_warning "$(basename "$f"): '[global]' anchor not found — vendor template changed upstream."
|
||||
log_warning " Add 'keep_alive_interval=15' manually inside [global] (not [transport-tls]) in this file's pjsip.conf heredoc."
|
||||
continue
|
||||
fi
|
||||
grep -q '^keep_alive_interval=' "$f" || sed -i '/^protocol=tls$/a keep_alive_interval=15' "$f"
|
||||
grep -q '^keep_alive_interval=' "$f" || sed -i '/^type=global$/a keep_alive_interval=15' "$f"
|
||||
done
|
||||
|
||||
log_success "Vendor generator functions patched for TLS transport keepalive."
|
||||
log_success "Vendor generator functions patched for SIP keepalive (pjsip.conf [global])."
|
||||
}
|
||||
|
||||
# Live-file counterpart to the vendor-template patch above, same reasoning
|
||||
@@ -1332,20 +1350,38 @@ _asterisk_patch_keepalive_vendor_files() {
|
||||
# a transport object — PJSIP transports are bound at module load, not
|
||||
# reloadable via sorcery like endpoints/AORs are — so this restarts the
|
||||
# container rather than issuing a reload, same as _asterisk_ensure_live_dangerously.
|
||||
#
|
||||
# `keep_alive_interval` belongs in `[global]` (`type=global`), not
|
||||
# `[transport-tls]` — see the comment on _asterisk_patch_keepalive_vendor_files
|
||||
# for why the old placement made sorcery reject the transport object outright
|
||||
# (killing TLS SIP entirely, not just the keepalive). This also self-heals a
|
||||
# box that already has the bad `[transport-tls]` entry from before that fix.
|
||||
_asterisk_ensure_live_keepalive() {
|
||||
local EA_DIR="$1" CONTAINER_NAME="$2"
|
||||
local CONF_LIVE="$EA_DIR/config/asterisk/pjsip.conf"
|
||||
[[ -f "$CONF_LIVE" ]] || return 0
|
||||
if ! grep -q '^\[transport-tls\]$' "$CONF_LIVE"; then
|
||||
log_warning "Couldn't find '[transport-tls]' in the live pjsip.conf — add"
|
||||
|
||||
local CHANGED=false
|
||||
if sed -n '/^\[transport-tls\]$/,/^\[/{/^keep_alive_interval=/p}' "$CONF_LIVE" | grep -q .; then
|
||||
sed -i '/^\[transport-tls\]$/,/^\[/{/^keep_alive_interval=/d}' "$CONF_LIVE"
|
||||
log_warning "Removed 'keep_alive_interval' from [transport-tls] — that option doesn't exist on a PJSIP"
|
||||
log_warning "transport object and was making the whole TLS transport fail to bind. Moving it to [global]."
|
||||
CHANGED=true
|
||||
fi
|
||||
|
||||
if ! grep -q '^\[global\]$' "$CONF_LIVE"; then
|
||||
log_warning "Couldn't find '[global]' in the live pjsip.conf — add"
|
||||
log_warning "'keep_alive_interval=15' manually inside that section, then: docker restart ${CONTAINER_NAME}"
|
||||
return 0
|
||||
fi
|
||||
grep -q '^keep_alive_interval=' "$CONF_LIVE" && return 0
|
||||
|
||||
sed -i '/^\[transport-tls\]$/,/^\[/{/^protocol=tls$/a keep_alive_interval=15
|
||||
if ! grep -q '^keep_alive_interval=' "$CONF_LIVE"; then
|
||||
sed -i '/^\[global\]$/,/^\[/{/^type=global$/a keep_alive_interval=15
|
||||
}' "$CONF_LIVE"
|
||||
log_success "Patched keep_alive_interval=15 into the live pjsip.conf's [transport-tls] transport."
|
||||
log_success "Patched keep_alive_interval=15 into the live pjsip.conf's [global] section."
|
||||
CHANGED=true
|
||||
fi
|
||||
|
||||
[[ "$CHANGED" == true ]] || return 0
|
||||
|
||||
log_info "Restarting Asterisk to apply (transport options aren't picked up by a reload)..."
|
||||
docker restart "$CONTAINER_NAME" &>/dev/null \
|
||||
|
||||
Reference in New Issue
Block a user