Chinaunix首页 | 论坛 | 博客
  • 博客访问: 23680
  • 博文数量: 4
  • 博客积分: 244
  • 博客等级: 入伍新兵
  • 技术积分: 60
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-26 21:13
文章分类
文章存档

2012年(1)

2011年(3)

分类: LINUX

2011-03-11 22:05:02

教你修改以及重构skb
【本文转载自飞诺网】
  
工具:
   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
2.#include
3.#include
4.#include
5.#include
6.#include
7.#include
8.#include
9.#include
10.#include
11.#include
12.#include
13.#include
14.
15.#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
16.#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
17.
18.MODULE_LICENSE("GPL");
19.MODULE_AUTHOR("");
20.
21.const char* hooks[] ={ "NF_IP_PRE_ROUTING",
22.                             "NF_IP_LOCAL_IN",
23.                             "NF_IP_FORWARD",
24.                             "NF_IP_LOCAL_OUT",
25.                             "NF_IP_POST_ROUTING"};
26.
27.void print_ipproto(int proto)
28.{
29.switch(proto)
30.{
31.        case IPPROTO_ICMP:
32.                printk("%s\n", "IPPROTO_ICMP");
33.          break;
34.        case IPPROTO_TCP:
35.                printk("%s\n", "IPPROTO_TCP");
36.          break;
37.        case IPPROTO_UDP:
38.                printk("%s\n", "IPPROTO_UDP");
39.          break;
40.        default:
41.                printk("%s\n", "other IPPROTO");
42.        }
43.}
44.
45.void print_mac(struct ethhdr* eth)
46.{
47.if(eth==NULL)
48.        return;
49.       
50.if(eth->h_source!=NULL)
51.        printk("SOURCE:" MAC_FMT "\n", MAC_ARG(eth->h_source));
52.
53.if(eth->h_dest!=NULL)
54.             printk("DEST:" MAC_FMT "\n", MAC_ARG(eth->h_dest));
55.}
56.
57.unsigned int
58.mac(unsigned int hooknum,
59.                 struct sk_buff** skb,
60.                 const struct net_device *in,
61.                 const struct net_device *out,
62.                 int (*okfn)(struct sk_buff*))
63.{
64.   struct sk_buff* nskb;
65.   struct iphdr *iph = NULL;
66.   struct ethhdr* eth;
67. 
68.  nskb = *skb;
69.  if(nskb==NULL)
70.  {
71.    printk("%s\n", "*skb is NULL");
72.    return NF_ACCEPT;
73.   }
74. 
75.  iph = ip_hdr(nskb);
76.  if(iph == NULL)
77.  {
78.    printk("%s\n", "*iph is NULL");
79.    return NF_ACCEPT;
80.   }
81.
82.     
83.   printk("------begin %s--------\n", hooks[hooknum]);
84.   print_ipproto(iph->protocol);
85.   printk("len is %d, data len is %d\n", nskb->len, nskb->data_len);
86.   if(nskb->mac_len > 0)
87.           {
88.            eth = (struct ethhdr*)(nskb->mac.raw);
89.            print_mac(eth);       
90.                   }
91.   else
92.    printk("%s", "mac is NULL");               
93.   
94.   
95.   printk("------end  %s--------\n", hooks[hooknum]);
96. 
97.    return NF_ACCEPT;
98.}
99.
100.                            
101.static struct nf_hook_ops mac_ops[] = {
102.        {
103.                .hook                = mac,
104.                .owner                = THIS_MODULE,
105.                .pf                = PF_INET,
106.                .hooknum        = NF_IP_PRE_ROUTING,
107.                .priority = NF_IP_PRI_FIRST,
108.        },
109.        {
110.                .hook                = mac,
111.                .owner                = THIS_MODULE,
112.                .pf                = PF_INET,
113.                .hooknum        = NF_IP_LOCAL_IN,
114.                .priority = NF_IP_PRI_FIRST,
115.        },
116.        {
117.                .hook                = mac,
118.                .owner                = THIS_MODULE,
119.                .pf                = PF_INET,
120.                .hooknum        = NF_IP_FORWARD,
121.                .priority = NF_IP_PRI_FIRST,
122.        },
123.        {
124.                .hook                = mac,
125.                .owner                = THIS_MODULE,
126.                .pf                = PF_INET,
127.                .hooknum        = NF_IP_LOCAL_OUT,
128.                .priority = NF_IP_PRI_FIRST,
129.        },
130.        {
131.                .hook                = mac,
132.                .owner                = THIS_MODULE,
133.                .pf                = PF_INET,
134.                .hooknum        = NF_IP_PRE_ROUTING,
135.                .priority = NF_IP_POST_ROUTING,
136.        },
137.};
138.
139.static int __init init(void)
140.{
141.    int ret;
142.    ret = nf_register_hooks(mac_ops, ARRAY_SIZE(mac_ops));
143.    if (ret < 0) {
144.        printk("http detect:can't register mac_ops detect hook!\n");
145.        return ret;
146.    }
147.    printk("insmod mac_ops detect module\n");
148.    return 0;
149.}
150.
151.static void __exit fini(void)
152.{
153.    nf_unregister_hooks(mac_ops, ARRAY_SIZE(mac_ops));
154.    printk("remove mac_ops detect module.\n");
155.}
156.
157.module_init(init);
158.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层协议的协议头。
发送包的过程与此相反,但是由于要为每一层添加新的协议头,这个过程要比接收包的过程复杂。
 
下载 (13.31 KB)
2010-01-10 14:40
      好的,到现在你已经知道要重新搞一个数据包需要自己来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之间添加新的协议数据
    
下载 (7.6 KB)
2010-01-10 14:40
那么具体操作这些指针呢?
(a)skb_put, (b)skb_push, (c)skb_pull, and (d)skb_reserve
 
下载 (38.67 KB)
2010-01-10 14:40
  再加上dev_queue_xmit这个函数,你已经可以完成整件事了,对你现在有点蒙感觉无从下手,我也是!!! 我是历经几十次的死机才成功的,写这个文章也是希望后来人少走点弯路...
  那就从修改开始吧....
 
1.#include
2.#include
3.#include
4.
5.#include
6.#include
7.#include
8.#include
9.#include
10.#include
11.#include
12.#include
13.#include
14.#include
15.#include
16.
17.
18.MODULE_LICENSE("GPL");
19.MODULE_AUTHOR("");
20.
21.#define    ETH    "eth0"
22.unsigned char   SMAC[ETH_ALEN] = {0x00,0x0C,0x29,0x4F,0xDE,0xAC};
23.unsigned char   DMAC[ETH_ALEN] = {0x00,0x50,0x56,0xFA,0x70,0x2A};
24.
25.static struct nf_hook_ops modify_ops;
26.
27.static unsigned int modify(unsigned int hooknum, struct sk_buff ** skb,
28.                                  const struct net_device * in, const struct net_device * out,
29.                                  int (*okfn)(struct sk_buff *))
30.{
31.    struct sk_buff* nskb;
32.    struct iphdr* nip_hdr;
33.    unsigned int   nip_hdr_off;
34.    struct tcphdr* ntcp_hdr;
35.    unsigned int ntcp_hdr_off;
36.    struct ethhdr* neth_hdr;
37.    int ret = 0;
38.  
39.   nskb = skb_copy(*skb, GFP_ATOMIC);
40.   if(nskb == NULL)
41.     {
42.             printk("%s\n", "skb_copy return NULL");
43.             return NF_ACCEPT;
44.     }
45.
46.  if( nskb->nh.iph->protocol != IPPROTO_TCP)
47.    {
48.            kfree_skb(nskb);
49.      return NF_ACCEPT;
50.     }
51.
52.    nip_hdr = nskb->nh.iph;
53.    nip_hdr_off = nip_hdr->ihl << 2;
54.   
55.    ntcp_hdr = (struct tcphdr *)((void *)nip_hdr + nip_hdr_off);
56.    ntcp_hdr_off = ntcp_hdr->doff << 2;
57.    if(!ntcp_hdr->syn)
58.            {
59.                    kfree_skb(nskb);
60.                    return NF_ACCEPT;
61.            }
62.   
63.    //evil!
64.    nip_hdr->daddr = in_aton("192.168.1.101");
65.
66.    nip_hdr->check = 0;
67.    nip_hdr->check = ip_fast_csum((unsigned char *)nip_hdr, nip_hdr->ihl);
68.       
69.    nskb->csum = 0;
70.    nskb->csum = csum_partial((unsigned char *)(ntcp_hdr + ntcp_hdr_off),
71.                                      ntohs(nip_hdr->tot_len) - nip_hdr_off - ntcp_hdr_off, 0);
72.
73.    ntcp_hdr->check = 0;
74.    ntcp_hdr->check = csum_tcpudp_magic(nip_hdr->saddr, nip_hdr->daddr,
75.                                        ntohs(nip_hdr->tot_len) - nip_hdr_off, nip_hdr->protocol,
76.                                        csum_partial((unsigned char *)ntcp_hdr, ntcp_hdr_off, nskb->csum));
77.
78.
79.    nskb->ip_summed = CHECKSUM_NONE;
80.    nskb->pkt_type  = PACKET_OTHERHOST;
81.   
82.    nskb->dev = dev_get_by_name(ETH);
83.    if(nskb->dev==NULL)
84.    {
85.            printk("%s\n", "dev_get_by_name return NULL");
86.            kfree_skb(nskb);
87.            return NF_ACCEPT;
88.            }
89.           
90.    nskb->mac.raw = skb_push (nskb, ETH_HLEN);
91.     { //eth headeri
92.      neth_hdr = (struct ethhdr *)nskb->mac.raw;
93.      memcpy (neth_hdr->h_dest, DMAC, ETH_ALEN);
94.      memcpy (neth_hdr->h_source, SMAC, ETH_ALEN);
95.      neth_hdr->h_proto = __constant_htons (ETH_P_IP);
96.    }
97.  
98.
99.    dev_hold(nskb->dev);
100.    printk("%s\n", "dev_hold ok");
101.   
102.    ret = dev_queue_xmit(nskb);
103.    printk("ret:%d\n", ret);
104.    return NF_STOLEN;
105.}
106.
107.
108.static int __init init(void)
109.{
110.  int  ret = 0;
111.  modify_ops.hook = modify;
112.  modify_ops.hooknum = NF_IP_LOCAL_OUT;
113.  modify_ops.pf = PF_INET;
114.  modify_ops.priority = NF_IP_PRI_FIRST;
115.
116.  ret = nf_register_hook(&modify_ops);
117.  if (ret < 0)
118.   {
119.     printk("%s\n", "can't modify skb hook!");
120.     return ret;
121.   }
122.
123.    printk("%s\n", "insmod modify skb module");
124.    return 0;
125.}
126.
127.static void __exit fini(void)
128.{
129.    nf_unregister_hook(&modify_ops);
130.    printk("%s\n", "remove modify skb module.");
131.}
132.
133.module_init(init);
134.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之类的呢
 
下载 (57.13 KB)
2010-01-10 14:40
上面的三个数据包是没有加载skb_modify模块的...上面的具体函数你们可以sourceinsight跟踪看看,我也不可能一一讲解 
因为我们是挂在NF_IP_LOCAL_OUT上所以我们需要重新搞mac header
那么DIY SKB呢?
 
1.#include
2.#include
3.#include
4.#include
5.#include
6.#include
7.#include
8.#include
9.#include
10.#include
11.#include
12.#include
13.#include
14.#include
15.#include
16.
17.MODULE_LICENSE("GPL");
18.MODULE_AUTHOR("");
19.
20.#define    ETH     "eth0"
21.#define    SIP     "192.168.238.180"
22.#define    DIP     "192.168.1.101"
23.#define    SPORT   39804
24.#define    DPORT   80
25.
26.unsigned char   SMAC[ETH_ALEN] = {0x00,0x0C,0x29,0x4F,0xDE,0xAC};
27.unsigned char   DMAC[ETH_ALEN] = {0x00,0x50,0x56,0xFA,0x70,0x2A};
28.
29.int cp_dev_xmit_tcp (char * eth, u_char * smac, u_char * dmac,
30.             u_char * pkt, int pkt_len,
31.             u_long sip, u_long dip,
32.             u_short sport, u_short dport, u_long seq, u_long ack_seq, u_char psh, u_char fin)
33.{
34.  struct sk_buff * skb = NULL;
35.  struct net_device * dev = NULL;
36.  struct ethhdr * ethdr = NULL;
37.  struct iphdr * iph = NULL;
38.  struct tcphdr * tcph = NULL;
39.  u_char * pdata = NULL;
40.  int nret = 1;
41.
42.  if (NULL == smac || NULL == dmac) goto out;
43.
44.  dev = dev_get_by_name(eth);
45.  if (NULL == dev)
46.   goto out;
47.
48.  skb = alloc_skb (pkt_len + sizeof (struct iphdr) + sizeof (struct tcphdr) + LL_RESERVED_SPACE (dev), GFP_ATOMIC);
49. 
50.  if (NULL == skb)
51.    goto out;
52. 
53.  skb_reserve (skb, LL_RESERVED_SPACE (dev));
54.
55.  skb->dev = dev;
56.  skb->pkt_type = PACKET_OTHERHOST;
57.  skb->protocol = __constant_htons(ETH_P_IP);
58.  skb->ip_summed = CHECKSUM_NONE;
59.  skb->priority = 0;
60. 
61.  skb->nh.iph = (struct iphdr*)skb_put(skb, sizeof (struct iphdr));
62.  skb->h.th = (struct tcphdr*)skb_put(skb, sizeof (struct tcphdr));
63.
64.  pdata = skb_put (skb, pkt_len);
65.  {
66.    if (NULL != pkt)
67.     memcpy (pdata, pkt, pkt_len);
68.  }
69. 
70.
71.  {
72.    tcph = (struct tcphdr *) skb->h.th;
73.    memset (tcph, 0, sizeof (struct tcphdr));
74.    tcph->source = sport;
75.    tcph->dest = dport;
76.    tcph->seq = seq;
77.    tcph->ack_seq = ack_seq;
78.    tcph->doff = 5;
79.    tcph->psh = psh;
80.    tcph->fin = fin;
81.    tcph->syn = 1;
82.    tcph->ack = 0;
83.    tcph->window = __constant_htons (5840);
84.    skb->csum = 0;
85.    tcph->check = 0;
86.  }
87. 
88.  {
89.    iph = (struct iphdr*) skb->nh.iph;
90.    iph->version = 4;
91.    iph->ihl = sizeof(struct iphdr)>>2;
92.    iph->frag_off = 0;
93.    iph->protocol = IPPROTO_TCP;
94.    iph->tos = 0;
95.    iph->daddr = dip;
96.    iph->saddr = sip;
97.    iph->ttl = 0x40;
98.    iph->tot_len = __constant_htons(skb->len);
99.    iph->check = 0;
100.  }
101. 
102.  skb->csum = skb_checksum (skb, iph->ihl*4, skb->len - iph->ihl * 4, 0);
103.  tcph->check = csum_tcpudp_magic (sip, dip, skb->len - iph->ihl * 4, IPPROTO_TCP, skb->csum);
104.
105. 
106.  skb->mac.raw = skb_push (skb, 14);
107.  {
108.    ethdr = (struct ethhdr *)skb->mac.raw;
109.    memcpy (ethdr->h_dest, dmac, ETH_ALEN);
110.    memcpy (ethdr->h_source, smac, ETH_ALEN);
111.    ethdr->h_proto = __constant_htons (ETH_P_IP);
112.  }
113.
114.
115.  if (0 > dev_queue_xmit(skb)) goto out;
116. 
117.  nret = 0;
118.out:
119.  if (0 != nret && NULL != skb) {dev_put (dev); kfree_skb (skb);}
120. 
121.  return (nret);
122.}
123.
124.static int __init init(void)
125.{
126.  printk("%s\n","insmod skb_diy module\n");
127.   
128.   cp_dev_xmit_tcp (ETH, SMAC, DMAC,NULL, 0,
129.                    in_aton(SIP),in_aton(DIP),
130.                    htons(SPORT),htons(DPORT),
131.                    0, 0, 0, 0);
132.    return 0;
133.}
134.
135.static void __exit fini(void)
136.{
137.    printk("%s\n","remove skb_diy module.\n");
138.}
139.
140.module_init(init);
141.module_exit(fini);
复制代码
测试结果:
 
下载 (67.45 KB)
2010-01-10 14:40

我这里并没有填充上层的东西 但是已经提供接口
pdata = skb_put (skb, pkt_len);
  {
    if (NULL != pkt)
     memcpy (pdata, pkt, pkt_len);
  }
你可以自己先截获一个上层的包再填充进去...  关于上层的东西我开源应用层DPI--l7detect初步成果 已经很清楚了,都已经DPI了 

就这么多吧,天冷在寝室又没有暖气和空调,考个研还不让我们进实验室^_^,经过这两天的奋战终于搞定修改skb DIY SKB再加上以前基于netfilter的深度数据包检测.... 至此我可以很自信的说对于netfilter不算静态也算熟练了...
由于本人也是菜鸟,纰漏和不对之处还望指正...   写这些东西纯属爱好,由于内核网络代码这块变化看对于测试环境不一样的机子,概不保证正确性...但是思路肯定还是这样的,主要就是几个API的变化而已

参考:
  1.linux tcp/ip协议栈关键数据结构sk_buff分析
  http://blog.chinaunix.net/u/33048/showart_2043789.html
  2.Linux TCP/IP 协议栈的关键数据结构Socket Buffer(sk_buff )
  ... 5f1d00213f2eb0.html  
如果图片或页面不能正常显示请点击这里
文章出处:飞诺网(
阅读(1135) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~