Модуль ядра ses traf
Общая информация
Если вы используете Radius, то в нем есть механизм регулярной отправки текущих данных по трафику по каждому абоненту. Это называется accounting. По умолчанию, NoDeny использует accounting только для того, чтобы удостовериться, что клиент все еще подключен. Данные по трафику просто игнорируются. Но можно настроить отправку этих данных в биллинг.
Необходимо изменить mysql-процедуры accounting-а так, чтобы они:
- принимали трафик от radius
- записывали в таблицу ses_traf
Напрямую начислять трафик абонентам не получится т.к. радиус присылает общий трафик с момента подключения, а не за последний интервал времени. А нам нужно с каждым запросом увеличивать в базе данные по трафику. Поэтому используется промежуточная таблица ses_traf и модуль ядра ses_traf, который обрабатывает данные из этой таблицы и начисляет абонентам.
Настроим radius на отправку данных по трафику
Freeradius версии 2
В файле /usr/local/etc/raddb/sql.conf заменить
postauth_query = "call radupdate('%{User-Name}','%{reply:Framed-IP-Address}',\ 'user=%{Calling-Station-Id};nas=%{NAS-IP-Address}')"
на
postauth_query = "call radupdate('%{User-Name}','%{Framed-IP-Address}',\ 'user=%{Calling-Station-Id};nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}','%{Acct-Session-Id}',\ (%{%{Acct-Input-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Input-Octets}:-0},\ (%{%{Acct-Output-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Output-Octets}:-0})"
а также
accounting_update_query = "call radupdate('%{User-Name}','%{reply:Framed-IP-Address}',\ 'user=%{Calling-Station-Id};nas=%{NAS-IP-Address}')"
на
accounting_update_query = "call radupdate('%{User-Name}','%{Framed-IP-Address}',\ 'user=%{Calling-Station-Id};nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}','%{Acct-Session-Id}',0,0)"
Freeradius версии 3
В файле /usr/local/etc/raddb/mods-enabled/sql заменить
start { query = "call radupdate('%{User-Name}','%{Framed-IP-Address}',\ 'user=%{Calling-Station-Id};nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}')" }
на
start {
query = "call radupdate('%{User-Name}','%{Framed-IP-Address}',\
'user=%{Calling-Station-Id};nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}','%{Acct-Session-Id}',\
(%{%{Acct-Input-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Input-Octets}:-0},\
(%{%{Acct-Output-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Output-Octets}:-0})"
}
Если ваш исходный query не соответствует примеру, вы должны к текущему запросу добавить фрагмент, который обозначен зеленым цветом.
Также
post-auth { query = "call radupdate('%{User-Name}','%{reply:Framed-IP-Address}',\ 'user=%{Calling-Station-Id};nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}')" }
на
post-auth { query = "call radupdate('%{User-Name}','%{reply:Framed-IP-Address}',\ 'user=%{Calling-Station-Id};nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}', '%{Acct-Session-Id}', 0, 0)" }
Меняем процедуру radupdate
Freeradius версии 2
CREATE DEFINER=`root`@`localhost` PROCEDURE `radupdate`(IN login VARCHAR(64), IN ip VARCHAR(16), IN properties VARCHAR(255), IN ses VARCHAR(32), IN trafin BIGINT(20), IN trafout BIGINT(20)) BEGIN DECLARE usr_id INT; DECLARE usr_ip VARCHAR(15) DEFAULT NULL; SELECT id INTO usr_id FROM users WHERE name=login LIMIT 1; SELECT get_ip(usr_id) INTO usr_ip; CALL set_auth(usr_ip, CONCAT('mod=pppoe;',REPLACE(properties,':',''))); INSERT INTO ses_traf SET ses_id=ses, traf_in=trafin, traf_out=trafout, time=UNIX_TIMESTAMP(), uid=usr_id; END
Freeradius версии 3
DROP PROCEDURE IF EXISTS `radupdate`; DELIMITER $$ CREATE PROCEDURE `radupdate`(IN login VARCHAR(64), IN usr_ip VARCHAR(16), IN properties VARCHAR(255), IN ses VARCHAR(32), IN trafin BIGINT(20), IN trafout BIGINT(20)) BEGIN IF( SELECT 1 FROM v_ips i JOIN users u ON i.uid=u.id WHERE u.name=login AND i.ip=usr_ip ) THEN CALL set_auth(usr_ip, CONCAT('mod=pppoe;',REPLACE(properties,':',''))); INSERT INTO ses_traf SET ses_id=ses, traf_in=trafin, traf_out=trafout, time=UNIX_TIMESTAMP(), uid=(SELECT id FROM users WHERE name=login LIMIT 1); ELSE UPDATE users SET name=login WHERE name=login LIMIT 1; END IF; END$$ DELIMITER ;
Проверка
Перезапустите radius-сервер и выполните sql-запрос:
select * from ses_traf;
Должны получить табличку с трафиком абонентов. Если нет - запускайте radiusd -X и смотрите какие ошибки он выводит.
Запускаем модуль ядра ses_traf
perl nokernel.pl -m=ses_traf -v