From e54de571050cfc32a1cb0507fd8457ac28c52f9d Mon Sep 17 00:00:00 2001 From: sorcier Date: Fri, 6 Nov 2026 09:54:39 +0100 Subject: [PATCH] fix(cluster): strict SIP isolation on standby node and progressive BLF wake on master to eliminate stuck BLF lights --- scripts/cluster/notify_backup.sh | 13 ++++++++++++- scripts/cluster/notify_fault.sh | 7 +++++++ scripts/cluster/notify_master.sh | 26 ++++++++++++++++++++------ scripts/nexus-cluster | 2 ++ 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/scripts/cluster/notify_backup.sh b/scripts/cluster/notify_backup.sh index 87ac026..71dc4d5 100755 --- a/scripts/cluster/notify_backup.sh +++ b/scripts/cluster/notify_backup.sh @@ -29,5 +29,16 @@ if pidof asterisk >/dev/null 2>&1; then /usr/sbin/asterisk -rx "dialplan reload" >> "$LOG_FILE" 2>&1 || true fi -echo "[$TIMESTAMP] [CLUSTER] Mode Standby actif. En écoute des battements de cœur VRRP." >> "$LOG_FILE" +# 3. Isolation SIP stricte du nœud Standby / Backup via iptables (Architecture Télécom HA) +# Un nœud en veille ne doit JAMAIS répondre aux requêtes SIP des téléphones. +# Tout paquet SIP arrivant sur le Slave est immédiatement rejeté (ICMP port unreachable), +# ce qui force les téléphones (Yealink T46S, T54W, Fanvil, Snom...) à clore immédiatement +# leurs anciens dialogues orphelins et à réémettre leurs SUBSCRIBE BLF et REGISTER vers la VIP active. +iptables -C INPUT -i lo -j ACCEPT 2>/dev/null || iptables -I INPUT -i lo -j ACCEPT +iptables -C INPUT -p udp -m multiport --dports 5060,5061 -j REJECT --reject-with icmp-port-unreachable 2>/dev/null || \ + iptables -A INPUT -p udp -m multiport --dports 5060,5061 -j REJECT --reject-with icmp-port-unreachable +iptables -C INPUT -p tcp -m multiport --dports 5060,5061 -j REJECT --reject-with tcp-reset 2>/dev/null || \ + iptables -A INPUT -p tcp -m multiport --dports 5060,5061 -j REJECT --reject-with tcp-reset + +echo "[$TIMESTAMP] [CLUSTER] Mode Standby actif (Ports SIP isolés). En écoute des battements de cœur VRRP." >> "$LOG_FILE" exit 0 diff --git a/scripts/cluster/notify_fault.sh b/scripts/cluster/notify_fault.sh index a0bf969..258bde7 100755 --- a/scripts/cluster/notify_fault.sh +++ b/scripts/cluster/notify_fault.sh @@ -15,4 +15,11 @@ if [ -f "$DB_PATH" ]; then sqlite3 "$DB_PATH" "UPDATE cluster_settings SET last_sync_status='fault', updated_at=CURRENT_TIMESTAMP WHERE id=1;" 2>/dev/null || true fi +# Isolation des ports SIP en cas d'anomalie +iptables -C INPUT -i lo -j ACCEPT 2>/dev/null || iptables -I INPUT -i lo -j ACCEPT +iptables -C INPUT -p udp -m multiport --dports 5060,5061 -j REJECT --reject-with icmp-port-unreachable 2>/dev/null || \ + iptables -A INPUT -p udp -m multiport --dports 5060,5061 -j REJECT --reject-with icmp-port-unreachable +iptables -C INPUT -p tcp -m multiport --dports 5060,5061 -j REJECT --reject-with tcp-reset 2>/dev/null || \ + iptables -A INPUT -p tcp -m multiport --dports 5060,5061 -j REJECT --reject-with tcp-reset + exit 0 diff --git a/scripts/cluster/notify_master.sh b/scripts/cluster/notify_master.sh index 9f635d0..005049a 100755 --- a/scripts/cluster/notify_master.sh +++ b/scripts/cluster/notify_master.sh @@ -10,6 +10,10 @@ TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') echo "[$TIMESTAMP] [CLUSTER] >>> Transition vers l'état MASTER (VIP active) <<<" >> "$LOG_FILE" +# 0. Ouverture immédiate des ports SIP entrants sur le nouveau MASTER (levée d'isolation) +iptables -D INPUT -p udp -m multiport --dports 5060,5061 -j REJECT --reject-with icmp-port-unreachable 2>/dev/null || true +iptables -D INPUT -p tcp -m multiport --dports 5060,5061 -j REJECT --reject-with tcp-reset 2>/dev/null || true + # 1. Mise à jour de l'état en base de données locale si SQLite disponible DB_PATH="/var/www/nexus-pbx/storage/database.sqlite" ASTDB_PATH="/var/lib/asterisk/astdb.sqlite3" @@ -55,13 +59,23 @@ if [ -n "$VIP_CLEAN" ] && command -v arping >/dev/null 2>&1; then arping -c 5 -U -I "$IFACE" "$VIP_CLEAN" >> "$LOG_FILE" 2>&1 || true fi -# 5. Envoi automatique du signal check-sync silencieux aux téléphones enregistrés -# Force Yealink, Fanvil, Snom à réémettre instantanément tous leurs SUBSCRIBE BLF sur ce serveur actif +# 5. Réveil progressif et réabonnement BLF des postes téléphoniques +# Dès que les postes se réenregistrent sur ce Master (via la VIP), un signal silencieux check-sync +# leur est transmis pour forcer la synchronisation immédiate de l'ensemble des touches BLF. if pidof asterisk >/dev/null 2>&1; then - echo "[$TIMESTAMP] [CLUSTER] Envoi check-sync de réveil aux postes pour réabonnement immédiat des BLF..." >> "$LOG_FILE" - for ep in $(/usr/sbin/asterisk -rx "pjsip show endpoints" 2>/dev/null | grep -o 'Endpoint: [0-9]*' | awk '{print $2}'); do - /usr/sbin/asterisk -rx "pjsip send notify check-sync endpoint $ep" >> "$LOG_FILE" 2>&1 || true - done + echo "[$TIMESTAMP] [CLUSTER] Lancement du réveil BLF progressif en arrière-plan..." >> "$LOG_FILE" + ( + for delay in 2 5 12 25; do + sleep "$delay" + if ! pidof asterisk >/dev/null 2>&1; then break; fi + # Cibler uniquement les postes actuellement joignables (Avail) + for ep in $(/usr/sbin/asterisk -rx "pjsip show contacts" 2>/dev/null | grep -E 'Contact:.*Avail' | awk '{print $2}' | cut -d'/' -f1 | sort -u); do + if [ -n "$ep" ]; then + /usr/sbin/asterisk -rx "pjsip send notify check-sync endpoint $ep" >> "$LOG_FILE" 2>&1 || true + fi + done + done + ) >/dev/null 2>&1 & fi echo "[$TIMESTAMP] [CLUSTER] Prise de relais MASTER terminée avec succès." >> "$LOG_FILE" diff --git a/scripts/nexus-cluster b/scripts/nexus-cluster index 619121e..b5a054e 100755 --- a/scripts/nexus-cluster +++ b/scripts/nexus-cluster @@ -53,6 +53,8 @@ case "$CMD" in stop) systemctl stop keepalived >/dev/null 2>&1 || true systemctl disable keepalived >/dev/null 2>&1 || true + iptables -D INPUT -p udp -m multiport --dports 5060,5061 -j REJECT --reject-with icmp-port-unreachable 2>/dev/null || true + iptables -D INPUT -p tcp -m multiport --dports 5060,5061 -j REJECT --reject-with tcp-reset 2>/dev/null || true echo "KEEPALIVED_STOPPED_OK" ;;