asterisk защита от телефонного DDoS

Опубликовано beregov.a.e - чт, 02/15/2018 - 10:26

По мативам https://habrahabr.ru/company/doktelecom/blog/143823/

Как от этого можно защитится? На этот вопрос попытаюсь ответить.

Есть несколько вариантов. Первый вариант, самый простой. Чтобы оператор предоставлял данную услугу только по предоплате. Второй это на стороне АТС организовать защиту. Собственно об этом и пойдёт речь. В начале настроим так: просто будим считать количество секунд которые принимались с начала месяца на sip учётке которая отвечает за входящий трафик на номер 8800. А далее можно усложнить. Например не принимать звонок если этот номер исчерпал лимит по количеству секунд или соединений на день. Допустим потенциальный клиент не может звонить на номер 8800 больше 10 раз в день и при этом общее количество секунд не должно превышать 1200 за весь месяц. Если только у вас компания не занимается технической поддержкой или консультацией. В общем исходя из ваших реалий. В данном примере имеем следующую картину. 

Допустим провайдер ростелеком у него минута на момент написания статьи стоит где-то 3,5 рубля. Лимит по расходам 10000 рублей в месяц. Значит 10000/3,5 и получим 2758 минут. Умножим это на 60 и получим 171420 секунд. Это наш теоретический придел по времени после которого стоит бить тревогу, что что-то не так. И так, настройка.

Стенд.

ОС Freebsd 11.3

Сервер баз данных postgresql96

сервер телефонии asterisk 13

к базе буду обращаться через odbc

за основу взял статью https://habrahabr.ru/sandbox/95915/

pkg info | grep odbc

postgresql-odbc-10.01.0000 PostgreSQL ODBC driver

настроим драйвер для подключения к базе

/usr/local/etc/odbcinst.ini

[PostgreSQL]

Description=ODBC for PostgreSQL

Driver = /usr/local/lib/psqlodbcw.so

FileUsage = 1

 

и настроим /usr/local/etc/odbc.ini

[asterisk-connector]

Description = PostgreSQL connection to 'asterisk' database

Driver = PostgreSQL

Database = asterisk_cdr # база куда cdr

Servername = localhost

Port = 5432

ReadOnly = No

RowVersioning = No

ShowSystemTables = No

ShowOidColumn = No

FakeOidIndex = No

ConnSettings =

 

теперь asterisk

/usr/local/etc/asterisk/res_odbc.conf

 

[psql_cdr]; Это имя используем в функции

enabled=>yes;

dsn=>asterisk-connector ; это значение из файла /etc/odbc.ini

pooling=>no;

limit=>1;

pre-connect=>yes;

username=>логин пользователя;

password=>пароль пользователя;

 

настройка функции в файле func_odbc.conf

[BUILDSECOND8800] ; Название функции

dsn=psql_cdr ; DSN имя которое мы указали в файле res_odbc.conf

readsql=select SUM(billsec) from cdr where channel like 'SIP_канал на который поступает звонок%' and start > date_trunc('month', now());

 

Настройка диаплана

предположим что что sip от провайдера на которой поступает звонок 666

exten => 666,1,Set(INFO_SECONDS=${ODBC_BUILDSECOND8800()})

same =>n,Gotoif($[${INFO_SECONDS}<171420)]?mainmenu,s,1)

same =>n,Hangup()

 

Хочу обратить внимание на то что функция в файле func_odbc.conf имеет имя BUILDSECOND8800 , вызываем её ODBC_BUILDSECOND8800

Прошу быть внимательние.

Тут сделали всё просто. Звонки не принимаем и всё на этом. Деньги не теряем.

И тут возникает следующее. А если звонит клиент, а не злодей. Это потенциальная потеря клиента.

Тогда нужно добавить ещё одну функцию в func_odbc.conf

[HOW_MANY_CALLS]

dsn=psql_cdr

readsql=select count(src) from cdr where channel like '${ARG1}%' and src='${ARG2}' and start > date_trunc('month', now());

 

Первый аргумент ${ARG1} это канал принимающий вызов, второй {ARG2} входящий номер телефона (callerid)

Сколько вызовов совершено с вызываемого номера на sip транк номера 8800.

За текущий месяц или день. Тут вы у сами как-нибудь. И исходя из полученной цифры создаём условие принимать вызов или нет.

Диаплан будет примерно такой

 

exten => 666,1,Set(HOW=${ODBC_HOW_MANY_CALLS(SIP/666,${CALLERID})})

same =>n,Set(INFO_SECONDS=${ODBC_BUILDSECOND8800()})

same =>n,NoOp(${HOW})

same =>n,NoOp(${INFO_SECONDS})

same =>n,Gotoif($[${INFO_SECONDS}<171420)]?mainmenu,s,1)

same =>n,Gotoif($[${HOW}<3)]?mainmenu,s,1)

same =>n,Hangup()

 

 

На этом можно было и закончить.

Как видите вроде всё хорошо и замечательно. Только вот один момент. Если у вас размер базы большой то такие запросы сильно будут нагружать сервер баз данных. Хотя нынче это не проблема, а для кого это проблема или хотят снизить нагрузку на сервер, то можно сделать представление для sip транка и текущего месяца. Так такая таблица будет заметно меньше чем основная таблица cdr.

Создадим представление

CREATE VIEW 800-trunk as select * from cdr where channel like 'SIP/666%' and start > date_trunc('month', now());

Сменим владельца таблицы на владельца базы cdr

ALTER TABLE 800-trunk OWNER TO asterisk_cdr_user;

И внесём небольшие изменения в файл func_odbc.conf

Изменим имя таблицы куда делаем запрос.

Благодарю за внимание.

 

 

Теги