Topologie:A = fr-par-1 cibleB = fr-par-2 ciblebascule carrier seulement pour les nouveaux appels

Chemin de signalisation

La cellule admet le carrier sur son interface publique, ancre le SDP localement et transmet à Asterisk sur loopback.

Pair carrier local

8.8.8.9:5061

INVITE mTLS hermétique; ce pair n’est pas un carrier réel.

Kamailio 6.0.7

8.8.8.8:5061

Admission publique, double Record-Route puis dialogue interne 5063.

RTPEngine 26.0.1.13

127.0.0.1:22222

SDP ancré sur 8.8.8.8, plage 10000-11000.

Asterisk 22.9.0

127.0.0.1:5062

TLS loopback exact puis cycle Stasis answer/hangup.

Admission fail-closed

Une identité valide sur une mauvaise interface reste refusée. Le DID est traduit vers un alias opaque généré, jamais vers une route arbitraire.

ContrôleDécisionÉchecPreuve
Transport / identitéTLS, certificat vérifié et CN carrier exact403mTLS local avec rôles/CA carrier et cellule séparés; pair sans certificat refusé
Intégrité SIPSanity, Max-Forwards et pike fixé à 12 requêtes par fenêtre de 2 s400, 483 ou 429Configuration seulement; seuil, CPS et bursts carrier non qualifiés
ServiceDID allowlisté vers alias Stasis404Service inconnu et tentative outbound refusés en lab
MéthodeProfil inbound explicitement borné405Code; interop carrier absente

Plans réseau et frontières de confiance

Input, output et forwarding sont fermés par défaut. Chaque autorisation associe interface, CIDR, protocole et port.

PlanFlux admisInterditsStatut
Public carrierSIP TLS 5061 depuis CIDR carrier5060, HTTP, TURN, SSHRègles lab; carrier absent
Edge privé8089 depuis contrôle NavyExposition InternetContrat IaC; réseau absent
ManagementSSH 22 via VPN/bastion, NTP 123Admin publique directeCible; VPN/BGP absent
Loopback celluleSIP TLS 127.0.0.1:5062, NG UDP 127.0.0.1:22222Accès inter-celluleSockets exacts exercés dans un namespace partagé local

Pare-feu et identité active

La santé lie la politique canonique, ses permissions, le fichier rendu et les règles nft effectivement chargées.

Quatre dérives

Identité vérifiée

Mode de configuration, SHA de la politique, SHA du fichier rendu et SHA de la table active sont testés séparément.

Pas de port ajouté

Santé hors chemin

Le timer local n’écoute sur aucun socket et sa panne ne coupe pas un appel. La readiness n’est consommée par aucun carrier.

Lab hermétique

Aucun port hôte

Kamailio, RTPEngine et Asterisk partagent le namespace réseau du lab; aucun port hôte, PSTN, cloud ou action externe n’est utilisé.

Profil SIP et dialogue

Le lab brut prouve un sous-ensemble précis du dialogue. Une route présente en code ne vaut toujours pas preuve pour les scénarios non exercés.

SurfaceComportement actuelLimite exacte
INVITE / ACKRoutes pour tout 1xx avec SDP et réponses finales; 1 re-INVITE offerless reçoit l’offre SDP 2xx puis une réponse SDP transformée dans ACK, avec compteur de succès. Pour le CSeq INVITE courant, ack-done empêche une retransmission 2xx de rouvrir ack-answer. La copie SDP exacte repasse cependant dans RTPEngine afin que chaque copie relayée reste réécrite et ancrée; un ACK SDP dupliqué peut être retraité pour la même raison, sans rouvrir l’état offre/réponse. Pour un ACK-SDP sans état correspondant, le lab injecte une anomalie et observe unexpectedAckSdpObserved=1; le vérificateur impose remove_body(), retrait de Content-Type, puis t_relay().Aucun pcap ni événement PBX indépendant ne confirme le corps effectivement reçu en aval. Un ACK late-offer sans SDP ou une transformation RTPEngine échouée reste aussi sans teardown contrôlé ni preuve d’alarme.
Réponses finalesProduction et lab chargent tmx.so. Une réponse finale 2xx d’INVITE initial, re-INVITE ou UPDATE qui perd le SDP requis ou ne peut pas être ancrée est arrêtée avec t_drop(). L’exception INVITE/re-INVITE est bornée au même CSeq: un échange PRACK fiable doit déjà avoir fourni la réponse attendue ou terminé l’offre/réponse. Après cet échange, un SDP redondant plus tardif est supprimé avec remove_body() et retrait de Content-Type.Le fail-close existe en code et les labs couvrent des branches ciblées, pas chaque branche t_drop() ni un carrier ou UAS externe.
PRACK / RFC 3262La campagne isolée du 29 août 2026 observe 7 PRACK: 1 RAck mal formé refusé localement en 400; 2 RAck bien formés mais non corrélés relayés au UAS sans mutation RTPEngine côté proxy; 1 PRACK corrélé sans answer SDP relayé; 1 PRACK d’acquittement sans SDP; 1 answer-in-PRACK; 1 offer-in-PRACK avec answer SDP dans le 2xx. La retransmission 183 cesse après le PRACK corrélé; chaque copie observée est revalidée comme SDP ancré sur adresse, port, crypto et direction.Les deux unmatched reçoivent un 200 Asterisk 22.9.0 vérifié sans corps SDP. Le SDP brut entrant peut néanmoins être accepté par l’UAS aval: contournement possible de l’ancrage RTPEngine côté aval. Le lab ne prouve jamais que l’UAS n’a pas muté son état. Le 200 au PRACK privé de l’answer attendue reste également un risque, pas un succès.
État offer/answerLa clé htable porte Call-ID + orientation exacte From/To + CSeq INVITE; un marqueur current monotone est conservé par orientation. Les INVITE en dialogue l’avancent seulement vers un CSeq supérieur; les branches initiales l’initialisent depuis l’AVP de transaction après apparition du To-tag. Les quatre onreply_route INVITE le comparent avant tout appel RTPEngine: une réponse ancienne 1xx reçoit le core drop, une 2xx t_drop(). RSeq et modes prack-answer / prack-offer restent dans la valeur du CSeq jusqu’au tombstone prack-done.Ce garde est présent dans la configuration chargée et les flux normaux des deux labs sont verts, mais aucun UAS artificiel n’injecte encore une réponse cross-CSeq retardée. La corrélation fiable couvre 101-199, pas 100; forks et plusieurs 1xx fiables séquentiels restent ouverts. Le cleanup et le delete RTPEngine couvrent les deux orientations; BYE supprime par préfixe toutes leurs clés CSeq.
re-INVITE / UPDATE3 re-INVITE: late offer, hold, reprise; 1 UPDATE SDP et 1 refresh offerless avec 2xx sans SDP; réponses reliable/late-offer/hold/reprise/UPDATE validées sur v/o/c/m/crypto, IP 172.31.93.20, ports 16000-16099 et directions recvonly/sendrecvAucun reset équivalent n’est appliqué au re-INVITE, car il pourrait tuer l’ancien média. Aucun RTP post-renégociation; rejet, glare ou timeout ne prouvent pas sa conservation.
Hold / reprise1 hold sendonly puis 1 reprise sendrecv traversent Kamailioinactive, adresse nulle, changement codec/port et effet média non exercés
Session timerstimers=yes, Min-SE 90 s, expiration 1800 s; une requête RFC avec Session-Expires 30 et sans Min-SE invalide reçoit 422 + Min-SE 90, ACK même branche, puis le dialogue normal réussitRotation/refresher et expiration réelle de session non testées
CANCEL / échec / BYECANCEL inconnu = 481. L’appel exact-socket observe le double Record-Route 5063 / 5061; le BYE Asterisk repasse par Kamailio interne 8.8.8.8:5063 et revient sur la même connexion TLS carrier. Le cleanup sht_rm_name supprime toutes les clés CSeq du dialogue dans les deux orientations.Courses CANCEL/183/200/BYE, retransmissions et double cleanup concurrents non prouvés
REFER / INFO / REGISTERHors profil inboundTransfert, DTMF INFO et enregistrement non acquis

HA et comportement de panne

A et B sont deux domaines de panne complets sans état d’appel partagé ni bascule interne cross-cell.

Nouveaux appels

Carrier décide

Le retrait de la cible en échec et l’envoi vers l’autre IP dépendent du carrier.

Appels actifs

Pas de migration

La perte d’une cellule peut couper ses sessions. Aucun drain ou transfert à chaud n’est prouvé.

RTPEngine absent

Fail-closed exercé

La perte simulée refuse un nouvel appel en lab; aucune route RTP centrale ne contourne la cellule.

Interopérabilité

À contractualiser

DNS/SRV, causes, codecs, DTMF, forks, suites de 1xx fiables, timers, SRTP et anti-fraude restent à qualifier avec le carrier.

Niveau de preuve

Les labs valident des comportements locaux ciblés. Le pair de test n’est ni un carrier réel, ni une preuve PSTN ou cloud.

Kamailio

Configuration et dialogue

Kamailio 6.0.7 accepte le rendu sous UID 1000 avec tmx.so. Les labs runtime et SBC passent avec t_drop(), tombstones ACK vérifiés avant média, 7 PRACK et sessions drainées à zéro.

Exact-socket local

Chemin image exercé

mTLS 8.8.8.9:5061 vers 8.8.8.8:5061, Asterisk TLS 127.0.0.1:5062, NG 127.0.0.1:22222, SDP ancré et cycle ARI Stasis complet.

IaC

Deux cellules décrites

OpenTofu teste une cible mockée, pas l’API Scaleway.

Couverture partielle

Limites maintenues

Le lab exact-socket ne prouve aucun RTP bidirectionnel sur ce même appel. Carrier/PSTN/cloud, réponse cross-CSeq retardée, forks, plusieurs 1xx fiables séquentiels, ancien média sur rejet/glare, reset sûr après re-INVITE, teardown ACK-SDP, observation PBX du stripping, rotation et expiration de session, courses CANCEL/200/BYE, branches stale t_drop() et RTP après chaque renégociation restent non prouvés dynamiquement.