- 论坛徽章:
- 0
|
这问题起源于这个贴:
http://linux.chinaunix.net/bbs/thread-1041617-1-1.html
我有两台单网卡机器A、B,他们连在同一交换机上,
A机器如下配置:
ifconfig eth0 192.168.2.1
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -j SNAT --to-source 192.168.16.2
B机器如下配置:
ifconfig eth0 192.168.2.3
现在我在A机器pingB机器,ping不通,因为ping包被修改源地址,B机器无法返回ping包
我再用B机器pingA机器,可以通,我的问题是A机器返回给B的ping回应包为何没有被iptables修改源地址,如果被修改的话,源地址将会变为
192.168.16.2,那么B机器将不接受这个包才对,因为B没有给192.168.16.2发过包,但是却可以ping通,并且A返回的回应PING包源地址没有被
改变为192.168.16.2,还是192.168.2.1,这是为什么呢?iptables不起作用吗?
我测试了一下,果然是这样。我感觉是一个NETFILTER的BUG。下面是代码的分析:
在"ip_output.c"里面:
279 return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
280 ip_finish_output,
281 !(IPCB(skb)->flags & IPSKB_REROUTED));
如果0==!(IPCB(skb)->flags & IPSKB_REROUTED), 则NF_HOOK_COND直接执行ip_finish_output, 就是说不执行
netfilter的功能,所以没有PREROUTING-->OUTPUT-->POSTROUTING的过程。具体在"include/linux/netfilter.h"
里面可以看出来:
198 static inline int nf_hook_thresh(int pf, unsigned int hook,
199 struct sk_buff **pskb,
200 struct net_device *indev,
201 struct net_device *outdev,
202 int (*okfn)(struct sk_buff *), int thresh,
203 int cond)
204 {
205 if (!cond)
206 return 1;
..........
212 }
249 #define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \
250 ({int __ret; \
251 if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, INT_MIN, cond)) == 1)\
252 __ret = (okfn)(skb); \
253 __ret;})
IPCB的定义在include/net/ip.h里面:
#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
所以!(IPCB(skb)->flags & IPSKB_REROUTED)展开后就是:
!(((struct inet_skb_parm*)((skb)->cb))->flags & IPSKB_REROUTED)
到底是为什么要做!(IPCB(skb)->flags & IPSKB_REROUTED)这个测试呢?我看了九贱兄弟关于IPSEC的分析:
http://blog.chinaunix.net/u/12313/showart_326041.html
是否因为IPSEC引入这个检查?如果是的话,为什么要这么做呢,九贱兄能否解释下啊?
另外,对于应该做POSTROUTING CHECK的包,比如这里的例子,是什么原因造成FLAG被设置成IPSKB_REROUTED
而没有进行检查呢?我猜测是发送包使用了接收包的SKBBUFF,而接收包的SKBBUFF是肯定先经过了PREROUTING的,所以FLAG被设置了。如果是
这样的话,我感觉这显然是一个BUG。
这个“BUG”对本机器主动发出的包没有影响,原因是主动发出的包用的skb_buff是系统分配的,没有经理PREROUTING的过程,
所以((skb)->cb))->flags没有被设置成IPSKB_REROUTED。
我个人感觉这应该是一个BUG,大家一起来看看? |
|