Asterisk et la Livebox bavarde

La Livebox d'Orange comporte, outre les connexions réseau et Wi-Fi habituelles, une prise FXS à l'arrière conçue pour y brancher un téléphone analogique. Comme je le disais auparavant, il s'agit là d'une des manières les plus simples d'exploiter la ligne fixe fournie avec toute connexion Internet Orange.

Sur la prise FXS et lorsque la Livebox détecte un problème sur la ligne téléphonique, elle substitue à la tonalité un message en boucle comme : « Un problème a été détecté sur votre ligne téléphonique. Veuillez redémarrer la Livebox. Si le problème persiste, veuillez contacter le service client Orange ». Puis la tonalité classique revient lorsque la ligne est à nouveau opérationnelle.

Seulement, dans certaines circonstances, cela allait de pair avec des sonneries intem­pestives  : la première lorsque la ligne était en dérangement et la seconde lorsque le pro­blème disparaissait. De plus, il s’agissait souvent de problèmes transitoires pendant que la Livebox se resynchronisait en PPPoE. Par conséquent, j’ai régulièrement été réveillé à 3 h du matin par cette box.

Étant donné, de plus, que j'avais déjà mis en œuvre Asterisk chez moi et que je supervisais déjà moi-même l'état des services Orange avec Icinga, je considérais donc que je disposais des outils pour filtrer ces sonneries intempestives. Ce billet propose donc de vous montrer comment j'ai fait.

L’idée

Ces sonneries intempestives prennent la forme d’appels anonymes et surviennent seulement lorsque la box considère que la ligne téléphonique est en dérangement. L’idée est donc de programmer Asterisk pour reconnaître ces deux caractéristiques.

Reconnaître un appel masqué dans Asterisk est facile. Déterminer la disponibilité du téléphone du point de vue de la Livebox est en revanche une autre histoire. Heureusement, mes scripts Nagios pour la Livebox remplissent exactement cette fonction ; il est donc possible de l’utiliser dans mon test. Nous allons également nous aider de l’interface AGI pour réaliser ce test.

Le script AGI

AGI, ou Asterisk Gateway Interface, est en effet une interface pour faire exécuter des scripts par Asterisk. Ces scripts accomplissent des tâches impossibles ou trop fastidieuses à mettre en œuvre via extensions.conf ou extensions.ael. Le principe est le même que celui de l’interface CGI dans le monde du Web : on peut utiliser n’importe quel langage de program­mation (C, Perl, Python…) du moment qu’on puisse écrire sur stdout, lire sur stdin, accepter des arguments de ligne de commande et que le fichier soit exécutable.

Les scripts AGI doivent être placés dans un répertoire spécifique qui dépend de votre installation Asterisk. Sous FreeBSD, il faut les placer dans /usr/local/share/asterisk/agi-bin et les rendre exécutables avec la commande chmod +x. J’ai appelé ce script stfu-livebox.agi. Voici son code source :

#!/usr/bin/env perl

use strict;
use warnings;

$| = 1;

use Asterisk::AGI;
use LWP::UserAgent;

my $AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();

my $replacement_name = $ARGV[0];
my $replacement_number = $ARGV[1];

$replacement_name ||= 'Livebox';
$replacement_number ||= 'Livebox';

$AGI->verbose("Run stfu-livebox.agi", 1);

sub is_trunk_alive {
    my $ret = system('/usr/local/libexec/nagios/check_livebox_phone', '-H', '192.168.1.1');
    $ret >>= 8;

    return ($ret == 0);
}

sub is_anon {
    return ($input{'callerid'} eq 'unknown');
}

sub main {
    if (is_anon() && !is_trunk_alive()) {
        $AGI->set_variable('CALLERID(name)', $replacement_name);
        $AGI->set_variable('CALLERID(name-pres)', 'allowed_not_screened');
        $AGI->set_variable('CALLERID(number)', $replacement_number);
        $AGI->set_variable('CALLERID(num-pres)', 'allowed_not_screened');
    }
}


main();

Le principe du script est le suivant : à chaque appel anonyme, il exécute le plugin Nagios check_livebox_phone, qui détermine l’état de la ligne téléphonique vue par la Livebox. Si la ligne est hors service, il positionne un numéro et un nom spécifiques.

Le nom et le numéro présentés sont « Livebox » par défaut, mais il est possible d’utiliser autre chose. Par exemple, sur mon installation, je lui fais présenter un numéro qui a peu de chances de m’appeler depuis l’extérieur : mon propre numéro.

Intégration dans le dialplan d’Asterisk

Maintenant que nous avons le script AGI, il ne reste plus qu’à l’appeler depuis le dialplan d’Asterisk au moyen de l’application AGI :

AGI(stfu-livebox.agi,Livebox,0199998765);

Il suffit ensuite de préparer le reste du dialplan, et notamment les instructions qui bloquent ces sonneries la nuit. Dans mon installation, j’en ai profité pour renvoyer les appels masqués immédiatement vers la messagerie vocale entre 23 h et 6 h et de complètement bloquer ces sonneries si elles proviennent de la Livebox durant cette même plage horaire. En AEL, cela donne :

Set(ALLOW_RINGING=1);
Set(ALLOW_VOICEMAIL=1);

// Traitement spécifique pour les appels anonymes
if ("${LEN(${CALLERID(number)})}" = "0") {
        Set(CALLERID(name-pres)=unavailable);
        Set(CALLERID(num-pres)=unavailable);

        AGI(stfu-livebox.agi,Livebox,0199998765);

        // Autoriser les appels anonymes de 6 h à 23 h seulement
        ifTime(06:00-22:59|*|*|*) {
                Verbose(1,Appel masqué autorisé le jour);
        } else {
                Set(ALLOW_RINGING=0);
                if ("${CALLERID(name)}" = "Livebox") {
                        Verbose(1,Sonnerie de la Livebox refusée la nuit);
                        Set(ALLOW_VOICEMAIL=0);
                } else {
                        Verbose(1,Appel masqué la nuit, renvoi vers répondeur);
                }
        }

} else {
        // Continuer normalement
}

// Faire sonner tous les téléphones
if ("${ALLOW_RINGING}" = "1") {
        Dial(${ALL_PHONES},25,xt);
}

// Si non-réponse ou rejeté, rediriger vers le répondeur
if ("${ALLOW_VOICEMAIL}" = "1") {
        Answer();
        VoiceMail(BoiteCommune);
} else {
        Hangup(21);
}

Hangup();

Vous remarquerez que j’utilise deux variables, ALLOW_RINGING pour déterminer si l’appel entrant peut accéder aux téléphones chez moi (c’est-à-dire les faire sonner) et ALLOW_VOICEMAIL pour déterminer si l’appelant peut enregistrer un message vocal. Ceci permet de gérer facilement les trois cas qui se présentent à nous dans ce dialplan.

Conclusion

Ces modifications à Asterisk font exactement ce que je voulais, c’est-à-dire ne plus être réveillé la nuit lorsque la Livebox se resynchronise. En pratique, seule la première des deux sonneries intempestives est effectivement filtrée : au moment où survient la seconde sonnerie, le script check_livebox_phone indique que la ligne téléphonique est à nouveau opérationnelle.

J’aurais pu résoudre ce problème en apportant une petite modification : lorsqu’Asterisk bloque la première de ces deux sonneries, qui est facile à reconnaître, on pourrait positionner une valeur dans la base de données AstDB pour bloquer l’appel anonyme qui suit immédiatement cette première sonnerie.

Mais en pratique, depuis qu’Orange a cessé d’utiliser PPPoE, ces resynchronisations hebdomadaires n’arrivent quasiment plus jamais, donc c’est plus difficile à tester.

Enfin, en cherchant un peu, ma solution était peut-être complètement excessive : d’après une poignée de forums, ces sonneries intempestives seraient dues à la notification visuelle de messages ; une fonction qui est seulement prise en charge par certains téléphones (mais pas Asterisk) et que je suis sûr de ne pas utiliser, parce que mon répondeur est déjà géré par Asterisk. Cela reste néanmoins un bon exercice de programmation AGI que je souhaitais partager.

Posté par x0r à 2 commentaires • Tags : orange livebox voip asterisk

Commentaires

Poster un commentaire

#1 — question

je connais un serveur qui détermine si le numéro d'appelant est du spam ou non. C'est possible de faire le même script agi qui interroge ce serveur? http://api.katia.ch/v1/open/check/00325235554545

#2 — x0r

Intéressant, je ne connaissais pas cette solution d’« antispam ».

Sur leur page d’accueil ils proposent justement une intégration de leur solution d’« antispam » téléphonique sous Asterisk, mais impossible d’avoir plus d’informations sans les contacter par e-mail. Dans tous les cas, un script AGI qui interrogerait l’API dont vous parlez serait alors relativement facile dans un langage comme Perl.

Poster un commentaire