免费注册 查看新帖 |

Chinaunix

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

在NF_IP_PRE_ROUTING挂钩子修改skbuff问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-07-18 22:17 |只看该作者 |倒序浏览
本帖最后由 kangle000 于 2010-07-19 06:59 编辑

以下代码是在2.6.31内核中执行的,根据send_rst改写的。但是代码存在以下几个问题:
1、捕包发现ip头的version字段为0,offset的值不为0,校验出错。
2、udp头的内容好像并没有更改。
3、us指针指向的内容并没有改变
4、经常死机
请大家帮我看看是哪里的问题
  1. #ifndef __KERNEL__
  2. #define __KERNEL__
  3. #endif

  4. #ifndef MODULE
  5. #define MODULE
  6. #endif

  7. #include <linux/module.h>
  8. #include <linux/kernel.h>
  9. #include <linux/skbuff.h>
  10. #include <linux/netfilter.h>
  11. #include <linux/netfilter_ipv4.h>
  12. #include <linux/ip.h>
  13. #include <linux/if_ether.h>
  14. #include <linux/netdevice.h>
  15. #include <linux/if_packet.h>
  16. #include <net/tcp.h>
  17. #include <net/udp.h>
  18. #include <asm/string.h>

  19. #define ETH "eth0"
  20. #define ETH_HLEN 14
  21. #define UDP_HLEN 8
  22. #define loc_swap(a,b) {(a)=(a)^(b);(b)=(a)^(b);(a)=(a)^(b);}
  23. #define DNSPORT 53
  24. #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
  25. #define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
  26. #define FLAGS 0x8003

  27. typedef struct _rfc1035_header rfc1035_header;
  28. struct _rfc1035_header {
  29.     unsigned short id;
  30.         unsigned int qr:1;
  31.         unsigned int opcode:4;
  32.         unsigned int aa:1;
  33.         unsigned int tc:1;
  34.         unsigned int rd:1;
  35.         unsigned int ra:1;
  36.         unsigned int rcode:4;
  37.         unsigned short qdcount;
  38.         unsigned short ancount;
  39.         unsigned short nscount;
  40.         unsigned short arcount;
  41. };  

  42. unsigned int modify_dns(unsigned int hooknum,
  43.                                                 struct sk_buff *skb,
  44.                                                 const struct net_device *in,
  45.                                                 const struct net_device *out,
  46.                                                 int (*okfn)(struct sk_buff *))
  47. {
  48.         struct net_device *dev;
  49.         struct iphdr *iph = NULL;
  50.         struct ethhdr *eth = NULL;
  51.         struct udphdr *udph = NULL;
  52.         unsigned char mac_temp[ETH_ALEN] = {0};
  53.         unsigned int iph_len;
  54.         char *dns_data;
  55.         int data_len;
  56.         rfc1035_header *qh;
  57.         unsigned short *us;
  58.         printk("before dev = in\n");
  59.         dev = dev_get_by_name(&init_net, "eth0");
  60.         if(NULL == dev)
  61.                 goto out;

  62.         if(NULL == skb)
  63.                 return NF_ACCEPT;
  64.         printk("before decide packet type\n");       
  65.         if((IPPROTO_UDP != (ip_hdr(skb)->protocol))
  66.                         && (DNSPORT != udp_hdr(skb)->dest))
  67.                 return NF_ACCEPT;
  68.        
  69.         iph = (struct iphdr *)ip_hdr(skb);
  70.         iph_len = iph->ihl << 2;
  71.         printk("iphdr_len=%d data_len=%d sip=%04x dip=%04x\n", iph_len, ntohs(iph->tot_len), iph->saddr, iph->daddr);
  72.         udph = udp_hdr(skb);
  73.         printk("source=%hu dest=%hu len=%d\n", ntohs(udph->source), ntohs(udph->dest), ntohs(udph->len));
  74.         data_len = ntohs(udph->len) - UDP_HLEN;
  75.         dns_data = (char *)udph + UDP_HLEN;
  76.         printk("before modify dns data\n");       
  77.         qh = (rfc1035_header *) dns_data;

  78.         us = (unsigned short *)(dns_data + 2);
  79.         *us = *us | FLAGS;
  80.         printk("flags=%hu\n", *us);
  81.        
  82.         loc_swap(iph->saddr, iph->daddr);
  83.         loc_swap(udph->source, udph->dest);
  84.         iph->ihl = sizeof(struct iphdr)/4;
  85.         iph->tot_len = htons(skb->len);
  86.        
  87.         printk("source=%uh dest=%uh len=%d\n", ntohs(udph->source), ntohs(udph->dest), ntohs(udph->len));
  88.         printk("before udp checksum\n");
  89.         udph->check = 0;
  90.         udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, ntohs(udph->len), IPPROTO_UDP, 0);
  91.         iph->frag_off = htons("IP_DF");
  92.         iph->id = 0;
  93.         printk("before ip checksum\n");
  94.         iph->check = 0;
  95.         iph->check = ip_fast_csum((unsigned char *)iph, iph_len);
  96.        

  97.         printk("before skb_push\n");
  98.         eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
  99.         if(NULL == eth)
  100.                 goto out;
  101.         if(NULL != eth->h_source)
  102.                 printk("SOURCE:" MAC_FMT "\n", MAC_ARG(eth->h_source));
  103.         if(NULL != eth->h_dest)
  104.                 printk("DEST:" MAC_FMT "\n", MAC_ARG(eth->h_dest));

  105.         printk("before swap mac adress\n");
  106.         memcpy(mac_temp, (unsigned char *)eth->h_dest, ETH_ALEN);
  107.         memcpy(eth->h_dest, (unsigned char *)eth->h_source, ETH_ALEN);
  108.         memcpy(eth->h_source, mac_temp, ETH_ALEN);


  109.         printk("before send packet\n");
  110.         if (0 > dev_queue_xmit(skb))
  111.                 goto out;
  112.         return NF_ACCEPT;

  113. out:
  114.         printk("in out:  ");
  115.         if (NULL != skb)
  116.         {
  117.                 printk("skb not null\n");
  118.                 dev_put(dev);
  119.                 kfree_skb(skb);
  120.         }
  121.         return NF_ACCEPT;
  122. }

  123. static struct nf_hook_ops dns_ops[] = {
  124.         {
  125.                 .hook = modify_dns,
  126.                 .owner = THIS_MODULE,
  127.                 .pf    = PF_INET,
  128.                 .hooknum = NF_IP_PRE_ROUTING,
  129.                 .priority = NF_IP_PRE_ROUTING,
  130.         }
  131. };

  132. static int __init init(void)
  133. {
  134.         int ret;
  135.         printk("before nf_register_hooks\n");
  136.         ret = nf_register_hooks(dns_ops, ARRAY_SIZE(dns_ops));
  137.         if(ret < 0)
  138.         {
  139.                 printk("can't register dns_ops!\n");
  140.                 return ret;
  141.         }
  142.         printk("insmod dns_ops ok!\n");
  143.         return 0;
  144. }

  145. static void __exit fini(void)
  146. {
  147.         nf_unregister_hooks(dns_ops, ARRAY_SIZE(dns_ops));
  148.         printk("rmmod dns_ops ok!\n");
  149. }

  150. module_init(init);
  151. module_exit(fini);
  152. MODULE_LICENSE("GPL");
  153. MODULE_AUTHOR("KAL");
  154. MODULE_DESCRIPTION("MODIFY DNS PACKETS");
复制代码

论坛徽章:
0
2 [报告]
发表于 2010-07-19 07:00 |只看该作者
请大家帮帮忙看是什么问题

论坛徽章:
0
3 [报告]
发表于 2010-07-19 08:17 |只看该作者
你首先要保证sk_buff是可写的,没有分段的,这些你的代码都没有处理

论坛徽章:
0
4 [报告]
发表于 2010-07-19 09:29 |只看该作者

  1. .priority = NF_IP_PRE_ROUTING,
复制代码
没见过这样的 prio 设置

  1.          iph = (struct iphdr *)ip_hdr(skb);
  2.          iph_len = iph->ihl << 2;
复制代码
这个算出来可不是 IP 头的长度

  1.         udph = udp_hdr(skb);
复制代码
在这里你无法通过这种方法计算 UDP 的头指针,这里是网络层,还没到系统的传输层

论坛徽章:
0
5 [报告]
发表于 2010-07-19 09:47 |只看该作者
没见过这样的 prio 设置这个算出来可不是 IP 头的长度在这里你无法通过这种方法计算 UDP 的头指针,这里是网 ...
platinum 发表于 2010-07-19 09:29



    谢谢,那个prio确实错了。但是ip头长度不就是iph->ihl *4 吗。那个udp指针是没问题的。udp_hdr调用了

  1. static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
  2. {
  3.         return skb->head + skb->transport_header;
  4. }
复制代码
来计算udp头

论坛徽章:
0
6 [报告]
发表于 2010-07-19 09:57 |只看该作者
谢谢,那个prio确实错了。但是ip头长度不就是iph->ihl *4 吗。

你从哪里看到的 IP 头长度就是 iph->ihl * 4 了?
如果是这样,那么 iph->tot_len 又是做什么的?
建议恶补一下 TCP/IP 详解卷一的 IP 那一章,基本概念都错了!

那个udp指针是没问题的。udp_hdr调用了

   1. static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
   2. {
   3.         return skb->head + skb->transport_header;
   4. }

复制代码
来计算udp头

你能确保此时 skb->transport_header 的数据是正确的吗?

论坛徽章:
0
7 [报告]
发表于 2010-07-19 10:07 |只看该作者
当前工作的L3层,udp_hdr返回的仍然是L3层头部,不是L4头部

论坛徽章:
0
8 [报告]
发表于 2010-07-19 23:53 |只看该作者
回复 1# kangle000


    1   不要在自己模块中想当然的修改数据包内容,因为有可能这个数据包被其它模块引用,如果是这样,你需要copy一份。可以使用skb_ip_make_writable
    2   不打算修改内容,但想查看L4头部时,不要直接使用偏移来取,使用skb_header_pointer, 因为你不能保证L4头部是线性的

论坛徽章:
0
9 [报告]
发表于 2010-07-20 09:02 |只看该作者
回复 8# lyl19


    哦,这样啊,谢谢指导。我看了skb_header_pointer函数,它是把L4的头部拷贝出来,然后查看。但是我现在需求就是要修改数据包。或者拷贝一份修改之后把原来的数据包drop掉。如果我要取L4头部,还要修改它,不用直接取偏移地址用什么函数

论坛徽章:
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
10 [报告]
发表于 2010-07-20 09:32 |只看该作者
如果去四层头部的话,就可以用iph头部加偏移取得四层头部。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP