在前面两篇文章中详细介绍了pptp ***的安装与使用,以及如何配置用户认证存入mysql数据库。本文将在前面两篇文章的基础上介绍如何对用户的流量做限制,同时限制相同账号的用户,同一时刻的在线数为1。
前文传送门地址:
PPTP-×××部署与简单使用 http://ylw6006.blog.51cto.com/470441/1794577
PPTP-×××使用mysql进行用户登录认证 http://ylw6006.blog.51cto.com/470441/1795201
一、向mysql库表中插入基础数据
mysql> use radius mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Auth-Type',':=','Local'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Service-Type',':=','Framed-User'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Framed-IP-Address',':=','255.255.255.255'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Framed-IP-Netmask',':=','255.255.255.0'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Acct-Interim-Interval',':=','600'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Max-Monthly-Traffic',':=','20480'); mysql> INSERT INTO radgroupcheck (groupname,attribute,op,VALUE) VALUES ('user','Simultaneous-Use',':=','1');
acct-interim-interval是计算流量的间隔(600秒),意味着每隔10分钟记录当前流量;
Max-Monthly-Traffic是每月最大流量,这里是20G(单位是M);
radgroupcheck表的Simultaneous-Use表示单个用户的同时连接数目;
这里要格外注意的是,许多网络上的文章介绍Max-Monthly-Traffic单位为字节,数值为5368709102,换算一下大概5G左右,而如果我们也精确到字节,数值设为20G,也就是21474836480,则用户拨入进行身份验证的时候将会报错。因而此次我们将流量限制的精度单位修改为M。详细可参考如下链接介绍:http://www.xj123.info/2856.html
二、修改配置文件
1、修改/etc/raddb/sites-enabled/default文件,添加流量限制的reject条件
# vi /etc/raddb/sites-enabled/default #找到authorize一节插入如下内容: update request { Group-Name := "%{sql:SELECT groupname FROM radusergroup WHERE username='%{User-Name}' ORDER BY priority}" } if ("%{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());}" >= "%{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';}") { reject }
2、由于使用了非内置的attribute Max-Monthly-Traffic,所以需要在/etc/raddb/dictionary里面定义
# tail -1 /etc/raddb/dictionary ATTRIBUTE Max-Monthly-Traffic 3003 integer
3、修改/etc/raddb/sql/mysql/dialup.conf文件,开启在线用户数检查
# vi /etc/raddb/sql/mysql/dialup.conf sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}" #sql_user_name = "%{User-Name}" #注释掉这行 # Uncomment simul_count_query to enable simultaneous use checking simul_count_query = "SELECT COUNT(*) \ FROM ${acct_table1} \ WHERE username = '%{SQL-User-Name}' \ AND acctstoptime IS NULL" simul_verify_query = "SELECT radacctid, acctsessionid, username, \ nasipaddress, nasportid, framedipaddress, \ callingstationid, framedprotocol \ FROM ${acct_table1} \ WHERE username = '%{SQL-User-Name}' \ AND acctstoptime IS NULL"
三、重启服务
# /etc/init.d/radiusd stop
# /etc/init.d/pptpd restart
四、测试
1、将rediusd服务运行在debug模式下,进行拨号测试,主要测试流量控制!
#radiusd -X
通过上面可以看到当前的用户流量消耗为2M,限制流量的值为20480M。
因而在/etc/raddb/sites-enabled/default文件,判断流量限制的reject条件的结果为false,用户可以通过验证,完成拨号!下面是详细的拨号日志:
rad_recv: Access-Request packet from host 127.0.0.1 port 49226, id=94, length=150 Service-Type = Framed-User Framed-Protocol = PPP User-Name = "ptest1" MS-CHAP-Challenge = 0x6716c32940f1c84ad213d2d52df1712d MS-CHAP2-Response = 0x2400c77c090296803fb3c0822b8c679547f000000000000000001eb41fe8e518c1f756fb5d9d5904ddb8dc1fe271e98aa055 Calling-Station-Id = "27.151.123.121" NAS-IP-Address = 127.0.0.1 NAS-Port = 0 # Executing section authorize from file /etc/raddb/sites-enabled/default +group authorize { ++update request { sql_xlat expand: %{Stripped-User-Name} -> ... expanding second conditional expand: %{User-Name} -> ptest1 expand: %{%{User-Name}:-DEFAULT} -> ptest1 expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 sql_set_user escaped user --> 'ptest1' expand: SELECT groupname FROM radusergroup WHERE username='%{User-Name}' ORDER BY priority -> SELECT groupname FROM radusergroup WHERE username='ptest1' ORDER BY priority rlm_sql (sql): Reserving sql socket id: 30 sql_xlat finished rlm_sql (sql): Released sql socket id: 30 expand: %{sql:SELECT groupname FROM radusergroup WHERE username='%{User-Name}' ORDER BY priority} -> user ++} # update request = noop ++? if ("%{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());}" >= "%{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';}") sql_xlat expand: %{Stripped-User-Name} -> ... expanding second conditional expand: %{User-Name} -> ptest1 expand: %{%{User-Name}:-DEFAULT} -> ptest1 expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 sql_set_user escaped user --> 'ptest1' expand: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now()); -> SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='ptest1' AND date_format(acctstarttime, '2016-06-30') >= date_format(now(),'2016-06-01') AND date_format(acctstoptime, '2016-06-30') <= last_day(now()); rlm_sql (sql): Reserving sql socket id: 29 sql_xlat finished rlm_sql (sql): Released sql socket id: 29 expand: %{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());} -> 2 sql_xlat expand: %{Stripped-User-Name} -> ... expanding second conditional expand: %{User-Name} -> ptest1 expand: %{%{User-Name}:-DEFAULT} -> ptest1 expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 sql_set_user escaped user --> 'ptest1' expand: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic'; -> SELECT value FROM radgroupreply WHERE groupname='user' AND attribute='Max-Monthly-Traffic'; rlm_sql (sql): Reserving sql socket id: 28 sql_xlat finished rlm_sql (sql): Released sql socket id: 28 expand: %{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';} -> 20480 ? Evaluating ("%{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());}" >= "%{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';}") -> FALSE ++? if ("%{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());}" >= "%{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';}") -> FALSE ++[preprocess] = ok ++[chap] = noop [mschap] Found MS-CHAP attributes. Setting 'Auth-Type = mschap' ++[mschap] = ok ++[digest] = noop [suffix] No '@' in User-Name = "ptest1", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] = noop [eap] No EAP-Message, not doing EAP ++[eap] = noop [sql] expand: %{Stripped-User-Name} -> [sql] ... expanding second conditional [sql] expand: %{User-Name} -> ptest1 [sql] expand: %{%{User-Name}:-DEFAULT} -> ptest1 [sql] expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 [sql] sql_set_user escaped user --> 'ptest1' rlm_sql (sql): Reserving sql socket id: 27 [sql] expand: SELECT id, username, attribute, value, op FROM radcheck WHERE username = '%{SQL-User-Name}' ORDER BY id -> SELECT id, username, attribute, value, op FROM radcheck WHERE username = 'ptest1' ORDER BY id WARNING: Found User-Password == "...". WARNING: Are you sure you don't mean Cleartext-Password? WARNING: See "man rlm_pap" for more information. [sql] User found in radcheck table [sql] expand: SELECT id, username, attribute, value, op FROM radreply WHERE username = '%{SQL-User-Name}' ORDER BY id -> SELECT id, username, attribute, value, op FROM radreply WHERE username = 'ptest1' ORDER BY id [sql] expand: SELECT groupname FROM radusergroup WHERE username = '%{SQL-User-Name}' ORDER BY priority -> SELECT groupname FROM radusergroup WHERE username = 'ptest1' ORDER BY priority [sql] expand: SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = '%{Sql-Group}' ORDER BY id -> SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = 'user' ORDER BY id [sql] User found in group user [sql] expand: SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = '%{Sql-Group}' ORDER BY id -> SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = 'user' ORDER BY id rlm_sql (sql): Released sql socket id: 27 ++[sql] = ok ++[expiration] = noop ++[logintime] = noop [pap] WARNING: Auth-Type already set. Not setting to PAP ++[pap] = noop +} # group authorize = ok Found Auth-Type = MSCHAP !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! Replacing User-Password in config items with Cleartext-Password. !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! Please update your configuration so that the "known good" !!! !!! clear text password is in Cleartext-Password, and not in User-Password. !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # Executing group from file /etc/raddb/sites-enabled/default +group MS-CHAP { [mschap] Creating challenge hash with username: ptest1 [mschap] Client is using MS-CHAPv2 for ptest1, we need NT-Password [mschap] adding MS-CHAPv2 MPPE keys ++[mschap] = ok +} # group MS-CHAP = ok # Executing section session from file /etc/raddb/sites-enabled/default +group session { [radutmp] expand: /var/log/radius/radutmp -> /var/log/radius/radutmp ++[radutmp] = ok +} # group session = ok # Executing section post-auth from file /etc/raddb/sites-enabled/default +group post-auth { [sql] expand: %{Stripped-User-Name} -> [sql] ... expanding second conditional [sql] expand: %{User-Name} -> ptest1 [sql] expand: %{%{User-Name}:-DEFAULT} -> ptest1 [sql] expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 [sql] sql_set_user escaped user --> 'ptest1' [sql] expand: %{User-Password} -> [sql] ... expanding second conditional [sql] expand: %{Chap-Password} -> [sql] expand: INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( '%{User-Name}', '%{%{User-Password}:-%{Chap-Password}}', '%{reply:Packet-Type}', '%S') -> INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( 'ptest1', '', 'Access-Accept', '2016-06-30 13:05:14') rlm_sql (sql) in sql_postauth: query is INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( 'ptest1', '', 'Access-Accept', '2016-06-30 13:05:14') rlm_sql (sql): Reserving sql socket id: 26 rlm_sql (sql): Released sql socket id: 26 ++[sql] = ok ++[exec] = noop +} # group post-auth = ok Sending Access-Accept of id 94 to 127.0.0.1 port 49226 Service-Type := Framed-User Framed-IP-Address := 255.255.255.255 Framed-IP-Netmask := 255.255.255.0 Acct-Interim-Interval := 600 MS-CHAP2-Success = 0x24533d46303044303641413737333432343231363234364143413245333041373133433531344439353037 MS-MPPE-Recv-Key = 0x3373da01475488084e5f82abae7cbda8 MS-MPPE-Send-Key = 0xdb408d5d7f18d9fd38e6c1888b8c0b13 MS-MPPE-Encryption-Policy = 0x00000001 MS-MPPE-Encryption-Types = 0x00000006 Finished request 0. Going to the next request Waking up in 4.9 seconds. Cleaning up request 0 ID 94 with timestamp +88 Ready to process requests. rad_recv: Accounting-Request packet from host 127.0.0.1 port 58801, id=95, length=114 Acct-Session-Id = "5774A890092400" User-Name = "ptest1" Acct-Status-Type = Start Service-Type = Framed-User Framed-Protocol = PPP Calling-Station-Id = "27.151.123.121" Acct-Authentic = RADIUS NAS-Port-Type = Async Framed-IP-Address = 192.168.222.10 NAS-IP-Address = 127.0.0.1 NAS-Port = 0 Acct-Delay-Time = 0 # Executing section preacct from file /etc/raddb/sites-enabled/default +group preacct { ++[preprocess] = ok [acct_unique] WARNING: Attribute NAS-Identifier was not found in request, unique ID MAY be inconsistent [acct_unique] Hashing 'NAS-Port = 0,,NAS-IP-Address = 127.0.0.1,Acct-Session-Id = "5774A890092400",User-Name = "ptest1"' [acct_unique] Acct-Unique-Session-ID = "413ac0cc5b5f4759". ++[acct_unique] = ok [suffix] No '@' in User-Name = "ptest1", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] = noop +} # group preacct = ok # Executing section accounting from file /etc/raddb/sites-enabled/default +group accounting { [detail] expand: %{Packet-Src-IP-Address} -> 127.0.0.1 [detail] expand: /var/log/radius/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d -> /var/log/radius/radacct/127.0.0.1/detail-20160630 [detail] /var/log/radius/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d expands to /var/log/radius/radacct/127.0.0.1/detail-20160630 [detail] expand: %t -> Thu Jun 30 13:05:20 2016 ++[detail] = ok [sql] expand: %{Stripped-User-Name} -> [sql] ... expanding second conditional [sql] expand: %{User-Name} -> ptest1 [sql] expand: %{%{User-Name}:-DEFAULT} -> ptest1 [sql] expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 [sql] sql_set_user escaped user --> 'ptest1' [sql] expand: %{Acct-Delay-Time} -> 0 [sql] expand: INSERT INTO radacct (acctsessionid, acctuniqueid, username, realm, nasipaddress, nasportid, nasporttype, acctstarttime, acctstoptime, acctsessiontime, acctauthentic, connectinfo_start, connectinfo_stop, acctinputoctets, acctoutputoctets, calledstationid, callingstationid, acctterminatecause, servicetype, framedprotocol, framedipaddress, acctstartdelay, acctstopdelay, xascendsessionsvrkey) VALUES ('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port}', '%{NAS-Port-Type}', '%S', NULL, '0', '%{Acct-Authentic}', '%{Connect-Info}', '', '0', '0', '%{Called-Station-Id}', '%{Calling-Station-Id}', '', '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', rlm_sql (sql): Reserving sql socket id: 25 rlm_sql (sql): Released sql socket id: 25 ++[sql] = ok ++[exec] = noop [attr_filter.accounting_response] expand: %{User-Name} -> ptest1 attr_filter: Matched entry DEFAULT at line 12 ++[attr_filter.accounting_response] = updated +} # group accounting = updated Sending Accounting-Response of id 95 to 127.0.0.1 port 58801 Finished request 1. Cleaning up request 1 ID 95 with timestamp +94 Going to the next request Ready to process requests.
2、测试同一个×××账号,多终端登录
通过如下sql语句可以看到当前用户的拨号连接情况,很明显通过前面的配置,并没有起到限制的效果。
mysql> SELECT radacctid, acctsessionid, username,nasipaddress, nasportid, framedipaddress, callingstationid, framedprotocol FROM radacct WHERE username ='yang' AND acctstoptime IS NULL; mysql> SELECT COUNT(*) from radacct WHERE username ='yang' AND acctstoptime IS NULL;
通过修改/etc/raddb/sites-enabled/default文件,注释掉session节的radutmp配置,重启radiusd服务后测试,发现效果符合预期
# vi /etc/raddb/sites-enabled/default
同一个账号的第二个拨号连接就会直接提示验证失败!