iptables的maual的BUG一节:
BUGS
Bugs? What's this? ;-) Well, you might want to have a look at
OK,我去netfilter的bug站点...唉,这帮人啊!
我相信很多人都遇到过iptables规则无法删除的问题,比如我使用了xtables-addons中的condition这个match模块,当我成功设置了一个规则后:
iptables -t mangle -A PREROUTING -m condition --condition xtt -j ACCEPT
然后尝试用上述规则的D命令删除之:
iptables -t mangle -D PREROUTING -m condition --condition xtt -j ACCEPT
我得到了一个报错:
iptables: Bad rule (does a matching rule exist in that chain?).
然而如果我用rulenum的方式则可以成功删除!即先查找上述规则的rulenum,然后删除该num标示的规则就可以成功,但是这样就多了一个步骤,我将不能仅仅通过简单的A或者D控制一条规则的增加和删除,于是,我必须找出来到底是哪里出了问题。
iptables规则的布局
iptables规则保存在哪里呢?答案是保存在内核里面,并且一条规则处在一个连续的地址空间,布局大致如下:
元数据|match1|match2|...|target
注意,用户态是不保存规则的,每当你要删除一条规则的时候,你必须提供足够的你要删除的规则的详细信息,然后和内核中的规则群做比对,只有在精确匹配成功,即没有任何二义性的匹配成功后,该规则直接从内核中删除,具体的通信机制(Netlink,ioctl等)不重要,重要的是,iptables有多种删除规则的方式。
iptables规则的删除
1.按照rulenum删除
内核会为每一条保存进内核的iptables规则进行编号索引,该索引在特定的HOOK点/TABLE上是唯一的,因此使用rulenum进行删除不会有任何二义性。
2.精确匹配删除
精确匹配删除比较复杂,你必须给出规则的每一个细节,正如你当初添加该规则时一样,和添加动作唯一不同的是,你要把-A改成-D。这种精确匹配删除的成功依赖的就是用户提供的所有match字段,target字段必须和内核中保存的一模一样,精确到字节级别的匹配。如果哪怕有一个字节不匹配,就会有二义性,删除失败。
3.整表整链删除
当你调用iptables -t $table -F的时候,该表下面的所有规则就不复存在了,由于规则隶属于表,因此不会有二义性。整链删除含义类似,主要是由于,不管表也好,链也罢,都是具体规则的上级组织,正所谓皮之不存,毛将焉附!
问题之所在
以我实际碰到的问题为例,xt_condition的info结构体如下:
enum {
CONDITION_NAME_LEN = 31,
};
struct xt_condition_mtinfo {
char name[CONDITION_NAME_LEN];
__u8 invert;
/* Used internally by the kernel */
void *condvar __attribute__((aligned(8)));
};
注意那个注释!condvar字段只用在内核。如果你用过condition模块,你会知道,它除了一个名称参数之外,不会携带任何参数,也就是说仅仅iptables的命令不会对condvar进行任何设置,默认可能是NULL,然而整个结构体,当然也包括condvar,在添加规则的时候,全都会被注入内核并被内核保存起来,condvar的赋值是在内核中进行的,它表示一个内核结构体的地址。
如果说现在使用精确匹配法则删除一条使用condition的规则,会怎样?内核中的该规则中的xt_condition_mtinfo结构体的condvar字段已经被赋值为一个内核态地址空间的地址,它会被用来和用户态的相同结构体进行字节级的比对,第一个字段name显然是精确匹配的,第二个字段也没有问题,condition_parse会处理得很好,然而第三个condvar字段就不匹配了,用户给出的规则中该字段为0,而内核态中该字段是一个地址!因此就会导致删除失败!
推荐阅读: