修改以及重构SKB

测试环境:
   CentOS5.3 2.6.18
工具:
   sendip和wireshark
   sendip可以发送各种数据包,确实方便.wireshark图形化的显示对于分析整个数据包还是相当不错的...
  
一:内核态基于Netfilter构造数据包
主要有两种方式:
1. alloc_skb申请一个skb结构体,然后根据实际的应用填充不同的成员,或者基于当前数据包的skb,
   调用skb_copy() pskb_copy() skb_copy_expand()等新申请一个nskb,并且拷贝skb的内容。
2. 直接在先前接收到的数据包skb上作修改,主要有源IP、目IP,如果是TCP/UDP协议的话,还有源端口目的端口号。
  就是根据你自己的需求去调整数据包的相关成员即可。然后重新计算各个部分的校验和。

   不管你第一种方式还是第二种方式,你需要知道你也必须知道的就是对于l2 l3 l4层的数据你都必须去构造,我之前就是
由于没有构造L2而郁闷了一天...
   让我们先从一个小程序开始,把5个hook都挂上mac这个函数,主要就是看看l2,对于l3 l4以及应用层我以前的几个帖子里面
已经有很多了,这里就不说了     
  1.    printk("------begin %s--------\n", hooks[hooknum]);
  2.    print_ipproto(iph->protocol);
  3. printk("len is %d, data len is %d\n", nskb->len, nskb->data_len);
  4.    if(nskb->mac_len > 0)
  5.            {
  6.             eth = (struct ethhdr*)(nskb->mac.raw);
  7.             print_mac(eth);       
  8.                    }   
  9.    printk("------end  %s--------\n", hooks[hooknum]);
复制代码

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/netfilter.h>
  5. #include <linux/skbuff.h>
  6. #include <linux/ip.h>
  7. #include <linux/netdevice.h>
  8. #include <linux/if_ether.h>
  9. #include <linux/if_packet.h>
  10. #include <net/tcp.h>
  11. #include <net/udp.h>
  12. #include <net/icmp.h>
  13. #include <linux/netfilter_ipv4.h>

  14. #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
  15. #define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]

  16. MODULE_LICENSE("GPL");
  17. MODULE_AUTHOR("kenthy@163.com");

  18. const char* hooks[] ={ "NF_IP_PRE_ROUTING",
  19.                              "NF_IP_LOCAL_IN",
  20.                              "NF_IP_FORWARD",
  21.                              "NF_IP_LOCAL_OUT",
  22.                              "NF_IP_POST_ROUTING"};

  23. void print_ipproto(int proto)
  24. {
  25. switch(proto)
  26. {
  27.          case IPPROTO_ICMP:
  28.                  printk("%s\n", "IPPROTO_ICMP");
  29.            break;
  30.          case IPPROTO_TCP:
  31.                  printk("%s\n", "IPPROTO_TCP");
  32.            break;
  33.          case IPPROTO_UDP:
  34.                  printk("%s\n", "IPPROTO_UDP");
  35.            break;
  36.          default:
  37.                  printk("%s\n", "other IPPROTO");
  38.          }
  39. }

  40. void print_mac(struct ethhdr* eth)
  41. {
  42. if(eth==NULL)
  43.          return;
  44.         
  45. if(eth->h_source!=NULL)
  46.         printk("SOURCE:" MAC_FMT "\n", MAC_ARG(eth->h_source));

  47. if(eth->h_dest!=NULL)
  48.              printk("DEST:" MAC_FMT "\n", MAC_ARG(eth->h_dest));
  49. }

  50. unsigned int
  51. mac(unsigned int hooknum,
  52.                  struct sk_buff** skb,
  53.                  const struct net_device *in,
  54.                  const struct net_device *out,
  55.                  int (*okfn)(struct sk_buff*))
  56. {
  57.    struct sk_buff* nskb;
  58.    struct iphdr *iph = NULL;
  59.    struct ethhdr* eth;
  60.  
  61.   nskb = *skb;
  62.   if(nskb==NULL)
  63.   {
  64.     printk("%s\n", "*skb is NULL");
  65.     return NF_ACCEPT;
  66.    }
  67.  
  68.   iph = ip_hdr(nskb);
  69.   if(iph == NULL)
  70.   {
  71.     printk("%s\n", "*iph is NULL");
  72.     return NF_ACCEPT;
  73.    }

  74.      
  75.    printk("------begin %s--------\n", hooks[hooknum]);
  76.    print_ipproto(iph->protocol);
  77.    printk("len is %d, data len is %d\n", nskb->len, nskb->data_len);
  78.    if(nskb->mac_len > 0)
  79.            {
  80.             eth = (struct ethhdr*)(nskb->mac.raw);
  81.             print_mac(eth);       
  82.                    }
  83.    else
  84.     printk("%s", "mac is NULL");               
  85.    
  86.    
  87.    printk("------end  %s--------\n", hooks[hooknum]);
  88.  
  89.     return NF_ACCEPT;
  90. }

  91.                             
  92. static struct nf_hook_ops mac_ops[] = {
  93.         {
  94.                 .hook                = mac,
  95.                 .owner                = THIS_MODULE,
  96.                 .pf                = PF_INET,
  97.                 .hooknum        = NF_IP_PRE_ROUTING,
  98.                 .priority = NF_IP_PRI_FIRST,
  99.         },
  100.         {
  101.                 .hook                = mac,
  102.                 .owner                = THIS_MODULE,
  103.                 .pf                = PF_INET,
  104.                 .hooknum        = NF_IP_LOCAL_IN,
  105.                 .priority = NF_IP_PRI_FIRST,
  106.         },
  107.         {
  108.                 .hook                = mac,
  109.                 .owner                = THIS_MODULE,
  110.                 .pf                = PF_INET,
  111.                 .hooknum        = NF_IP_FORWARD,
  112.                 .priority = NF_IP_PRI_FIRST,
  113.         },
  114.         {
  115.                 .hook                = mac,
  116.                 .owner                = THIS_MODULE,
  117.                 .pf                = PF_INET,
  118.                 .hooknum        = NF_IP_LOCAL_OUT,
  119.                 .priority = NF_IP_PRI_FIRST,
  120.         },
  121.         {
  122.                 .hook                = mac,
  123.                 .owner                = THIS_MODULE,
  124.                 .pf                = PF_INET,
  125.                 .hooknum        = NF_IP_PRE_ROUTING,
  126.                 .priority = NF_IP_POST_ROUTING,
  127.         },
  128. };

  129. static int __init init(void)
  130. {
  131.     int ret;
  132.     ret = nf_register_hooks(mac_ops, ARRAY_SIZE(mac_ops));
  133.     if (ret < 0) {
  134.         printk("http detect:can't register mac_ops detect hook!\n");
  135.         return ret;
  136.     }
  137.     printk("insmod mac_ops detect module\n");
  138.     return 0;
  139. }

  140. static void __exit fini(void)
  141. {
  142.     nf_unregister_hooks(mac_ops, ARRAY_SIZE(mac_ops));
  143.     printk("remove mac_ops detect module.\n");
  144. }

  145. module_init(init);
  146. module_exit(fini);
复制代码

  insmod mac.ko加载mac模块后,随便发个ping包
  Jan 10 09:44:13 nfs-client kernel: ------begin NF_IP_LOCAL_OUT--------
Jan 10 09:44:13 nfs-client kernel: IPPROTO_ICMP
Jan 10 09:44:13 nfs-client kernel: len is 84, data len is 0
Jan 10 09:44:13 nfs-client kernel: mac is NULL------end  NF_IP_LOCAL_OUT--------
Jan 10 09:44:13 nfs-client kernel: ------begin NF_IP_PRE_ROUTING--------
Jan 10 09:44:13 nfs-client kernel: IPPROTO_ICMP
Jan 10 09:44:13 nfs-client kernel: len is 84, data len is 0
Jan 10 09:44:13 nfs-client kernel: SOURCE:00:50:56:fa:70:2a
Jan 10 09:44:13 nfs-client kernel: DEST:00:0c:29:4f:de:ac
Jan 10 09:44:13 nfs-client kernel: ------end  NF_IP_PRE_ROUTING--------
Jan 10 09:44:13 nfs-client kernel: ------begin NF_IP_LOCAL_IN--------
Jan 10 09:44:13 nfs-client kernel: IPPROTO_ICMP
Jan 10 09:44:13 nfs-client kernel: len is 84, data len is 0
Jan 10 09:44:13 nfs-client kernel: SOURCE:00:50:56:fa:70:2a
Jan 10 09:44:13 nfs-client kernel: DEST:00:0c:29:4f:de:ac
Jan 10 09:44:13 nfs-client kernel: ------end  NF_IP_LOCAL_IN--------
   可以看到对于挂载在out上的数据包mac已经被剥掉

当接收一个包时,处理n层协议头的函数从n-1层收到一个缓冲区,它的skb->data指向n层协议的头。处理n层协议的函数把本层的指针(例如,L3对应的是skb->nh指针)初始化为skb->data,因为这个指针的值会在处理下一层协议时改变(skb->data将被初始化成缓冲区里的其他地址)。在处理n层协议的函数结束时,在把包传递给n+1层的处理函数前,它会把skb->data指针指向n层协议头的末尾,这正好是n+1层协议的协议头。

发送包的过程与此相反,但是由于要为每一层添加新的协议头,这个过程要比接收包的过程复杂。

sk_buff_003.jpg
2010-01-10 14:40 上传
下载附件 (13.31 KB)


      好的,到现在你已经知道要重新搞一个数据包需要自己来DIY l2 l3 l4当然还有l7如果你想....  
    来先看看skb的几个重要指针吧
unsigned char *head
unsigned char *end
unsigned char *data
unsigned char *tail
它们表示缓冲区和数据部分的边界。在每一层申请缓冲区时,它会分配比协议头或协议数据大的空间。head和end指向缓冲区的头部和尾部,而data和tail指向实际数据的头部和尾部。每一层会在head和data之间填充协议头,或者在tail和end之间添加新的协议数据
  sk_buff_002.jpg
2010-01-10 14:40 上传
下载附件 (7.6 KB)


那么具体操作这些指针呢?
(a)skb_put, (b)skb_push, (c)skb_pull, and (d)skb_reserve
sk_buff_004.jpg
2010-01-10 14:40 上传
下载附件 (38.67 KB)


  再加上dev_queue_xmit这个函数,你已经可以完成整件事了,对你现在有点蒙感觉无从下手,我也是!!! 我是历经几十次的死机才成功的,写这个文章也是希望后来人少走点弯路...

  那就从修改开始吧....
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>

  4. #include <linux/netfilter.h>
  5. #include <linux/skbuff.h>
  6. #include <linux/ip.h>
  7. #include <linux/netdevice.h>
  8. #include <linux/if_ether.h>
  9. #include <linux/if_packet.h>
  10. #include <linux/inet.h>
  11. #include <net/tcp.h>
  12. #include <net/udp.h>
  13. #include <net/icmp.h>
  14. #include <linux/netfilter_ipv4.h>


  15. MODULE_LICENSE("GPL");
  16. MODULE_AUTHOR("kenthy@163.com");

  17. #define    ETH    "eth0"
  18. unsigned char   SMAC[ETH_ALEN] = {0x00,0x0C,0x29,0x4F,0xDE,0xAC};
  19. unsigned char   DMAC[ETH_ALEN] = {0x00,0x50,0x56,0xFA,0x70,0x2A};

  20. static struct nf_hook_ops modify_ops;

  21. static unsigned int modify(unsigned int hooknum, struct sk_buff ** skb,
  22.                                   const struct net_device * in, const struct net_device * out,
  23.                                   int (*okfn)(struct sk_buff *))
  24. {
  25.     struct sk_buff* nskb;
  26.     struct iphdr* nip_hdr;
  27.     unsigned int   nip_hdr_off;
  28.     struct tcphdr* ntcp_hdr;
  29.     unsigned int ntcp_hdr_off;
  30.     struct ethhdr* neth_hdr;
  31.     int ret = 0;
  32.   
  33.    nskb = skb_copy(*skb, GFP_ATOMIC);
  34.    if(nskb == NULL)
  35.      {
  36.              printk("%s\n", "skb_copy return NULL");
  37.              return NF_ACCEPT;
  38.      }

  39.   if( nskb->nh.iph->protocol != IPPROTO_TCP)
  40.     {
  41.             kfree_skb(nskb);
  42.       return NF_ACCEPT;
  43.      }

  44.     nip_hdr = nskb->nh.iph;
  45.     nip_hdr_off = nip_hdr->ihl << 2;
  46.    
  47.     ntcp_hdr = (struct tcphdr *)((void *)nip_hdr + nip_hdr_off);
  48.     ntcp_hdr_off = ntcp_hdr->doff << 2;
  49.     if(!ntcp_hdr->syn)
  50.             {
  51.                     kfree_skb(nskb);
  52.                     return NF_ACCEPT;
  53.             }
  54.    
  55.     //evil!
  56.     nip_hdr->daddr = in_aton("192.168.1.101");

  57.     nip_hdr->check = 0;
  58.     nip_hdr->check = ip_fast_csum((unsigned char *)nip_hdr, nip_hdr->ihl);
  59.        
  60.     nskb->csum = 0;
  61.     nskb->csum = csum_partial((unsigned char *)(ntcp_hdr + ntcp_hdr_off),
  62.                                       ntohs(nip_hdr->tot_len) - nip_hdr_off - ntcp_hdr_off, 0);

  63.     ntcp_hdr->check = 0;
  64.     ntcp_hdr->check = csum_tcpudp_magic(nip_hdr->saddr, nip_hdr->daddr,
  65.                                         ntohs(nip_hdr->tot_len) - nip_hdr_off, nip_hdr->protocol,
  66.                                         csum_partial((unsigned char *)ntcp_hdr, ntcp_hdr_off, nskb->csum));


  67.     nskb->ip_summed = CHECKSUM_NONE;
  68.     nskb->pkt_type  = PACKET_OTHERHOST;
  69.    
  70.     nskb->dev = dev_get_by_name(ETH);
  71.     if(nskb->dev==NULL)
  72.     {
  73.             printk("%s\n", "dev_get_by_name return NULL");
  74.             kfree_skb(nskb);
  75.             return NF_ACCEPT;
  76.             }
  77.            
  78.     nskb->mac.raw = skb_push (nskb, ETH_HLEN);
  79.      { //eth headeri
  80.       neth_hdr = (struct ethhdr *)nskb->mac.raw;
  81.       memcpy (neth_hdr->h_dest, DMAC, ETH_ALEN);
  82.       memcpy (neth_hdr->h_source, SMAC, ETH_ALEN);
  83.       neth_hdr->h_proto = __constant_htons (ETH_P_IP);
  84.     }
  85.   

  86.     dev_hold(nskb->dev);
  87.     printk("%s\n", "dev_hold ok");
  88.    
  89.     ret = dev_queue_xmit(nskb);
  90.     printk("ret:%d\n", ret);
  91.     return NF_STOLEN;
  92. }


  93. static int __init init(void)
  94. {
  95.   int  ret = 0;
  96.   modify_ops.hook = modify;
  97.   modify_ops.hooknum = NF_IP_LOCAL_OUT;
  98.   modify_ops.pf = PF_INET;
  99.   modify_ops.priority = NF_IP_PRI_FIRST;

  100.   ret = nf_register_hook(&modify_ops);
  101.   if (ret < 0)
  102.    {
  103.      printk("%s\n", "can't modify skb hook!");
  104.      return ret;
  105.    }

  106.     printk("%s\n", "insmod modify skb module");
  107.     return 0;
  108. }

  109. static void __exit fini(void)
  110. {
  111.     nf_unregister_hook(&modify_ops);
  112.     printk("%s\n", "remove modify skb module.");
  113. }

  114. module_init(init);
  115. module_exit(fini);
复制代码


测试结果:

sendip -p ipv4 -is 192.168.238.180 -p tcp -ts 598982 -td 80 192.168.1.1
//                                  sip                                 sport       dport  dip
sendip比较好用吧,你可以指定syn ack之类的呢
skb_modify.JPG
2010-01-10 14:40 上传
下载附件 (57.13 KB)

上面的三个数据包是没有加载skb_modify模块的...上面的具体函数你们可以sourceinsight跟踪看看,我也不可能一一讲解

因为我们是挂在NF_IP_LOCAL_OUT上所以我们需要重新搞mac header

那么DIY SKB呢?
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/netfilter.h>
  5. #include <linux/skbuff.h>
  6. #include <linux/ip.h>
  7. #include <linux/inet.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 <net/udp.h>
  13. #include <net/route.h>
  14. #include <net/icmp.h>
  15. #include <linux/netfilter_ipv4.h>

  16. MODULE_LICENSE("GPL");
  17. MODULE_AUTHOR("kenthy@163.com");

  18. #define    ETH     "eth0"
  19. #define    SIP     "192.168.238.180"
  20. #define    DIP     "192.168.1.101"
  21. #define    SPORT   39804
  22. #define    DPORT   80

  23. unsigned char   SMAC[ETH_ALEN] = {0x00,0x0C,0x29,0x4F,0xDE,0xAC};
  24. unsigned char   DMAC[ETH_ALEN] = {0x00,0x50,0x56,0xFA,0x70,0x2A};

  25. int cp_dev_xmit_tcp (char * eth, u_char * smac, u_char * dmac,
  26.              u_char * pkt, int pkt_len,
  27.              u_long sip, u_long dip,
  28.              u_short sport, u_short dport, u_long seq, u_long ack_seq, u_char psh, u_char fin)
  29. {
  30.   struct sk_buff * skb = NULL;
  31.   struct net_device * dev = NULL;
  32.   struct ethhdr * ethdr = NULL;
  33.   struct iphdr * iph = NULL;
  34.   struct tcphdr * tcph = NULL;
  35.   u_char * pdata = NULL;
  36.   int nret = 1;

  37.   if (NULL == smac || NULL == dmac) goto out;

  38.   dev = dev_get_by_name(eth);
  39.   if (NULL == dev)
  40.    goto out;

  41.   skb = alloc_skb (pkt_len + sizeof (struct iphdr) + sizeof (struct tcphdr) + LL_RESERVED_SPACE (dev), GFP_ATOMIC);
  42.  
  43.   if (NULL == skb)
  44.     goto out;
  45.  
  46.   skb_reserve (skb, LL_RESERVED_SPACE (dev));

  47.   skb->dev = dev;
  48.   skb->pkt_type = PACKET_OTHERHOST;
  49.   skb->protocol = __constant_htons(ETH_P_IP);
  50.   skb->ip_summed = CHECKSUM_NONE;
  51.   skb->priority = 0;
  52.  
  53.   skb->nh.iph = (struct iphdr*)skb_put(skb, sizeof (struct iphdr));
  54.   skb->h.th = (struct tcphdr*)skb_put(skb, sizeof (struct tcphdr));

  55.   pdata = skb_put (skb, pkt_len);
  56.   {
  57.     if (NULL != pkt)
  58.      memcpy (pdata, pkt, pkt_len);
  59.   }
  60.  

  61.   {
  62.     tcph = (struct tcphdr *) skb->h.th;
  63.     memset (tcph, 0, sizeof (struct tcphdr));
  64.     tcph->source = sport;
  65.     tcph->dest = dport;
  66.     tcph->seq = seq;
  67.     tcph->ack_seq = ack_seq;
  68.     tcph->doff = 5;
  69.     tcph->psh = psh;
  70.     tcph->fin = fin;
  71.     tcph->syn = 1;
  72.     tcph->ack = 0;
  73.     tcph->window = __constant_htons (5840);
  74.     skb->csum = 0;
  75.     tcph->check = 0;
  76.   }
  77.  
  78.   {
  79.     iph = (struct iphdr*) skb->nh.iph;
  80.     iph->version = 4;
  81.     iph->ihl = sizeof(struct iphdr)>>2;
  82.     iph->frag_off = 0;
  83.     iph->protocol = IPPROTO_TCP;
  84.     iph->tos = 0;
  85.     iph->daddr = dip;
  86.     iph->saddr = sip;
  87.     iph->ttl = 0x40;
  88.     iph->tot_len = __constant_htons(skb->len);
  89.     iph->check = 0;
  90.   }
  91.  
  92.   skb->csum = skb_checksum (skb, iph->ihl*4, skb->len - iph->ihl * 4, 0);
  93.   tcph->check = csum_tcpudp_magic (sip, dip, skb->len - iph->ihl * 4, IPPROTO_TCP, skb->csum);

  94.  
  95.   skb->mac.raw = skb_push (skb, 14);
  96.   {
  97.     ethdr = (struct ethhdr *)skb->mac.raw;
  98.     memcpy (ethdr->h_dest, dmac, ETH_ALEN);
  99.     memcpy (ethdr->h_source, smac, ETH_ALEN);
  100.     ethdr->h_proto = __constant_htons (ETH_P_IP);
  101.   }


  102.   if (0 > dev_queue_xmit(skb)) goto out;
  103.  
  104.   nret = 0;
  105. out:
  106.   if (0 != nret && NULL != skb) {dev_put (dev); kfree_skb (skb);}
  107.  
  108.   return (nret);
  109. }

  110. static int __init init(void)
  111. {
  112.   printk("%s\n","insmod skb_diy module\n");
  113.    
  114.    cp_dev_xmit_tcp (ETH, SMAC, DMAC,NULL, 0,
  115.                     in_aton(SIP),in_aton(DIP),
  116.                     htons(SPORT),htons(DPORT),
  117.                     0, 0, 0, 0);
  118.     return 0;
  119. }

  120. static void __exit fini(void)
  121. {
  122.     printk("%s\n","remove skb_diy module.\n");
  123. }

  124. module_init(init);
  125. module_exit(fini);
复制代码


测试结果:
skb_diy.JPG
2010-01-10 14:40 上传
下载附件 (67.45 KB)



我这里并没有填充上层的东西 但是已经提供接口
pdata = skb_put (skb, pkt_len);
  {
    if (NULL != pkt)
     memcpy (pdata, pkt, pkt_len);
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值