FreeRADIUS+Postgresql+OpenVPN续:流量控制

实质上很简单,就是求和+if判断,枉自研究了半天的rlm_sql_counter

示例的是每月限制流量,针对用户组

  1. 设定限制

    radgroupreply组里面插入一行,命令如下:

     insert into radgroupreply (groupname, attribute, op, value) values ('user','Max-Monthly-Traffic', ':=', '5368709120');
    

    以上命令表示对用户组user限制流量为5G,单位是bytes

    同时还要加入Acct-Interim-Interval,该参数是定义让OpenVPN plugin更新流量记录的间隔,必须是为300-3600秒之间的一个值

  2. 判断命令

    修改/etc/freeradius/sites-enabled/default的authorize一节,插入:

     update request {
         User-Group := "%{sql:SELECT groupname FROM radusergroup WHERE username='%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}' ORDER BY priority}"
     }
    
     if ("%{sql: SELECT SUM(acctinputoctets+acctoutputoctets) FROM radacct WHERE username='%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}' AND date_trunc('day', acctstarttime) >= date_trunc ('month', current_date) AND date_trunc('day', acctstoptime) < = last_day(current_date);}" >= "%{sql: SELECT value FROM radgroupreply WHERE groupname='%{User-Group}' AND attribute='Max-Monthly-Traffic';}") {
         reject
     }
    

    该行作用是用户连接时检查本月内上下行流量之和(1日-月末,acctinputoctet+acctoutputoctet),与限制相比较,如果相同或超过则拒绝认证。

    中间使用了自定义函数last_day,所以需要在pgsql中定义。

  3. 定义日期函数

    来自http://wiki.postgresql.org/wiki/Date_LastDay

     CREATE OR REPLACE FUNCTION last_day(date) RETURNS date AS $$
    
     SELECT (date_trunc('MONTH', $1) + INTERVAL '1 MONTH - 1 day')::date; $$ LANGUAGE 'sql' IMMUTABLE STRICT;
    
  4. 定义Max-Monthly-Traffic和User-Group

    由于这不是Freeradius自带的属性,所以需要在dictionary中定义,否则freeradius不会去读这个属性

    修改/etc/freeradius/dictionary

    加入

     Attribute Max-Monthly-Traffic 3003 integer
     Attribute User-Group 3004 string
    

    重启大功告成。试验的话把流量限制改成1,应该会被拒绝连接。

    bug:如果用户一直不断开连接的话就无法拒绝认证了……FreeRADIUS不能踢人下线的。

    OpenVPN plugin的作者建议在openvpn.conf里加入reneg-sec xx让用户定时重新验证,同时在radiusplugin.cnf中使用useauthcontrolfile=true让用户在验证时不掉线。不过在实验中useauthcontrolfile=true这条始终没成功过,不知道是什么原因。