天天看点

关于Netfilter NF_HOOK宏的outdev参数bug

正确的方式要么是不传递,要么是传递指针的地址,即地址的地址。

因 为在该HOOK点可能存在多个HOOK函数,每一个函数都有可能改变skb的路由,即调用reroute,比如NAT,比如IP Mark等,这样后续的HOOK函数看到的依然是旧的outdev参数,而不是reroute之后的skb_dst(skb)->dev。

设置默认路由

0.0.0.0/0 via 192.168.1.1 eth0

设置策略路由

iptables -t mangle -A OUTPUT -d 1.1.1.1 -j MARK --set-mark 100

ip rule fwmark 100 table my

ip route add 0.0.0.0/0 via 192.168.2.1 dev eth1 table my

防止mark 100的数据包从eth0出去(这实际上只是为了展现问题而添加的多余的一条规则)

iptables -A OUTPUT -d 1.1.1.1 -o eth0 -j DROP

效 果是到达1.1.1.1的数据包被DROP掉了。是的,策略路由确实生效了,问题在于进入OUTPUT的filter HOOK函数的时候,outdev还是旧的outdev。因为OUTPUT处在路由之后,如果其中的mangle表改变了skb的mark,那么会 reroute,不幸的是,reroute并无法改变OUTPUT点上NF_HOOK的outdev参数值!

办法很多,依次介绍:

a.使用setsockopt打mark而不是iptables打mark,绕开OUTPUT和路由的暧昧关系;

b. 修改NF_HOOK的dev参数为struct net_device **类型,然后在reroute中重路由成功后执行*out = (struct dst_entry*)skb_dst(skb)->dev;从而改变NF_HOOK中的outdev的值;

c.去掉NF_HOOK宏的outdev参数,需要时从skb_dst(skb)->dev中实时获取;

很简单,在ipt_do_table的开头位置,即变量声明的完结处,加入下面的代码:

实时替换掉参数定义的out值。

d.使用非传值机制!C语言是传值的啊!使用连续的******可以为了寻址一个字节遍历整个内存,即整个内存只存储一个字节的值,其它的都被填满为它的直接或者间接的地址,地址,地址...

一个实体只能同时存在于一个位置!就像人一样,进入了一个房间,外面就没有这个人了,可惜编程语言不是这样的。

 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1423292

继续阅读