[转]限制UDP连接数方法

@zhoutao0712 2010-1-1

在dual的QOS中,限制连接是利用 发包数/s 的方法来限制UDP连接数的。 但这样限制,有个坏处就会干扰正常连线的上传。
经过大量的GOOGLE,我找出了一种更好的方法。欢迎高手拍砖指教 


先说限制某个IP的TCP连接的方法:

iptables -I FORWARD -s 192.168.1.6 -p tcp --syn -m connlimit --connlimit-above 10 -j DROP

上面这条命令就可以限制192.168.1.6的TCP连接数使其不超过10。

如果写成下面这样:

iptables -I FORWARD -s 192.168.1.6 -p tcp -m connlimit --connlimit-above 10 -j DROP

虽然也能限制连接数,但我认为不是很好。而恩山论坛上有个QOS脚本生成器就是这种方法。

两者有什么区别:后者比前者少了 --syn,syn是tcp数据包中的一个标志,是新建一个TCP连接时使用的握手信号。
其他标志还有ack等。而ack是确认应答的标志,是对收到数据包的一种确认。已经建立的连接中大量存在ack应答数据包。
所以第二条命令不仅丢掉syn包,还会丢掉正常的ack应答包。

命令中有-p tcp,这个表示这条命令只对TCP协议起作用。看看将其改成udp怎么样。

iptables -I FORWARD -s 192.168.1.6 -p udp -m connlimit --connlimit-above 10 -j DROP

但却提示 iptables:Invalid argument (意思是“非法参数”)
经过google,发现这条命令在最新的linux 2.6核心中的iptables中才支持。

没办法限制了么?但google上找到了下面一条命令:

iptables -I FORWARD -s 192.168.1.6 -p! tcp -m connlimit --connlimit-above 10 -j DROP

注意其中的-p! tcp,意思是非tcp协议。

哈哈,在tomato中一试,果然有效。非tcp协议的数据包多数就是UDP数据包了。
但是,还是有点不爽,这条命令的意思是:当源地址为192.168.1.6的非tcp协议的连接数超过10的时候,把后面来的
那些源地址为192.168.1.6的数据包丢掉。 这样的话,会把正常连线的上传数据包也丢掉。
但是,udp中没有syn之类的标志。通过研究《LINUX iptable应用手册》,找到了一种方法。
iptables中有一种连线状态机制,有4中状态:

ESTABLISHED,INVALID,NEW,RELATED

其中NEW是和新建连接有关的。
具体到代码,就使用下面代码可限制192.168.1.2和192.168.1.3的udp连接不超过100。

modprobe /lib/modules/2.4.37.6/kernel/net/ipv4/netfilter/ipt_conntrack.o
iptables -N UDPLIMIT
iptables -I FORWARD -s 192.168.1.2 -p! tcp -m connlimit --connlimit-above 100 -j UDPLIMIT
iptables -I FORWARD -s 192.168.1.3 -p! tcp -m connlimit --connlimit-above 100 -j UDPLIMIT
iptables -A UDPLIMIT -m conntrack --ctstate NEW --ctproto udp -j DROP
iptables -I FORWARD -p udp --dport 53 -j ACCEPT

解释:第1条:是在iptables的filter链中创建一条自定义子链UDPLIMIT,以便存放超过连接数后的udp数据包。
第2---3条:当192.168.1.2和192.168.1.3的连接数超过100的时候,把后来的数据包放进UDPLIMIT中(-j UDPLIMIT)。
第4条:丢弃状态为NEW的udp数据包。(因为就是新建UDP数据包了)
第5条:在FORWARD链所有规则前面放一条允许dns数据包通过的规则(防止UDP连接满后无法浏览网页 )。

做实验时观察结果很有效的命令:iptable -vnL,可以观察到filter链中每条规则的详细情况。


参考资料:《LINUX iptable应用手册》
http://www.netfilter.org/
http://man.chinaunix.net/linux/how/Adv-Routing-HOWTO.html#toc13

----------

admin@dualwan.cn

感谢楼主分享,TTDW固件里有个ipt_udplimit的模块,应该能满足你限制UDP连接数限制的要求,那样的话你上面的代码量会少一些,执行的效率也会高一些。

udplimit v1.3.8 options:
[!] --udplimit-above n          match if the number of existing udp connections
is (not) above n
--udplimit-mask n              group hosts using mask

另外TTDW的固件里还有一个ipt_hashlimit的模块,可以根据源IP、源端口、目的IP、目的端口来组合限制每秒、每分、每小时、每天的 发包数。

hashlimit v1.3.8 options:
[!] --hashlimit <avg>           max average match rate
                                [Packets per second unless followed by
                                /sec /minute /hour /day postfixes]
--hashlimit-mode <mode>         mode is a comma-separated list of
                                        dstip,srcip,dstport,srcport
--hashlimit-name <name>         name for /proc/net/ipt_hashlimit/
[--hashlimit-burst <num>]       number to match in a burst, default 5
[--hashlimit-htable-size <num>] number of hashtable buckets
[--hashlimit-htable-max <num>]  number of hashtable entries
[--hashlimit-htable-gcinterval] interval between garbage collection runs
[--hashlimit-htable-expire]     after which time are idle entries expired?

Read more

[转]使用路由模式,使Dualwan达到带机极限

@zhoutao0712 2010-2-21

希望我有限的知识能够给你带来一些实际的利益,强力支持DualWan。

本文的主题是分离DualWan的NAT功能,让DualWan专注于QOS和防火墙等其它功能,达到更高的带机量。(高手看到这里可以飘过了,这对你们来说是小菜一碟了 )


什么是“路由模式”?

我们都知道,一般路由器有个普遍存在的功能就是NAT(网络地址转换),一般的很垃圾的路由器都有这个功能。这个功能可以让多个PC共享一条宽带(实质是共用一个公网IP)。当然,这也是ISP们深恶痛绝的一个功能了。 当然,这里的NAT更严格的说是指PAT。 取消NAT功能后,路由器就工作在“路由模式”下。


先不管这些复杂的概念,还是先看下网络连接方式吧。


ADSL猫------tplink r402--------DualWan路由器


也可以使用一种等价的方式


带路由功能ADSL一体猫--------DualWan路由器


具体步骤:

  1. 开启DualWan的“路由模式”
  2. 开启DualWan的“路由模式”.jpg
  3. 设置tp-link r402(或带路由功能ADSL一体猫)能够上网。
  4. 更改tp-link r402(或带路由功能ADSL一体猫)的LAN子网范围。
  5. LAN IP地址:192.168.0.1
    LAN网络掩码:255.255.255.0
  6. (关键)在tp-link r402(或带路由功能ADSL一体猫)LAN接口上添加一条静态路由。
  7. 目的地址:192.168.1.0
    网络掩码:255.255.255.0
    网关/下一跳地址:192.168.0.2
  8. DualWan的网络设置。指定为“静态IP”类型,手动设置IP地址和DNS地址。
  9. 手动设置IP地址和DNS地址.jpg
注:DNS也可以在下面DHCP中中指定,或者在PC中手动填写。
上面的第4步添加静态路由是关键,很多网络新手可能还不理解其原理。


优化原理及手段:

  1. 把NAT交给另外的路由器来做,Dualwan需要承担的任务更少,达到“多路由器分布式处理”的效果
  2. TP-LINK R402不要开启任何其他的功能,关闭DHCP,关闭防火墙,关闭UPNP,关闭QOS……这样做的目的是让其专注于NAT。
  3. 关闭DualWan的多余功能(依照本论坛的优化指南)
  4. 做QOS。如果可以的话,自己写QOS脚本。
  5. 因为DualWan自身的QOS只针对带机数量较少的情况设计,并且使用了imq虚接口。
    如果带机量较多,连接数增多,这些因素会影响效率。
    技巧1:尽可能少的创建虚接口,使用实接口来做QOS。
    技巧2:使用hash表优化TC的filter。

由于没有测试环境,无法给出具体稳定运行的结果。

依据网络上一些朋友对tomato固件基本性能测试数据:
200MCPU,32M内存,在NAT条件下,WAN-----LAN的吞吐量大致为:单向30Mbit/s,双向20Mbit/s。

如果工作在路由模式下,去掉了NAT这个影响吞吐量的因素,结果应该好得多(有兴趣的自己测试下)


依照我的经验估计,如果使用优化的QOS策略,使用本论坛的WR-500U,再加上tp-link R460,
网吧环境10M光纤带机100台绝对没有问题,公司环境带机一个子网应该没问题。(自己去测试 )


关于最大连接数,可能会受到tp-link r402的限制(据说是5000),但这其实是官方的人为的限制,可以使用改版的NR2805,连接数可以上W

Read more

[转]K26 QOS脚本 2011-5-14

@zhoutao0712 2011-5-14

近一段时间以来,openwrt势力有所抬头,为了强力打压他们,特发布最新的K26可用的QOS脚本(原来的脚本只在K24好用)。

ps:虽然都是linux,理论上说QOS效果都可以做到一样,但我比较偏爱tomato。

脚本说明在这里,只针对K26有些模块名称的更新作了更改 感谢各位网友的长期支持,欢迎试用

#copyright by zhoutao0712
UIP="192.168.1."
NET="192.168.1.0/24"
IPS="2"
IPE="200"
UP=35
DOWN=175
UPLOADR=2
UPLOADC=15
DOWNLOADR=10
DOWNLOADC=$((DOWN*9/10))
UPLOADR2=1
UPLOADC2=5
DOWNLOADR2=2
DOWNLOADC2=$((DOWN*6/10))

modprobe imq
modprobe ipt_IMQ
modprobe xt_length
modprobe xt_hashlimit
modprobe xt_recent
ifconfig imq1 up
ifconfig imq0 up
iptables -t mangle -N QOSDOWN
iptables -t mangle -N QOSUP
iptables -t mangle -A PREROUTING -p ! icmp -s $NET -d ! $NET -j QOSUP
iptables -t mangle -I POSTROUTING -p ! icmp -d $NET -s ! $NET -j QOSDOWN
iptables -t mangle -A OUTPUT -o br0 -j ACCEPT
iptables -t mangle -A INPUT -i br0 -j ACCEPT
iptables -t mangle -A OUTPUT -j QOSUP
iptables -t mangle -A INPUT -j QOSDOWN

iptables -t mangle -A QOSDOWN -p udp -m mport --sports 53,67,68 -j RETURN
iptables -t mangle -A QOSUP -p udp -m mport --dports 53,67,68 -j RETURN
iptables -t mangle -N PUNISH0
iptables -t mangle -A QOSUP -p udp -j PUNISH0
iptables -t mangle -A PUNISH0 -m hashlimit --hashlimit 100/sec --hashlimit-mode srcip --hashlimit-name udplmt -j RETURN
iptables -t mangle -A PUNISH0 -m recent --rcheck --seconds 20 -j DROP
iptables -t mangle -A PUNISH0 -m recent --set
iptables -t mangle -N NEWCONN
iptables -t mangle -A QOSUP -m state --state NEW -j NEWCONN
iptables -t mangle -A NEWCONN -p ! tcp -m connlimit --connlimit-above 100 -j DROP
iptables -t mangle -A NEWCONN -p tcp -m connlimit --connlimit-above 200 -j DROP

iptables -t mangle -A QOSDOWN -p tcp ! --syn -m length --length :128 -j RETURN
iptables -t mangle -A QOSUP -p tcp ! --syn -m length --length :80 -j RETURN

iptables -t mangle -A QOSDOWN -j IMQ --todev 0
iptables -t mangle -A QOSUP -j IMQ --todev 1

iptables -t mangle -A QOSDOWN -p tcp -m length --length :768 -j MARK --set-mark-return 255
iptables -t mangle -A QOSUP -p tcp -m length --length :512 -j MARK --set-mark-return 255
iptables -t mangle -A QOSDOWN -p tcp -m mport --sports 80,443,25,110 -j BCOUNT
iptables -t mangle -A QOSDOWN -p tcp -m mport --sports 80,443,25,110 -m bcount --range :153600 -j MARK --set-mark-return 254
iptables -t mangle -A QOSUP -p tcp -m mport --dports 80,443,25,110 -j BCOUNT
iptables -t mangle -A QOSUP -p tcp -m mport --dports 80,443,25,110 -m bcount --range :51200 -j MARK --set-mark-return 254
iptables -t mangle -A QOSDOWN -m recent --rdest --rcheck  --seconds 120 -j MARK --set-mark-return 253
iptables -t mangle -A QOSUP -p udp -m recent --rcheck --seconds 120 -j MARK --set-mark-return 253
iptables -t mangle -A QOSDOWN -j MARK --set-mark 252
iptables -t mangle -A QOSUP -j MARK --set-mark 252

if [ $(cat /tmp/qos_state) -eq 1 ]
then
exit
else
echo 1 >/tmp/qos_state
fi
tc qdisc del dev imq0 root;tc qdisc del dev imq1 root
tc qdisc add dev imq0 root handle 1: htb default 999
tc qdisc add dev imq1 root handle 1: htb default 999
tc class add dev imq1 parent 1: classid 1:1 htb rate $((UP))kbps
tc class add dev imq0 parent 1: classid 1:1 htb rate $((DOWN))kbps
tc class add dev imq0 parent 1:1 classid 1:5000 htb rate $((DOWN/5))kbps quantum 15000 prio 1
tc filter add dev imq0 parent 1:0 protocol ip prio 5 handle 255 fw flowid 1:5000
tc class add dev imq1 parent 1:1 classid 1:5000 htb rate $((UP))kbps quantum 15000 prio 1
tc filter add dev imq1 parent 1:0 protocol ip prio 5 handle 255 fw flowid 1:5000
tc class add dev imq0 parent 1:1 classid 1:4000 htb rate $((DOWN/10))kbps ceil $((DOWN*6/10))kbps quantum 8000 prio 3
tc filter add dev imq0 parent 1:0 protocol ip prio 10 handle 254 fw flowid 1:4000
tc class add dev imq1 parent 1:1 classid 1:4000 htb rate $((UP/10))kbps ceil $((UP/2))kbps quantum 1500 prio 3
tc filter add dev imq1 parent 1:0 protocol ip prio 10 handle 254 fw flowid 1:4000
tc class add dev imq1 parent 1:1 classid 1:3000 htb rate $((UP/3))kbps ceil $((UP))kbps
tc class add dev imq0 parent 1:1 classid 1:3000 htb rate $((DOWN/3))kbps ceil $((DOWN))kbps
tc filter add dev imq1 parent 1:0 protocol ip prio 20 handle 253 fw flowid 1:3000
tc filter add dev imq0 parent 1:0 protocol ip prio 20 handle 253 fw flowid 1:3000
tc class add dev imq1 parent 1:1 classid 1:2000 htb rate $((UP*2/3))kbps ceil $((UP))kbps
tc class add dev imq0 parent 1:1 classid 1:2000 htb rate $((DOWN*2/3))kbps ceil $((DOWN))kbps
tc filter add dev imq1 parent 1:0 protocol ip prio 15 handle 252 fw flowid 1:2000
tc filter add dev imq0 parent 1:0 protocol ip prio 15 handle 252 fw flowid 1:2000
tc filter add dev imq0 parent 1:3000 prio 200 handle f0: protocol ip u32 divisor 256
tc filter add dev imq0 protocol ip parent 1:3000 prio 200 u32 ht 800:: match ip dst $NET hashkey mask 0x000000ff at 16 link f0:
tc filter add dev imq1 parent 1:3000 prio 200 handle f0: protocol ip u32 divisor 256
tc filter add dev imq1 protocol ip parent 1:3000 prio 200 u32 ht 800:: match ip src $NET hashkey mask 0x000000ff at 12 link f0:
tc filter add dev imq0 parent 1:2000 prio 100 handle f1: protocol ip u32 divisor 256
tc filter add dev imq0 protocol ip parent 1:2000 prio 100 u32 ht 801:: match ip dst $NET hashkey mask 0x000000ff at 16 link f1:
tc filter add dev imq1 parent 1:2000 prio 100 handle f1: protocol ip u32 divisor 256
tc filter add dev imq1 protocol ip parent 1:2000 prio 100 u32 ht 801:: match ip src $NET hashkey mask 0x000000ff at 12 link f1:
n=$IPS;
while [ $n -le $IPE ]
do
m=$(printf "%x\n" $n)
tc class add dev imq1 parent 1:3000 classid 1:${n}f htb rate $((UPLOADR2))kbps ceil $((UPLOADC2))kbps quantum 1500 prio 7
tc class add dev imq0 parent 1:3000 classid 1:${n}f htb rate $((DOWNLOADR2))kbps ceil $((DOWNLOADC2))kbps quantum 1500 prio 7
tc qdisc add dev imq1 parent 1:${n}f handle ${n}f bfifo limit 8kb
tc qdisc add dev imq0 parent 1:${n}f handle ${n}f sfq perturb 15
tc filter add dev imq1 parent 1:3000 protocol ip prio 200 u32 ht f0:${m}: match ip src 0/0 flowid 1:${n}f
tc filter add dev imq0 parent 1:3000 protocol ip prio 200 u32 ht f0:${m}: match ip dst 0/0 flowid 1:${n}f
tc class add dev imq1 parent 1:2000 classid 1:${n}a htb rate $((UPLOADR))kbps ceil $((UPLOADC))kbps quantum 1500 prio 5
tc class add dev imq0 parent 1:2000 classid 1:${n}a htb rate $((DOWNLOADR))kbps ceil $((DOWNLOADC))kbps quantum 2000 prio 5
tc qdisc add dev imq1 parent 1:${n}a handle ${n}a bfifo limit 8kb
tc qdisc add dev imq0 parent 1:${n}a handle ${n}a sfq perturb 15
tc filter add dev imq1 parent 1:2000 protocol ip prio 100 u32 ht f1:${m}: match ip src 0/0 flowid 1:${n}a
tc filter add dev imq0 parent 1:2000 protocol ip prio 100 u32 ht f1:${m}: match ip dst 0/0 flowid 1:${n}a
n=$((n+1))
done
tc class add dev imq1 parent 1:1 classid 1:999 htb rate 1kbps ceil $((UP/5))kbps quantum 1500 prio 7
tc class add dev imq0 parent 1:1 classid 1:999 htb rate 2kbps ceil $((DOWN))kbps quantum 1500 prio 7
echo 0 >/tmp/qos_state

iptables -t mangle -I PUNISH0 -m iprange --src-range 192.168.1.80-192.168.1.90 -j RETURN
iptables -t mangle -I PUNISH0 -s 192.168.1.8 -j RETURN

cat >/tmp/qos_scheduler <<"EOF"
echo 1 >/tmp/state_scheduler
if [ $(cat /proc/net/arp|fgrep -c 0x2) -eq 1 ]
then
ifconfig imq0 down
ifconfig imq1 down
exit
fi
if [ $(ifconfig |grep -c imq0) -eq 0 ]
then
ifconfig imq0 up
ifconfig imq1 up
fi
ip neigh flush dev $(nvram get lan_ifname)
EOF
chmod +x /tmp/qos_scheduler
cru d qos_scheduler
echo -e '*/1 * * * *  sh /tmp/qos_scheduler #qos_scheduler#' >>/tmp/var/spool/cron/crontabs/root

Read more

[转]QOS脚本编写资料指南 2010-6-19

@zhoutao0712 2010-6-19

不断有朋友询问脚本如何写,不是我保守技术什么的,因为这个东西如果很简单的话,那么WAYOS的固件就不会卖那么贵了。

列个清单出来,留给有需要的人参考


首先必须掌握IP地址划分,路由器,交换机等基本概念

  1. 《TCP/IP详解》第一卷。主要掌握IP数据包结构和tcp连接建立过程。
  2. 《高级Bash脚本编程指南》,掌握linux shell编程。
  3. 《iptables指南1.1.19》(本地镜像),理解iptables基本概念
  4. 《Linux的高级路由和流量控制HOWTO》,经典的linux流量控制指南书,反复读,反复实践。
  5. 《Coyote Linux 頻寬管制(QoS) 設定教學》,网上流传的linux流量控制小册子,我稍微看了下,废话比较多,但适合新手。
  6. 《Linux 防火墙》,这本书深入讲解iptables使用原则和技巧,不过理论性过多,稍微看下就OK。
  7. iptables和HTB官方网站。尤其是HTB队列规定指南,需要反复观看和揣摩。这个是HTB作者写的,讲的是HTB算法原理。
  8. 《Differentiated Service on Linux HOWTO 》,这个网站是深入研究QOS技术的人常去的地方,English的。
  9. RFC和流量控制相关的文档,比如双速率三色令牌桶(RFC 2698)

另外,需要大量实践才能掌握,实践才能真正理解,同时多google,死看书是不行的。
只要真正读懂,网络数据包可以随心所欲地控制,我写过的QOS脚本都过百了。

Read more

[转]智能QOS脚本修改版 2010-4-13

@zhoutao0712 2010-4-13

喜新厌旧,喜欢折腾的快过来看。

主要变化:

  1. 修正一个长期BUG
  2. 由于我的路由器不带USB接口,所以没有考虑脱机下载的情况。以前版本的脱机下载都未得到限制。
    以前版本只要加上以下2条命令(防火墙)即可修正。
    iptables -t mangle -A OUTPUT -d ! $NET -j QOSUP
    iptables -t mangle -A INPUT -s ! $NET -j QOSDOWN
    PS:dualwan自带的3种“QOS设置”,“QOS限速”和“智能QOS”都存在这个问题。
  3. 重新启用小包,但只队tcp和icmp小包和dns优先。
  4. 去掉“游戏爆发”和“p2p惩罚”,以减少CPU占用率。
    PS:某些固件说带机20多台下载满速度,但CPU占用率只有2%~3%,本人对这些数据表示严重怀疑。
    电信级电话交换机C&C08(中国多数的电话仍然在使用)在最初通过中国电信验收前,满载CPU达到90%,但当时的验收结果是CPU占用率最高才50%
    当然,后来随着软件优化和CPU芯片提升,CPU占用率完全符合标准。
  5. 本版本可用于其它dualwan之外的其它tomato版本。应该也可以用于dd-wrt(未验证),用于dd-wrt时web优先会失效。
  6. 本版使用ARP探测在线主机,所以网段无法改成PPPOE-SERVER和VPN-SERVER网段。
  7. 为了方便操作,本版需要指定IP地址范围(不要指定192.168.1.2--192.168.1.254,不然防火墙脚本执行都要1分多种)

防火墙脚本:

#copyright by zhoutao0712
insmod imq;insmod ipt_length.o;insmod ipt_IMQ
modprobe imq;modprobe ipt_length.o;modprobe ipt_IMQ
ifconfig imq1 up;ifconfig imq0 up
cat >/tmp/regist_env.sh <<"EOF"
export UIP="192.168.1."
export NET="192.168.1.0/24"
export IPS="2"
export IPE="20"
export UP=40
export DOWN=170
export ONLINE=$(ip neigh sh |grep :|grep -c $UIP)
export UPLOADR=2
export UPLOADC=$(($UP*((26+ONLINE))/((30+10*ONLINE))))
export DOWNLOADR=15
export DOWNLOADC=$(($DOWN*((30+ONLINE))/((20+8*ONLINE))))
ip neigh sh |grep :|cut -d' ' -f1|grep $UIP >/tmp/new
EOF
sleep 1s;. /tmp/regist_env.sh

iptables -t mangle -N QOSDOWN;iptables -t mangle -N QOSUP
iptables -t mangle -I PREROUTING -s $NET -d ! $NET -j QOSUP
iptables -t mangle -I POSTROUTING -d $NET -s ! $NET -j QOSDOWN
iptables -t mangle -A OUTPUT -d ! $NET -j QOSUP
iptables -t mangle -A INPUT -s ! $NET -j QOSDOWN
iptables -t mangle -A QOSDOWN -j IMQ --todev 0;iptables -t mangle -A QOSUP -j IMQ --todev 1
iptables -t mangle -N CONNLMT
iptables -t mangle -I QOSUP -m state --state NEW -p ! icmp -j CONNLMT
iptables -t mangle -A CONNLMT -p tcp -m mport --dports 25,80,110,443 -j RETURN
iptables -t mangle -A CONNLMT -p udp -m mport --dports 53,4000:4050 -j RETURN
iptables -t mangle -A CONNLMT -p tcp -m connlimit --connlimit-above 100 -j DROP
iptables -t mangle -A CONNLMT -p ! tcp -m connlimit --connlimit-above 150 -j DROP
iptables -t mangle -I QOSDOWN -p udp -m mport --sports 53,67,68 -j RETURN
iptables -t mangle -I QOSUP -p udp -m mport --dports 53,67,68 -j RETURN

iptables -t mangle -A QOSDOWN -j MARK --set-mark 0
iptables -t mangle -A QOSDOWN -p ! udp -m length --length :512 -j MARK --set-mark 254
iptables -t mangle -A QOSDOWN -p tcp -m mport --sports 25,80,110,443 -j BCOUNT
iptables -t mangle -A QOSDOWN -p tcp -m mport --sports 25,80,110,443 -m bcount --range :102400 -j MARK --set-mark 255
iptables -t mangle -A QOSDOWN -m mark ! --mark 0 -j RETURN
iptables -t mangle -A QOSDOWN -j MARK --set-mark 253
iptables -t mangle -A QOSUP -j MARK --set-mark 0
iptables -t mangle -A QOSUP -p ! udp -m length --length :256 -j MARK --set-mark 254
iptables -t mangle -A QOSUP -p tcp -m mport --dports 25,80,110,443 -j BCOUNT
iptables -t mangle -A QOSUP -p tcp -m mport --dports 25,80,110,443 -m bcount --range :51200 -j MARK --set-mark 255
iptables -t mangle -A QOSUP -m mark ! --mark 0 -j RETURN
iptables -t mangle -A QOSUP -j MARK --set-mark 253

tc qdisc del dev imq0 root;tc qdisc del dev imq1 root
cat >/tmp/pref_qos <<"EOF"
tc qdisc add dev imq0 root handle 1: htb;tc qdisc add dev imq1 root handle 1: htb
tc class add dev imq1 parent 1: classid 1:1 htb rate $((UP))kbps
tc class add dev imq0 parent 1: classid 1:1 htb rate $((DOWN))kbps
tc class add dev imq0 parent 1:1 classid 1:1000 htb rate $((DOWN/3))kbps quantum 20000 prio 0
tc filter add dev imq0 parent 1:0 protocol ip prio 4 handle 254 fw flowid 1:1000
tc class add dev imq1 parent 1:1 classid 1:1000 htb rate $((UP))kbps quantum 20000 prio 0
tc filter add dev imq1 parent 1:0 protocol ip prio 4 handle 254 fw flowid 1:1000
tc class add dev imq0 parent 1:1 classid 1:255 htb rate $((DOWN*2/10))kbps ceil $((DOWN*6/10))kbps quantum 8000 prio 3
tc filter add dev imq0 parent 1:0 protocol ip prio 5 handle 255 fw flowid 1:255
tc class add dev imq1 parent 1:1 classid 1:255 htb rate $((UP/10))kbps ceil $((UP*5/10))kbps quantum 2000 prio 3
tc filter add dev imq1 parent 1:0 protocol ip prio 5 handle 255 fw flowid 1:255
tc class add dev imq0 parent 1:1 classid 1:999 htb rate $((DOWN/20))kbps ceil $((DOWN))kbps quantum 2000 prio 7
tc class add dev imq1 parent 1:1 classid 1:999 htb rate $((UP/10))kbps ceil $((UP*2/10))kbps quantum 1500 prio 7
tc filter add dev imq0 parent 1:0 protocol ip prio 1000 handle 253 fw flowid 1:999
tc filter add dev imq1 parent 1:0 protocol ip prio 1000 handle 253 fw flowid 1:999
EOF
sleep 1s;. /tmp/pref_qos

cat >/tmp/filter_hash <<"EOF"
tc filter add dev imq0 parent 1:0 prio 100 handle 10: protocol ip u32 divisor 256
tc filter add dev imq0 protocol ip parent 1:0 prio 100 u32 ht 800:: match ip dst $NET hashkey mask 0x000000ff at 16 link 10:
tc filter add dev imq1 parent 1:0 prio 100 handle 10: protocol ip u32 divisor 256
tc filter add dev imq1 protocol ip parent 1:0 prio 100 u32 ht 800:: match ip src $NET hashkey mask 0x000000ff at 12 link 10:
n=$IPS;
while [ $n -le $IPE ]
do
m=$(printf "%x\n" $n)
tc filter add dev imq0 parent 1:0 protocol ip prio 100 u32 ht 10:${m}: match ip dst 0/0 flowid 1:${n}
tc filter add dev imq1 parent 1:0 protocol ip prio 100 u32 ht 10:${m}: match ip src 0/0 flowid 1:${n}
n=$((n+1))
done
EOF
sleep 1s;. /tmp/filter_hash

cat >/tmp/qos_ip <<"EOF"
qos_ip(){
handle_i=$(echo $1 |cut -d'.' -f4)
tc class replace dev imq0 parent 1:1 classid 1:$handle_i htb rate $((DOWNLOADR))kbps ceil $((DOWNLOADC))kbps quantum 2000 prio 5
tc qdisc add dev imq0 parent 1:$handle_i handle $handle_i sfq perturb 15
tc class replace dev imq1 parent 1:1 classid 1:$handle_i htb rate $((UPLOADR))kbps ceil $((UPLOADC))kbps quantum 1500 prio 5
tc qdisc add dev imq1 parent 1:$handle_i handle $handle_i bfifo limit 6kb
}
EOF
cat /tmp/old_old >/tmp/old

每分钟执行一次脚本

if [ ! -e /tmp/old ]
then
logger "smart qos:Can't find file /tmp/old"
exit
fi
. /tmp/regist_env.sh
#无变化就退出
cmp /tmp/new /tmp/old
if [ $? -eq 0 ]
then
ip neigh flush dev $(nvram get lan_ifname)
exit
fi
#有变化时分3种情况
case "$(cat /tmp/new |wc -l)" in
1)
ifconfig imq1 down
handle_i=$(cat /tmp/new |cut -d'.' -f4)
tc class replace dev imq0 parent 1:1 classid 1:$handle_i htb rate $((DOWN*10/7))kbps prio 5
cat /tmp/new >/tmp/old
;;
0)
ifconfig imq1 down
ifconfig imq0 down
cat /tmp/new >/tmp/old
;;
*)
. /tmp/qos_ip
ifconfig imq1 up
ifconfig imq0 up
i=1
while [ $i -le $(cat /tmp/new |wc -l) ]
do
ip_i=$(sed -n ${i}p /tmp/new)
qos_ip $ip_i
i=`expr $i + 1`
done
cat /tmp/new >/tmp/old
esac
ip neigh flush dev $(nvram get lan_ifname)

----------

脚本修正:

  1. 17楼高人zy5172534发现最大上传表达式错误。已经修改。
  2. 最大上传和最大下载的表达式中,ONLINE代表“在线”人数,这个表达式子我是按照ADSL带宽特性
    所设计的一种数据模型。大家可以自己尝试修改为其它不同模型。
  3. 关于5楼的baitai开迅雷后ping不通DNS的问题
  4. 是因为对每个IP的NAT连接数作了限制(TCP100,UDP150),但对DNS,WEB,MAIL和QQ等最常见的服务端口作了例外。
    原来有一句
    iptables -t mangle -I QOSUP -m state --state NEW -s $NET CONNLMT
    改为
    iptables -t mangle -I QOSUP -m state --state NEW -s $NET -p ! icmp -j CONNLMT
    开迅雷后ping不通DNS的问题就解决了。
    至于调试脚本,有两个关键的文件:
    /tmp/new和/tmp/old分别存储上次的“在线”IP地址和当前的“在线”IP地址。
    /tmp/new在每次执行定时脚本时候取得,和/tmp/old进行比较,然后实施相应的QOS策略,
    实施完后再用/tmp/new替换/tmp/old,最后在执行ip neigh flush dev $(nvram get lan_ifname)清空ARP地址表,
    以便把开机但是不访问外网的IP地址“踢出”“在线”IP地址表。
  5. 原版tomato由于MARK模块不支持 -j MARK --set-mark-return导致qos失效,现在已经改写,既适合dualwan也适合原版tomato
  6. DHCP问题已经修正

附带说明:

“在线主机”是指真正存在网络访问行为的主机,网卡长实际不收发任何数据包的主机是不算“在线”。
DOWNLOADC=$(($DOWN*((30+ONLINE))/((20+8*ONLINE))))
“在线”2人时(开机可能不止2PC):DOWNLOADC:DOWN=88.8%
“在线”5人时:DOWNLOADC:DOWN=58.3%
“在线”20人时:DOWNLOADC:DOWN=27.7%

如果觉得该算法不合适可以自己定义算法表达式子

----------

包括前面几版的,以及dualwan自带的QOS,上传限制都是准确的。你所看到的上传和实际通过路由器的是不一样的(很多包被路由器丢弃了)。
要想延迟小,不能贪心。参考总带宽必须设小点。
因为即使不做QOS,只要你的带宽占用达到总带宽的80%以后,延迟也会直线上升。


先检查ISP给你带宽是否“达到业务规范”,也就是官方测速软件是否达到规定。
然后把出口总带宽设置得保守点。

具体操作是(适合多数ADSL):
ADSL上传总带宽想充分利用就设置40KB/S,保守就设置35KB/S,极度要求低延迟就设置30KB/S
下载(假如ISP给你是 n 兆ADSL)
充分利用:100×n×90%

保守:100×n×85%
极度要求低延迟:100×n×80%


具体如何,得看具体情况尝试。
这个参考总带宽设置方法适用于所有的QOS,包括tp-link的那些企业级路由器的QOS

----------

DHCP问题已经修正(大量P2P存在时候会出现获取不到IP)。

本脚本无端口优先,你们修改的所谓的游戏端口优先只能维持几分钟。
只所以没支持端口优先,一是因为游戏端口不好定义,二是如果BT下载正好是优先端口就……

Read more