30.10.2021

Talant Blogs about VOIP

Alexey Kazantsev Blog

Igor Olhovsky

19.11.2019

Asterisk Click2Call API

  1. Готовый скрипт для вызовов между extension и внешним номером, а также для запуска любого диалплана и передачи ему параметров. Использовалась библиотека https://github.com/chan-sccp/PAMI это форк самой популярной библиотеки от marcelog/PAMI. Используется потому, что в ней исправлена ошибка при использовании CommandAction. в оригинальной библиотеке она будет выдавать read timeout. Скрипт выдает статус оригинации в json формате и unqueid. техническое задание в конце кода.
ini_set('display_errors', 0);
require __DIR__ . '/vendor/autoload.php';

use PAMI\Client\Impl\ClientImpl;
use PAMI\Listener\IEventListener;
use PAMI\Message\Event\EventMessage;
use PAMI\Message\Action\OriginateAction;
use \PAMI\Message\Event\NewchannelEvent;

class A implements IEventListener
{
    public $result;

    public function handle(EventMessage $event)
    {

        if ($event instanceof \PAMI\Message\Event\NewchannelEvent) {

            $this->result = $event->getUniqueID();
            return $this->result;
        }


    }
}

$agent          = $_GET['agent'];
$extension      = $_GET['extension'];
$destination    = $_GET['destination'];

while ($agent && $extension) {
    echo "No agent and extension possible!";
    exit;
}

include "config.php";

        $a = new ClientImpl($options);
        $a->open();
        $ClassA = new A();
        $a->registerEventListener($ClassA);

        while ($agent && $destination) {

            echo "Agent && Destination";
            $result = makecallagent($a,$agent,$destination);
            $arr = array('success' => false, 'errormsg' => $result);

            if ($result === true)
                $arr = array('success' => $result,'errormsg' => NULL, 'uniqueid' =>  $ClassA->result);


            echo json_encode($arr);

            $a->close();
            exit;
        }

        while ($extension && $destination) {

            $result = makecall($a,$extension,$destination);

            $arr = array('success' => false, 'errormsg' => $result);

            if ($result === true)
                $arr = array('success' => $result,'errormsg' => NULL, 'uniqueid' =>  $ClassA->result);


            echo json_encode($arr);

            $a->close();
            exit;
        }

        echo "No extension\agent and destination correctly passed";
        exit;


function makecall($a,$source,$number) {

        $originateMsg = new OriginateAction("PJSIP/$source");
        $originateMsg->setContext('from-internal');
        $originateMsg->setPriority('1');
        $originateMsg->setExtension("$number");
        $res = $a->send($originateMsg);

        if ($res->isSuccess()) return true;   //return tru if originating success
        return $res->getKeys()['message'];    //otherwise return error message

}

function makecallagent($a,$source,$number) {

        $originateMsg = new OriginateAction("Local/28@queuemetrics");
        $originateMsg->setContext('queuemetrics');
        $originateMsg->setPriority('1');
        $originateMsg->setVariable('AGENTCODE',$source);
        $originateMsg->setVariable('QDIALER_QUEUE','outqueue');
        $originateMsg->setVariable('EXTTODIAL',$number);

        $originateMsg->setExtension("28");
        $res = $a->send($originateMsg);

        if ($res->isSuccess()) return true;   //return tru if originating success
        return $res->getKeys()['message'];    //otherwise return error message
}

15.11.2019

Removing plus symbol from CLI (Asterisk)

If CLI coming with +, then remove it, otherwise do nothing.

same = n,Set(CALLERID(num)=${IF($["${CALLERID(num):0:1}"="+"]?${CALLERID(num):1}:${CALLERID(num)})})

12.08.2019

Colored Fax with raspberry and hylafax+.

Для работа цветных факсов нужно использовать hylafax+ , не путать с обычным Hylafax. В целом установка проходит по порядку, основные проблемы это как обычно поставить все нужные пакеты аккуратно.

Для работы используются следующие статьи:

Hylafax+ на sourceforge скачать нужно последнюю версию 7+.

hylafax+ installation from svn.

hylafax+ about colored fax – во время ./configure необходимо обратить внимание на то, что нужные библиотеки присутствуют в системе.

для работы понадобится iaxmodem и две библиотеки spandsp и libiax2, которые идут вместе с iaxmodem.

  1. Скачать hylafax+ и скомпилировать, во время компиляции gs программа была не найдена, но я просто создал symlink на то место где hylfax+ её искала. хотя это не обязательно.
  2. скачать iaxmodem и скомпилировать две библиотеки идущие с ним в папке Lib. (кстати вероятно этот шаг можно облегчить, если использовать готовые пакеты с iaxmodem )
  3. Сконнектить iaxmodem с астериском, статьи которые помогут это сделать: статья про обычный hylafax и связке с астериском, у меня в прицнипе получилось всё сделать через web freepbx, единственное, что если Host для iax пользователя установить как 127.0.0.1 то, регистрация не проходила, либо проходила с ошибкой, поэтому я сделал dynamic, но permit выставил для 127.0.0.1/32 . О запуске модема можно также в этой статье почитать, но и описание внутри пакета тоже простое и подробное.
  4. После того как модем появился в системе, можно запустить faxgetty и позвонить на номер модема в примере он указан как iaxmodem0, но я использовал 2000.

Для тестирования факсов использовал кстати, ventafax – Это программа с очень долгой историей, но удивительно робит и сейчас.

3.07.2019

Asterisk as Wholesale. PAMI instead of AGI. Stable AMI connection.

Во время выполнения диалплана необходимо уточнять маршруты для звонка и делать то нужно из базы Mysql. Классический вариант использовать AGI Либо FastAGI, Но здесь я рассмотрю вариант запуска в фоне скрипта который, получая информацию о звонке, будет устанавливать переменную обратно в диалплан.

Asterisk адаптированный для wholesale, кстати, достаточно быстро всё обрабатывает используя минимум модулей и запросы в базу через ODBC. на удивление. Но всё равно с Opensips И Kamailio не сравнится.

Используем: PAMI library при установке пришлось повозиться т.к. не очень знаком с composer, но почитав про него – всё получилось. библиотеки ставятся в текущую директорию agi-bin, тогда будет доступ.

Основная проблема это поддержка коннекта между скриптом и астером, а также отсутствие ошибок между ними. Если вы запустите по умолчанию скрипты с ами, то вы наверняка получите внезапное завершение программы при анализе event от астериска. Есть несколько факторов, которые влияют на стабильность соединения:

  1. read timeout\read error – возникает на стороне скрипта, нужно обрабатывать такие события, в скрипте для этого будет try { } catch {}.
  2. Снизить поток событий из Астериска. В manager.conf Использовать eventfilter=Event: Newchannel тогда пользователю будет прилетать только определенный события.
  3. Не подключаться каждый раз при чтении и записи. В рамках библиотеки PAMI пришлось разбираться с классами в php.
  4. Астериск должен подождать в диалплане пока AMI скрипт установит переменную в канал, вот тут я не нашел ничего лучше чем просто подвесить его на 1500 циклов присвоения переменной – это ужасно я знаю.

Пример pami.php

Пример extensions.conf

Пример manager.conf

1.05.2019

Черный список ip адресов для voip

sh скрипт который

!/bin/bash
BADIPSFILE="badips.list"
BADIPSFILETEMP="$BADIPSFILE".temp
ADDLISTFILE="$BADIPSFILE".load
# get new list
wget https://www.badips.com/get/list/voip/0 -O $BADIPSFILETEMP
# sort new list
sort $BADIPSFILETEMP -o $BADIPSFILETEMP
# touch to be sure that file exist
touch $BADIPSFILE
# diff old ans new file
diff $BADIPSFILE $BADIPSFILETEMP | grep -Po '\d+.\d+.\d+.\d+' > $ADDLISTFILE
# copy new file to old for next ips going fast
cp -f $BADIPSFILETEMP $BADIPSFILE
cp -f drop_temp.xml drop_temp_.xml
BLOCKED_IP=$ADDLISTFILE
IPTABLES="iptables"
if [ -f $BLOCKED_IP ]; then
while read BLOCKED; do
$IPTABLES -A INPUT_direct -i ens192 -s $BLOCKED -p udp -j DROP
done < $BLOCKED_IP
fi

13.03.2019

connecting TATA sip trunk

TATA выдает подключает sip-trunkи через локальные сети, т.е. например они дают подсеть 10.0.8.6/32 со шлюзом 10.0.8.5 и только назначив первый ip адрес вы сможете подключиться к их voip сети.

Сразу укажу статью оригинал, которая помогла понять смысл подключения.

В качестве IP SBC\PBX тоже используются локальный адрес, например это может быть 10.0.74.11.

Едем дальше, чтобы получать входящие звонки нужно:

  • добавить интерфейс к centos ip address add 10.0.86.6/30 dev eth0:0
  • создать статический маршрут route add 10.0.74.11 gateway 10.0.8.5
  • регистрироваться на их SBC (пароль по-умолчанию 1234)
    register => 66810000:1234:66810000@10.0.74.11/66810000

для совершения исходящих:

  • нужно звонить по определенным правилам набора, например для индии это набор номера 10 знаков без 5.
  • нужно использовать в поле FROM правильный номер,
  • А также необходимо удостовериться что поле contact соответствует 10.0.8.6 (если такое сделать не получится, то у меня звонки проходили и без этого пункта ),
  • Обязательно добавьте SIP заголовок к исходящим
    P-Preferred-Identity: <sip:66810000@SBC_IP> ,

для FREEPBX добавить sip заголовок к исходящему звонку просто:

  • добавить в файл extensions_custom.conf нужный контекст, например такой:
[add-tata1-header] 
exten => s,1,SipAddHeader(P-Preferred-Identity: ${ARG1})
exten => s,n,Return
  • в настройках транка переопределить DIAL опции на:
B(add-tata1-header^s^1(66810000@10.0.76.11))

Вот так сумбурно, но в целом это все требования.

PS: чтобы freepbx подставлял в поле contact нужные данные, необходимо чтобы был маршрут до SBC. route add sbc_ip gateway gateway_IP. А также сети должны быть прописаны в конфигах Asterisk как localnet

1.03.2019

pjsip, pitch_shift, real-time

Необходимо решить такую задачу нужно в режиме реального времени менять тональность каналов на asterisk 13.

Для реализации будем использовать AMI который есть почти во всех астерисках.

  1. Получаем список активных каналов через команду
  2. “core show channels concise”
  3. Отображаем пользователям каналы и кнопки увеличения,уменьшения тональности для конкретных каналов
  4. Применяем к каналам данные настройки через команду:

Action: SetVar
Channel: 1551426910.36
Variable: PITCH_SHIFT(both)
Value: 3

или как итоге получилось:

dialplan set chanvar $channel PITCH_SHIFT(both) high

20.12.2018

sox asterisk wav mp3

Хорошая статья по теме конвертации в mp3 для centos7. 

у меня лично возникла проблема со входящими файлами wav почему-то – sox не видел данных в них, пришлось явно указывать.

скрипт для конвертации всех файлов в каталоге в mp3

#!/usr/bin/perl
use strict;
use Proc::PID::File;

if (Proc::PID::File->running()) {
        print "Already running, exiting now\n";
        exit(0);
}


my @monitor_dirs=("/var/spool/asterisk/monitor");

foreach my $monitor_dir (@monitor_dirs) {
    opendir(my $dh,$monitor_dir) or die ("Cannot open dir $monitor_dir");
    print "Processing dir $monitor_dir\n";
    while (my $file=readdir($dh))  {

        next if $file !~m/\.wav$/;
        print "Processing file $file\n";
        my $newfile=$file;
        $newfile=~s/\.wav$/\.mp3/;

        system ("/usr/local/bin/sox -t raw -r 8000 -b 16 -e signed-integer  $monitor_dir/$file -t mp3 -C32 $monitor_dir/$newfile");
        sleep(0.01);
        if (-e "$monitor_dir/$newfile") {
            print "Coneverted sucessfully $file\n";
            unlink "$monitor_dir/$file";
        }

    }
    closedir($dh);
}

6.12.2018

firewalld asterisk fail2ban

На centos 7 по умолчанию используется firewalld и возникла проблема с тем что fail2ban не банит после неуспешных попыток авторизации и звонков

проблемы тут 2:

Первая это сами правила которыми пользуется  fail2ban чтобы банить, я их заменил на 

actionban = firewall-cmd –direct –add-rule ipv4 raw PREROUTING 0 -s -j DROP && firewall-cmd –change-source= –zone=block && firewall-cmd –change-source= –zone=block –permanent

actionunban = firewall-cmd –direct –remove-rule ipv4 raw PREROUTING 0 -s -j DROP && firewall-cmd –change-source= –zone=block && firewall-cmd –change-source= –zone=block –permanent && firewall-cmd –remove-source= –zone=block && firewall-cmd –remove-source= –zone=block –permanent 

Вторая это то, что firewalld разрешает все соединения которые были установлены и остались в таблицах, посмотреть их можно командой iptstate

решается первым правилом 
firewall-cmd –direct –add-rule ipv4 raw PREROUTING 0 -s -j DROP 

Которое добавляет блокировку пакетов до проверки ESTABLESHED,RELATED

А третья проблема была в фильтре fail2ban который смотрит для регистраций accountID, и по мнению fail2ban он может быть только числовым или <unknown> 

решается изменением регулярного выражения accountID = “(.+)” в фильтрах fail2ban.