J'ai égratigné un peu le sujet de la VOIP à la fac. Si vous voulez vous y mettre, je vous conseille le cours suivant :
https://jitsi.org/Education/RTCSof . Depuis longtemps, j'avais envie d'aller plus loin, de monter un serveur SIP capable de communiquer avec des téléphones fixes et mobiles.
Ça tombe bien : chez ARN, FAI associatif en Alsace, on a des ressources Internet uniques (un bloc d'adresses IPv4, un d'IPv6 et un numéro d'AS). Toutes les informations technico-administratives concernant ces ressources sont consignées dans des bases de données publiques, dans notre cas, celle du RIPE (qui gère la région Europe (au sens trèèèès large) + Moyen-Orient). Pour plus d'infos, voir
http://www.guiguishow.info/2014/04/18/decouvrons-la-ripe-database/ . Cela inclu les emails et les numéros de téléphone de personnes responsables (mais pas forcément techniciennes) de ces ressources. Pour le mail, pas de problème : il s'agit d'alias et d'adresses avec un délimiteur donc en cas de spam, on change les adresses et basta, même pas besoin d'installer un antispam complexe. Pour les numéros de téléphone, c'est nos 06 persos et c'est bien là le blem. Bon, il faut être honnête : les spammeurs n'utilisent pas ces données : depuis l'allocation de nos ressources (en février 2013), soit bientôt 3 ans, nous avons reçu un seul appel commercial pour du transit IP (donc c'était du démarchage ciblé). Néanmoins, ça va servir de point de départ, de motivation, pour monter un serveur SIP dans l'asso.
On veut donc un serveur SIP qui permet de recevoir et d'émettre des appels depuis/vers les fixes et les mobiles + émettre et recevoir des appels entre nous, les admins (comme Mumble mais en plus "j'me la pète corporate" voyez). Quand on reçoit un appel depuis un fixe ou un mobile, on transfert ça sur les 06 persos. Le premier admin ARN qui décroche gagne le droit de causer à l'interlocuteur.
Pour faire le lien avec l'extérieur, on prend une ligne SIP chez OVH à 1,20€/mois. Attention quand même : elle permet un unique appel en simultanée donc quand nous recevrons un appel de l'extérieur, nous ne pourrons pas réémettre vers nos 06 persos (la seule ligne disponible sera occupée). Il faut donc que chaque admin installe un logiciel de VOIP sur son ordiphone. Pour les admins qui n'ont pas d'ordiphone baaaaaaah c'est perdu ou il faut prendre une ligne SIP à 6€/mois ce qu'on n'a pas voulu faire compte tenu de l'utilité de la chose. On notera donc que chaque appel émis coûte aussi à l'admin ARN s'il décroche alors qu'il est connecté en 3G/4G.
Alors oui, on n'est pas obligé de brancher un serveur SIP derrière OVH, c'est totalement overkill puisqu'on pourrait très bien faire du renvoi d'appel depuis le manager mais je rappelle que le but initial c'est de découvrir plus en détail la VOIP, pas d'avoir un truc tout fait. :)
Pour le choix du serveur SIP, j'en connais deux en logiciel libre : Asterisk et FreeSWITCH. Selon moi, ce qui les sépare c'est la même chose que ce qui différencie apache httpd de nginx : Asterisk est le standard, le plus complet et le plus documenté. FreeSWITCH est plus léger et modulaire. Niveau config, c'est texte pour Asterisk, XML pour FreeSWITCH, si ça peut vous aider. ;) Afin de comprendre pourquoi le standard du marché n'est pas adapté à notre cas d'usage, il faut l'expérimenter. Donc allons-y pour Asterisk.
Pour configurer notre Asterisk, je me suis beaucoup servi de l'article publié dans GNU/Linux Pratique Essentiel numéro 90 de juillet-août 2015.
On installe Asterisk (sans les voix, sans les sonneries, sans rien car nous n'en avons pas besoin) : apt-get install asterisk
La config' par défaut est extrêmement complète, bien annotée avec beaucoup d'exemples. Il faut donc la conserver intacte : cd /etc/asterisk ; mv sip.conf sip.conf.origin ; mv extensions.conf extensions.conf.origin ; mv extensions.lua extensions.lua.origin . Attention à bien virer extensions.lua sinon vous aurez des comportements inattendus (Asterisk qui répond sur des numéros pour lesquels on n'aura pourtant rien configuré dans extensions.conf).
À partir de là, nous allons travailler sur deux fichiers de conf' (vides puisqu'on vient de les déplacer ;) ) :
* sip.conf qui sert à configurer les paramètres généraux du serveur (écoute sur tels protocoles, tels ports,...) + la liste des utilisateurs autorisés, leur mdp et leurs options spécifiques.
* extensions.conf qui contient le dialplan, c'est-à-dire les associations entre un numéro de téléphone et les actions ordonnées à faire (1) décrocher, 2) lancer un message vocal, 3) faire suivre l'appel au bon interlocuteur selon le choix effectué par l'appelant, 4) prendre un message si l'interlocuteur ne décroche pas,...). C'est donc ici qu'on dit que, quand on est connecté au serveur en tant qu'abonné, le numéro de téléphone « 2 » permet de téléphoner à GuiGui et « 3 » à tonton. Notons que mon morceau de phrase « en tant qu'abonné », ça se nomme un contexte et ça ressemble à un VirtualHost : un numéro n'a pas le même sens (il ne permet pas de téléphoner à la même personne) dans deux contextes différents. Le contexte peut être vu comme une autorisation : je t'ai reconnu, tu es GuiGui, on t'a assigné le contexte « abonnés », donc tu peux téléphoner à tonton avec le numéro « 3 » et émettre des appels externes via la ligne SIP OVH. En revanche, quand tu te présentes avec l'identité GuiGui-tel, tu peux simplement recevoir des appels, pas émettre). Ce ne sont que des exemples, tout est possible avec Asterisk. :)
Voici notre sip.conf :
[general]
; On écoute sur UDP, en IPv4 et IPv6 (dépend de la valeur de bindv6only côté noyau), sur le port par défaut (5060)
transport=udp
udpbindaddr=::
; bindport=5061
; On écoute sur TCP, en IPv4 et IPv6 (même remarque), sur le port par défaut (5060)
tcpenable=yes
tcpbindaddr=::
; tcpbindport=5061
; Pour les appels inter-domaines, on peut utiliser les enregistrements DNS. Ça sort de notre cahier des charges donc non.
srvlookup=no
; Un client s'enregistre pour 30 minutes. Une valeur plus petite augmente le trafic réseau inutile, une valeur plus grande détectera plus tard un changement d'IP du client, par exemple.
defaultexpiry=1800
; On n'attend pas plus longtemps entre l'appui sur deux touches durant la composition d'un numéro.
allowoverlap=no
; Les utilisateurs qui ne se sont pas authentifiés sur le serveur ne peuvent pas émettre des appels !
allowguest=no
; Ne jamais dire si un login seul est valide mais toujours valider le couple login+mdp en entier.
; Un attaquant ne sait ainsi pas quels logins sont valides et donc sur quels logins il doit se concentrer pour trouver les mdps
alwaysauthreject=yes
; Si on ne spécifie pas un contexte pour un utilisateur, il tombe dans le contexte nommé « ext »
context=ext
; Asterisk doit s'enregistrer auprès de notre fournisseur SIP, à savoir OVH
; Le login est le numéro de téléphone attribué à la ligne au format international mais le « + » est remplacé par deux zéros. Exemple : 01 23 45 67 89 => 0033123456789
register => <login>:<mdp>@sip3.ovh.fr
; Lors de la mise en relation entre deux utilisateurs de notre serveur, Asterisk envoie cette liste de codecs (les clients des deux interlocuteurs renégocieront après cette liste).
; Il est parfois utile d'avoir une petite liste de codec, par exemple pour éviter de crasher un SIP ALG. Voir
http://shaarli.guiguishow.info/?h4fUtQ
; On peut aussi préciser les codecs utilisateur par utilisateur.
; disallow=all
; allow=speex32
; allow=speex16
; allow=alaw
; allow=ulaw
allow=all
; Normalement, les flux audio/vidéo ne transitent pas par le serveur SIP, seulement la signalisation (à qui je veux téléphoner, ça sonne, fin d'appel,...) passe par le serveur SIP.
; Néanmoins, pour aider la traversée des NA(P)T, on peut demander à Asterisk de faire transiter les flux médias par lui-même.
directmedia=no
; On définit tous les utilisateurs, y compris le fournisseur qu'est OVH.
[guigui]
type=friend ; Défini le type d'appels : peer = appels sortants / user = appels entrants / friend = les deux.
host=dynamic ; L'utilisateur peur se connecter depuis n'importe où (on peut filtrer par adresse IP si elle est fixe ;) )
secret=monMdP ; Le mot de passe de cet utilisateur. Mettez un mdp résistant car il ne faudra que quelques minutes d'existence à votre serveur pour se faire bruteforcer.
context=abonne ; Dans quel contexte tombe cet utilisateur ?
; nat=yes ; Cet utilisateur est derrière un NAT, il faut donc être plus coulant (même si ça ne change pas grand'chose)
[ovh]
type=peer
host=sip3.ovh.fr
defaultuser=<login> ; voir « register ci-dessus »
secret=monMDP
insecure=invite ; pas besoin d'être authentifié pour téléphoner depuis ici
dtmfmode=rfc2833 ; norme d'encodage des appuis sur les touches du téléphone (pour composer un numéro ou "communiquer" avec un serveur vocal interactif ("appuyez sur 1 pour joindre le service"...)
; Comme on n'a pas précisé le contexte, ovh tombera dans le contexte par défaut que l'on a défini, aka « ext » ;)
Voici notre dialplan (extensions.conf) :
[general]
; Défini si le dialplan peut être modifié dynamiquement et sauvegardé depuis la console (ici : non).
static=yes
writeprotect=yes
; Lorsqu'une extension arrive en manque de chose à faire, alors Asterisk termine l'appel de la manière qui lui semble appropriée (raccrocher normalement, raccrocher en occupé,...) au lieu d'attendre qu'une nouvelle extension soit utilisée lors d'un nouvel appel.
; C'est pourquoi, ci-dessous, je ne précise pas une étape après Dial() alors qu'on pourrait envisager une étape supplémentaire : Hangup(). ;)
autofallthrough=yes
; Les personnes qui nous téléphonent depuis un fixe ou un portable (et qui passent donc par notre ligne OVH) tombent dans ce contexte...
[ext]
; ... et leur seule action possible et de faire sonner les téléphones de guigui. Ils ne peuvent pas téléphoner à qui que ce soit d'autre ni même téléphoner à des numéros surtaxés.
; Le premier téléphone qui décroche cesse de faire sonner les autres téléphones.
exten => s,1,Dial(SIP/guigui&SIP/guigui-tel) ; notons que cet exemple ne fonctionnera pas puisque l'utilisateur « guigui-tel » n'existe pas dans sip.conf.
; Nos utilisateurs enregistrés
[abonne]
; Syntaxe : exten => X,Y,<Action>. X, c'est le numéro qu'il faudra composer. Y c'est l'ordre puisqu'on peut enchaîner plusieurs actions (1) décrocher, 2) lancer un message vocal, 3) faire suivre l'appel au bon interlocuteur selon le choix effectué par l'appelant, 4) prendre un message si l'interlocuteur ne décroche pas,...). Action est une action comme faire suivre l'appel (Dial), raccrocher (Hangout). Chaque action à des paramètres (Dial peut tenter de faire sonner l'interlocuteur Z secondes, par exemple).
; Ici, taper le numéro de téléphone « 1 » ou la chaîne de caractères « guigui » permet de téléphoner à l'utilisateur « guigui » défini dans sip.conf ;)
exten => 1,1,Dial(SIP/guigui)
exten => guigui,1,Dial(SIP/guigui)
; Ici, taper « 2 » téléphone à guigui mais sur un autre compte. Cet exemple ne fonctionnera pas puisque l'utilisateur « guigui-tel » n'est pas défini dans sip.conf ;)
; exten => 2,1,Dial(SIP/guigui-tel)
; exten => guigui-tel,1,Dial(SIP/guigui-tel)
; Taper « 22 » et Asterisk décroche et envoie « Je voudrais le 22 à Asnières », utile pour savoir si le serveur fonctionne sans avoir d'amis ;))))
exten => 22,1,answer
exten => 22,n,Morsecode("Je voudrais le 22 à Asnières.")
; Tout autre numéro sera envoyé sur la ligne OVH (Asterisk permet d'utiliser des regex sur les numéros).
exten => _X.,1,Dial(SIP/${EXTEN}@ovh);
; On pourrait être plus rigoureux et filtrer pour n'envoyer que les numéros commençant par 01,02,03,04,05,06,07 et 09, ce qui éviterait les problèmes de facturation (08, tout ça) :
; exten => _0[1-7]XXXXXXXX,1,Dial(SIP/${EXTEN}@ovh)
; exten => _09XXXXXXXX,1,Dial(SIP/${EXTEN}@ovh)
Il faut ensuite relancer le serveur SIP : sudo systemctl restart asterisk.
Pour le debug, Asterisk possède une console accessible via la commande asterisk -r. Commandes utiles :
* sip show registry pour vérifier qu'Asterisk s'enregistre bien chez les fournisseurs (OVH dans notre cas) ;
* sip reload pour recharger la configuration comme le dialplan ;
* sip show peers pour voir tous les utilisateurs, lesquels sont connectés, depuis quelle IP,... ;
* dialplan show permet de voir le dialplan complet (tous fichiers de conf' confondus) ;
* console dial <extension>@<contexte> permet de se faire appeler par Asterisk pour vérifier que ça fonctionne. Exemple : console dial 1@abonne ou console dial guigui@abonne téléphonera à l'utilisateur guigui dans notre cas ;
* sip show channels permet de voir les dialogues en cours (tel utilisateur vient de s'enregistrer, un appel en est dans telle phase,...) ;
* Si vous précisez « -vvv » pour entrer sur la console (« asterisk -r -vvv »), vous aurez le debug : qui appelle, comment Asterisk route l'appel (quelle partie du dialplan il a utilisée), problème de codec,...
Passons maintenant à nos pires cauchemars :
* Le NA(P)T et les pare-feux. En effet, le protocole SIP transmet juste la signalisation de l'appel (à qui je veux téléphoner, le téléphone du correspondant sonne, il décroche, fin de l'appel). Les flux médias sont transmis sur des sessions UDP différentes dont les numéros de ports sont échangés... dans le contenu SIP. Ça ne vous rappelle rien ? Si, les sessions données de FTP ou les transferts de fichiers sur IRC. Autrement dit, ça passe super mal les NAT et les pare-feux. Pour voir l'ampleur du problème et sa complexité, je vous recommande la lecture de
http://www.asteriskguru.com/tutorials/sip_nat_oneway_or_no_audio_asterisk.html . Pour que ça fonctionne quand même, il faudra déployer toute la panoplie côté client : un routeur équipé d'un ALG/NAT helper, un logiciel client qui implémente STUN (afin qu'il obtienne sa véritable IP publique) voir des techniques plus pointues comme ICE... La prise en charge de ces techniques de contournement de NAT varie beaucoup d'un logiciel client à l'autre. IPv6 n'est d'aucun secours ici vu le faible support. Un VPN chez un FAI de la FFDN est, en revanche, une bonne idée puisque pas de NAT par défaut.
* Les attaquants. Ils vont attaquer votre serveur dans l'optique d'obtenir des appels à l'international gratuit pour faire des campagnes de phishing téléphoniques et/ou vous ruiner. Il faut donc veiller à ce qu'un utilisateur pas défini dans sip.conf NE tombe PAS dans le contexte qui permet de sortir avec la ligne SIP OVH sinon la facture va être vraiment salée. Dans la même veine, il faut interdire aux utilisateurs non-identifiés sur votre serveur de passer des appels anonymes. C'est redondant avec la mesure précédente mais il vaut mieux ceinture et bretelles. Dans la continuité, il faut avoir des mots de passe solides pour vos utilisateurs car votre serveur sera bruteforcé en permanence.
Pour utiliser votre serveur SIP, il vous faudra un logiciel de VOIP. J'en ai testé plusieurs, tous ont des lacunes, les résultats sont consignés là :
http://shaarli.guiguishow.info/?EYkbVQ .
Prolongement possible : je pense à ouvrir ce serveur SIP à tous les membres d'ARN. En configurant TLS (afin de ne pas faire fuiter les métadonnées, qui téléphone à qui, quand, selon quelle fréquence,...) et en demandant aux adhérents d'installer un logiciel simple d'utilisation mais supportant ZRTP (chiffrement des flux médias de bout en bout) sur son ordiphone comme CSipSimple, on obtient de la communication vocale sécurisée et conviviale entre adhérents de l'association.
Pas besoin de Signal et autres applis kikoos modernes centralisées (voir ici pour mes critiques de ces applis
http://shaarli.guiguishow.info/?CGDOlw et
http://shaarli.guiguishow.info/?vungLg).
Pourquoi ce n'est pas déjà en place ? Parce que je ne suis pas un VOIP guru et qu'avec le NAT que l'on a de partout de nos jours, il va falloir être prêt à debug comme des porcs (voir
http://shaarli.guiguishow.info/?a5nv4A et
http://shaarli.guiguishow.info/?h4fUtQ pour des exemples de merdes).