讲了filter、ct、nat 现在剩下最后一个知名模块mangle,但是自身虽然知道内核支持修改数据包的信息,它主要用在策略路由和qos上.我们就具体分析一下.
mangle表主要用于修改数据包的TOS(Type Of Service,服务类型)、TTL(Time To Live,生存周期)指以及为数据包设置Mark标记,以实现Qos(Quality Of Service,服务质量)调整以及策略路由等应用,由于需要相应的路由设备支持,因此应用并不广泛
关于mangle模块,内核里主要有三个功能模块:mark match、MARK target 、CONNMARK target。
1)CONNMARK target的选项
选项 功能
--set-mark value[/mask] 给链接跟踪记录打标记。
--save-mark [--mask mask] 将数据包上的标记值记录到链接跟踪记录上。
--restore-mark [--mask mask] 重新设置数据包的nfmark值。
2)MARK target 的选项
选项 功能
--set-mark value 设置数据包的nfmark值。
--and-mark value 数据包的nfmark值和value进行按位与运算。
--or-mark value 数据包的nfmark值和value进行按或与运算。
3)MARK match的选项
选项 功能
[!] --mark value[/mask] 数据包的nfmark值与value进行匹配,其中mask的值为可选的
先说说CONNMARK和MARK的区别:
同样是打标记,但CONNMARK是针对连接的,而MARK是针对单一数据包的
这两种机制一般都要和ip rule中的fwmark联用,实现对满足某一类条件的数据包的策略路由
1.对连接打了标记,只是标记了连接,没有标记连接中的每个数据包。标记单个数据包,也不会对整条连接的标记有影响。二者是相对独立的
2. 路由判定(routing decision)是以单一数据包为单位的。或者说,在netfilter框架之外,并没有连接标记的概念。或者说,ip命令只知道MARK, 而不知道CONNMARK是什么。
3.关键在于:给所有要进行ip rule匹配的单一数据包打上标记。方法一般有二:用MARK直接打,或者用CONNMARK –restore-mark把打在连接上的标记转移到数据包上。
下面就代码分析一下:
mangle它的模块代码在iptable_mangle.c中它的初始化工作和之前的filter、nat类似.Mangle作用在所有的hook点
1.首先iptable_mangle.c的主要工作就是注册和初始化mangle表
注册mangl钩子函数.
2.其实我们发现除了ct的hook是单独处理外,其他的filter、nat、mangle都是通过hook之后调用ipt_do_table来处理,要么重点在match里,要么重点在target处理中.但是这个基本机制框架没变. 即都是通过rules.
3.首先我们就看看 –j MARK –set-mark 1 这个target的执行
4.其实应该分析下规则的下发.
先看一条命令:
#iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 80 -j MARK --set-mark 1
即targetMARK
内核里是这样的
点击(此处)折叠或打开
static unsigned int
mark_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_mark_tginfo2 *info = par->targinfo;
skb->mark = (skb->mark & ~info->mask) ^ info->mark;
return XT_CONTINUE;
} 它就是设置了skb->mark而已,并没有改变报文内容.
我们看看具体命令怎么配置:
mark match:它依赖MARK target 先设置标记
#iptables -A POSTROUTING -t mangle -m mark ! --mark 0 -j ACCEPT
MARK target:
iptables -t mangle -A PREROUTING -i eth0 -p tcp--dport 80 -j MARK --set-mark 1
CONNMARK target:
#iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark
然后我们看看几种应用场景:
1. 策略路由
现要求对内网进行策略路由,所有通过TCP协议访问80端口的数据包都从ChinaNet线路出去,而所有访问UDP协议53号端口的数据包都从Cernet线路出去
打标记:
点击(此处)折叠或打开
iptables -t mangle -A PREROUTING -i eth0 -p tcp--dport 80 -j MARK --set-mark 1 iptables -t mangle -A PREROUTING -i eth0 -p udp--dprot 53 -j MARK --set-mark 2 建表:
点击(此处)折叠或打开
ip rule add from all fwmark 1 table 10
ip rule add from all fwmark 2 table 20 策略路由:
点击(此处)折叠或打开
ip route add default via 10.10.1.1 dev eth1 table 10
ip route add default via 10.10.2.1 dev eth2 table 20 2. CONNMARK和MARK结合:
点击(此处)折叠或打开
1.iptables -A POSTROUTING -t mangle -j CONNMARK --restore-mark
2.iptables -A POSTROUTING -t mangle -m mark ! --mark 0 -j ACCEPT
3.iptables -A POSTROUTING -m mark --mark 0 -p tcp --dport 21 -t mangle -j MARK --set-mark 1
4.iptables -A POSTROUTING -m mark --mark 0 -p tcp --dport 80 -t mangle -j MARK --set-mark 2
5.iptables -A POSTROUTING -m mark --mark 0 -t mangle -p tcp -j MARK --set-mark 3
6.iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark 1)第1条规则就是完成了将链接跟踪上的标记记录到该连接上的每一个数据包中;
2)第2条规则判断数据包的标记,如果不为0,则直接ACCEPT。如果数据包上没有被打标记,则交由后面的规则进行匹配并打标记。这里为什么会出现经过了CONNMARK模块,数据包仍未被打标记呢?可以想到,如果一条链接的第1个数据包经过第1条规则处理之后,由于ct->mark为0,所以其数据包的标记skb->nfmark应该仍旧为0,就需要进行后面规则的匹配。
3)第3~5条规则,则按照匹配选项对符合规则的数据包打上不同的标记
4)第6条规则,则是把之前打的标记信息保存到ct里.
3.结合tc的应用:
点击(此处)折叠或打开
#tc fi add dev eth0 parent 1: pref 1000 protocol ip handle 13 fw flowid 1:1 #iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST ACK -m length --length40:60 -j MARK --set-mark 13 题外扯点其他东西:
mangle可以修改IP包头的TTL值,修改ip报头dscp值(QOS)
Iptables下MSS数据调整模块TCPMSS使用
比如说string模块其实挺强大的,本身已经支持过来报文data里特征码,但是功能依然有缺陷所以才有了l7的插件.
点击(此处)折叠或打开
Iptables –A OUTPUT –m string –string “” –algo bm –j DROP 关于algo参数的查找算法 它在内核里是通过textsearch_register注册的
内核默认注册了名字为fsm、bm 、kmp
简单的就说这么多,具体应用需求还需要我们自己去挖掘和开发.