Настройка FreeRadius для логирования CDR от Cisco VoIP
Есть Cisco для VoIP, которая отправляет вызовы на множество операторов. Звонок проходит через dial-peer’ов по указанным в них префиксам и в случае факапа одного из внешних операторов узнать через кого из них ушёл вызов не представляется возможным по обычным логам. Для полноценного логирования всех звонков проходящих через Cisco с множеством dial-peer’ов необходимо использовать RADIUS, чтобы точно знать через какого dial-peer’а вышел звонок.
Cisco
На Cisco необходимо включить отправку accounting сообщений в RADIUS. Авторизацию и аутентификацию использовать не будем.
Настройка как клиента RADIUS’а
enable
configure terminal
aaa new-model
aaa accounting connection h323 start-stop radius
radius-server host <ip address> acct-port 1813
radius-server key <password>
exit
Настройка отправки accounting сообщений
enable
configure terminal
radius-server vsa send accounting
gw-accounting aaa
acct-template callhistory-detail
end
Подробнее о настройке Cisco для отправки сообщений в RADIUS можно почитать тут.
RADIUS
RADIUS сервер будет поднят на Debian Linux
и все полученные данные будут складываться в базу данных PostgreSQL. Смысла в Start пакетах нет, т.к. абсолютно полная информация о завершившихся вызовах содержится в Stop пакетах. Поэтому обрабатывать будем только их.
Для начала установим freerardius:
sudo apt-get install -y freeradius freeradius-postgresql
radiusd.conf
Теперь приступим к настройке. В radiusd.conf
:
- оставляем только одну секцию
listen
, в которая принимает accounting $INCLUDE clients.conf
- в секции modules включаем sql.conf:
$INCLUDE sql.conf
Полное содержимое файла:
prefix = /usr
exec_prefix = /usr
sysconfdir = /etc
localstatedir = /var
sbindir = ${exec_prefix}/sbin
logdir = /var/log/freeradius
raddbdir = /etc/freeradius
radacctdir = ${logdir}/radacct
name = freeradius
confdir = ${raddbdir}
run_dir = ${localstatedir}/run/${name}
db_dir = ${raddbdir}
libdir = /usr/lib/freeradius
pidfile = ${run_dir}/${name}.pid
user = freerad
group = freerad
max_request_time = 30
cleanup_delay = 5
max_requests = 1024
listen {
type = acct
ipaddr = *
port = 0
}
hostname_lookups = no
allow_core_dumps = no
regular_expressions = yes
extended_expressions = yes
log {
destination = files
file = ${logdir}/radius.log
syslog_facility = daemon
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 = yes
$INCLUDE proxy.conf
$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 eap.conf
$INCLUDE sql.conf
}
instantiate {
exec
expr
expiration
logintime
}
$INCLUDE policy.conf
$INCLUDE sites-enabled/
clients.conf
В clients.conf
добавляем нашу Cisco:
client <ipaddr> {
ipaddr = <ipaddr>
secret = <password>
shortname = Cisco-VoIP
}
В secret
указывается тот пароль, что был ранее указан при конфигурации Cisco.
sql.conf
В sql.conf
указываем сервер, логин, пароль, таблицу базы данных, в которую будем складывать полученный CDR. Также из таблиц оставляем только ту, в которую будут складывать Stop пакеты. Полное содержимое файла:
sql {
database = "postgresql"
driver = "rlm_sql_${database}"
server = "aaa.bbb.ccc.ddd"
login = "radius"
password = "sup3rs3cr3tpa$$w0rd"
radius_db = "cdr"
acct_table2 = "cdr"
deletestalesessions = yes
sqltrace = no
sqltracefile = ${logdir}/sqltrace.sql
num_sql_socks = 5
connect_failure_retry_delay = 60
lifetime = 0
max_queries = 0
$INCLUDE sql/${database}/dialup.conf
}
dialup.conf
Перейдем к подключаемому dialup.conf
. В этом файле оставим только одну секцию, которая отвечает за обработку Stop пакетов. Полное содержимое файла:
sql_user_name = "%{User-Name}"
accounting_stop_query = "INSERT INTO ${acct_table2} \
(src,dst,start,connect,stop,duration,cause,localip,remoteip,mediaip) \
VALUES('%{User-Name}', '%{Called-Station-Id}', \
to_timestamp(overlay('%{h323-setup-time}' placing '' from 13 for 11), 'HH24:MI:SS.MS Mon DD YYYY')::timestamp, \
to_timestamp(overlay('%{h323-connect-time}' placing '' from 13 for 11), 'HH24:MI:SS.MS Mon DD YYYY')::timestamp, \
to_timestamp(overlay('%{h323-disconnect-time}' placing '' from 13 for 11), 'HH24:MI:SS.MS Mon DD YYYY')::timestamp, \
'%{Acct-Session-Time}'::BIGINT, \
'%{h323-disconnect-cause}', \
NULLIF('%{NAS-IP-Address}', '')::inet, \
NULLIF('%{h323-remote-address}', '')::inet, \
NULLIF('%{remote-media-address}', '')::inet)"
Здесь составляется собственный запрос к БД, чтобы нужным мне способом заполнить таблицу. Подробнее о функциях форматирования и о функциях над данными в PostgreSQL.
preprocess
Теперь необходимо в файле module/preprocess
в секции preprocess
указать, что необходимо преобразовывать VSA:
with_cisco_vsa_hack = yes
PostgreSQL
CREATE TABLE cdr (
id serial NOT NULL,
src character varying(30) DEFAULT ''::character varying,
dst character varying(30) DEFAULT ''::character varying,
start timestamp without time zone DEFAULT '1970-01-01 00:00:00'::timestamp without time zone,
"connect" timestamp without time zone DEFAULT '1970-01-01 00:00:00'::timestamp without time zone,
stop timestamp without time zone DEFAULT '1970-01-01 00:00:00'::timestamp without time zone,
duration bigint DEFAULT 0,
cause integer,
localip inet DEFAULT '0.0.0.0'::inet,
remoteip inet DEFAULT '0.0.0.0'::inet,
mediaip inet DEFAULT '0.0.0.0'::inet,
CONSTRAINT cdr_pkey PRIMARY KEY (id),
CONSTRAINT cdr_src_dst_start_key UNIQUE (src, dst, start)
);
ALTER TABLE cdr OWNER TO radius;
COMMENT ON TABLE cdr IS 'CDR через Radius';
CREATE INDEX cdr_cause ON cdr USING btree (cause);
CREATE INDEX cdr_dst ON cdr USING btree (dst);
CREATE INDEX cdr_dst_like ON cdr USING btree (dst varchar_pattern_ops);
CREATE INDEX cdr_duration ON cdr USING btree (duration);
CREATE INDEX cdr_localip ON cdr USING btree (localip);
CREATE INDEX cdr_mediaip ON cdr USING btree (mediaip);
CREATE INDEX cdr_remoteip ON cdr USING btree (remoteip);
CREATE INDEX cdr_src ON cdr USING btree (src);
CREATE INDEX cdr_src_like ON cdr USING btree (src varchar_pattern_ops);
Теперь у нас все готово. Можно сказать freeradius
перезапуститься и наблюдать как увеличивается количество записей в таблице cdr
.