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. ack-done empêche une retransmission 2xx de rouvrir ack-answer. La copie SDP exacte repasse dans RTPEngine pour rester ancrée; un SDP ACK ancien ou redondant après une mutation plus récente est retiré. 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 8 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é; 2 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 ancrée. Un PRACK corrélé ne mute le média que si le CSeq INVITE de son RAck égale current_invite. Dans le scénario ordonné, un UAS mTLS séparé retient les réponses via des barrières JSON-lines internes, sans port hôte. Le 200 bodyless du PRACK est libéré pendant qu’UPDATE CSeq 502 possède active; prack_ack_while_update_active=1. Les SHA-256 des octets retenus et écrits sont identiques.La garde active de la réponse PRACK ne s’applique qu’au mode PRACK offer. Les deux unmatched reçoivent un 200 Asterisk 22.9.0 sans corps SDP, mais leur SDP brut entrant peut être accepté par l’UAS aval: contournement possible de l’ancrage. Le lab ne prouve pas que l’UAS n’a pas muté son état.
État offer/answernp_oa_lock est une htable de verrouillage dédiée, séparée de l’état et indexée canoniquement par Call-ID; elle couvre vérification, transition et mutation RTPEngine. Le registre d’admission CSeq typé current + current_method est distinct des registres de corrélation current_invite et current_update. L’owner active sérialise une offre en cours. media_owner identifie la transaction ayant effectué la dernière mutation: un rollback ne détruit le média que si cette version est encore la sienne. ACK et PRACK restent corrélés au CSeq INVITE courant.Le lock et les registres sont chargés dans les deux labs; les scénarios ciblés ci-dessous sont exercés. Un glare réellement bidirectionnel, les forks, plusieurs 1xx fiables séquentiels et le comportement d’un UAS ou carrier externe restent ouverts. La corrélation fiable couvre 101-199, pas 100.
re-INVITE / UPDATE3 re-INVITE couvrent late offer, hold et reprise; UPDATE SDP et refresh offerless sont validés. Une offre chevauchante est refusée une fois par 491 Request Pending. Après UPDATE CSeq 106, INVITE CSeq 103 est refusé par 500 Out-of-Order CSeq + Retry-After: 0; INVITE CSeq 106 est refusé de même pour collision de méthode. UPDATE CSeq 302 réussit dans l’early dialog avant la réponse finale INVITE CSeq 300.Le 491 prouve une collision d’offre dans le scénario local, pas un glare bidirectionnel. Le reset d’une offre re-INVITE reste interdit sans preuve, car il pourrait tuer l’ancien média. Aucun RTP post-renégociation; rejet, glare ou timeout ne prouvent pas sa continuité.
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. Sous np_oa_lock, BYE supprime les deux orientations, vide les owners, pose la tombstone globale terminated au Call-ID, puis détruit le média. Le rejeu de l’INVITE initial CSeq 100 après BYE reçoit 481 et ne recrée pas de média. Le UAS contrôlé prépare le 200 UPDATE CSeq 503, retient ces octets, laisse BYE CSeq 504 recevoir son 200, puis libère exactement les mêmes octets UPDATE: Kamailio les arrête après la tombstone, terminated_update_answer_dropped=1, le média reste drainé et les sessions finissent à zéro.Supprimer ce 2xx UPDATE tardif est une politique de hardening fail-closed non transparente, pas une affirmation de conformité RFC d’un proxy. L’interopérabilité carrier/UAS externe, les autres ordonnancements BYE/réponse, les retransmissions et doubles cleanup concurrents restent à qualifier.
REFER / INFO / REGISTERHors profil inboundTransfert, DTMF INFO et enregistrement non acquis