Problèmes des appels entrants causés par l’expiration du NAT port mapping

Oussama Hammami, 2011-06-27

Switzernet

 

Introduction. 1

Problématique. 3

Exemple. 3

Conclusion. 3

SIP OPTION.. 4

SIP NOTIFY. 4

Configuration. 4

Statistique. 5

Utilisation CPU.. 9

Référence. 11

Introduction

Un routeur NAT, comme son nom l'indique, redirige les paquets qu'il reçoit en fonction d'une table de routage vers le routeur suivant jusqu'à atteindre le réseau local de destination. Chaque paquet comporte l'adresse d'origine et l'adresse de destination. Dans le cas d'adresses privées, l'adresse d'origine est une adresse privée inconnue dans l'Internet. Le destinataire ne pourra pas répondre. Il faut donc remplacer l'adresse privée d'origine par une adresse publique. C'est le travail du routeur NAT (Network Address Translation) qui effectue la transformation des adresses.

Pour pouvoir configurer correctement un routeur NAT, il faut comprendre la notion de port.

Le protocole TCP/IP utilise des ports (un nombre de 0 à 65535) comme le moyen de nommer les bouts d'une connexion logique, une conversation qui comporte plusieurs échanges. Les ports permettent de réaliser simultanément des milliers de connexions logiques sur la même adresse IP. Ils permettent de partager la liaison Internet entre des programmes différents et des machines différentes. Comme pour les adresses IP, l'IANA a classé les ports en 3 catégories [http://www.iana.org/assignments/port-numbers].

 

Par défaut, le protocole SIP utilise le port 5060, http le port 80, le SMTP le port 25, etc.

Lorsqu'une machine du réseau local envoie des paquets à un serveur à l'extérieur, l'adresse d'origine est une adresse privée. Le destinataire ne pourra pas répondre à cette adresse. Pour résoudre ce problème, le routeur NAT remplace l'adresse et le port d'origine par l'adresse Internet publique du routeur et un numéro de port libre choisi au hasard en notant adresse et port associés à la machine locale (voir sur le dessin ci-après).

 

 

La machine de destination renvoie la réponse sur l'adresse et le port visible de l'Internet au routeur NAT. Celui-ci fait alors la transformation inverse pour renvoyer les paquets vers la machine locale. Dans ce cas de figure, il n'y a rien de spécial à configurer. C'est comme cela que fonctionnent le VOIP. Le téléphone SIP dans le réseau privé se connecte au serveur SIP (Asterisk) qui connaît ainsi l'adresse externe et le numéro de port du routeur qui permet de contacter cette machine.

En revanche, une machine qui appelle depuis l'Internet pour atteindre une adresse privée n'a aucun moyen d'y arriver puisque le routeur ne sait pas sur quelle machine du réseau Interne il faut router l'appel sauf si le port forwarding est configuré sur ce dernier.

Problématique

Lors de l’enregistrement du téléphone SIP (REGISTER), l’Astrad garde l’IP et le Port (URI) de ce dernier dans sa base de données (table MySQL sipppeer), l’information remonte jusqu’au serveur de routage et de ce cette manière tous les appels entrant vers ce client seront routés vers l’Asterisk en question. Ce dernier utilisera l’IP et le port utilisés par le téléphone lors du dernier enregistrement pour router les appels entrants de ce client mais il arrive que le routeur NAT du client libère ce port et par conséquent la transformation inverse pour renvoyer les paquets SIP vers l’IP locale devient impossible.

Exemple

Ci-dessous un scénario d’un appel entrant échoué à cause de la perte de porta mapping du compte 41215500327.

 

IP: 81.62.117.251

Port: 64920

IP: 81.62.117.251

Port: 55466

Le téléphone a changé le port après 3 minutes.

Conclusion

En générale, le routeur libère les ports inactifs durant les 3 dernières minutes.

Pour contourner ce problème, les téléphones SIP Siemens Gigaset (C450, C470 …) envoient des paquets UDP vides vers le serveur SIP d’enregistrement afin de garder le port dans le routeur NAT ouvert [eml]:

"To keep NAT/firewall bindings open, empty UDP packets are sent to any SIP proxy and registration gateway of all registered ITSP…

The filter behavior is of no interest to the HiPath / OpenScape telephony system: It always assumes that it needs to open a binding to the IP address and port of its peers and thus send empty UDP packets to open connections (RTP) or keeping bindings alive (SIP registration)."

http://wiki.siemens-enterprise.com/wiki/Network_Configuration_for_VoIP_Providers

 

La même solution est aussi utilisée par les serveurs SIP Porta-Sip [eml]: http://switzernet.com/3/public/110623-portasip-vs-astradV7-incoming/

Pour plus d’information sur l’implémentation de cette solution (paquets UDP vide) sur les Astrad: http://switzernet.com/3/public/110627-astrad-empty-udp-keepalive/

Autrement et pour résoudre ce problème, une solution très simple consiste à forcer la durée d’enregistrement a une valeur plus petite que 3 minutes, ce qui est possible avec Asterisk (les options maxexpiry, minexpiry, defautlexpiry dans le fichier sip.conf) [eml] : http://switzernet.com/3/public/112706-astrad-forcing-expire-time/

SIP OPTION

Une première solution consiste à utiliser qualify dans sip.conf d’Asterisk mais on a abandonné l'utilisation de cette option car la fréquence par défaut est très élevée ce qui peut causer le redémarrage du téléphone.

L’option qualifyfreq (qualify fréquence) est disponible depuis la version 1.6 d’Asterisk.

 

“An OPTIONS request MAY be sent as part of an established dialog to query the peer on capabilities that may be utilized later in the dialog.”

RFC3261 [http://www.faqs.org/rfcs/rfc3261.html]

SIP NOTIFY

Cette solution consiste a envoyer des paquets SIP NOTIFY avec l’événement keep-alive au lieu d’un paquet UDP vide, la même solution est utilisée par les téléphone SIP Cisco Linksys (SPA921, SPA1001…)

 

 

U 85.3.70.29:58984 -> 94.23.225.212:5060

NOTIFY sip:astrad.switzernet.com SIP/2.0.

Via: SIP/2.0/UDP 192.168.1.121:5060;branch=z9hG4bK-15a5b87c.

From: "41215500327" <sip:41215500327@astrad.switzernet.com>;tag=da7194e2851cd498o0.

To: <sip:astrad.switzernet.com>.

Call-ID: a68e04ea-f787e430@192.168.1.121.

CSeq: 1 NOTIFY.

Max-Forwards: 70.

Event: keep-alive.

User-Agent: Linksys/SPA921-5.1.8.

Content-Length: 0.

.

Configuration

Le fichier de configuration de cette option est :

sip_notify.conf

[nat]

Event=>keep-alive

Content-Length=>0

 

Pour activer cette fonctionnalité il suffit d’ajouter ce fichier dans le répertoire de configuration d’asterisk (/etc/asterisk) et de reloader ce dernier (/etc/init.d/asterisk reload).

Vous pouvez envoyer les paquets NOTIFY depuis Asterisk Manager comme suit :

# asterisk -rx 'sip notify nat <USER>'

 

L’échange SIP est le suivant::

U 94.23.225.212:5060 -> 85.3.70.29:58984

NOTIFY sip:41215500327@192.168.1.121:5060 SIP/2.0.

Via: SIP/2.0/UDP 94.23.225.212:5060;branch=z9hG4bK6e3e0254;rport.

From: "asterisk" <sip:asterisk@94.23.225.212>;tag=as34c24274.

To: <sip:41215500327@192.168.1.121:5060>.

Contact: <sip:asterisk@94.23.225.212>.

Call-ID: 392bb43a250918af5f5ee1b71c650916@94.23.225.212.

CSeq: 102 NOTIFY.

User-Agent: Asterisk PBX.

Max-Forwards: 70.

Event: keep-alive.

Content-Length: 0.

.

 

U 85.3.70.29:58984 -> 94.23.225.212:5060

SIP/2.0 200 OK.

To: <sip:41215500327@192.168.1.121:5060>;tag=46d36a4f71acb611i0.

From: "asterisk" <sip:asterisk@94.23.225.212>;tag=as34c24274.

Call-ID: 392bb43a250918af5f5ee1b71c650916@94.23.225.212.

CSeq: 102 NOTIFY.

Via: SIP/2.0/UDP 94.23.225.212:5060;branch=z9hG4bK6e3e0254.

Server: Linksys/SPA921-5.1.8.

Content-Length: 0.

.

 

Pour plus d’information sur ces tests : [eml] http://switzernet.com/3/public/110609-astradv8-notify/

Statistique

Les graphes ci-dessous ont été obtenus de la manière suivante [eml] :

 

# ngrep -pql -W byline "" port 5060 | egrep -i -B6 '^CSeq.*NOTIFY' | perl -ne 'use POSIX;print strftime("%Y-%m-%d %H:%M:%S", localtime(time()))." ".$_' > notify.log

 

# cat notify.log | perl ./t3.pl > 110622-astrad5-notify.csv

 

1-

Source : [xls] [eml] [protected]

Source : [xls] [eml] [protected]

 

Le routeurs NAT de certains clients change ou libère le port (port mapping) utilisé pour router le trafic SIP plus fréquemment que la fréquence d'enregistrement de l'UA (User Agent).

En conséquence, après un certain temps l'UA n'est plus joignable. Dans cette expérience, nous envoyons des NOTIFY à tous les UA enregistrés sur le serveur SIP et nous enregistrons le taux de réponses renvoyées par l’UA. Si le port dans le routeur NAT est libéré, l'UA ne répondra pas. Cependant, comme nous continuons à envoyer les NOTIFY, dès que l'UA nous envoie un nouveau enregistrement et qu’il met à jour son port, le flux de messages de notification (NOTIFY) gardera le port ouvert jusqu'à l'enregistrement suivant quel que soit le délai de l’expire. Cela signifie que nous devons observer un taux élevé de pertes qui diminuera progressivement à la suite de la réception des enregistrements des UA dont la valeur d’expire est grande. Nous envoyons des NOTIFY à tous les utilisateurs avec un intervalle de 30 secondes. L'envoie prend environ 5 secondes ainsi, la périodicité est d'environ 35 secondes.

 

2-

Source: [xls] [eml] [protected]

 

Ce graphique montre le résultat d'une expérience où nous envoyons des NOTIFY à tous UA enregistrés sur un serveur SIP donnée et où l’on mesure le taux de réponses retournées. Les premiers NOTIFY sont envoyés avec un long intervalle, mais la fréquence augmente progressivement.

 

Si le mappage de port de l'UA est expiré, l'UA ne répondra pas aux NOTIFY. Cependant, comme nous continuons à envoyer des messages de notification (à l'adresse:port enregistré dans la table de localisation), dès que l'UA met à jour son emplacement, et si la fréquence d’envoi des NOTIFY est suffisamment élevée, ce flux gardera obligatoirement le port NAT ouvert et il n'y aura plus de pertes.

 

Tant que les NOTIFY sont envoyés avec un taux élevé, les pertes vont disparaître indépendamment du retard entre les enregistrements. Cela signifie que nous devons observer un taux élevé de pertes de réponses aux NOTIFY (environ 14%) au début (lorsque les NOTIFY sont envoyés aussi lentement que le plus lent enregistrement). L'allure du graphe changera et les pertes disparaîtront graduellement au cour de la réception des mises à jour d'enregistrement provenant de téléphones SIP.

 

Nous envoyons des NOTIFY à tous les utilisateurs avec un intervalle entre les vagues d’envoie de départ d'une valeur de 4000 secondes. L'envoie  prend environ 5 secondes. L'intervalle diminue progressivement avec un facteur de 1,1 jusqu'à ce qu'il atteigne le plus bas niveau autorisé de 30 secondes. Une fois ce niveau atteint, les NOTIFY sont envoyés en continu pendant un certain temps (environ 2h).

 

3-

Source: [xls] [eml] [protected]

 

Le graphique suivant montre le pourcentage de clients avec un port différent pour chaque enregistrement (courbe bleue) et le taux de perte de NOTIFY (courbe rouge)

Nous voyons que dès que le taux de perte de NOTIFY est tombé à environ 1%, le ratio de téléphones avec une instabilité de mappage de port tombe ainsi à environ 4%.

Le ratio non nul est probablement dû à une douzaine de téléphones partageant le même compte. Nous observons également que l'instabilité de mappage de port dépasse 12% dès que la transmission des NOTIFY est interrompue.

 

La procédure MySQL utilisée pour obtenir la courbe bleue est StatReg dont le code est [eml] [zip].

Cette dernière est basée sur location_history qui était ajouté avec la version 3 de DBA [DBA-V3]

Son algorithme est [eml] :

Assume we have a period from A to B.

For each account

  Count records

    Where

      Start < B and Stop > A (meaning any intersection)

  If count = 1

    Then the account does not loose its port

    Else the telephone looses the connection

 

Mais cette dernière avait une erreur car avec un intervalle de 30 min il affiche des valeurs dans les deux colonnes alors qu’avec intervalle de 5 minutes, il affiche zéro dans la dernière colonne. Si l'algorithme est correct, même avec des intervalles très petits la dernière colonne doit afficher une valeur non nulle.

Pour contourner se problème on a exécuté cette procédure plusieurs fois avec un intervalle de 30 minutes et en incrémentant la valeur de START de 5 minutes [zip].

 

Version complète des statistiques ci-dessus [protected]

Version complete de projects mail archive [protected]

Utilisation CPU

1- Ci-dessous les graphes d’utilisation CPU pour astrad6 et astrad7 avant (2011-06-16) et après (2011-06-17) l’activation de Notify (durant la nuit : de 00h à 07h)

L’envoi des Notify est regroupé par 10 [eml].

 

 

On remarque que l’utilisation CPU a augmenté de 2%.

 

2- ci-dessous les graphes d’utilisation CPU d’astrad5 dans lequel on a activé l’envoi de Notify un par un de 01 :00 à 03 :00 et par groupes de 20 de 03 :00 à 05 :00 [eml]

 

 

On remarque que le regroupement de Notify optimise l’utilisation CPU (03 :00).

 

 

À 05 :00 on a désactivé l’envoi de Notify.

 

Ce test a été programmé dans le cron comme il suit [eml]:

cron

# cat /etc/cron.d/astrad

00 01 * * *  root /etc/astrad/script/ast-notify-send-1.pl

Lacement de l’envoi de NOTIFY un par un.

 

00 03 * * *  root /etc/astrad/cron/teststart

Arrêt de premier script d’envoie et lancement de l’envoi de NOTIFY par groupes de 20

 

00 05 * * *  root /etc/astrad/cron/teststop

Arrêt de deuxième script d’envoi de NOTIFY.

 

Les scripts utilisés lors de ce teste sont les suivants [zip]:

Référence

Notify response loss on astrad5.switzernet.com with 191 clients

[xls] [eml] [protected]

 

Notify response loss rate on astrad9.switzernet.com with 234 clients

[xls] [eml] [protected]

 

Loss rate on astrad5.switzernet.com with 48025 notifies sent to 171 clients from 18:24 Jun 21through 08:38 Jun 22, with 46880 replies, and 1145 losses

[xls] [eml] [protected]

 

Effect of notifies transmitted to all 171 customers with an interval of initially 4000 seconds decreasing exponentially by a factor 1/1.1 down to the floor value of 30 seconds maintained for another 02h20m

[xls] [eml] [protected]

 

Statistic of NOTIFY sending (Original Excel files with customer account, unpublished in the public version of this document)

[protected]

 

Projects@ mail archive

[public]

 

Version complète de Projects@ mail archive

[protected]

 

Test d’Astrad vs PortaSip (maintient du port SIP ouvert)

http://switzernet.com/3/public/110623-portasip-vs-astradV7-incoming/

 

Forcing expire time on asterisk

http://switzernet.com/3/public/112706-astrad-forcing-expire-time/

 

Send empty UDP packets to keeping NAT router port alive

http://switzernet.com/3/public/110627-astrad-empty-udp-keepalive/

 

Astrad V8 : Test Notify

http://switzernet.com/3/public/110609-astradv8-notify/

 

Asterisk & NAT

http://switzernet.com/3/public/110303-asterisk-nat/

 

DBA versions

http://switzernet.com/3/public/110317-db3-versions/

 

Astrad Versionning

http://switzernet.com/3/public/110126-astrad-versions/