使用u32过滤器设置基于mac地址的下载限制

u32过滤器一般使用ip地址作为匹配规则,但按照其定义,它可以匹配ip包头的任意地址,这里使用mac地址限制局域网的下载速度,避免客户端修改ip后其下载速度得不到控制。
tc qdisc del dev eth2 root
tc qdisc add dev eth2 root handle 200: cbq bandwidth 10Mbit avpkt 1000
tc class add dev eth2 parent 200:0 classid 200:1 cbq bandwidth 10Mbit rate 40000Kbit allot 1514 weight 200Kbit prio 8 maxburst 8 avp
kt 1000 bounded
tc class add dev eth2 parent 200:1 classid 200:2 cbq bandwidth 10Mbit rate 600Kbit allot 1513 weight 60Kbit prio 5 maxburst 8 avpkt 1000 bounded
tc qdisc add dev eth2 parent 200:2 sfq quantum 1514b perturb 15
tc filter add dev eth2 parent 200:0 protocol ip prio 5 u32 match u16 0x0800 0xffff at -2 match u32 0x5BB3DB90 0xffffffff at -12 match u16 0x0011 0xffff at -14 flowid 200:2
其中红色的数字是客户端网卡mac地址(可以用arp命令查看客户端mac地址),前面的8位是mac地址的后8位,后面的4位是mac地址的前4位,该语句可以限制mac地址为00115BB3DB90的客户端下载速度不超过600kbit。
下面是匹配目地mac地址的语法(M0-M5是mac地址)
(match destination MAC):
tc filter add dev eth1 parent 1: protocol ip prio 5 u32 match u16 
  0x0800 0xffff at -2 match u32 0xM2M3M4M5 0xffffffff at -12 match u16 0xM0M1 0xffff at -14 flowid 1:40
下面是匹配源mac地址的语法(M0-M5是mac地址)
(match source MAC):
tc filter add dev eth1 parent 1: protocol ip prio 5 u32 match u16 
  0x0800 0xffff at -2 match u16 0xM4M5 0xffff at -4 match u32 
  0xM0M1M2M3 0xffffffff at -8 flowid 1:40



u32过滤器的基本用法(http://www.study-area.org/tips/adv-route/Adv-Routing-HOWTO-11.html)

"u32" 分类器 (The "u32" classifier)

 

U32 过滤器是目前实作中所能找到的最强劲的过滤器。它完全依靠杂凑表(hashing tables)﹐配合众多过滤规则而变得扎实耐用。

 

最简单的做法是﹐U32 过滤器有一整列的记录(records)﹐各自包含两个字段﹕选择器(selector)和动作(action)。选择器(后面会介绍)﹐会与当前处理的 IP 封包做比较﹐当碰到第一个符合的封包﹐然后就作出相应的动作。最简单的动作﹐是将封包送至指定的 CBQ 类别去。

 

我们可用 tc filter 命令程序去设定过滤器﹐一共有 3 个部份﹕过滤器的规格(specification)﹑选择器﹑以及动作。过滤器规则可以如下定义﹕

tc filter add dev IF [ protocol PROTO ]
                     [ (preference|priority) PRIO ]
                     [ parent CBQ ]

其中的 protocol 字段说明过滤器所适用的协议﹐我们这里只就 ip 协议进行讨论。至于 preference(偏好值) 字段(也可以用priority 来代替)﹐设定当前过滤器的优先值。这很重要﹐因为您或许会有好几个过滤器(规则列表)﹐各自拥有不同的优先值。每一列规则按照规则新增顺序通过﹐然后才处理低优先值(高偏好值)的规则列。最后的 parent 字段定义出过滤器所属的 CBQ 树顶(如 1:0)。

 

以上选项均适用于所有过滤器﹐非 U32 独美。

 

U32 选择器 (U32 selector)

 

U32 选择器包含式样(pattern)定义﹐以比对当前处理的封包。它一丝不苟的定义出哪些封包标头的位(bits)要用来比对﹐心无旁骛﹐然却四两拨千斤。不如让我们看看以下范例﹐直接取自一个复杂且真实的过滤器﹕

# filter parent 1: protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:3 
  match 00100000/00ff0000 at 0

我们暂时不用管第一行 --- 全部参数度是用来描述过滤器之杂凑表而已。且让我们仔细看看关于选择器那一行﹐也就是带 match 关键词的那行。选择器会比对第 2 个 byte 为 0x10(0010) 的 IP 标头。或许您已猜到﹐那个 00ff 数字就是比对屏蔽(mask)。目前为 0xff﹐所以﹐这个 byte 只能是 0x10。然后 at 关键词意思是说﹐这个比对是从指定的 offset(以 bytes 算)开始 --- 在目前范例中﹐在封包的一开始处。换成我们的人类语言来说的话﹐如果封包的 Type of Serice 字段带有 `low delay` 位设定﹐那这个比对就符合了。

 

(译者注﹕假如读者不清楚 IP 封包标头的排列规则﹐可参考读者网站﹕ http://www.study-area.org/network/network_packet.htm)

 

让我们在看看另一个规则吧﹕

# filter parent 1: protocol ip pref 10 u32 fh 800::803 order 2051 key ht 800 bkt 0 flowid 1:3 
  match 00000016/0000ffff at nexthdr+0

此处﹐有一个 nexthdr 选项﹐代表 IP 封包里面的下一个标头﹐例如上层协议的标头。这个比对也是从下一个标头的一开始处进行。比对应该出现在标头首 32-bit 中的第二个字(word)。在 TCP 和 UDP 协议里﹐此字段包含封包目的端埠口(port)。此数字以 big-endian 格式显示﹐例如 older 位排前面﹐所以我们只要将0x0016 换成十进制就是 22 了﹐换而言之﹐如果这是 TCP 的话﹐那他就是 SSH 服务。正如您所猜的﹐如果离开相关承接(我们后面再述)﹐这个比对会变得不明所以。

 

当我们对前述都有一定了解之后﹐就会发现如下这个选择器其实蛮好理解的﹕match c0a80100/ffffff00 at 16 。我们只要从 IP 标头开始﹐比对第 17 个 byte 起的 3 个 byte 即可。这会比对所有目的地为网络192.168.1/24 的封包(译者注﹕将十六进制的 c0.q8.01.00 换成十进制就是 192.168.1.0﹔而 ff.ff.ff.00则是 255.255.255.0)。看过这些范例之后﹐然后让我们将所学的归纳一下吧。

 

通用选择器 (General selectors)

 

通用选择器定义出式样(pattern)﹑屏蔽(mask)﹑还有封包内容里关于比对式样的 offsest。使用通用选择器﹐您实际上可以比对 IP (或上层) 标头里的每一个单独的位(bit) 。比较后面介绍的特定选择器﹐它们更难读写。通用选择器的语法如下﹕

match [ u32 | u16 | u8 ] PATTERN MASK [ at OFFSET | nexthdr+OFFSET]

u32u16﹑或 u8 这些关键词﹐各自指定位里的式样长度。PATTERN 和 MASK 必须接在前面关键词定义的长度后面。至于 OFFSET 参数﹐则以 byte 为单位﹐指定开始比对的 offset 所在。如果 nexthdr+ 有设定﹐那么offset 则相对的从上层协议标头开始算起。

 

范例﹕

# tc filter add dev ppp14 parent 1:0 prio 10 u32 
     match u8 64 0xff at 8 
     flowid 1:4

如果存活期(TTL)为 64 的话﹐封包就符合比对。从 IP 标头数起﹐第 8 个 byte 开始就是 TTL 字段了。

# tc filter add dev ppp14 parent 1:0 prio 10 u32 
     match u8 0x10 0xff at nexthdr+13 
     protocol tcp 
     flowid 1:3 

此规则仅比对带 ACK 位设定的 TCP 封包。这里我们可以看到一个范例中使用两个选择器﹐最终结果则将两个结果用 AND 逻辑运算得出。如果我们仔细的看看 TCP 标头结构图﹐我们会发现 ACK 位﹐是 TCP 标头第 14个 byte 算起(at nexthdr+13)第 2 个 older 位(0x10)。至于第二个选择器﹐如果我们想试试克难的方法﹐不透过特定选择器上使用 protocol tcp (而是用通用选择器)的话﹐可这样写﹕ match u8 0x06 0xff at 9﹐ 因为 TCP 的协议号码是 6 (译者注﹕在 Linux 里面﹐您可以从 /etc/protocols 这个档案﹐得知各种协议的号码)﹐位于 IP 标头的第 10 个 byte。相对而言﹐在此范例中﹐我们不能用特定选择器来做第一个比对 ---这是因为没有特定选择器可以比对 TCP ACK 位于之故。

 

特定选择器 (Specific selectors)

 

如下表格列出了本章作者所从 tc 程序中发现的全部特定选择器。他们帮您省掉许多工作﹐同时让您的过滤器设定更具可读性。

 

FIXME: 表格存放位置 --- 存于另外的档案﹕selector.html。

 

FIXME: 只有波兰语 :-(

 

FIXME: 有待转成 sgml 格式。

 

范例:

# tc filter add dev ppp0 parent 1:0 prio 10 u32 
     match ip tos 0x10 0xff 
     flowid 1:4

以上规则会比对那些 TOS 字段设为 0x10 的封包。TOS 字段从封包的第 2 个 byte 开始﹐并占一个 byte 的长度﹐这样好比我们另写一个相等的通用选择器﹕match u8 0x10 0xff at 1。由此﹐我们就可以一窥 U32 过滤器的内里乾坤 --- 特定规则都会被转换为通用规则﹐同时以此形式存于核心内存之内。举一反三 --- tcp和 udp 选择器也是如法泡制﹐这也是为何您不能用单独的 match tcp dst 53 0xffff 选择器﹐来比对那些送给特定埠口(port) 的 TCP 封包 --- 它们也同时比对送至此埠口的 UDP 封包。另外﹐您不要忘了指定协议哦﹐并且最后产生如下规则﹕

# tc filter add dev ppp0 parent 1:0 prio 10 u32 
        match tcp dst 53 0xffff 
        match ip protocol 0x6 0xff 
        flowid 1:2
原文地址:https://www.cnblogs.com/CasonChan/p/5033949.html