+ -
当前位置:首页 → 问答吧 → 关于Netfilter中连接跟踪机制的方向问题 Original or Relay

关于Netfilter中连接跟踪机制的方向问题 Original or Relay

时间:2010-10-26

来源:互联网

内核版本2.6.30
由于之前一直在2.4版本的内核,现在刚刚改用2.6.30,其内核一些数据结构和实现机制都发送了改变,因此变写了几个小程序去验证性的跑一下,结果却发现了这个另我费解的问题。。。
本意是在测试最新版本内核中连接跟踪模块的使用情况,在新版本内核中通过struct nf_conn代替之前的ip_conntrack结构,但其中主要的一个数据结构
struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]并没有太大改变。
好了,问题来了,按照道理说这个连接数组中        IP_CT_DIR_ORIGINAL代表的应该是原始方向的数据包,其源地址应该与ip头部中的源地址是相同的,而IP_CT_DIR_REPLY代表回复方向的数据包,其目的地址才应该为本机地址。(这是我之前的理解)
但是在我写的一个小测试用例中,得到的结果恰恰相反,ORIGINAL方向的连接的目的地址才是ip头部中的源地址,RELAY方向连接的源地址才是ip头部中的目的地址,很是困惑,想不明白,难道说是我之前对于连接跟踪方向一直理解错了吗?。。。
现在贴一下我的代码以及测试结果,有些长,各位看官不要嫌麻烦,因此这个问题真的很困扰我,急求给为牛人解惑,小弟不胜感激。。。。
  1. #include  <linux/module.h>
  2. #include  <linux/init.h>
  3. #include  <linux/kernel.h>

  4. #include  <linux/types.h>
  5. #include  <linux/errno.h>
  6. #include  <linux/sched.h>
  7. #include  <linux/slab.h>
  8. #include  <linux/fs.h>
  9. #include  <linux/poll.h>
  10. #include  <linux/spinlock.h>
  11. #include        <linux/ioctl.h>
  12. #include        <linux/proc_fs.h>
  13. #include        <linux/list.h>
  14. #include        <linux/param.h>
  15. #include        <asm/uaccess.h>
  16. #include        <asm/atomic.h>


  17. #include        <linux/skbuff.h>
  18. #include        <linux/in.h>
  19. #include        <linux/ip.h>
  20. #include        <linux/tcp.h>
  21. #include        <linux/udp.h>
  22. #include        <linux/icmp.h>
  23. #include        <linux/netdevice.h>
  24. #include        <linux/netfilter.h>
  25. #include        <linux/netfilter_ipv4.h>
  26. #include <linux/netfilter/nf_conntrack_tuple_common.h>
  27. #include <net/netfilter/nf_conntrack.h>

  28. #include        <linux/byteorder/generic.h>
  29. #include        <linux/if_arp.h>
  30. #include        <linux/if_ether.h>
  31. #include        <linux/if_packet.h>
  32. #include        <linux/delay.h>

  33. #define HASH_SIZE 1024

  34. static unsigned int       
  35. conn_hook(unsigned int hook,
  36.                            struct sk_buff *skb,
  37.                            const struct net_device *indev,
  38.                            const struct net_device *outdev,
  39.                            int        (*okfn)(struct sk_buff *))
  40. {
  41.         struct nf_conn *conn;
  42.         struct nf_conntrack_tuple_hash tuple_list;
  43.         struct nf_conntrack_tuple orig_tuple;
  44.         struct nf_conntrack_tuple relay_tuple;
  45.         struct iphdr *iph;
  46.         struct tcphdr *tcph;
  47.         u32 ip_saddr;
  48.         u32 ip_daddr;
  49.        
  50.         if(!skb)
  51.                 {
  52.                         return NF_ACCEPT;       
  53.                 }
  54.         printk("Hook functions\n");
  55.         //获取连接跟踪数据结构
  56.         conn = (struct nf_conn *)(skb->nfct);
  57.         if(!conn)
  58.                 {
  59.                         printk("no nf_conntrack \n");
  60.                         return NF_ACCEPT;       
  61.                 }
  62.                
  63. #if 1
  64.         iph = ip_hdr(skb);
  65.         tcph = tcp_hdr(skb);
  66.         printk("ipv4 src addr: %d.%d.%d.%d,dst addr:%d.%d.%d.%d\n", NIPQUAD(iph->saddr),NIPQUAD(iph->daddr));
  67.         printk("ipv4 tcp src port %d, dst port %d\n",tcph->source,tcph->dest);
  68.         tuple_list = conn->tuplehash[IP_CT_DIR_REPLY];
  69.         orig_tuple = conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
  70.         relay_tuple = conn->tuplehash[IP_CT_DIR_REPLY].tuple;
  71.         ip_saddr = orig_tuple.src.u3.ip;
  72.         ip_daddr = orig_tuple.dst.u3.ip;
  73.         printk("ipv4 original src addr: %d.%d.%d.%d,dst src addr: %d.%d.%d.%d\n", NIPQUAD(ip_saddr),NIPQUAD(ip_daddr));
  74.         printk("src original port: %d,dst prot: %d\n",orig_tuple.src.u.tcp.port,orig_tuple.dst.u.tcp.port);       
  75.         ip_saddr = relay_tuple.src.u3.ip;
  76.         ip_daddr = relay_tuple.dst.u3.ip;
  77.         printk("ipv4 relay src addr: %d.%d.%d.%d,dst src addr: %d.%d.%d.%d\n", NIPQUAD(ip_saddr),NIPQUAD(ip_daddr));
  78.         printk("src relay port: %d,dst prot: %d\n",relay_tuple.src.u.tcp.port,relay_tuple.dst.u.tcp.port);
  79. #endif

  80.         return NF_ACCEPT;
  81. }

  82. static struct nf_hook_ops conn_hook_ops = {
  83. .hook =       conn_hook,
  84. .pf =         PF_INET,
  85. .hooknum =    NF_INET_POST_ROUTING,
  86. .priority =    NF_IP_PRI_LAST-1,
  87. };

  88. static int conn_init(void)
  89. {
  90.         int ret = 0;
  91. //注册钩子
  92.         ret = nf_register_hook(&conn_hook_ops);
  93.         if (ret < 0)
  94.         {
  95.                 printk("register isatap hook ops error!\n");
  96.         return -ENOMEM;
  97.         }
  98.     return 0;
  99. }

  100. static void conn_exit(void)
  101. {
  102.         nf_unregister_hook(&conn_hook_ops);       
  103.         printk("Unregister conntrack hook ok\n");
  104.         return;
  105. }

  106. module_init(conn_init);
  107. module_exit(conn_exit);

  108. MODULE_LICENSE("GPL");
复制代码
然后使运行结果;
  1. Hook functions
  2. ipv4 src addr: 192.168.1.4,dst addr:192.168.1.221
  3. ipv4 tcp src port 5632, dst port 2824
  4. ipv4 original src addr: 192.168.1.221,dst src addr: 192.168.1.4
  5. src original port: 2824,dst prot: 5632
  6. ipv4 relay src addr: 192.168.1.4,dst src addr: 192.168.1.221
  7. src relay port: 5632,dst prot: 2824
  8. Hook functions
  9. ipv4 src addr: 192.168.1.4,dst addr:192.168.1.221
  10. ipv4 tcp src port 5632, dst port 2824
  11. ipv4 original src addr: 192.168.1.221,dst src addr: 192.168.1.4
  12. src original port: 2824,dst prot: 5632
  13. ipv4 relay src addr: 192.168.1.4,dst src addr: 192.168.1.221
  14. src relay port: 5632,dst prot: 2824
  15. Hook functions
  16. ipv4 src addr: 192.168.1.4,dst addr:192.168.1.221
  17. ipv4 tcp src port 5632, dst port 2824
  18. ipv4 original src addr: 192.168.1.221,dst src addr: 192.168.1.4
  19. src original port: 2824,dst prot: 5632
  20. ipv4 relay src addr: 192.168.1.4,dst src addr: 192.168.1.221
  21. src relay port: 5632,dst prot: 2824
  22. Hook functions
  23. ipv4 src addr: 192.168.1.4,dst addr:192.168.1.221
  24. ipv4 tcp src port 5632, dst port 10760
  25. ipv4 original src addr: 192.168.1.221,dst src addr: 192.168.1.4
  26. src original port: 10760,dst prot: 5632
  27. ipv4 relay src addr: 192.168.1.4,dst src addr: 192.168.1.221
  28. src relay port: 5632,dst prot: 10760
复制代码
从这个结果来看,ip首部的源地址和目的地址对应的是relay方向的连接包,通过tcp头部的端口号也证明了这一点。。。
而且我刚刚看了下ipv4_pkt_to_tuple,它所做的工作的确是从ip首部自动的源地址开始,读取两个32字节的变量,分别赋给tuple中的源地址和目的地址,按照道理说应该不会出错啊,可是我怎么得出了这么个结果。。。

这个真的很困惑,本人也是刚开始学Netfilter不久,还请各位高手帮忙解答。。。

作者: luoyan_xy   发布时间: 2010-10-26

貌似我忘记考虑端口的网络字节序的问题了。。。。
各位请直接跳过这个问题

作者: luoyan_xy   发布时间: 2010-10-26