免费注册 查看新帖 |

Chinaunix

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

netfilter连接跟踪 resolve_normal_ct函数中的疑问(已解决) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-08-10 20:37 |只看该作者 |倒序浏览
本帖最后由 __dreamcatcher 于 2010-08-12 10:39 编辑

本人在看netfilter的连接跟踪模块时,遇到了些疑问,请大家给与指点。
    在nf_conntrack_in()的函数中调用了resolve_normal_ct,我在看这个函数时有点不明白的是if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)这句话什么时候才可以执行?
static inline struct nf_conn *
resolve_normal_ct(struct net *net,
                  struct sk_buff *skb,
                  unsigned int dataoff,
                  u_int16_t l3num,
                  u_int8_t protonum,
                  struct nf_conntrack_l3proto *l3proto,
                  struct nf_conntrack_l4proto *l4proto,
                  int *set_reply,
                  enum ip_conntrack_info *ctinfo)
{       
        if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
                             dataoff, l3num, protonum, &tuple, l3proto,
                             l4proto)) {
                pr_debug("resolve_normal_ct: Can't get tuple\n");
                return NULL;
        }

        /* look for tuple match */
        h = nf_conntrack_find_get(net, &tuple);
       
        ct = nf_ct_tuplehash_to_ctrack(h);


        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 {
                 .......
                *set_reply = 0;
        }
      .......
}
首先分析nf_ct_get_tuple()函数,在函数中存在这么一个问题,就是dst.dir始终被初始化为IP_CT_DIR_ORIGINAL,如下标记所示:
bool
nf_ct_get_tuple(const struct sk_buff *skb,
                unsigned int nhoff,
                unsigned int dataoff,
                u_int16_t l3num,
                u_int8_t protonum,
                struct nf_conntrack_tuple *tuple,
                const struct nf_conntrack_l3proto *l3proto,
                const struct nf_conntrack_l4proto *l4proto)
{
        memset(tuple, 0, sizeof(*tuple));

        tuple->src.l3num = l3num;
        if (l3proto->pkt_to_tuple(skb, nhoff, tuple) == 0)
                return false;

        tuple->dst.protonum = protonum;
        tuple->dst.dir = IP_CT_DIR_ORIGINAL;

        return l4proto->pkt_to_tuple(skb, dataoff, tuple);
}
在以后的nf_conntrack_find_get() 和 nf_ct_tuplehash_to_ctrack()函数中也没有发现tuple的dst.dir被修改,所以感觉resolve_normal_ct()函数中的
if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) {  ,,,,,,   }段一直无法执行。

知道我的某些地方理解的不正确,还请各位大虾帮忙指点一下,谢谢了!
此内核版本为linux-2.6.33.2

论坛徽章:
0
2 [报告]
发表于 2010-08-11 09:54 |只看该作者
自己顶,求教!

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
3 [报告]
发表于 2010-08-12 09:25 |只看该作者
我的理解reply对于TCP而言,你发送了SYN包之后,收到了服务器的SYN+ACK的时候

论坛徽章:
0
4 [报告]
发表于 2010-08-12 09:54 |只看该作者
本帖最后由 __dreamcatcher 于 2010-08-12 10:01 编辑
我的理解reply对于TCP而言,你发送了SYN包之后,收到了服务器的SYN+ACK的时候
Godbach 发表于 2010-08-12 09:25

谢谢Godbach兄,我不理解的是,钩子函数nf_conntrack_in()调用resolve_normal_ct,resolve_normal_ct()调用nf_ct_get_tuple,而nf_ct_get_tuple将每一个接收的数据包的dst.dir  初始化为IP_CT_DIR_ORIGINAL,而且在reslove_normal_ct函数中dst.dir却好像始终未发生变化,所以不知道这个函数中的if(NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY){...}怎么执行的,请大哥再指点一下吧。谢谢!

论坛徽章:
0
5 [报告]
发表于 2010-08-12 10:08 |只看该作者
本帖最后由 独孤九贱 于 2010-08-12 10:13 编辑

这是哪跟哪儿呀??这个tuple跟那个NF_CT_DIRECTION(h) 都不是一个东东!!!

nf_ct_get_tuple是把当前的skb翻译成tuple,做为查找状态表的一个标的。此时,无法知道状态的方向(因为还没有去查),所以

tuple->dst.dir = IP_CT_DIR_ORIGINAL;

只是一个赋初值的操作。

当根据这个翻译的tuple找到hash表中相应的记录项了,这个记录项虽然也是tuple,但是跟刚才那个是不同滴,这下才有真正的方向了。
简单地讲,前者是skb的tuple,后都是netfilter hash表中的tuple。它们是不同的东东,但是一个特殊情况下,前者会变成后者,就是在初始状态下,后面来分析。

进一步地讲,hash表中的记录项tuple中的方向,又是何时确认的呢?

这是因为,状态表中hash记录项的tuple一共有两个(而不是一个),一个是请求方向,一个是应答方向,查看新建连接项的代码:
static struct nf_conntrack_tuple_hash *
init_conntrack(struct net *net,
               const struct nf_conntrack_tuple *tuple,
               struct nf_conntrack_l3proto *l3proto,
               struct nf_conntrack_l4proto *l4proto,
               struct sk_buff *skb,
               unsigned int dataoff)
{
……
        if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) {
                pr_debug("Can't invert tuple.\n");
                return NULL;
        }
……

这是根据当前原始的(请求方向)的tuple,翻转一个应答方向的tuple出来:
bool
nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
                   const struct nf_conntrack_tuple *orig,
                   const struct nf_conntrack_l3proto *l3proto,
                   const struct nf_conntrack_l4proto *l4proto)
{
        memset(inverse, 0, sizeof(*inverse));

        inverse->src.l3num = orig->src.l3num;
        if (l3proto->invert_tuple(inverse, orig) == 0)
                return false;

        inverse->dst.dir = !orig->dst.dir;

        inverse->dst.protonum = orig->dst.protonum;
        return l4proto->invert_tuple(inverse, orig);
}

inverse->dst.dir = !orig->dst.dir;

就是你要的答案了!!!

紧跟着,在分配状态项ct的函数nf_conntrack_alloc中,又有:
struct nf_conn *nf_conntrack_alloc(struct net *net,
                                   const struct nf_conntrack_tuple *orig,
                                   const struct nf_conntrack_tuple *repl,
                                   gfp_t gfp)
{
……
        ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
        ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.pprev = NULL;
        ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
        ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev = NULL;
……

这下就记录了正反两个方向的tuple了。

回头查询hash的动作,它找到匹备的orig,就是请求方向啦,如果匹备了repl,就是答应方向了。

注意到这里:
ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
这里是赋值操作,不是指针操作。所以,前面说的“前者变后者”也不准确,应该是一个拷贝操作,是父子关系,而并不是其本身。所以,skb 的tuple和ct 的tuple终究是不同的东东!!!

剧终!!

评分

参与人数 1可用积分 +18 收起 理由
Godbach + 18 九贱兄的回复就是精彩

查看全部评分

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
6 [报告]
发表于 2010-08-12 10:22 |只看该作者
九贱兄一出马,问题就解决了

论坛徽章:
0
7 [报告]
发表于 2010-08-12 10:41 |只看该作者
本帖最后由 __dreamcatcher 于 2010-08-12 10:51 编辑

回复 5# 独孤九贱
谢谢九贱大哥和 Godbach大哥,受益匪浅!继续学习
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP