Freeradius Xlat

Материал из Wiki
Перейти к: навигация, поиск

FreeRadius Xlat

FreeRadius предоставляет интересные возможности для опереривания с данными. В моем случае мне не хотелось для каждого абонента делать дублирование данных из биллинга ( в моем случае таблица mtraf) в radcheck и radreply. Проверка Auth-Type - на основании данных из биллинга.

select * from radcheck;
+----+----------+------------------+----+---------------------------------------------------------------------------------------------------------------+
| id | username | attribute        | op | value                                                                                                         |
+----+----------+------------------+----+---------------------------------------------------------------------------------------------------------------+
|  4 | tan      | Simultaneous-Use | := | 1                                                                                                             |
|  7 | tan      | Password         | := | `%{sql:SELECT pwd FROM mtraf WHERE domain='%{User-Name}'}`                                                    |
| 11 | tan      | Auth-Type        | := | `%{sql:SELECT IF (0n_a<0 OR (debt=0 AND 0n_a=0),'REJECT','MS-CHAP') from mtraf  where domain='%{User-Name}'}` |
+----+----------+------------------+----+---------------------------------------------------------------------------------------------------------------+

(обратить внимание на обратные кавычки, в которые взят запрос)
Аналогично, для передачи лимитов по скорости (но вместо того что бы указать для каждого %{User-Name} можно указать значения по умолчани.

#
DEFAULT Framed-Protocol == PPP
        Framed-Protocol = PPP,
        Service-Type = Framed-User,
        Cisco-AVPair += "%{sql:SELECT CONCAT('lcp:interface-config=rate-limit input ',ul_in*1024, ' ', ROUND(ul_in*1000/8), ' ', ROUND(ul_in*1000/8), ' conform-action transmit exceed-action drop') from mtraf where domain='%{User-Name}'}",
        Cisco-AVPair += "%{sql:SELECT CONCAT('lcp:interface-config=rate-limit output ',ul_in*1024, ' ', ROUND(ul_out*1000/8), ' ', ROUND(ul_out*1000/8), ' conform-action transmit exceed-action drop') from mtraf where domain='%{User-Name}'}",
        PPPD-Upstream-Speed-Limit  :=  "%{sql:SELECT ul_in  from mtraf where domain='%{User-Name}'} ",
        PPPD-Downstream-Speed-Limit := "%{sql:SELECT ul_out from mtraf where domain='%{User-Name}'} "

Обратить внимание, что для cisco передается Cisco-AVPair, для VPN на базе Linux я использую атрибуты PPPD-Upstream-Speed-Limit / PPPD-Downstream-Speed-Limit со значением скорости в килобитах (а не в битах как для Cisco) в секунду. Т.к. радиус не знает этих атрибутов, то их следует вписать в словарь.


Но, как можно заметить, авторизация пользователя все равно требует наличия записей в таблице radcheck - хоть и одинаковых для всех.
Хотелось бы избежать ненужного дублирования информации, однако мне не удалось заставить работать конструкции вида '%{sql: SELECT ... }' для check атрибутов если проверка идет из файла users.
конструкция вида

DEFAULT Framed-Protocol == PPP, Password := "%{sql:SELECT pwd FROM mtraf WHERE domain='%{User-Name}'}"
...

у меня не заработала.


Обходным решением является использование групп. Я создал "группу по-умолчанию", для которой один раз в таблице radgroupcheck указал атрибуты для проверки. (группа называется PPTP)

select * from radgroupcheck;
+----+-----------+-----------+----+--------------------------------------------------------------------------------------------------------------+
| id | groupname | attribute | op | value                                                                                                        |
+----+-----------+-----------+----+--------------------------------------------------------------------------------------------------------------+
|  1 | PPTP      | Auth-Type | := | `%{sql:SELECT IF (0n_a<0 OR (debt=0 AND 0n_a=0),'REJECT','MS-CHAP') FROM mtraf WHERE domain='%{User-Name}'}` |
|  2 | PPTP      | Password  | := | `%{sql:SELECT pwd FROM mtraf WHERE domain='%{User-Name}'}`                                                   |
|  3 | PPTP      | Pool-Name | := | Test-Pool                                                                                                    |
+----+-----------+-----------+----+--------------------------------------------------------------------------------------------------------------+

и изменил запросы провеки групп, что бы для пользователя который не входит ни в одну группу использовались атрибуты группы "по-умолчанию" в файле sql.conf:

default_group =  "PPTP"

authorize_group_check_query = " SELECT \
    ${groupcheck_table}.id, \
    ${groupcheck_table}.GroupName, \
    ${groupcheck_table}.Attribute, \
    ${groupcheck_table}.Value,radgroupcheck.op \
    FROM \
    ${groupcheck_table} \
    LEFT JOIN  ${usergroup_table}\
    USING (GroupName) \
    WHERE \
    ${groupcheck_table}.GroupName = '${default_group}' OR \
    ${usergroup_table}.Username = '%{SQL-User-Name}'  \
    ORDER BY \
    ${groupcheck_table}.id"



authorize_group_reply_query = " SELECT \
    ${groupreply_table}.id, \
    ${groupreply_table}.GroupName, \
    ${groupreply_table}.Attribute, \
    ${groupreply_table}.Value,radgroupcheck.op \
    FROM \
    ${groupreply_table} \
    LEFT JOIN  ${usergroup_table}\
    USING (GroupName) \
    WHERE \
    ${groupreply_table}.GroupName = '${default_group}' OR \
    ${usergroup_table}.Username = '%{SQL-User-Name}'  \
    ORDER BY \
    ${groupreply_table}.id"


group_membership_query = "SELECT IFNULL((SELECT GroupName FROM  radusergroup  WHERE UserName='%{SQL-User-Name}'),'${default_group}')"

Для того что бы перекрыть адрес из пула, можно использовать атрибут Framed-IP-Address (и, вероятно, любые другие) из таблицы radreply. После добавления записи:

select * from radreply;
+----+----------+-------------------+----+--------------+
| id | username | attribute         | op | value        |
+----+----------+-------------------+----+--------------+
| 27 | tan      | Framed-IP-Address | := | XX.XX.128.11 |
+----+----------+-------------------+----+--------------+

абонент получает, соответвенно, статический ip. Если в таблице radreply никаких записей для username=tan то будет выда адрес из пула.

Еще идеи и их реализация




DROP PROCEDURE GetPool;
delimiter //
CREATE PROCEDURE GetPool(in SQLUserName varchar(64), OnetBorder INTEGER(11) )
begin
    DECLARE CurrentId           INTEGER(11);
    DECLARE CurrentId_Onet      INTEGER(11);
    DECLARE CurrentId_AB        INTEGER(11);

    SELECT id INTO CurrentId_Onet       FROM mtraf WHERE domain=SQLUserName;
    SELECT id INTO CurrentId_AB         FROM mtraf WHERE domain=SUBSTRING(SQLUserName,3);

    SELECT IFNULL(CurrentID_Onet,CurrentId_AB) INTO CurrentId;

    if CurrentId < OnetBorder then
         SELECT IF (0n_a<0 OR (debt=0 AND 0n_a=0),'NOPAY-Pool','Pool0') FROM mtraf WHERE domain=SUBSTRING(SQLUserName,3);

    else
         SELECT IF (0n_a<0 OR (debt=0 AND 0n_a=0),'NOPAY-Pool','Pool0') FROM mtraf WHERE domain=SQLUserName;
    end if;
end;
//
delimiter ;