пятница, 29 марта 2013 г.

Детализация звонков в Asterisk

Детализация звонков очень важная возможность контроля в работе предприятия, уверен сомнений по этому поводу не возникает. Посмотрев готовые решения я с удивлением обнаружил что действительно хороших решений не так уж и много. Одни разработки явно перегружены избыточными функциями, делая уклон в сторону биллинг систем. Другие решения ужасны дизайном. Многие решения уже давно заброшены разработчиками и более не поддерживаются.
Взвесив все за и против я решил написать собственную разработку по детализации звонков, которая будет обладать рядом преимуществ по сравнению с теми предложениями что существуют на данный момент.
  • Приятный и удобный дизайн
  • Отсутствие проблем при миграции на новые версии Asterisk
  • Возможность получать детализацию с нескольких серверов Asterisk
Разработка будет разделена на две публикации:
В первой публикации разъясняется настройка Asterisk для сбора информации о детализации звонков в базу данных. Во второй публикации информация о детализации из базы данных будет показана при помощи web интерфейса ACViewer.

Модель работы
Для получения общей детализации сразу с нескольких серверов Asterisk будет задействован RADIUS сервер. Введение дополнительного звена такого как RADIUS сервер даёт также следующие преимущества:
  • Атрибуты RADIUS со временем не изменяются, что может гарантировать лёгкость миграции на новые версии Asterisk
  • Работа по UDP протоколу снижает нагрузку на сеть при размещении RADIUS сервера и Asterisk на разном оборудовании
Работа будет вестись на дистрибутиве CentOS 6.x, в случае использования иного дистрибутива, ознакомьтесь с соответствующим разделом документации по установке программного обеспечения.

Конфигурация ПО
Конфигурация сервера MySQL
Работу начинаем с установки и настройки сервера MySQL, далее подключаемся к консоли MySQL как пользователь root и создаём базу данных в которой будут храниться данные по детализации звонков с Asterisk.

$ mysql -u root -p
CREATE DATABASE radius;
GRANT ALL ON radius.* TO 'astradius'@'127.0.0.1' IDENTIFIED BY 'radpass';
GRANT ALL ON radius.* TO 'astradius'@'localhost' IDENTIFIED BY 'radpass';
FLUSH PRIVILEGES;
SQL схему показанную ниже сохраняем в файл "radius.sql" и импортируем в базу данных.
CREATE TABLE `radacct` (
    `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    `clid` VARCHAR(80) NOT NULL DEFAULT '',
    `src` VARCHAR(80) NOT NULL DEFAULT '',
    `dst` VARCHAR(80) NOT NULL DEFAULT '',
    `dcontext` VARCHAR(80) NOT NULL DEFAULT '',
    `lastapp` VARCHAR(200) NOT NULL DEFAULT '',
    `lastdata` VARCHAR(200) NOT NULL DEFAULT '',
    `duration` FLOAT UNSIGNED NULL DEFAULT NULL,
    `billsec` FLOAT UNSIGNED NULL DEFAULT NULL,
    `disposition` ENUM('ANSWERED','BUSY','FAILED','NO ANSWER','CONGESTION') NULL DEFAULT NULL,
    `channel` VARCHAR(50) NULL DEFAULT NULL,
    `dstchannel` VARCHAR(50) NULL DEFAULT NULL,
    `amaflags` VARCHAR(50) NULL DEFAULT NULL,
    `accountcode` VARCHAR(20) NULL DEFAULT NULL,
    `uniqueid` VARCHAR(32) NOT NULL DEFAULT '',
    `userfield` FLOAT UNSIGNED NULL DEFAULT NULL,
    `start` DATETIME NOT NULL,
    `answer` DATETIME NOT NULL,
    `end` DATETIME NOT NULL,
    PRIMARY KEY (`id`),
    INDEX `clid` (`clid`),
    INDEX `src` (`src`),
    INDEX `dst` (`dst`),
    INDEX `start` (`start`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
$ mysql -u astradius -p radius < radius.sql

Конфигурация RADIUS
В работе будет использован сервер freeRADIUS, установим требуемые пакеты.
$ sudo yum install freeradius freeradius-mysql freeradius-utils radiusclient-ng
Конфигурация RADIUS делится на две части:
  • Конфигурация RADIUS клиента
  • Конфигурация RADIUS сервера

Конфигурация клиента radiusclient-ng
Клиент radiusclient-ng является связующим звеном между Asterisk (который является NAS в терминологии RADIUS) и сервером freeRADIUS. Следует отметить что изначально с сервером freeRADIUS поставлялся Radiusclient, но потом он оказался заброшен, новая функциональность перестала добавляться. Поэтому был сделан форк родного RADIUS клиента radiusclient-ng в который были добавлены новые возможности, его и будем использовать в работе.
Клиенту radiusclient-ng для работы с Asterisk требуется подключить файл словаря от компании Digium, находящийся в директории “contrib” архива исходных текстов Asterisk. Копируем файл словаря “asterisk.digium” и файл базового словаря который поставляется с “radiusclient-ng” в директорию с конфигурационными файлами “radiusclient-ng”
$ sudo cp /usr/share/radiusclient-ng/dictionary /etc/radiusclient-ng/
Подключаем в окончании файла “dictionary” словарь от компании Digium
$INCLUDE /usr/share/freeradius/dictionary.digium
В файле “servers” указываем учётные данные которые будут использоваться клиентом при обращении к серверу freeRADIUS. Файл “servers”:
127.0.0.1       myradiussecret
Файл “radiusclient.conf” приводим к следующему виду:
auth_order      radius
login_tries     4
login_timeout   60
nologin         /etc/nologin
issue           /etc/radiusclient-ng/issue
authserver      127.0.0.1:1812
acctserver      127.0.0.1:1813
servers         /etc/radiusclient-ng/servers
dictionary      /etc/radiusclient-ng/dictionary
login_radius    /usr/sbin/login.radius
seqfile         /var/run/radius.seq
mapfile         /etc/radiusclient-ng/port-id-map
default_realm
radius_timeout  10
radius_retries  3
login_local     /bin/login

Конфигурация сервера freeRADIUS
Файлы конфигурации сервера находятся в директории “/etc/raddb”, требуется отредактировать конфигурационные файлы находящиеся в указанной директории. Файл “clients.conf” содержит описание клиентов RADIUS которым позволено подключаться к серверу freeRADIUS. Для каждой клиентской записи требуется указать IP адрес с которого будет производиться подключение и пароль. Пароль должен соответствовать тому что указан в файле “servers” клиента “radiusclient-ng”
Файл “clients.conf”
client localhost {
        ipaddr = 127.0.0.1
        secret = myradiussecret
}
Файл “radiusd.conf” приводим к виду:
prefix = /usr
exec_prefix = /usr
sysconfdir = /etc
localstatedir = /var
sbindir = /usr/sbin
logdir = ${localstatedir}/log/radius
raddbdir = ${sysconfdir}/raddb
radacctdir = ${logdir}/radacct

name = radiusd

confdir = ${raddbdir}
run_dir = ${localstatedir}/run/${name}
db_dir = ${raddbdir}
libdir = /usr/lib64/freeradius
pidfile = ${run_dir}/${name}.pid

user = radiusd
group = radiusd

max_request_time = 30
cleanup_delay = 5
max_requests = 1024

listen {
        ipaddr = *
        port = 1812
        type = auth
}

listen {
        ipaddr = *
        port = 1813
        type = acct
}

hostname_lookups = no
allow_core_dumps = no

regular_expressions     = yes
extended_expressions    = yes

log {
        destination = files
        file = ${logdir}/radius.log
        stripped_names = no
        auth = no
        auth_badpass = no
        auth_goodpass = no
}

checkrad = ${sbindir}/checkrad

security {
        max_attributes = 200
        reject_delay = 1
        status_server = yes
}

proxy_requests  = no

$INCLUDE clients.conf

thread pool {
        start_servers = 5
        max_servers = 32
        min_spare_servers = 3
        max_spare_servers = 10
        max_requests_per_server = 0
}

modules {
        $INCLUDE ${confdir}/modules/
        $INCLUDE sql.conf
}

instantiate {
        exec
        expr
        expiration
        logintime
}

$INCLUDE policy.conf
$INCLUDE sites-enabled/
В штатной поставке freeRADIUS начиная с версии 1.1.2 уже идёт словарь от компании Digium, поэтому подключать дополнительный словарь к серверу RADIUS не требуется.
Файл “sql.conf” приводим к виду:
sql {
        database = "mysql"
        driver = "rlm_sql_${database}"
        server = "127.0.0.1"
        port = 3306
        login = "astradius"
        password = "radpass"
        radius_db = "radius"

        acct_table1 = "radacct"
        acct_table2 = "radacct"

        deletestalesessions = yes

        sqltrace = no
        sqltracefile = ${logdir}/sqltrace.sql

        num_sql_socks = 5
        connect_failure_retry_delay = 60
        lifetime = 0
        max_queries = 0
        nas_table = "nas"

        $INCLUDE sql/${database}/radcdr.conf
}
Файл "sites-enabled/default" приводим к виду:
authorize {
        preprocess
        sql
        expiration
        logintime
}

authenticate {

}

preacct {
        acct_unique
}

accounting {
        sql
        attr_filter.accounting_response
}

session {
        sql
}

post-auth {
        sql
        Post-Auth-Type REJECT {
                sql
                attr_filter.access_reject
        }
}
Символьную ссылку на файл “sites-enabled/inner-tunel” удаляем.
Создаём файл "sql/mysql/radcdr.conf" в котором описываем запрос к базе данных MySQL. При помощи указанного запроса данные детализации звонков полученные сервером freeRADIUS помещаются в MySQL таблицу.
accounting_stop_query = " \
    INSERT INTO ${acct_table2} \
        (accountcode, src, dst, dcontext, \
            clid, channel, dstchannel, lastapp, \
            lastdata, start, answer, end, duration, billsec, \
            disposition, amaflags, uniqueid, userfield) \
    VALUES \
        ('%{Asterisk-Acc-Code}', '%{Asterisk-Src}', '%{Asterisk-Dst}', '%{Asterisk-Dst-Ctx}', \
            '%{Asterisk-Clid}', '%{Asterisk-Chan}', '%{Asterisk-Dst-Chan}', '%{Asterisk-Last-App}', \
            '%{Asterisk-Last-Data}', '%{Asterisk-Start-Time}', '%{Asterisk-Answer-Time}', \
            '%{Asterisk-End-Time}', '%{Asterisk-Duration}', '%{Asterisk-Bill-Sec}', \
            '%{Asterisk-Disposition}', '%{Asterisk-AMA-Flags}', '%{Asterisk-Unique-ID}', \
            '%{Asterisk-User-Field}')"
Активируем запусе freeRADIUS сервера при загрузке системы.
$ sudo chkconfig radiusd on

Конфигурация Asterisk
Реализованная на данный момент модель работы Asterisk по протоколу RADIUS не предполагает аутентификации (Authentication) и авторизации (Authorization), пока возможен только сбор учётных данных об используемых ресурсах (Accounting). Для биллинг систем подобная модель работы конечно не годится, но для сбора детализации вполне подходит. Предполагается что сервер Asterisk уже установлен, поэтому потребуется установить лишь один пакет для работы Asterisk совместно с RADIUS сервером.
$ sudo yum install asterisk-radius
Для детализации звонков в Asterisk на имеется два модуля: RADIUS CDR Backend и RADIUS CEL Backend. Выбор пал на “CDR Backend”, поскольку модуль “CEL Backend” имеет незакрытый баг.
Всё что требуется сделать в Asterisk это привести файл конфигурации "cdr.conf" к следующему виду:
[general]

enable=yes
unanswered = yes

[radius]
usegmtime = yes    ; log date/time in GMT
loguniqueid = yes  ; log uniqueid
loguserfield = yes ; log user field
radiuscfg => /etc/radiusclient-ng/radiusclient.conf
После редактирования конфигурации подключимся к консоли Asterisk и перезагрузим модуль.
localhost*CLI> module unload cdr_radius.so
localhost*CLI> module load cdr_radius.so
Loaded cdr_radius.so
 == Parsing '/etc/asterisk/cdr.conf':   == Found
Loaded cdr_radius.so => (RADIUS CDR Backend)
Готово! Делаем звонок.
Подключаемся к MySQL серверу, и убеждаемся в корректной работе детализации.
mysql> use radius;
Database changed
mysql> SELECT src, dst, start, end, duration, answer  FROM radacct;
+-----+-----+---------------------+---------------------+----------+---------------------+
| src | dst | start               | end                 | duration | answer              |
+-----+-----+---------------------+---------------------+----------+---------------------+
| 100 | 500 | 2013-03-29 15:57:15 | 2013-03-29 15:57:22 |        7 | 2013-03-29 15:57:15 |
| 100 | 500 | 2013-03-29 16:13:31 | 2013-03-29 16:13:35 |        4 | 2013-03-29 16:13:31 |
+-----+-----+---------------------+---------------------+----------+---------------------+
2 rows in set (0.00 sec)
Получить детализацию с дополнительного сервера Asterisk достаточно просто, требуется лишь добавить секцию клиента в файле “clients.conf” и дать возможность серверу RADIUS слушать соединения на нужных сетевых интерфейсах. После этого можно переходить к настройке дополнительного сервера Asterisk с клиентом radiusclient-ng.

Отображение информации о детализации из базы данных при помощи WEB интерфейса описано в следующей публикации.

суббота, 23 марта 2013 г.

Типовая конфигурация сервера MySQL

Многие администраторы в своей работе используют шаблоны готовых конфигураций. Подобный подход вполне разумен, в этом случае сокращается время на развёртывание сервиса, уменьшается вероятность ошибок, не требуется постоянно помнить опции конфигурации. Всем кому интересен подобный подход предлагаю воспользоваться моими наработками оформленными в файле конфигурации MySQL.

В основе конфигурации лежит шаблон my-large.cnf и наработки взятые из блога Sergey Danielyan. Конфигурация для сервера MySQL  5.1 обладает следующими возможностями:
  • Транзакционным механизмом InnoDB
  • Кодировкой UTF-8
  • Ограничением на бинарные лог файлы по времени (2 суток) и по максимальному размеру (1Гб)
  • Ожиданием подключений только на адресе 127.0.0.1
В дистрибутиве CentOS 6.x сервер MySQL устанавливаем при помощи команды
$ sudo yum groupinstall "Сервер базы данных MySQL"
Листинг файла конфигурации /etc/my.cnf
[client]
port = 3306
socket = /var/lib/mysql/mysql.sock
default-character-set = utf8

[mysqld]
port = 3306
bind-address = 127.0.0.1
socket = /var/lib/mysql/mysql.sock
init_connect='SET collation_connection = utf8_unicode_ci'
character-set-server = utf8
collation-server = utf8_unicode_ci

skip-external-locking
key_buffer_size = 256M
max_allowed_packet = 1M
table_open_cache = 256
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size= 16M
thread_concurrency = 8

log-bin = mysql-bin
expire_logs_days = 2
max_binlog_size = 1024M
binlog_format = mixed
log-error = /var/log/mysqld.log

server-id = 1

default-storage-engine = InnoDB
innodb_data_home_dir = /var/lib/mysql
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = /var/lib/mysql
innodb_buffer_pool_size = 256M
innodb_additional_mem_pool_size = 20M
innodb_log_file_size = 64M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash

[myisamchk]
key_buffer_size = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout
Запускаем установленный MySQL сервер
$ sudo service mysqld start
Завершаем конфигурирование
$ sudo /usr/bin/mysql_secure_installation
При новой установке MySQL пароль на root пользователя отсутствует, поэтому просто нажимаем Enter и далее в конфигурации устанавливаем новый пароль. В большинстве вопросов которые будут задаваться в конфигурационном меню подходят ответы заданные по умолчанию.

Последним штрихом активируем запуск MySQL сервера при загрузке системы
$ sudo chkconfig mysqld on