6135 links
  • GuiGui's Show
  • Home
  • Login
  • RSS Feed
  • ATOM Feed
  • Tag cloud
  • Picture wall
  • Daily
Links per page: 20 50 100
 
  • Le lulz de la VOIP - Tome 8 : softphones et VPN partiel / split tunnel

    Résumé : les logiciels de téléphonie indiquent souvent une mauvaise adresse IP à leur interlocuteur, surtout quand ils sont utilisés avec un VPN partiel / split tunnel / VPN sans route par défaut. Les VPN peuvent bricoler les paquets SIP contre la volonté de l'administrateur systèmes et réseaux. La fonctionnalité d'apprentissage RTP du commutateur téléphonique Asterisk est plutôt chatouilleuse aux interférences. Certaines versions de logiciels de téléphonie résistent plus ou moins bien aux magouilles d'un VPN. Pour toutes ces raisons, si tu dois fournir de la téléphonie d'entreprise à des personnels en télétravail et que ça foire de manière aléatoire, ajoute les lignes nat=force_rport,comedia et directmedia=no dans la définition de chaque ligne SIP dans le fichier sip.conf d'Asterisk ou dans les paramètres (paramètres avancés pour « directmedia ») d'une ligne SIP dans XiVo. La première réécrit l'adresse IP contenue dans le paquet SIP/SDP avec l'adresse IP source de ce paquet, garantissant ainsi que l'IP est la bonne. La deuxième fait circuler les flux audio via le commutateur téléphonique plutôt qu'en pair-à-pair, ce qui évite les ratés de l'apprentissage RTP, les bidouilles d'un VPN et la sensibilité des softphones.


    Présentation

    Rappel sur le fonctionnement de la téléphonie sur Internet. D'un côté, il y a la signalisation (je veux appeler untel, il a décroché, il met en attente, il reprend l'appel, etc.) avec le protocole SIP. Cet échange se fait via un commutateur téléphonique. La voix transite via le protocole RTP (et son protocole de contrôle RTCP). Il y a un flux audio par interlocuteur. Les flux audio sont échangés en pair-à-pair, sans passer par le commutateur téléphonique. L'adresse IP, le port UDP ("envoie ton flux RTP ici") et les codecs à utiliser sont négociés via le protocole SDP lui-même relayé par SIP, donc via le commutateur.

    J'ai déjà exposé notre architecture de téléphonie. Notre commutateur téléphonique est donc un Asterisk empaqueté dans produit avec interface web, API, etc. nommé XiVo. On dira qu'il a l'adresse IP 192.0.2.1 avec une seule route par défaut vers le routeur global de notre organisation. Nous avons des téléphones IP de la marque SNOM. Ils sont dans le réseau 198.51.100.0/24. Il y a donc du routage / du niveau 3 entre nos téléphones et le commutateur téléphonique. Nous avons également quelques rares softphones / logiciels de téléphonie Linphone (choisi car un des seuls logiciels libres encore maintenus + interface agréable depuis la version 4.X). On utilise ça depuis des années sans problème.

    Depuis environ six mois, nous avons quelques logiciels de téléphonie utilisés depuis l'extérieur (mise en place progressive du télétravail) à travers un VPN, car notre XiVo n'est pas joignable depuis l'extérieur (filtrage volontaire). Il s'agit d'un VPN partiel / split tunnel : il ne donne pas accès à Internet, seulement aux réseaux internes de l'organisation. Il n'installe donc pas une route par défaut sur le client, mais une route pour chacun de nos réseaux internes. Tous les clients sont dans un même réseau, disons 203.0.113.0/24. Notre VPN ne fait ni filtrage ni NAT. Donc, le commutateur téléphonique voit l'IP VPN d'un client. Exemple : « Registered SIP 'bczhcigi' at 203.0.113.42:62633 ». 203.0.113.42 est bien l'IP que le client VPN a sur son interface réseau VPN. Nos clients VPN peuvent se parler entre eux : un netcat TCP et UDP entre deux clients VPN fonctionne. Notre VPN est un Cisco ASA. Ces personnels en télétravail ne nous ont pas signalé de problème.

    Avec le Covid-19, il a fallu généraliser le télétravail, donc fournir une ligne de téléphone et un logiciel de téléphonie à chaque personnel. Et là ça ne fonctionne plus. Enfin, si, mais pas pour tout le monde ni tout le temps ! On est donc sur un problème aléatoire, les plus chiants à diagnostiquer…


    Notes générales

    • Ci-dessous, je vais essentiellement parler du logiciel de téléphonie Linphone, car c'est celui qu'on a sélectionné en amont des problèmes que je vais décrire, mais nous avons aussi essayé Jitsi, Zoiper, Blink, microSIP et d'autres, et les problèmes décrits ci-dessous se produisent aussi avec ces logiciels ;

    • Pour conduire nos diagnostics, nous avons désactivé les éventuels pare-feux sur les ordinateurs de télétravail, que ce soit Netfilter Linux ou le pare-feu winwin.


    Problème numéro 1

    Entre un poste téléphonique SNOM du bureau (ou un numéro externe 0[1-9]) et un Linphone à domicile, l'appel a lieu mais la personne à domicile entend rien. Entre deux Linphones, chacun dans un domicile différent, personne s'entend.

    Ça, c'est le signe classique d'un filtrage ou d'un NAT. Mais, comme écrit ci-dessus, notre VPN ne NAT pas et il ne filtre pas. Il n'y a pas d'autres filtrages en interne. Il n'y a pas de filtrage aux extrémités puisqu'on a désactivé les pare-feux.

    Si l'on effectue une capture réseau avec tcpdump (sur le commutateur téléphonique) et wireshark (sur l'ordinateur de télétravail), on constate que, dans la négociation SDP, Linphone ne communique pas l'adresse IP de l'interface réseau VPN (vpn0, disons), mais celle de l'interface eth0 (ou wlan0), c'est-à-dire celle sur le réseau local du domicile du personnel (genre 192.168.0.X). Forcément, l'interlocuteur ne peut pas émettre un flux audio vers cette destination.

    Parfois, Linphone communique la """"bonne"""" adresse IP, celle de l'interface réseau VPN, et dans ce cas-là, tout fonctionne. Cela peut, en partie, expliquer pourquoi nos personnels en télétravail depuis six mois ont rien signalé.

    On pourrait penser qu'il suffit de lancer Linphone après avoir établi le VPN, mais non, car, parfois, Linphone échoue même quand il a été démarré après l'établissement du VPN. De plus, on ne peut pas attendre de nos personnels qu'ils se préoccupent de lancer tel logiciel après tel autre.

    On peut configurer Linphone pour forcer la communication de l'adresse IP de l'interface réseau VPN. C'est l'option « nat gateway ». Les appels fonctionnent alors dans 100 % des cas. Mais cette option a disparu dans la version 4.X, celle que l'on utilise (parce que son interface est agréable). De toute façon, tous les logiciels qui permettent de configurer l'adresse IP (microSIP, Linphone, etc.) ne conviennent pas : sur notre VPN, nous distribuons des IPs de manière dynamique : à chaque connexion, l'adresse IP du client VPN change. On ne peut pas demander à nos personnels de configurer leur téléphone à chaque fois.

    On notera que, dans le cadre de webRTC, les navigateurs web sont mieux équipés que les logiciels de téléphonie ! Dans la config' avancée de Firefox, la clé « media.peerconnection.ice.force_interface » permet de sélectionner l'interface à utiliser, par exemple. Donc ça fonctionnerait impec avec les IP dynamiques de notre VPN. Ça a aussi ses inconvénients : quelqu'un qui voudrait faire de la téléphonie professionnelle (supposons avec VPN) et personnelle (sans VPN) devrait en changer la valeur en permanence…

    On peut utiliser ICE, une méthode qui consiste à échanger tous les couples IP+port possibles lors de la négociation SDP et à les tester un par un. J'ai activé ICE dans Linphone et sur le commutateur (même si ça a aucun sens puisqu'il a une seule adresse IP) : ça ne fonctionne pas. D'après mes connaissances, c'est très curieux, mais c'est ainsi.

    On peut utiliser STUN, un serveur qui se contente de répondre "voici l'adresse IP source du paquet IP avec lequel tu viens de me causer". On ne peut pas utiliser l'un des serveurs STUN public, car il retournerait l'adresse IP publique de la box Internet du personnel. En revanche, si l'on installe un serveur STUN en interne, la communication avec ce serveur sera contrainte, par le routage, de passer par le VPN. Donc l'adresse IP retournée sera toujours celle de l'interface réseau VPN.

    Je ne veux pas trop toucher à notre commutateur téléphonique afin de rien casser (surtout qu'avec le confinement, on ne reviendra pas au bureau avant longtemps, donc on ne saura pas que l'on a cassé l'existant). De plus, nous avons un contrat d'assistance (support) et de maintenance pour notre commutateur et on n'a pas envie de l'invalider avec des modifications trop conséquentes. Pour installer un serveur STUN, j'ai utilisé le logiciel coturn. Avec Debian GNU/Linux, un simple sudo apt-get install coturn ; sudo systemctl start coturn suffit.

    STUN fonctionne parfaitement. Mais il y a des limites.

    • Parfois, ça cesse de fonctionner. Linphone émet bien une requête STUN, obtient bien une réponse dans les temps… mais ne l'utilise pas lors de la négociation SDP. Il faut le redémarrer, plusieurs fois, et encore, ça ne suffit pas toujours. Il semblerait que la prise en charge de STUN par Linphone échoue quand une adresse IPv6 est configurée sur l'une des interfaces de la machine, mais c'est une hypothèse ;

    • Tous les logiciels de téléphonie ne permettent pas de configurer explicitement un serveur STUN (Jitsi, par exemple), donc la pérennité de cette solution est remise en question (qui dit que Linphone ne va pas retirer cette possibilité ?) et l'on dépend d'un logiciel ;

    • Ce n'est pas configurable partout car l'usage exclusif de STUN est déconseillé ;

    • Un serveur STUN est une brique de plus à superviser et à maintenir afin d'assurer le service de téléphonie.

    Une meilleure solution est de demander au commutateur téléphonique, Asterisk, de réécrire l'adresse IP contenue dans les messages SDP avec l'adresse IP source des paquets IP (on est sûr qu'il s'agit de celle de l'interface réseau VPN car elle a été choisie par le système d'exploitation en fonction de l'interface de sortie).

    Avec Asterisk, cela se fait en ajoutant une ligne nat=force_rport,comedia pour chaque ligne téléphonique de télétravail dans le fichier sip.conf. Dans XiVo, cela se fait dans l'onglet « Général » de chaque ligne de télétravail (note : XiVo recharge automatiquement la configuration d'Asterisk quand on modifie une ligne ;) ). On peut aussi appliquer cette option sur l'ensemble du parc, mais je ne le fais pas pour les raisons sus-mentionnées : ne pas casser l'existant et ne pas invalider notre contrat d'assistance / maintenance.


    Problème numéro 2

    Des personnels continuent de ne pas entendre leur interlocuteur. wireshark / tcpdump montre des messages SDP parfaitement valables qui contiennent la """"bonne IP"""" de l'interlocuteur (celle sur l'interface réseau VPN, donc). Si l'on regarde, il y a le début de l'appel (SIP INVITE, SIP TRYING, SIP RINGING, SIP ACK, etc.) puis un premier message SDP est émit par le commutateur téléphonique contenant son adresse IP, donc Linphone émet un flux audio RTP à destination du commutateur puis il reçoit le SDP émis par l'interlocuteur (et réécrite par le commutateur, voir chapitre précédent). Il cesse alors d'émettre le flux RTP. Pourquoi Linphone ne respecte-t-il pas la dernière négociation SDP ?

    Je précise que changer la destination des flux RTP en cours de route est parfaitement normal. C'est comme ça que fonctionne la mise en attente ou le fait de se rendre muet : en renégociant en SDP.

    Activons le journal de Linphone. Menu -> « Préférences » -> « Avancé » -> « Logs activés ». Le dossier qui contiendra le journal peut également être consulté / changé.

    Lisons ce journal. Linphone reçoit bien le dernier SDP, l'analyse et le consigne : « Change audio stream destination: RTP=203.0.113.1:7078 RTCP=203.0.113.1:7079 ». L'adresse IP est la """"bonne"""". Pourquoi Linphone l'ignore-t-il ? Je n'aurai pas la réponse.



    Dans le journal du commutateur, Asterisk, je remarque qu'à chaque fois que le problème constaté côté Linphone survient, l'apprentissage RTP ne va pas à son terme. L'apprentissage RTP ou RTP learning ou RTP autolearning est une tambouille interne d'Asterisk qui fait un peu de la magie dans le but d'identifier la """"bonne"""" IP à utiliser.

    Quand tout fonctionne bien, le journal consigne une ligne « Strict RTP learning after remote address set to 203.0.113.1:7078 » pour chaque IP de chaque interlocuteur puis une unique ligne « Strict RTP learning complete - Locking on source address 203.0.113.1:7078 » pour chaque interlocuteur.

    Quand l'un des interlocuteurs ne s'entend pas et qu'un Linphone n'émet plus de flux RTP en contradiction avec le dernier SDP, je remarque que, soit il n'y a pas de « Strict RTP learning complete […] », juste des « Strict RTP learning after remote address set […] » pour chaque interlocuteur, soit il y a un seul « Complete », pour un seul des interlocuteurs.

    Pourquoi l'apprentissage RTP d'Asterisk échoue-t-il ? Comment le désactiver afin d'être sûr qu'il est bien l'origine du problème ? Aucune idée.



    Quand les deux interlocuteurs s'entendent, il est possible qui cela coupe après 32 ou 36 secondes de communication. Cela dépend de qui téléphone. Si A téléphone à B, ça peut couper alors que ça ne coupera pas si c'est B qui téléphone à A. Ce point est constant : c'est toujours dans le même sens que cela foire. Cela semble dépendre de la version de Linphone. Si une 4.1.1 téléphone à une 3.11 / 3.12, alors ça coupera. Pas l'inverse.

    Avec wireshark, on voit un message SIP BYE avec un entête « X-Asterisk-HangupCause: no user responding » destiné au Linphone 3.X. Dans le journal d'Asterisk, on lit « Packet timed out after 32000ms with no response ».

    Ajouter session-timers=refuse dans la définition d'une ligne téléphonique dans sip.conf ou dans l'onglet « Avancé » des paramètres d'une ligne téléphonique dans XiVo, n'aide pas.



    Qui peut bien être responsable de tout ce qui précède ? Le seul qu'on n'a pas encore remis en cause est le VPN ASA.

    Dès le début du diagnostic, nous avons désactivé son ALG (« no inspect sip ») et constaté que les timeouts UDP et SIP étaient déjà de plusieurs minutes. Pour savoir ce qu'est un ALG et les emmerdes pratiques que cela pose parfois, je te renvoie vers cet article : Le lulz de la VOIP - Tome 3 : Numericable.

    Dans un coin, j'ai un PFSense (routeur, pare-feu, VPN, etc. en logiciel libre pour lequel on peut acheter des appliances, de la prestation d'intégration, de l'assistance, etc.) de test avec un OpenVPN de test déjà configuré. Niveau 3 (TUN). Tous les clients dans un même réseau /24. Aucun filtrage. Pas de NAT. Il a donc la même architecture que notre VPN ASA.

    Je décide de tester. Ça fonctionne moyen. D'un côté, certains couples de testeurs qui ne s'entendaient pas s'entendent, ce qui est un gain. De l'autre côté, la coupure après 32 / 36 secondes d'appel en fonction des clients demeure. De même, le RTP autolearning d'Asterisk continue de foirer quelques fois. Mais, quand ça arrive, la communication pair-à-paire fonctionne systématiquement.

    Du coup, le VPN ASA est en cause sur l'un des trois problèmes (communication pair-à-pair dysfonctionnelle). Néanmoins, ce n'est pas lui qui fait parfois échouer le RTP autolearn ni qui provoque une coupure après 32 / 36 secondes d'appel.



    Ne sachant pas désactiver le RTP autolearn d'Asterisk, j'ai décidé de faire transiter les flux audio par le commutateur téléphonique. Ainsi, le résultat de l'apprentissage RTP aura peu d'importance, donc il n'y aura pas de bascule vers une communication pair-à-pair qui pose parfois problème avec notre VPN Cisco ASA.

    Pour ce faire, il faut ajouter une ligne directmedia=no dans la définition de chaque ligne SIP de télétravail dans le fichier sip.conf d'Asterisk ou dans l'onglet « Avancé » d'une ligne téléphonique dans XiVo. Comme le reste, on peut activer ça pour tous les clients SIP, mais on ne le veut pas afin de ne pas détraquer le reste du parc qui fonctionne très bien et de ne pas rendre caduc notre contrat d'assistance / maintenance.

    Ça fonctionne parfaitement. Tous les appels aboutissent. Aucun se termine après 32 / 36 secondes.

    VICTOIRE \o/

    Si tu ne veux pas charger ton commutateur téléphonique (d'après les pros de FRnOG, c'est relatif, c'est """"juste"""" de la copie de paquets RTP ) tout en obtenant le même résultat, tu peux le décharger en faisant transiter tes flux audio via un serveur TURN interne.


    Conclusion

    Que retenir de tout ça ?

    • Les softphones / logiciels de téléphonie indiquent n'importe laquelle de leur adresse IP dans la négociation SDP et souvent pas celle d'un VPN partiel / split tunnel / VPN sans route par défaut. Il y a parfois aucune constance dans le choix ;

    • La fonctionnalité magique RTP autolearn d'Asterisk est chatouilleuse. Même sans filtrage ni NAT et avec un VPN décent (OpenVPN), elle peut foirer et faire basculer une conversation en pair-à-pair (ce qui en soi n'est pas un problème sauf si des perturbateurs sont à l'œuvre sur le réseau, voir point suivant) ;

    • Un VPN Cisco ASA en niveau 3 avec lequel on ne fait ni filtrage ni NAT et sur lequel on désactive le SIP ALG et l'on configure des timeouts UDP et SIP élevés pose problème. Notamment, lors de la bascule pair-à-pair après échec de l'apprentissage RTP. Ça se produit pour certains clients, sans que j'ai trouvé un discriminant ;

    • Certaines versions de certains logiciels de téléphonie rattrapent des mauvais coups en douce. Exemple : Linphone 4.X gère une bascule sur le mode pair-à-pair quand le RTP learning échoue et qu'un Cisco ASA semble bidouiller le paquet alors que Linphone 3.X ne sait pas faire. De même, Linphone 4.X résiste au phénomène (qui ne peut pas être l'ASA puisque le problème se produit aussi avec un OpenVPN) qui provoque une coupure des appels 32 à 36 secondes après leur début, alors que Linphone 3.X ne sait pas faire ;

    • Il y a quand même des bugs curieux dans les logiciels de téléphonie. La version winwin de Linphone ne peut pas être réduite dans la zone de notification lors d'un appel sinon le son est coupé. La version Android de Linphone utilise parfois les mauvais serveurs DNS récursifs. Linphone 4.1.1 sous winwin ne peut pas être appelé pendant quelques dizaines de secondes après avoir raccroché un appel (même si c'est lui qui raccroche) alors qu'Asterisk voit bien la fin de l'appel. Linphone ignore parfois l'adresse IP obtenue via STUN. Etc. ;

    • La meilleure solution à (presque) tout ça est d'ajouter une ligne nat=force_rport,comedia et une autre ligne directmedia=no dans la définition de chaque ligne SIP dans le fichier sip.conf d'Asterisk ou dans les paramètres (onglet « Avancé » pour directmedia=no) d'une ligne dans XiVo. La première réécrit l'IP contenue dans le paquet SDP avec l'adresse IP source de ce paquet, garantissant ainsi que l'IP transmise à l'interlocuteur est la bonne. La deuxième fait circuler les flux audio via le commutateur téléphonique plutôt qu'en pair-à-pair, ce qui évite les ratés de l'apprentissage RTP, les bidouilles de l'ASA et la sensibilité de certains softphones.


    Conseils

    Lors d'un diagnostic de VoIP, ne prend pas les problèmes un par un, séparément, sinon tu ne vas pas t'en sortir. Si tu commences à noter que telle version de tel logiciel de téléphonie ne fonctionne pas ou que telle version a un comportement différent sous winwin et GNU/Linux ou que tel logiciel fonctionnait et ne fonctionne plus, tu ne vas pas t'en sortir car il y a trop d'éléments variants. Essaye de penser global, de revenir aux bases de la VoIP.

    Soit vigilant à l'environnement de test : un testeur qui lance deux instances du VPN et, vlam, la """"mauvaise"""" IP se retrouve dans le paquet SDP ; un testeur qui ré-active le pare-feu winwin et, pouf, tes conditions de test changent ; un testeur lance un appel entre deux Jitsi sur deux ordinateurs situés dans le même LAN et constate que ça fonctionne très bien… car le flux ne passe pas par le VPN, mais par le LAN, etc.



    Merci aux gens qui fréquentent FRnOG, une liste de discussion entre opérateurs de réseaux / téléphonie, pour leurs coups de main. :)

    April 17, 2020 at 6:46:44 PM UTC - permalink - http://shaarli.guiguishow.info/?7zueag
Links per page: 20 50 100
 
Mentions légales identiques à celles de mon blog | CC BY-SA 3.0

Shaarli - The personal, minimalist, super fast, database-free, bookmarking service by the Shaarli community