Introduction

  • J'ai de plus en plus d'appels de type “Spam”
  • Je suis en France donc j'ai deja de la chance que le CallerId fonctionne, mais faudrait pas qu'on m'envoie le callerName.
    • Pour cela j'ai les carnets d'adresse de mon GSM et de celui de ma femme stockes sur mon Owncloud
    • Pour cela j'ai trouvé un site www fort sympatique http://french-phone.com/ qui fait un annuaire inverse

Plan d'action

  1. Je ne veux pas dependre d'Internet ie si les sites ne repondent plus ⇒ l'appel doit pouvoir etre traité
  2. Je ne desire ne pas solliciter en permance l'Internet ⇒ Generation de caches

Appels masqués

  • Je veux que les appels masqués atterissent sur un repondeur special pour si jamais c'etait un etre humain
  • Si l'appelant appuis sur une touche de son clavier (DTMF) alors, ca passe la barriere

Appels Spam / blacklist

  • Je veux que les appels commerciaux atterissent sur un repondeur special, pour si jamais il y a une erreure ds les blacklistes

Carnets d'addresse

  • Je considere nos carnets d'addresses comme des white listes

Pendant un appel accepté

  • Je desire que pendant l'appel (non reconnu comme un spammeur) on puisse qualifier l'appel:
    • appuyer sur le 0, et ca deroule toute la procedure d'inscription a la blackliste, envoyer sur un repondeur…
    • appuyer sur le 1, que ca ne fasse qu'envoyer la vcard par mail de l'appelant (pour proposer l'enregistrement dans l'annuaire)

Repondeurs

  • Peut importe l'appelant, le repondeur doit envoyer les messages ainsi
    1. Le sujet du mail doit contenir la cause du rejet d'appel (SPAM/BlackList/Anonyme/Absence)
    2. Si le numero n'est pas dans les annuaiers interne cela doit renvoyer une VCard dans le mail pour stocker ce numero (Attention cela le blanchit…)
    3. Si le numero n'est pas trouvé sur l'Internet, cela renvoie vers un formulaire web pour generer la vcard
    4. Le mail doit contenir un liens vers une procedure de blacklistage Interne et Internet
    5. Le sujet du mail doit contenir le nom de l'appelant, si connu
  • Le repondeur lorsqu'il s'enclanche, en fonction des tranches horaires doit se mettre a parler, comme les vieux repondeurs
    1. Mettre les telephones listes pour cela en mode intercom
    2. Pendant que le message d'accueil est lue cote appelant, cote intercom, si le nom est dans l'annuaire, tentative de lecture de celui ci
    3. L'appelant est ensuite mis sur l'intercom, mais ne peut entendre ce qui est dit
    4. Si quelqu'un appuis sur des touches il y a les reaction qui suit :
      1. 1 Decrochage et mise en relation directe
      2. 3 Mise en silence
      3. 0 Mise en silence et envoyé sur le repondeur SPAM
      4. Rien pendant 5 secondes passage en siliencieux
    5. Peut importe le moment si l'on fait un *8 ou autre… on doit pouvoir recuperer l'appel en cours d'enregistrement sur le repondeur
    6. En cas de prise d'appel est envoyé un message avec la partie d'enregistrement faire et la cause de l'enregistrement : prise d'appel en cours

Techniquement...

FIXME Absolument rien de la partie Repondeur n'est traité

FIXME Lorsqu'un numero est dans l'annuaire interne, on lance quand meme les procedure AntiSpam, et c'est mal (mais bien pour mes tests)

FIXME Actuellement rien n'est fait sur la partie reverse annuaire sur l'internet

FIXME Actuellement rien n'est fait sur la qualification de l'appel en cours

Dialplan

appel entrant

exten => _X.,1,NoOp(Entrant ${EXTEN} CallerId ${CALLERID(all)})
exten => _X.,n,AGI(jabber_notif,"Debut ${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}" "${EXTEN}" "${CALLERID(all)}")
exten => _X.,n,macro(loadvcard,${CALLERID(num)})
exten => _X.,n,macro(spamcheck, ${CALLERID(num)}, 1)
...Traitement de l'appel Normalement (repondeur, ou pas...)
FIXME documenter l'AGI jabber_notif, et meme la faire evoluer pour son parametrage

Macro: loadvcard

Il y-aura ici autant d'appel a des chargement d'annuaire que necessaire, c'est pourquoi il n'y a qu'une ligne, aujourd'hui

[macro-loadvcard]
exten => s,1,Noop(Debut de la macro-loadvcard, tel a identifier ${ARG1})
exten => s,n,AGI(VCardReader4Asterisk,"CALLERID(name)",${ARG1},"VCRRET","/usr/local/etc/VCardReader4Asterisk.conf")

exten =>s,n,MacroExit

Macro: spamcheck

[macro-spamcheck]
exten => s,1,Noop(Determinig to be a spam or not)
exten => s,n,GotoIf($["${CALLERID(num)}" = ""]?NOCID,1:)
exten => s,n,AGI(localbwlist,${CALLERID(num)},"LOCALWHITELISTRC","/usr/local/etc/asterisk_whitelist.txt")
exten => s,n,GotoIf($["${LOCALWHITELISTRC}" = "0"]?NOSPAM,1:)
exten => s,n,AGI(localbwlist,${CALLERID(num)},"LOCALBLACKLISTRC","/usr/local/etc/asterisk_blacklist.txt","LOCALBLACKLISTEX")
exten => s,n,Set(SPAMDISCOVER="localblacklist")
exten => s,n,Set(SPAMSCODE=${LOCALBLACKLISTEX})
exten => s,n,GotoIf($["${LOCALBLACKLISTRC}" = "0"]?SPAM,1:)
exten => s,n,AGI(phonespamfilter.php)
exten => s,n,Set(SPAMDISCOVER="phonespamfilter.php")
exten => s,n,Set(SPAMSCODE=${PHONESPAMFILTER})
exten => s,n,GotoIf($["${PHONESPAMFILTER}" = "2"]?SPAM,1:)
exten => s,n,AGI(fr.spampages.info,${CALLERID(num)},"SPAMPAGEINFORC","SPALPAGEINFOEX")
exten => s,n,Set(SPAMDISCOVER="fr.spampages.info")
exten => s,n,Set(SPAMSCODE=${SPAMPAGEINFORC})
exten => s,n,GotoIf($["${SPAMPAGEINFORC}" = "0"]?SPAM,1:)
exten => s,n,MacroExit
exten => NOSPAM,1,MacroExit

; For SPAM calls
exten => SPAM,1,Noop(You are a spammer)
exten => SPAM,n,AGI(add2localbwlist,${CALLERID(num)},${SPAMDISCOVER},${SPAMSCODE},"localblacklist","/usr/local/etc/asterisk_blacklist.txt")
exten => SPAM,n,AGI(jabber_notif,"${CALLERID(num)} is a spammer because : ${SPAMDISCOVER} (${SPAMSCODE})")                                                              exten => SPAM,n,Answer()
exten => SPAM,n,Wait(1)
exten => SPAM,n,Hangup()
exten => SPAM,n,MacroExit

; For NOCID calls
exten => NOCID,1,Noop(No callerid)
exten => NOCID,n,Answer(1)
exten => NOCID,n,Wait(1)
exten => NOCID,n,Hangup()
exten => NOCID,n,MacroExit

AGI

VCardReader4Asterisk

exten => s,n,AGI(VCardReader4Asterisk,"CALLERID(name)",${ARG1},"VCRRET","/usr/local/etc/VCardReader4Asterisk.conf")

Information complementaire:

  • Ce script execute un programme mis dans le fichier de configuration qui doit lui renvoyer un fichier vcard
  • Dans l'exemple ci-dessous, il genere un export d'un Owncloud, mais cela reste un exemple !

Parametres:

  1. Variable ou sera stoke le nom s'il est trouve
    • Defaut : CALLERID(name)
  2. Le numero de l'appelant
  3. Variable ou est stocke le code retour pour post traitement
    • Depend du fichier de configuration
  4. Fichier de configuration
    • Defaut : /usr/local/etc/VCardReader4Asterisk.conf

Fichier de configuration:

[returns]
code_anonymous=0
code_unknown=1
code_wellknown=2
str_anonymous="Appel Masque"
#str_unknown="Inconnu"
#str_wellknown="Connu"

[vcardaccess]
cachettl=0.5
#0.028 == 10min
cachefile=/var/lib/asterisk/VCardReader4Asterisk.cache
vcardreq="/usr/bin/wget --quiet --timeout=2 --auth-no-challenge --no-clobber --http-user=LOGIN --http-password=PASSWORD --no-check-certificate -O - https://example.lan/owncloud/index.php/apps/contacts/addressbook/local/4/export"

#!/usr/bin/perl
# License
#   GPLv2 (http://www.gnu.org/licenses/gpl-2.0.txt)
# Authors
#   DELAPORTE Antoine
 
use strict;
use warnings;
use Asterisk::AGI;
use Text::vCard::Addressbook;
use Text::vCard::Node;
use Text::vCard;
use Storable;
use Data::Dumper;
use Config::Simple;
 
my $AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
 
my $wh2answh=$ARGV[0] || "CALLERID(name)";
my $callerid=$ARGV[1] || "";
my $returnco=$ARGV[2];
my $conffile=$ARGV[3] || "/usr/local/etc/VCardReader4Asterisk.conf";
my %cfg;
 
my $config = new Config::Simple();
if(-s $conffile) {
    $config->read($conffile);
    %cfg = $config->vars();
    }
 
my $callername;
my $returncode;
 
if(defined($cfg{'vcardaccess.vcardreq'}) or defined($cfg{'vcardaccess.cachefile'})) {
    #Ya un peu de conf, on accepte d'aller plus loin :)
    if(!defined($cfg{'vcardaccess.cachettl'}))      { $cfg{'vcardaccess.cachettl'}=0.028; }
 
    if(!defined($cfg{'returns.code_anonymous'}))    { $cfg{'returns.code_anonymous'}=10; }
    if(!defined($cfg{'returns.code_unknown'}))      { $cfg{'returns.code_unknown'}=20; }
    if(!defined($cfg{'returns.code_wellknown'}))    { $cfg{'returns.code_wellknown'}=30; }
    if(!defined($cfg{'returns.str_anonymous'}))     { $cfg{'returns.str_anonymous'}="Anonymous"; }
 
    if   ($callerid eq "")      {
        $callername=$cfg{'returns.str_anonymous'};
        $returncode=$cfg{'returns.code_anonymous'};
        }
    elsif(!defined($callername=FromVcard($callerid))) {
        if(defined($cfg{'returns.str_unknown'})) { $callername=$cfg{'returns.str_unknown'}; }
        $returncode=$cfg{'returns.code_unknown'};
        }
    else {
        $returncode=$cfg{'returns.code_wellknown'};
        }
    }
else { $returncode=10; }
 
$AGI->set_variable("$wh2answh", "$callername");
if(defined($returnco)) { $AGI->set_variable("$returnco", $returncode); }
 
exit($returncode);
 
sub FromVcard {
    my ($callerid)=@_;
 
    if(CacheIsOld($cfg{'vcardaccess.cachefile'},$cfg{'vcardaccess.cachettl'}))  {
        LoadNewCache($cfg{'vcardaccess.cachefile'},$cfg{'vcardaccess.vcardreq'})
        }
 
    $callername=FindNumInCache($cfg{'vcardaccess.cachefile'},$callerid);
 
    return($callername);
    }
 
sub FindNumInCache {
    my ($CacheFile,$callerid)=@_;
 
    my %CacheData = %{retrieve($cfg{'vcardaccess.cachefile'})};
 
    return($CacheData{$callerid});
    }
 
sub CacheIsOld {
    my ($CacheFile,$CacheTTL)=@_;
    my $ret=0;
    if((! -s $CacheFile) or (-M $CacheFile > $CacheTTL )) {
        $ret=1;
        }
    return($ret);
    }
 
sub LoadNewCache {
    my ($CacheFile,$VCardReq)=@_;
 
    my $card_text="";
    my %CacheData;
 
    open(WWW,"$VCardReq |");
    while(<WWW>) { $card_text.=$_; }
    close(WWW);
 
    # Create Addressbook
    my $address_book = Text::vCard::Addressbook->new({ 'source_text' => $card_text, });
    my $count=0;
 
    #Loop through Addressbook
    foreach my $vcard ($address_book->vcards()) {
        my $tels = $vcard->get({ 'node_type' => 'tel' });
        if(defined($tels)) {
            my %tabgr;
            my $xabs = $vcard->get({ 'node_type' => 'X-ABLABEL' });
            if(defined($xabs)) { # Load all the X-ABLABEL in a table to get them faster
                my $xab;
                foreach $xab (@{$xabs}) { $tabgr{$xab->group}=$xab->value; }
                }
 
            my $tel;
            foreach $tel (@{$tels}) { # Boucle sur chaques numeros
                my $com;
                my $name;
                my @nm=$tel->types;
                if    (defined($nm[0]))         { $com=$nm[0]; }
                elsif (defined($tel->group))    { $com=$tabgr{$tel->group}; }
                else                            { $com="Other"; }
                my $telnumber=$tel->value();
                $telnumber=~s/\+33/0/g;
                $telnumber=~s/#31#//g;
                $telnumber=~s/[^0-9\+]//g;
                if(!defined($vcard->fullname()))    { $name="<$telnumber>"; }
                else                                { $name=$vcard->fullname();}
                $CacheData{$telnumber}= $name."($com)";
                $count++;
                }
            }
        }
    if($count) { store(\%CacheData,$CacheFile); } #On ne stocj pas si on a rien lu
    }

localbwlist

exten => s,n,AGI(localbwlist,${CALLERID(num)},"LOCALBLACKLISTRC","/usr/local/etc/asterisk_blacklist.txt","LOCALBLACKLISTEX")
#!/usr/bin/perl
 
# License
#   GPLv2 (http://www.gnu.org/licenses/gpl-2.0.txt)
# Authors
#   DELAPORTE Antoine
 
use Asterisk::AGI;
use strict;
use warnings;
 
my $AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
 
my $returncode=10;
my $returnstr;
 
if(!defined($ARGV[0]))                      { $returncode=2; $returnstr="No number given"; }
elsif(!defined($ARGV[1]))                   { $returncode=3; $returnstr="No comment"; }
elsif(!defined($ARGV[2]) or (!-e $ARGV[2])) { $returncode=4; $returnstr="No X-list File"; }
 
if($returncode == 10) {
    open(BWLF,"< $ARGV[2]")  or  $returncode=5;
    if($returncode != 5) {
        $returnstr="Not in the file";
        $returncode=6;
        while(<BWLF>) {
            if(/^$ARGV[0];/ or /^$ARGV[0]$/) {
                chomp();
                $returncode=0;
                $returnstr=$_;
                ### Ici il faudrait trouver l'instruction pour sortir de la boucle en express
                }
            }
        close(BWLF);
        }
    else { $returnstr="Pb access X-list File"; }
    }
 
if(defined($ARGV[1])) { $AGI->set_variable("$ARGV[1]", $returncode); }
if(defined($ARGV[3])) { $AGI->set_variable("$ARGV[3]", $returnstr); }
 
exit($returncode);

add2localbwlist

exten => SPAM,n,AGI(add2localbwlist,${CALLERID(num)},${SPAMDISCOVER},${SPAMSCODE},"localblacklist","/usr/local/etc/asterisk_blacklist.txt")
#!/usr/bin/perl
 
# License
#   GPLv2 (http://www.gnu.org/licenses/gpl-2.0.txt)
# Authors
#   DELAPORTE Antoine
 
use Asterisk::AGI;
use POSIX;
use strict;
use warnings;
 
my $AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
 
# 0 Call number
# 1 Who want to add
# 2 With spam score
# 3 in which list (to avoid doublon...) but a fake...
# 4 in which file
 
 
if(defined($ARGV[1]) and defined($ARGV[2])) {
    if($ARGV[1] ne $ARGV[3]) {
        if(defined($ARGV[0]) and defined($ARGV[3]) and defined($ARGV[4])) {
            open(BWF,">>$ARGV[4]") or die;
            my $nwl=$ARGV[0].";".$ARGV[1]."(".$ARGV[2].");".strftime("%F %T", localtime $^T);
            print BWF $nwl."\n";
            close(BWF);
            }
        }
    }

phonespamfilter.php

Je vous invite aller voire l'AGI proposé sur le site : FIXME

Je la reecrirais un jour, de tel facon a ce qu'elle accpete plus de parametre, dont le callerid

fr.spampages.info

Je trouve ma facon de travailler pas tres correcte, desole pour eux… :/

Il faudra tout de meme qu'un jour je prenne la peine de les contacter…

exten => s,n,AGI(fr.spampages.info,${CALLERID(num)},"SPAMPAGEINFORC","SPALPAGEINFOEX")
#!/usr/bin/perl
 
# License
#   GPLv2 (http://www.gnu.org/licenses/gpl-2.0.txt)
# Authors
#   DELAPORTE Antoine
 
use Asterisk::AGI;
use strict;
use warnings;
use LWP;
 
my $AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
my $browser = LWP::UserAgent->new;
$browser->timeout(2);
 
 
my $response = $browser->get("http://fr.spampages.info/".$ARGV[0]);
my $returncode;
my $retstr;
 
 
$_=$response->status_line;
if((!defined($ARGV[0])) or ($ARGV[0] eq "")) {
    $returncode=4; $retstr="Bad argument";
    }
elsif(/^500 /)    { $returncode=2; $retstr="Service Unavailable"; }
elsif(/^200 /)    { $returncode=0; $retstr="Number declared"; }
elsif(/^404 /)    { $returncode=1; $retstr="Number not declared"; }
else              { $returncode=3; $retstr="Script Lost"; }
 
if(defined($ARGV[1])) { $AGI->set_variable("$ARGV[1]", $returncode); }
if(defined($ARGV[2])) { $AGI->set_variable("$ARGV[2]", $retstr); }
 
 
exit($returncode);

Remerciments

  • Daniel de chez Tootai.net
  • fr.spampages.info.pl chez qui je vais lachement recuperer des infos
  • Stebalien qui m'a appris a jouer avec les vcard
  • Tanghus qui m'a montre comment backup les vcard d'un Owncloud :)
docs/linuxeries/asterisk/antispam.txt · Dernière modification: 2014/03/15 17:36 (édition externe)
Recent changes RSS feed Debian Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki