免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 7082 | 回复: 16
打印 上一主题 下一主题

NETFILTER的BUG?-九贱,白金兄弟请进 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-03 13:23 |只看该作者 |倒序浏览
这问题起源于这个贴:
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,大家一起来看看?

论坛徽章:
0
2 [报告]
发表于 2008-11-03 16:44 |只看该作者
并不是BUG,而是你没了解netfilter的机制。
因为NAT是基于nf_conntrack的,并且NAT的信息是在NEW状态时才会设置的。skb的NAT动作是根据所属conntrack的配置来进行,并不是孤立的。

论坛徽章:
0
3 [报告]
发表于 2008-11-03 16:50 |只看该作者
ShadowStar 说的对,NAT 在初次进入 netfilter 框架(state NEW)时就已经把源、转换后的 conntrack 表创建好了,以后的传输只需查表
net/ipv4/netfilter/nf_conntrack_proto_icmp.c

  1. 108 /* Called when a new connection for this protocol found. */
  2. 109 static int icmp_new(struct nf_conn *conntrack,
  3. 110                     const struct sk_buff *skb, unsigned int dataoff)
  4. 111 {
  5. 112         static const u_int8_t valid_new[] = {
  6. 113                 [ICMP_ECHO] = 1,
  7. 114                 [ICMP_TIMESTAMP] = 1,
  8. 115                 [ICMP_INFO_REQUEST] = 1,
  9. 116                 [ICMP_ADDRESS] = 1
  10. 117         };
  11. 118
  12. 119         if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
  13. 120             || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
  14. 121                 /* Can't create a new ICMP `conn' with this. */
  15. 122                 pr_debug("icmp: can't create new conn with type %u\n",
  16. 123                          conntrack->tuplehash[0].tuple.dst.u.icmp.type);
  17. 124                 NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
  18. 125                 return 0;
  19. 126         }
  20. 127         atomic_set(&conntrack->proto.icmp.count, 0);
  21. 128         return 1;
  22. 129 }
复制代码

  1. 83 /* Returns verdict for packet, or -1 for invalid. */
  2. 84 static int icmp_packet(struct nf_conn *ct,
  3. 85                        const struct sk_buff *skb,
  4. 86                        unsigned int dataoff,
  5. 87                        enum ip_conntrack_info ctinfo,
  6. 88                        int pf,
  7. 89                        unsigned int hooknum)
  8. 90 {
  9. 91         /* Try to delete connection immediately after all replies:
  10. 92            won't actually vanish as we still have skb, and del_timer
  11. 93            means this will only run once even if count hits zero twice
  12. 94            (theoretically possible with SMP) */
  13. 95         if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
  14. 96                 if (atomic_dec_and_test(&ct->proto.icmp.count)
  15. 97                     && del_timer(&ct->timeout))
  16. 98                         ct->timeout.function((unsigned long)ct);
  17. 99         } else {
  18. 100                 atomic_inc(&ct->proto.icmp.count);
  19. 101                 nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
  20. 102                 nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout);
  21. 103         }
  22. 104
  23. 105         return NF_ACCEPT;
  24. 106 }
复制代码

而且,ICMP 包比较特殊,在收到 REPLY 之后自动从 conntrack 列表中清除

论坛徽章:
0
4 [报告]
发表于 2008-11-03 16:50 |只看该作者
原帖由 ShadowStar 于 2008-11-3 16:44 发表
并不是BUG,而是你没了解netfilter的机制。
因为NAT是基于nf_conntrack的,并且NAT的信息是在NEW状态时才会设置的。skb的NAT动作是根据所属conntrack的配置来进行,并不是孤立的。


可是为什么返回的PING包没有被SNAT呢? 我试了, TCP连接也是一样的.

论坛徽章:
0
5 [报告]
发表于 2008-11-03 22:52 |只看该作者
原帖由 Au_Hank 于 2008-11-3 16:50 发表


可是为什么返回的PING包没有被SNAT呢? 我试了, TCP连接也是一样的.


上面都说了是链接状态为new的时候才会设置 nat信息, 简单的说就是只有一个链接的第一个包才会去匹配配置的SNAT, 在上面的例子中第一包匹配不中那条规则, 所以nat信息就没有设置, 返回的包是这条链接上的第二个包了, 所以自然不会被snat

论坛徽章:
0
6 [报告]
发表于 2008-11-05 06:21 |只看该作者
白金跟我同个时间16:50发了个回复啊,太巧了,我都没有注意到。

你们说的NAT的NEW的问题我没有注意到,回头再去看看代码。谢谢了。

做了下测试,发现无论是主动发出的包,还是回复的包,SKB-》FLAG都没有被设置成IPSKB_REROUTED。所以我的猜测是错误的。

[ 本帖最后由 Au_Hank 于 2008-11-5 07:34 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2008-11-26 10:48 |只看该作者
不是一个BUG,NAT是基于ORIGINAL方向,NEW状态的。也就是说只在ORIGINAL方向调用ipt_do_table( &nat_table )把nat的信息保存到了ip_conntrack里面,在返回的方向上只根据ip_conntrack中的ip_nat_info做NAT操作,而不会去调用ipt_do_table( &nat_table )这个方法,所以返回的包没有匹配到POSTROUTING上nat表里面的SNAT规则

论坛徽章:
0
8 [报告]
发表于 2008-12-01 00:31 |只看该作者
原帖由 Au_Hank 于 2008-11-3 13:23 发表
到底是为什么要做!(IPCB(skb)->flags & IPSKB_REROUTED)这个测试呢?我看了九贱兄弟关于IPSEC的分析:
http://blog.chinaunix.net/u/12313/showart_326041.html
是否因为IPSEC引入这个检查?如果是的话,为什么要这么做呢,九贱兄能否解释下啊?

这个blog是九贱的吗?

论坛徽章:
0
9 [报告]
发表于 2009-07-08 17:30 |只看该作者
不明白为什么用NF_HOOK_COND宏然后做这个测试!(IPCB(skb)->flags & IPSKB_REROUTED)

记得以前版本的内核是用NF_HOOK宏的,没有这个参数来测试


请大家帮解释一下,多谢了先!

论坛徽章:
0
10 [报告]
发表于 2009-07-13 10:53 |只看该作者
内核模块开发,是不是 必须重新下载内核进行内核编译,才能进行开发?新装的系统 难道就不行吗 ?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP