PPTP/OpenVPN 利用TC/HTB进行差异化限速的思路和参考脚本

PPTP/L2TP的实现是非常容易的 ,因为每个用户都会生成一个ppp+设备 直接在这个设备上进行速度限制就可以了
在/etc/ppp/ip-up.d/新建一个没有后缀的可执行脚本 内容如下即可:

[bash]#!/bin/bash
speed=612kbps
#删除之前的定义
tc qdisc del dev $1 root
#重新定义策略
tc qdisc add dev $1 root handle 2: htb default 10
tc class add dev $1 parent 2: classid 2:1 htb rate 100mbps ceil 100mbps
tc class add dev $1 parent 2:1 classid 2:10 htb rate $speed ceil $speed prio 1 [/bash]

关于/etc/ppp/ip-up.d/这个目录和传递进来的参数 之前我已经介绍过了 可以在我博客里面查找相关资料。
如果要针对不同的人进行不同的速度限制 可以考虑使用PPTP/L2TP的logwtmp插件来获取PPP设备和用户名的关系。
对于PPTP来说,直接在pptpd.conf启用logwtmp选项就可以了,而L2TP要在options.xl2tpd手动加上

plugin /usr/lib/pptpd/pptpd-logwtmp.so

强制启用才可以 ,这个插件启用以后,会把用户的登录状态和对应的PPP设备名称(TTY)写入到wtmp文件内 这样就可以使用who或者last命令查看到当前的登录状态。下面给出一种实现思路:

[bash]#!/bin/bash
tc qdisc del dev $1 root

#获取姓名
name=who |grep $1|awk '{print $1}'

#[ "$name" == 'ihipop' ] && exit;

#如果登录数目超过2个 就 杀掉后面那个链接进来的PPP进程
if [ who |grep ppp |grep -c $name -ge "2" ]
then
kill -TERM cat /var/run/$1.pid && exit;
fi

#如果没超过 进行基于名字的速率选择
#大小写转换
name=echo $name | tr 'A-Z' 'a-z'
case $name in
abc|test)
speed=150kbps;;
vip|ihipop)
echo skiping
exit;;
*)
speed=612kbps;;
esac

#应用TC策略
tc qdisc del dev $1 root
tc qdisc add dev $1 root handle 2: htb default 10
tc class add dev $1 parent 2: classid 2:1 htb rate 100mbps ceil 100mbps
tc class add dev $1 parent 2:1 classid 2:10 htb rate $speed ceil $speed prio 1 [/bash]

此外 PPP的Radius插件会把收到的radius属性存放在/var/run/radattr.ppp* 也可利用这个原理让radius下发限速属性,然后自己用脚本分析后,执行差异化限速,思路和上面是一样的。


为避免概念混乱,tc 采用如下规定来描述带宽:
mbps = 1024 kbps = 1024 * 1024 bps => byte/s
mbit = 1024 kbit => kilo bit/s.
mb = 1024 kb = 1024 * 1024 b => byte
mbit = 1024 kbit => kilo bit.
内定:数字以 bps 和 b 方式储存。
但当 tc输出速率时,使用如下表示:
1Mbit = 1024 Kbit = 1024 * 1024 bps => byte/s


openVPN的实现和策略要复杂一点,因为工作在tun模式喜爱的openVPN运行后只产生一个tun设备(比如tun0),如果像PPTP/L2TP一样直接对这个端口限速,就会导致用户争抢这个端口的带宽,所以只能进行基于IP的限速,大致思路是这样的:

使用HTB的filter/u32 过滤规则 进行match ip,OpenVPN的client-connect/client-disconnect 指定的脚本或者程序里面执行就可以了(script-security 2)。如果openVPN工作在nobody用户下,还需要 对这个程序set一个UID 才能正常执行

在进行基于filter/u32的规则编写前 要先创建一个在该设备上根策略和默认策略,我们通过在openvpn的up事件上进行操作,被up事件调用的程序会收到类似如下的环境变量

ifconfig_remote=10.8.0.2
route_gateway_1=10.8.0.2
ifconfig_local=10.8.0.1
proto_1=udp
tun_mtu=1500
script_type=up
verb=3
local_port_1=53
config=/etc/openvpn/server.conf
local_1=219.230.144.XXX
dev=tun0
remote_port_1=53
route_network_1=10.8.0.0
PWD=/etc/openvpn
daemon=1
route_net_gateway=219.230.144.XXX
SHLVL=1
route_vpn_gateway=10.8.0.2
script_context=init
daemon_start_time=1307009961
route_netmask_1=255.255.255.0
daemon_pid=1973
daemon_log_redirect=1
link_mtu=1542
_=/usr/bin/env

可见 设备名存储在dev环境变量里面 我们就可以利用这个进行根策略创建 参考实现脚本如下

[bash]#创建根先在设备上,指定默认策略是1:10
tc qdisc add dev ${dev} root handle 1: htb default 10
#为这个设备划定100mbps的总带宽
tc class add dev ${dev} parent 1: classid 1:1 htb rate 100mbps ceil 100mbps burst 15k
#设定默认策略 无论在总带宽是否充裕的时候 都执行固定速率 600k下行
tc class add dev ${dev} parent 1:1 classid 1:10 htb rate 612kbps ceil 612kbps burst 15k
[/bash]

下面我们就要针对不同的IP进行策略生成和filter过滤器加了,为了区别不同的过滤器,和策略类,我使用如下的方法来产生过滤器ID

比如 当一个客户端的IP是10.8.0.6 我要对其进行限速
由于在我的配置中,OpenVPN的配置的IP段落都是 10.8.0.0/16 我掐头(去掉10)去点(去掉‘.’间隔符)产生的一串数字作为策略类的ID编号, 比如原来是10.a.b.c 就是用标识号abc来标识子策略树类
client-connect传递给程序类似如下环境变量

common_name=test
ifconfig_pool_remote_ip=10.8.0.6
route_gateway_1=10.8.0.2
ifconfig_remote=10.8.0.2
#发起IP 也就是客户端IP
untrusted_ip=219.230.144.OXO
ifconfig_local=10.8.0.1
ifconfig_pool_local_ip=10.8.0.5
proto_1=udp
tun_mtu=1500
time_unix=1307017128
script_type=client-connect
verb=3
username=test
local_port_1=53
config=/etc/openvpn/server.conf
dev=tun0
#服务器IP
local_1=219.230.144.XXX
auth_control_file=/tmp/openvpn_acf_d4b5b787fe8ab7617bfe58cade528969.tmp
trusted_port=2740
route_network_1=10.8.0.0
remote_port_1=53
PWD=/etc/openvpn
route_net_gateway=219.230.144.OPX
daemon=1
untrusted_port=2740
SHLVL=1
script_context=init
route_vpn_gateway=10.8.0.2
route_netmask_1=255.255.255.0
daemon_start_time=1307010859
#发起IP 也就是客户端IP
trusted_ip=219.230.144.OXO
daemon_pid=2094
time_ascii=Thu Jun 2 20:18:48 2011
daemon_log_redirect=1
link_mtu=1542
_=/usr/bin/env

所以我们可以这样生成ID并应用策略和筛选器

[bash]
#!/bin/bash
#生成标识号码
a=echo $ifconfig_pool_remote_ip |sed 's/\.//g' -
id=${a:2}

#tc filter delete dev ${dev} parent 1: protocol ip prio 1 u32 match ip dst ${ifconfig_pool_remote_ip}/32 flowid 1:${id}
#要选出句柄才能删除filter

handles=tc filter list dev ${dev} |grep "flowid 1:${id}"|awk '{print $10}'

for handle in $handles
do
tc filter delete dev ${dev} parent 1: protocol ip prio 1 handle ${handle} u32
done

#删除之前残留的策略
old_class=tc class list dev ${dev} |grep "class htb 1:${id}"
old_rate=echo $old_class|awk '{print $9}'
#old_ceil=echo $old_class|awk '{print $11}'
tc class delete dev ${dev} parent 1:1 classid 1:${id} htb rate $old_rate

#大小写转换
name=echo ${common_name} | tr 'A-Z' 'a-z'

# 进行基于名字的速率选择
case $name in
abc|test)
speed=150kbps;;
vip|ihipop)
speed=100mbps;;
*)
speed=612kbps;;
esac

#创建用这个ID命名的策略类
tc class add dev ${dev} parent 1:1 classid 1:${id} htb rate ${speed} ceil ${speed} burst 15k
#从根上把目的地址是10.8.0.6的流量过滤出来导入到并应用到对应策略树
tc filter add dev ${dev} parent 1: protocol ip prio 1 u32 match ip dst ${ifconfig_pool_remote_ip}/32 flowid 1:${id}
[/bash]

更多关于HTB的资料 参考HTB官方网站 : http://luxik.cdi.cz/~devik/qos/htb/

本文参考了:Linux的高级路由和流量控制HOWTO-LARTC-zh_CN.GB2312

Author Info :
  • From:PPTP/OpenVPN 利用TC/HTB进行差异化限速的思路和参考脚本
  • URL:https://blog.ihipop.com/2011/06/2390.html
  • Please Reserve This Link,Thanks!
  • 《PPTP/OpenVPN 利用TC/HTB进行差异化限速的思路和参考脚本》上有2条评论

    回复 vhlv 取消回复

    您的电子邮箱地址不会被公开。 必填项已用*标注