iptables的手册也不能尽信啊

简介:
我很自豪的找到了一种截获数据包的秘籍,那就是使用conntrack的ctdir,第一步当然是看iptables的man手册,发现:
--ctdir {ORIGINAL|REPLY}
    Match packets that are flowing in the specified direction. If this flag is not specified at all, matches  packets
    in both directions.
于是我写下来以下以下的规则:
iptables -t mangle -A PREROUTING -d x.x.x.x/a -i eth2 -m conntrack --ctdir ORIGINAL -j MARK --set-xmark 100 iptables -t mangle -A PREROUTING -s y.y.y.y/b -i eth2 -m conntrack --ctdir REPLY -j MARK --set-xmark 100
我这么写有什么问题吗?绝对没有!懂iptables的人都知道我要做什么,我要做的就是截获两类流,一个是主动访问x.x.x.x/a的流,另一类是y.y.y.y/b被访问的流。OK,一切看起来很好。然而当我将上述规则实际部署的时候,出问题了,截取竟然是相反的流,也就是说,截取了两类流,一类是x.x.x.x/a被访问的流,另一类是主动访问y.y.y.y/b的流...我该怎么办?很长一段时间,我一直认为我错了,google过,百度过,毫无结果。作为一个成熟的用了这么久的iptables,不会犯错,一定是我错了。因此我的下一个计划就是找到:我哪里错了?
        这只是一个安慰罢了,其实我知道我没有错,按照英文字面理解,REPLY就是代表返回的意思。我的实际计划应该是,找到一个证据证明自己没有错。这个证据我在互联网找了好久,因此我决定看一下代码。首先我看的是conntrack的通用match函数,内核版本为2.6.32。通过match函数在/net/netfilter/xt_conntrack.c中:
static bool conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par,              u16 state_mask, u16 status_mask) {     const struct xt_conntrack_mtinfo2 *info = par->matchinfo;     enum ip_conntrack_info ctinfo;     const struct nf_conn *ct;     unsigned int statebit;      ct = nf_ct_get(skb, &ctinfo);     /* 这些都不是当前所关注的,当前只关注ctdir */     ...          if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&         (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^         !!(info->invert_flags & XT_CONNTRACK_DIRECTION))         return false;      /* 这些都不是当前所关注的,当前只关注ctdir */     ...     return true; }
为了思路更清晰,将帮助函数/宏也列举出来:
enum ip_conntrack_dir {     IP_CT_DIR_ORIGINAL,     IP_CT_DIR_REPLY,     IP_CT_DIR_MAX }; enum ip_conntrack_info {     /* Part of an established connection (either direction). */     IP_CT_ESTABLISHED,      /* Like NEW, but related to an existing connection, or ICMP error        (in either direction). */     IP_CT_RELATED,      /* Started a new connection to track (only            IP_CT_DIR_ORIGINAL); may be a retransmission. */     IP_CT_NEW,      /* >= this indicates reply direction */     IP_CT_IS_REPLY,      /* Number of distinct IP_CT types (no NEW in reply dirn). */     IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1 }; #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) static inline struct nf_conn * nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo) {     *ctinfo = skb->nfctinfo;     return (struct nf_conn *)skb->nfct; }
然后我们看一下skb->nfctinfo到底在哪里初始化的,实际上不用找也知道是nf_conntrack_in里面的resolve_normal_ct中:
if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) {     *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;     /* Please set reply bit if this packet OK */     *set_reply = 1; } else {  //只要不是返回方向的,都是正向包。     /* Once we've had two way comms, always ESTABLISHED. */     if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {         *ctinfo = IP_CT_ESTABLISHED;     } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {         *ctinfo = IP_CT_RELATED;     } else {         *ctinfo = IP_CT_NEW;     }     *set_reply = 0; } skb->nfct = &ct->ct_general; skb->nfctinfo = *ctinfo;
可见,正方向的数据包的nfctinfo被初始化成了IP_CT_ESTABLISHED,IP_CT_RELATED或者IP_CT_NEW,而这些都比IP_CT_IS_REPLY要小,因此正方向的数据包的CTINFO2DIR肯定是IP_CT_DIR_ORIGINAL(详见CTINFO2DIR宏定义)。另一个证据在init_conntrack函数,它是一个初始化ct的函数,这种情况下ct肯定被认为是正方向的,该函数在最后返回的是&ct->tuplehash[IP_CT_DIR_ORIGINAL],一个IP_CT_DIR_ORIGINAL方向的ct-part。
        现在看看conntrack_mt函数,对于正方向的包,(CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)为1,如果iptables的ctdir设置为ORIGINAL的话,(info->invert_flags & XT_CONNTRACK_DIRECTION))为0(详见ip_conntrack_dir枚举),因此二者异或为1,最终返回false,这不是瞪着眼睛说瞎话吗?对于返回包,也就是反方向的包,反而返回true...起码从代码看来,ip_conntrack将ctdir完全搞反了。因此如果想让你的配置按照你的想法生效,那就要反过来配置:
iptables -t mangle -A PREROUTING -d x.x.x.x/a -i eth2 -m conntrack --ctdir REPLY -j MARK --set-xmark 100 
iptables -t mangle -A PREROUTING -s y.y.y.y/b -i eth2 -m conntrack --ctdir ORIGINAL -j MARK --set-xmark 100

很奇怪,然而正确!要想修正这个问题,除了配置很奇怪的规则之外,只需要去掉一个“!”号即可:
(CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^ !!(info->invert_flags & XT_CONNTRACK_DIRECTION))
改为:
(CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^ !(info->invert_flags & XT_CONNTRACK_DIRECTION))

从“!!(info->invert_flags & XT_CONNTRACK_DIRECTION)”这一行代码来看,笔误的可能性比较大,否则实在想不通为何要用双重否定句。

       令人气愤的是,如此一个问题怎么竟然很少有人提出来啊,难道真的是能用就行吗?或者说真的是我错了?唉,反正不管怎么说,我配反了就能用,配正了就错误!搞了一下午,真TM fuXX the conntrack,怎么就没人管呢?这么成熟的iptables竟然都不可信,茫茫尘世,我还能信谁?



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

相关文章
|
3月前
|
存储 网络协议 网络安全
iptables速查
iptables速查
36 0
|
网络协议 安全 开发者
iptables 命令使用 | 学习笔记
快速学习iptables 命令使用
iptables 命令使用 | 学习笔记
|
Linux 网络安全
iptables简介1及常用命令
第一章:简述 iptables是一个用户态工具,用于操作linux内核部分的netfilter模块(包过滤),用来完成防火墙相关的工作。linux的netfilter工作于2层(开启bridge-nf时刻)和3层(ip层),可以对ip包,二层数据链路包进行操作;而市面上还有一种防火墙是应用层防火墙,可以对应用层包进行检查(过滤)。
1090 0
|
网络协议 Linux 网络安全
|
网络协议 网络安全
|
网络协议 关系型数据库 网络安全
|
Linux 网络安全