PPTP+FreeRADIUS+MySQL搭建VPN认证和流量控制

最近帮论坛上朋友建了个OpenVPN+PPTP的VPN服务器,记下来过程以备不时之需。

系统环境是CentOS 5.6 xen,所有过程中软件均从源码编译。

需要软件:

PopTop: http://poptop.sourceforge.net/

PPPd: http://ppp.samba.org/

FreeRADIUS: http://freeradius.org/

RADIUSClient: http://wiki.freeradius.org/Radiusclient

MySQL: http://www.mysql.com/

同时为了方便管理数据库,最好再装个php,使用phpmyadmin来管理。

编译过程很简单,pptpd、pppd和freeradius都是

./configure && make && make install

就可以了。 完成之后freeradius的启动脚本在redhat/里面,pptpd需要自己写一个,很简单:

#!/bin/sh
#
# Startup script for pptpd
#
# chkconfig: 345 40 70
# description: PPTP server
# processname: pptpd
# config: /etc/pptpd.conf
# Source function library.
. /etc/rc.d/init.d/functions
# See how we were called.
case "$1" in
	start)
		echo -n "Starting pptpd: "
		if [ -f /var/lock/subsys/pptpd ] ; then
			echo
			exit 1
		fi
		/usr/local/sbin/pptpd -d
		echo
		touch /var/lock/subsys/pptpd
	;;
	stop)
		echo -n "Shutting down pptpd: "
		killproc pptpd
		echo
		rm -f /var/lock/subsys/pptpd
	;;
	status)
		status pptpd
	;;
	restart)
		$0 stop
		$0 start
	;;
*)
	echo "Usage: $0 {start|stop|restart|status}"
	exit 1
esac
exit 0

然后修改一些FreeRADIUS的配置文件,位于/usr/local/etc/raddb/

sites-enabled/default

在所有的unixfiles前面加上注释,并去掉所有sql前面的注释。

radiusd.conf

去掉include sql.conf前面的注释。

clients.conf

这个文件控制连接的客户端的地址以及secret code。 secret要记下来,测试和写配置文件的时候要用。默认是testing123

sql.conf

这个文件控制连接到sql的参数,改成实际数据库的用户名和密码。

sql/mysql/dialup.conf

取消

sql_user_name = '%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}'

前面的注释,把下一行注释掉。 同时如果需要打开simultanoues-use(控制同时在线用户数)的话需要把simul_query_check取消注释。

然后建立基本数据库:

/usr/local/mysql/bin/mysql -uroot -p
create database radius;
grant all privileges on radius.* to radius@localhost identified by 'radiuspassword';
flush privileges;
exit;
/usr/local/mysql/bin/mysql -uradius -p radius < /usr/local/etc/raddb/sql/mysql/schema.sql

建立表格:

INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Auth-Type',':=','Local');
INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Service-Type',':=','Framed-User');
INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Framed-IP-Address',':=','255.255.255.254');
INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Framed-IP-Netmask',':=','255.255.255.0');
INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Acct-Interim-Interval',':=','600');
INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Max-Monthly-Traffic',':=','5368709120');
INSERT INTO radgroupcheck (groupname,attribute,op,VALUE) VALUES ('user','Simultaneous-Use',':=','1');

以上前四行不用改动,acct-interim-interval是计算流量的间隔(600秒),意味着每隔10分钟记录当前流量。倒数第二行是每月最大流量,这里是5G(单位是字节)。最后一行是允许同时连接数目。

输入测试用户信息:

INSERT INTO radcheck (username,attribute,op,VALUE) VALUES ('test','Cleartext-Password',':=','test');
INSERT INTO radusergroup (username,groupname) VALUES ('test','user');

用户名与密码必须以明文/NTLM Crypt形式保存,因为MS-CHAPv2不支持MD5保存的密码。

由于上步中有非内置的attribute Max-Monthly-Traffic,所以需要在/usr/local/etc/raddb/dictionary里面定义:

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

初步测试:

/etc/init.d/freeradius stop
radiusd -X &
radtest test test localhost 1649 testing123

如果结果中有Access-Accept就代表成功了,否则退回去检查设置。 测试成功的话添加在认证时检测流量的语句,打开/usr/local/etc/raddb/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_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='%{User-Group}' AND attribute='Max-Monthly-Traffic';}') {
        reject
}

设置radiusclient:

打开/usr/local/etc/radiusclient/radiusclient.conf,修改

authserver localhost:1812
acctserver localhost:1813

修改server

最后加上localhost secret(就是FreeRadius的client.conf里面定义的secret)

修改dictionary

最后加上

INCLUDE /usr/local/etc/radiusclient/dictionary.merit
INCLUDE /usr/local/etc/radiusclient/dictionary.microsoft

如果没有dicitionary.microsoft的话看这里:http://wiki.freeradius.org/PopTop

一切正常后设置pptp:

把源码包里面的options.pptpdpptpd.conf拷到/etc/

修改options.pptpd

取消ms-dns前面的注释,后面的ip改为8.8.8.8 加入一行noaccomp,以提供对iOS 4.3+的支持(否则连上就断)。 最后加上插件:

plugin /usr/local/lib/pppd/2.4.5/radius.so
plugin /usr/local/lib/pppd/2.4.5/radattr.so
radius-config-file /usr/local/etc/radiusclient/radiusclient.conf

修改pptpd.conf

ppp路径改为/usr/local/sbin/pppd

option路径为/etc/options.pptpd

注释掉logwtmp避免619错误

最后的localip根据需要设置

示例:

localip 192.168.100.1
remoteip 192.168.100.100-150

重要的一点:一定要注释掉delegate,之前没有注释结果连接的时候log显示LCP terminated by peer跟着一堆乱码直接掉线,客户端则显示720,注释掉就好了。(虽然个人认为不应该注释,因为delegate的作用是让radius来处理ip分配) 启动服务测试下是否能连接,多用radiusd -X看输出信息。

最后是相应的iptables设置:/etc/sysconfig/iptables

nat里面加入:

-A POSTROUTING -s 192.168.100.0/255.255.255.0 -o eth0 -j MASQUERADE

filter里面加入:

-A INPUT -i lo -j ACCEPT  
-A INPUT -i ! lo -d 127.0.0.0/8 -j REJECT  
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT  
-A OUTPUT -j ACCEPT  
-A INPUT -p gre -j ACCEPT  
-A INPUT -p tcp -m state --state NEW --dport 1723 -j ACCEPT  
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT  
-A INPUT -j REJECT  
-A FORWARD -i ppp+ -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --set-mss 1356

设置mss以防止过大的包被丢弃,从而造成无法载入。

大功告成!

本文参考:

http://wiki.freeradius.org/PopTop

http://freeradius.1045715.n5.nabble.com/group-variable-td2776238.html

http://hi.baidu.com/ox188/blog/item/4ae1373f33d90fe455e723a4.html

http://www.accountingenhancements.com/filetree/pptp-HOWTO-linux-2.6.9.txt

http://discussions.apple.com/thread.jspa?threadID=2778039&start=60&tstart=0