免费注册 查看新帖 |

Chinaunix

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

[求助]在netfilter挂载点对sk_buff进行操作的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-11-02 10:51 |只看该作者 |倒序浏览
本帖最后由 令人愉悦的忧伤 于 2010-11-02 14:12 编辑

两台主机(A,B)通信,A->B发送数据报。
A,B都加载模块。A发时,对数据报进行“包裹”;B收时,进行“解包”。我所说的“包裹”,就是在ip包头和四层数据之间,添加一个数据结构(保存一些信息);“解包”时恢复原数据。
基本思路是:仿照aodv-uu网关功能的实现。在A(192.168.3.3)的NF_IP_LOCAL_OUT,对源为192.168.3.3的skb_buff进行重新封装(申请一个新的skb_buff,把原始报的所有数据复制进新skb_buff,并在ip包头和四层数据之间添加一个数据结构,然后释放原始skb_buff),然后然后让新的skb_buff沿netfiter继续流动;在B(192.168.3.4)的NF_IP_PRE_ROUTING,对源为192.168.3.3的sk_buff,进行恢复。

但是,我测试发现在A的NF_IP_LOCAL_OUT对192.168.3.3的skb_buff做任何修改都会引起内核崩溃,不知缘故,特来求救。
测试所用的内核版本是2.6.28.10
代码如下
  1. /*#define _KERNEL_ */
  2. /*#define _KERNEL_ */
  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. #include <linux/netfilter.h>
  6. #include <linux/skbuff.h>
  7. #include <linux/ip.h>
  8. #include <linux/netdevice.h>
  9. #include <linux/if_ether.h>
  10. #include <linux/if_packet.h>
  11. #include <net/tcp.h>
  12. #include <linux/netfilter_ipv4.h>
  13. #include <linux/timer.h>
  14. #include <net/xfrm.h>
  15. #include <linux/netdevice.h>
  16. #include <linux/inet.h>

  17. #define NF_IP_PRE_ROUTING        0
  18. #define NF_IP_LOCAL_IN        1
  19. #define NF_IP_FORWARD  2
  20. #define NF_IP_LOCAL_OUT         3
  21. #define NF_IP_POST_ROUTING 4

  22. /*定义新的四层协议*/
  23. #define IPPROTO_MIPE 55

  24. /*在ip包头和四层数据之间添加数据结构*/
  25. struct ip_add_hdr
  26. {
  27.   u_int8_t protocol;
  28.   u_int8_t res:7;
  29.   u_int8_t s:1;
  30.   u_int16_t check;
  31.   u_int32_t saddr;
  32. };

  33. u_int16_t
  34. my_re_check (u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
  35. {
  36.   u_int32_t diffs[] = { oldvalinv, newval };
  37.   return
  38.     csum_fold (csum_partial
  39.                ((char *) diffs, sizeof (diffs), oldcheck ^ 0xFFFF));
  40. }

  41. /* Simple function (based on R. Stevens) to calculate IP header checksum */
  42. static u_int16_t
  43. ip_csum (unsigned short *buf, int nshorts)
  44. {
  45.   u_int32_t sum;

  46.   for (sum = 0; nshorts > 0; nshorts--)
  47.     {
  48.       sum += *buf++;
  49.     }

  50.   sum = (sum >> 16) + (sum & 0xffff);
  51.   sum += (sum >> 16);

  52.   return ~sum;
  53. }

  54. /*重新封包*/
  55. struct sk_buff *
  56. ip_mpkt_encapsulate (struct sk_buff *skb, __u32 src)
  57. {
  58.   struct ip_add_hdr *ipahr;
  59.   struct sk_buff *nskb;
  60.   struct iphdr *iph;
  61. /*复制原始数据到新sk_buff*/
  62.   nskb = skb_copy_expand (skb, skb_headroom (skb),
  63.                           skb_tailroom (skb) + sizeof (struct ip_add_hdr),
  64.                           GFP_ATOMIC);
  65.   if (nskb == NULL)
  66.     {
  67.       printk ("Could not allocate new skb\n");
  68.       kfree_skb (skb);
  69.       return NULL;
  70.     }
  71.   if (skb->sk != NULL)
  72.     skb_set_owner_w (nskb, skb->sk);
  73.   iph = (struct iphdr *) skb->network_header;

  74.   skb_put (nskb, sizeof (struct ip_add_hdr));

  75.   memcpy (nskb->data, skb->data, (iph->ihl << 2));
  76.   memcpy (nskb->data + (iph->ihl << 2) + sizeof (struct ip_add_hdr),
  77.           skb->data + (iph->ihl << 2), skb->len - (iph->ihl << 2));

  78.             
  79.   memcpy (nskb->data + (iph->ihl << 2),
  80.                                 skb->data + (iph->ihl << 2), skb->len - (iph->ihl << 2));

  81.   kfree_skb (skb);
  82.   skb = nskb;

  83.   iph = (struct iphdr *) skb->data;
  84.   skb->network_header = skb->data;
  85. /*对添加的数据结构进行赋值*/
  86.   ipahr = (struct ip_add_hdr *) (skb->data + (iph->ihl << 2));
  87.   ipahr->protocol = iph->protocol;
  88.   ipahr->s = 0;
  89.   ipahr->res = 0;
  90.   ipahr->check = 0;
  91.   ipahr->saddr = iph->saddr;
  92. /*修改ip包头*/
  93.   iph->saddr = src;
  94.   iph->protocol = IPPROTO_MIPE;
  95.   iph->tot_len = htons (ntohs (iph->tot_len) + sizeof (struct ip_add_hdr));
  96.   ipahr->check = ip_csum ((unsigned short *) ipahr, 4);
  97.   
  98.   ip_send_check (iph);
  99.   if (iph->id == 0)
  100.     {
  101.       if (skb->dst)
  102.         ip_select_ident (iph, skb->dst, NULL);
  103.     }

  104.   return skb;
  105. }

  106. /*解包*/
  107. struct sk_buff *
  108. ip_mpkt_decapsulate (struct sk_buff *skb)
  109. {
  110.   struct ip_add_hdr *ipahdr;
  111.   struct iphdr *iph = (struct iphdr *) skb->network_header;

  112.   ipahdr = (struct ip_add_hdr *) ((char *) iph + (iph->ihl << 2));

  113.   iph->protocol = ipahdr->protocol;
  114.   iph->saddr = ipahdr->saddr;

  115.   memmove (skb->data + (iph->ihl << 2),
  116.            skb->data + (iph->ihl << 2) + sizeof (struct ip_add_hdr),
  117.            skb->len - (iph->ihl << 2) - sizeof (struct ip_add_hdr));
  118.   skb_trim (skb, skb->len - sizeof (struct ip_add_hdr));

  119.   iph = (struct iphdr *) skb->data;
  120.   skb->network_header = skb->data;

  121.   iph->tot_len = htons (ntohs (iph->tot_len) - sizeof (struct ip_add_hdr));

  122.   ip_send_check (iph);
  123.   return skb;
  124. }






  125. unsigned int
  126. hook_func (unsigned int hooknum,
  127.            struct sk_buff *skb,
  128.            const struct net_device *in,
  129.            const struct net_device *out, int (*okfn) (struct sk_buff *))
  130. {
  131.   struct sk_buff *sb = skb;
  132.   __u32 src_ip_n;    /* _n 代表网络字节序 */
  133.   __u32 des_ip_n;    /* _n 代表网络字节序 */
  134.   struct iphdr *iph =ip_hdr (sb);
  135.   if (iph == NULL)
  136.     return NF_ACCEPT;

  137.    src_ip_n =iph->saddr;
  138.    des_ip_n = iph->daddr;

  139.   switch (hooknum)
  140.     {
  141. /*NF_IP_PRE_ROUTING解包处理*/   
  142. case NF_IP_PRE_ROUTING:
  143.       if (iph->protocol == IPPROTO_MIPE && src_ip_n == in_aton("192.168.3.3"))
  144.         {
  145.             ip_mpkt_decapsulate(skb);
  146.           return NF_ACCEPT;
  147.         }
  148.       break;
  149. /*NF_IP_LOCAL_OUT重新封包处理*/        
  150. case NF_IP_LOCAL_OUT:
  151.        if (src_ip_n == in_aton("192.168.3.3"))
  152.         {

  153.                 skb = ip_mpkt_encapsulate (skb, iph->saddr);
  154.          
  155.           if (!skb)
  156.             return NF_STOLEN;
  157.           ip_route_me_harder(skb,RTN_LOCAL);
  158.         }
  159.     }
  160.   return NF_ACCEPT;
  161. }


  162. static struct nf_hook_ops hook_ops[] = {
  163.   {
  164.    .hook = hook_func,
  165.    .owner = THIS_MODULE,
  166.    .pf = PF_INET,
  167.    .hooknum = NF_IP_PRE_ROUTING,
  168.    .priority = NF_IP_PRI_FIRST,
  169.    },
  170.   {
  171.    .hook = hook_func,
  172.    .owner = THIS_MODULE,
  173.    .pf = PF_INET,
  174.    .hooknum = NF_IP_LOCAL_OUT,
  175.    .priority = NF_IP_PRI_FIRST,
  176.    },
  177. };



  178. static int __init nat_init (void)
  179. {
  180.   int ret;
  181.   ret = nf_register_hook (&hook_ops[0]);

  182.   if (ret < 0)
  183.     goto cleanup_hook0;

  184.   ret = nf_register_hook (&hook_ops[1]);

  185.   if (ret < 0)
  186.     goto cleanup_hook1;
  187.   return ret;
  188. cleanup_hook1:
  189.   nf_unregister_hook (&hook_ops[1]);
  190. cleanup_hook0:
  191.   nf_unregister_hook (&hook_ops[0]);
  192.   return ret;
  193. }


  194. void __exit nat_exit (void)
  195. {
  196.   nf_unregister_hook (&hook_ops[1]);
  197.   nf_unregister_hook (&hook_ops[0]);
  198. }

  199. module_init(nat_init);
  200. module_exit(nat_exit);
复制代码

论坛徽章:
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
2 [报告]
发表于 2010-11-02 10:56 |只看该作者
  struct sk_buff *sb = skb;
  unsigned char src_ip[4];
  unsigned char des_ip[4];
  struct iphdr *iph = (struct iphdr *) (skb->network_header);

  *(unsigned int *) src_ip = ip_hdr (sb)->saddr;
  *(unsigned int *) des_ip = ip_hdr (sb)->daddr;
  if (iph == NULL)
    return NF_ACCEPT;


这块代码写的有点乱啊。而且前后的一致性不太好

BTW,贴出 oops 信息吧

论坛徽章:
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-11-02 10:58 |只看该作者
  struct sk_buff *sb = skb;
  unsigned char src_ip[4];
  unsigned char des_ip[4];
  struct iphdr *iph = (struct iphdr *) (skb->network_header);

  *(unsigned int *) src_ip = ip_hdr (sb)->saddr;
  *(unsigned int *) des_ip = ip_hdr (sb)->daddr;
  if (iph == NULL)
    return NF_ACCEPT;

改成这样,看起来舒服一些
  struct sk_buff *sb = skb;
  unsigned char src_ip[4];
  unsigned char des_ip[4];
  struct iphdr *iph =ip_hdr (sb);
  if (iph == NULL)
    return NF_ACCEPT;

  *(unsigned int *) src_ip =iph->saddr;
  *(unsigned int *) des_ip = iph->daddr;

论坛徽章:
0
4 [报告]
发表于 2010-11-02 12:09 |只看该作者
本帖最后由 platinum 于 2010-11-02 12:16 编辑

改成这样,看起来舒服些

  1.   struct sk_buff *sb = skb;
  2.   __u32 src_ip_n;    /* _n 代表网络字节序 */
  3.   __u32 des_ip_n;    /* _n 代表网络字节序 */
  4.   struct iphdr *iph =ip_hdr (sb);
  5.   if (iph == NULL)
  6.     return NF_ACCEPT;

  7.   src_ip_n =iph->saddr;
  8.   des_ip_n = iph->daddr;
复制代码

  1. #include <linux/inet.h>

  2. /*NF_IP_PRE_ROUTING解包处理*/   
  3. case NF_IP_PRE_ROUTING:
  4.       if (iph->protocol == IPPROTO_MIPE && src_ip_n == in_aton("192.168.3.3"))
  5.         {
  6.             ip_mpkt_decapsulate(skb);
  7.           return NF_ACCEPT;
  8.         }
  9.       break;
复制代码

评分

参与人数 1可用积分 +18 收起 理由
Godbach + 18 多谢白金兄分享。内核编程最好还是按照内核 ...

查看全部评分

论坛徽章:
0
5 [报告]
发表于 2010-11-02 12:22 |只看该作者
其实上面的代码仍然有些冗余了,根本不需要中间变量 src_ip_n 和 des_ip_n
比较时之用用 iph->saddr 和 iph->daddr 就行了

论坛徽章:
0
6 [报告]
发表于 2010-11-02 12:55 |只看该作者
本帖最后由 令人愉悦的忧伤 于 2010-11-02 13:01 编辑

谢楼上2位对小弟编码上的问题提出的批评指正,已经改过来了
因为写这个代码想实现的不仅是这些功能,上述代码是后来发帖时现改的,可能有些冗余信息,写得也比较挫,大家将就看看吧

oops什么意思,小弟新手,还望各位指导

论坛徽章:
0
7 [报告]
发表于 2010-11-02 13:17 |只看该作者
你把旧的skb释放了,那么该hook点上其他func怎么办?
我建议新的skb 重新走__ip_local_out,包裹要标记,避免迭代包裹。

具体是:
你的func 进入时,发现已skb 已”包裹“,就返回NF_ACCEPT,
否则进行”包裹“并让新的skb 来一次__ip_local_out,  然后返回NF_DROP(让协议栈丢掉旧的skb);

论坛徽章:
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
8 [报告]
发表于 2010-11-02 13:44 |只看该作者
嗯,现在 hook 的接口中 skb 已经变成 1 级指针,也就是说在 hook 函数内部修改 skb 指针指向的内存,对 其他 hook 函数是不可见的,其他 hook 函数读取的仍旧是原始的那块内存,但是又被你释放了,so panic...

论坛徽章:
0
9 [报告]
发表于 2010-11-02 14:22 |只看该作者
回复 7# 奇门遁甲-lu
你把旧的skb释放了,那么该hook点上其他func怎么办?

谢谢你的建议。
NF_ACCEPT的话可以继续,让该挂载点上的其他函数继续检查新的sk_buff,应该也没问题吧,可以试试看吧

论坛徽章:
0
10 [报告]
发表于 2010-11-02 14:32 |只看该作者
本帖最后由 令人愉悦的忧伤 于 2010-11-02 14:33 编辑

回复 8# Godbach
嗯,现在 hook 的接口中 skb 已经变成 1 级指针,也就是说在 hook 函数内部修改 skb 指针指向的内存,对 其他 hook 函数是不可见的,其他 hook 函数读取的仍旧是原始的那块内存,但是又被你释放了,so panic...

恩,确实是个问题,aodv_uu关于网关那块也是这么写的,也没有太细想。

那不把旧的sk_buff释放,而是NF_STOLEN,而让新的sk_buff调用okfn( )会有什么问题吗?
如果要让新的sk_buff进入挂载点,是不是只有像7L说的那样做?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP