FreeRADIUS+Postgresql+OpenVPN续:流量控制
实质上很简单,就是求和+if判断,枉自研究了半天的rlm_sql_counter
示例的是每月限制流量,针对用户组
-
设定限制
radgroupreply组里面插入一行,命令如下:
insert into radgroupreply (groupname, attribute, op, value) values ('user','Max-Monthly-Traffic', ':=', '5368709120');
以上命令表示对用户组user限制流量为5G,单位是bytes
同时还要加入Acct-Interim-Interval,该参数是定义让OpenVPN plugin更新流量记录的间隔,必须是为300-3600秒之间的一个值
-
判断命令
修改/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中定义。 -
定义日期函数
来自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;
-
定义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
这条始终没成功过,不知道是什么原因。