Asterisk als SPAM-Voicemail für FritzBox mit tellows-Abfrage

Vor Jahren schon war es mir irgendwann zu blöd, dass ständig irgendwelche Gewinnspielfuzzis & Co. bei mir angerufen haben und an meine Daten wollten.

Also hab ich überlegt und recherchiert, was ich tun kann. Dabei bin ich auf die Tellows-Community gestoßen, die auch eine einfache Web-Abfrage ermöglicht.

Hier ist das Ergebnis...

Voraussetzungen

Irgendein System (z.B. Raspberry mit Raspbian), auf dem Asterisk läuft. Es müsste eigentlich sogar ein Raspberry Pi Zero W reichen...

Asterisk sollte mindestens in Version 1.6 installiert werden. Sollte bei aktuellen Distributionen kein Problem sein.

Das System muss außerdem in der Lage sein, mit dem Befehl "mail" E-Mails zu senden. Ggf. sind hier noch weitere Installations- und Konfigurationsschritte nötig (z.B. Nullmailer oder Postfix), auf die ich hier nicht eingehe. Eine Suche bei den einschlägigen Suchmaschinen sollte hier schnell ein passendes Ergebnis liefern.

FritzBox

In der FritzBox einen neuen Telefonapparat vom Typ „LAN/WLAN“ anlegen, Passwort und interne Nummer (z.B. 621) merken. Alle Rufnummern, für die der SPAM-Schutz gelten soll, bei „Auf diese Rufnummern reagieren“ anhaken, alternativ kann auch „Alle Rufnummern“ ausgewählt bleiben, wenn der Schutz für sämtliche in der FritzBox konfigurierten Rufnummern gelten soll.

Installation

...unter Debian Stretch (auf anderen Systemen mit den entsprechenden Systemwerkzeugen)…

Asterisk installieren sowie den Textbrowser lynx:

root@asterisk:~# apt install asterisk asterisk-prompt-de lynx

White-/Blacklists

Mit der White- und Blacklist werden Nummern später von der tellows-Abfrage ausgeschlossen. Nummern, die in der Datei tellows.agi_whitelist enthalten sind, werden nie geblockt, Nummern in tellows.agi_blacklist immer. Falls eine Nummer in beiden enthalten ist, gewinnt die Blacklist!

White- und Blacklist anlegen mit

touch /etc/asterisk/tellows.agi_whitelist
touch /etc/asterisk/tellows.agi_blacklist

Zur einfacheren Verwaltung zwei Skripte unter /usr/local/sbin/ anlegen.

Whitelist-Script

/usr/local/sbin/whitelist

#!/bin/sh
#
# Script to manage the Asterisk tellows.agi whitelist
 
WHITELIST="/etc/asterisk/tellows.agi_whitelist"
TMPLIST="/tmp/tmplist"
MAN_USAGE="Usage:\n Add entry to the list:\n  whitelist <number> [description]\n   Example: whitelist 0123434344 \"Name or something\"\n Remove entry from the list:\n  whitelist remove <number>\n   Example: whitelist remove 0123434344"
 
#Create temp file
touch $TMPLIST
echo "***Whitelist management for Asterisk tellows.agi***\n"
 
#Check if parameter given
if [ "$1" = " " ] || [ -z "$1" ]; then
  echo "$MAN_USAGE"
else
  P1=`echo $1 | sed -e "s/\ //g"`
  #If Parameter 1 is "remove" start the removal process
  if [ "$P1" = "remove" ]; then
    if [ "$2" = " " ] || [ -z "$2" ]; then
      echo "Missing parameter 2!\n"
      echo "$MAN_USAGE"
    #Remove the given number and check errorlevel
    else
      NUM2REMOVE=`echo $2 | sed -e "s/\ //g"`
      if grep -lq $NUM2REMOVE $WHITELIST; then
        echo "Removing $NUM2REMOVE from list..."
        grep -v $NUM2REMOVE $WHITELIST>$TMPLIST
        if [ "$?" = "0" ]; then
          echo "Done."
          mv $TMPLIST $WHITELIST
        else
          echo "Error. Return code \"$?\" from running 'grep -v $NUM2REMOVE $WHITELIST'."
        fi
      else
        echo "Number not found. Doing nothing."
      fi
    fi
  #Start the number adding process
  else
    NUM2ADD=`echo $1 | sed -e "s/\ //g"`
    if grep -lq $NUM2ADD $WHITELIST; then
      echo "Number $NUM2ADD is already in the list."
    else
      if [ "$2" = " " ] || [ -z "$2" ]; then
        echo "$NUM2ADD #?">>$WHITELIST
        echo "Added \"$NUM2ADD\ #-\" to $WHITELIST."
      else
        echo "$NUM2ADD #$2">>$WHITELIST
        echo "Added \"$NUM2ADD\ #$2\" to $WHITELIST."
      fi
    fi
  fi
fi
 
# Delete the temp file
if [ -f $TMPLIST ]; then
  rm $TMPLIST
fi
 
# Output current list
echo "\nBelow is your current whitelist:\n**********"
cat $WHITELIST
echo "**********"
 
exit 0

 

Blacklist-Script

/usr/local/sbin/blacklist

#!/bin/sh
#
# Script to manage the Asterisk tellows.agi blacklist
 
BLACKLIST="/etc/asterisk/tellows.agi_blacklist"
TMPLIST="/tmp/tmplist"
MAN_USAGE="Usage:\n Add entry to the list:\n  blacklist <number> [description]\n   Example: blacklist 0123434344 \"Name or something\"\n Remove entry from the list:\n  blacklist remove <number>\n   Example: blacklist remove 0123434344"
 
#Create temp file
touch $TMPLIST
echo "***Blacklist management for Asterisk tellows.agi***\n"
 
#Check if parameter given
if [ "$1" = " " ] || [ -z "$1" ]; then
  echo "$MAN_USAGE"
else
  P1=`echo $1 | sed -e "s/\ //g"`
  #If Parameter 1 is "remove" start the removal process
  if [ "$P1" = "remove" ]; then
    if [ "$2" = " " ] || [ -z "$2" ]; then
      echo "Missing parameter 2!\n"
      echo "$MAN_USAGE"
    #Remove the given number and check errorlevel
    else
      NUM2REMOVE=`echo $2 | sed -e "s/\ //g"`
      if grep -lq $NUM2REMOVE $BLACKLIST; then
        echo "Removing $NUM2REMOVE from list..."
        grep -v $NUM2REMOVE $BLACKLIST>$TMPLIST
        if [ "$?" = "0" ]; then
          echo "Done."
          mv $TMPLIST $BLACKLIST
        else
          echo "Error. Return code \"$?\" from running 'grep -v $NUM2REMOVE $BLACKLIST'."
        fi
      else
        echo "Number not found. Doing nothing."
      fi
    fi
  #Start the number adding process
  else
    NUM2ADD=`echo $1 | sed -e "s/\ //g"`
    if grep -lq $NUM2ADD $BLACKLIST; then
      echo "Number $NUM2ADD is already in the list."
    else
      if [ "$2" = " " ] || [ -z "$2" ]; then
        echo "$NUM2ADD #?">>$BLACKLIST
        echo "Added \"$NUM2ADD\ #-\" to $BLACKLIST."
      else
        echo "$NUM2ADD #$2">>$BLACKLIST
        echo "Added \"$NUM2ADD\ #$2\" to $BLACKLIST."
      fi
    fi
  fi
fi
 
# Delete the temp file
if [ -f $TMPLIST ]; then
  rm $TMPLIST
fi
 
# Output current list
echo "\nBelow is your current blacklist:\n**********"
cat $BLACKLIST
echo "**********"
 
exit 0

 

Anwendung

Beide Dateien mit chmod +x ausführbar machen.

Jetzt kann mit

blacklist <Nummer> ["Name o.ä."]

eine Nummer einfach zur Blacklist hinzugefügt werden. Eine Nummer wieder aus der Liste entfernen ist mit

blacklist remove <Nummer>

möglich.

Analog dazu die Whitelist, z.B.

whitelist 07321123456 "Max Muster"

und

whitelist remove 07321123456

Configs

Allgemein

Asterisk auf Deutsch stellen.

/etc/asterisk/indications.conf

[general]
country=de
[...]

tellows.agi-Script

Das Script macht nacheinander folgendes:

  • Prüfen, ob eine Nummer übergeben wurde, wenn nicht, SPAMCORE = 5 (neutral) setzen und zum Ende springen.
  • Prüfen, ob der String „anonymous“ übergeben wurde, wenn ja (→ keine Rufnummer übetragen), SPAMCORE = 5 (neutral) setzen und zum Ende springen.
  • Prüfen, ob die Nummer in der Blacklist enthalten ist, wenn ja, SPAMSCORE = 10 setzen und zum Ende springen.
  • Prüfen, ob die Nummer in der Whitelist enthalten ist, wenn ja, SPAMSCORE = 0 setzen und zum Ende springen.
  • Nummer bei tellows.de nachschlagen und SPAMSCORE entsprechend setzen. Wenn kein gültiger Wert zurückgegeben wurde, SPAMSCORE = 5 setzen.
  • Ende: SET VARIABLE SPAMSCORE „$SPAMSCORE“ zurückgeben.

Des Weiteren werden noch diverse Logs geschrieben.

Die Datei nach Erstellung mit chmod +x ausführbar machen!

/usr/share/asterisk/agi-bin/tellows.agi

#!/bin/bash
#^ Debian needs #!/bin/bash, other systems may need /bin/sh to work (depends on where /bin/sh is linked to)
#read agi_request
#read agi_language
#read agi_channel
#read agi_type
#read agi_uniqueid
#read agi_callerid
#read agi_dnid
#read agi_rdnis
#read agi_context
#read agi_extension
#read agi_priority
#read agi_enhanced
#read agi_accountcode
#read emptyline
 
#Log will be handled by asterisk logrotate because of *_log (at least on Debain)
LOG="/var/log/asterisk/agi_tellows_log"
#White- and blacklist files, may only contain plain numbers
WHITELIST="/etc/asterisk/tellows.agi_whitelist"
BLACKLIST="/etc/asterisk/tellows.agi_blacklist"
COMMENT="-"
SOURCE="-"
NUMBER="-"
 
printf "**********\nStart `date +%Y-%m-%d\ %H:%M`\n">>$LOG
printf " Param 1: $1\n">>$LOG
printf " Param 2: $2\n">>$LOG
 
#Check if empty string given
if [ "$1" = " " ] || [ -z "$1" ]; then
  SPAMSCORE=5
  printf " No param given...\n">>$LOG
  COMMENT="keine Rufnummer &uuml;bermittelt"
#Process $1:
else
  NUMCLEAN=`echo $1 | sed "s/\ //g"`
  #check if number is "anonymous"
  if [ "$NUMCLEAN" = "anonymous" ]; then
    SPAMSCORE=5
    printf " Anonymous call...\n">>$LOG
    COMMENT="keine Rufnummer &uuml;bermittelt"
  else
    #Check if second parameter given (real number via CDR(src)), if yes, use this
    if [ "$2" != " " ] && [ -n "$2" ]; then
      NUMCLEAN=`echo $2 | sed "s/\ //g"`
    fi
    #Convert to plain phone number (convert +49 to 0, then + to 00, then remove all non-numeric characters
    NUMBER=`echo $NUMCLEAN | sed -e "s/\ //g" -e "s/+49/0/" -e "s/+/00/" -e "s/[^0-9*#]//g"`
    printf " Normal request...\n">>$LOG
    printf " NUMBER is \"$NUMBER\"\n">>$LOG
    #check if NUMBER is found in blacklist file
    if grep -lq $NUMBER $BLACKLIST; then
      SPAMSCORE=10
      printf " NUMBER is in Blacklist\n">>$LOG
      COMMENT=`grep $NUMBER $BLACKLIST`
      SOURCE="Blacklist"
    #check if NUMBER is found in whitelist file
    elif grep -lq $NUMBER $WHITELIST; then
      SPAMSCORE=0
      printf " NUMBER is in Whitelist\n">>$LOG
      COMMENT=`grep $NUMBER $WHITELIST`
      SOURCE="Whitelist"
    #if none of the above do a tellows search
    else
      printf " Doing tellows request with http://www.tellows.de/basic/num/$NUMBER\n">>$LOG
      SOURCE="tellows-Request"
      SPAMSCORE=$(lynx -connect_timeout=5 -dump http://www.tellows.de/basic/num/$NUMBER | sed -ne '/Score:/{s/.*.: //p}')
      #check if SPAMSCORE has a valid value (1-9), if not, set it to neutral
      if [[ $SPAMSCORE =~ ^[1-9]$ ]]; then
        printf " Valid result returned.\n">>$LOG
      else
        printf " Invalid result returned (\"$SPAMSCORE\"), setting SPAMSCORE to neutral.\n">>$LOG
        SPAMSCORE=5
      fi
      COMMENT="<a href=\"http://www.tellows.de/num/$NUMBER\" target=\"blank\">Tellows-Suche</a>"
    fi
  fi
fi
 
#return this:
echo 'SET VARIABLE SPAMSCORE '"\"$SPAMSCORE\"" >/dev/stdout
 
printf " SPAMSCORE is \"$SPAMSCORE\"...\n">>$LOG
printf "End `date +%Y-%m-%d\ %H:%M`\n**********\n\n">>$LOG
 
exit 0

 

Anmeldung an FritzBox per SIP

Grundeinstellungen für SIP und Einrichten der Verbindung als Nebenstelle an der FritzBox. Hier brauchen wir jetzt die Anmeldedaten der Nebenstelle an der FritzBox, die wir am Anfang konfiguriert haben.

/etc/asterisk/sip.conf

[general]
port = 5060
transport = udp
bindaddr = 0.0.0.0
context = default
language = de
register => 621:***@fritz.box/621
 
[621]
type=peer
defaultuser=621
fromuser=621
secret=***
host=fritz.box
insecure=port,invite
canreinvite=no
dtmfmode=rfc2833
qualify=no
nat=no
context=von-fritzbox

 

VoiceMail

Grundeinstellungen für Voicemail sowie Definition der Voicemail für Nst. 621 inkl. PIN und Mail-Adresse.

/etc/asterisk/voicemail.conf

[general]
format = wav
serveremail=<Absender-E-Mail-Adresse>
attach=yes
emailsubject = New Voicemail from ${VM_CALLERID}
pbxskip = no
emailbody = New voicemail from ${VM_CIDNUM}, recordet at ${VM_DATE} with a length of ${VM_DUR}.
maxsecs = 180
maxsilence = 5
newzonename=Europe/Berlin|R
 
[default]
621 => <PIN>,<Name>,<E-Mail-Adresse>

 

DialPlan

Dies ist das Herzstück. Hier wird die Rufbehandlung gemacht.

Da hier die Asterisk Extension Language verwendet wird, erst mal die originale extensions.conf löschen oder umbenennen.

Ablauf in dieser Konfiguration:

Wenn die anrufende Nummer eine interne Nummer der FritzBox ist (**610 - **629, **50 - **59; **1 oder **2) ist, dann das AB-Menü inkl. PIN-Abfrage ausgeben, so dass Nachrichten abgehört bzw. der AB konfiguriert werden können.

Bei allen anderen Nummern: das o.g. Script aufrufen und auf den Rückgabewert warten, dann:

  • Wenn SPAMSCORE 7-10: sofort auf den AB umleiten, entsprechende Info-Mail versenden.
  • Sonst: 35 Sekunden warten und dann auflegen.

/etc/asterisk/extensions.ael

context von-fritzbox {
  621 => {
    switch (${CALLERID(num)}) { //Goto VoiceMailMain, if Caller is from internal
      pattern **6[1-2][0-9]: //DECT and VoIP phones on FritzBox
        Answer();
        NoOp(Internal DECT or SIP phone, running VoiceMailMain);
        VoiceMailMain(621);
        break;
      pattern **5[0-9]: //ISDN phones on FritzBox
        Answer();
        NoOp(Internal ISDN phone, running VoiceMailMain);
        VoiceMailMain(621);
        break;
      pattern **[1-2]: //Analog phone on FritzBox
        Answer();
        NoOp(Internal analog phone, running VoiceMailMain);
        VoiceMailMain(621);
        break;
      default: //In all other cases start regular tellows routine
        Ringing();
        Wait(1);
        AGI(tellows.agi, ${CALLERID(num)}, ${CDR(src)});
        NoOp(SPAMSCORE is ${SPAMSCORE});
        switch (${SPAMSCORE}) { //redirect to voicemail if spamscore 7-10, othwerwise wait 35 secs, then hangup
          pattern [7-9]:
            Answer();
            System(echo "${CALLERID(all)} (${CDR(src)}) has been redirected to the SPAM VoicemailBox: tellows SPAMSCORE ${SPAMSCORE} (see http://www.tellows.de/num/${CALLERID(num)} or http://www.tellows.de/num/${CDR(src)})." | mail -s "Asterisk: Suspect call" <E-Mail-Adresse>);
            VoiceMail(621,su);
            NoOp(SPAMSCORE 7-9);
            break;
          case 10:
            Answer();
            System(echo "${CALLERID(all)} (${CDR(src)}) has been redirected to the SPAM VoicemailBox by Blacklist." | mail -s "Asterisk: Suspect call" <E-Mail-Adresse>);
            VoiceMail(621,su);
            NoOp(SPAMSCORE 10!);
            break;
          default:
            Wait(35);
            NoOp(No SPAM or unknown.);
        }
    }
    Hangup();
  }
}

 

Wichtige Befehle

Asterisk überwachen (CLI öffnen und verbosity auf 5 setzen):

root@asterisk:~# asterisk -r -vvvvv

Dort dann:

root@asterisk:~# help //Alle vefügbaren Befehle ansehen
root@asterisk:~# reload //komplette Config neu laden (= Asterisk-Neustart)
root@asterisk:~# <ael|dialplan|sip|voicemail|...> reload //Entsprechende Config-Datei neu laden
root@asterisk:~# dialplan show //Dialplan (=Konvertierte extensions.ael) ansehen

Quellen