+ -
当前位置:首页 → 问答吧 → [求助]在netfilter挂载点对sk_buff进行操作的问题

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

时间:2010-11-02

来源:互联网

两台主机(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做任何修改都会引起内核崩溃,不知缘故,特来求救。

代码如下
/*#define _KERNEL_ */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <net/tcp.h>
#include <linux/netfilter_ipv4.h>
#include <linux/timer.h>
#include <net/xfrm.h>
#include <linux/netdevice.h>
#define NF_IP_PRE_ROUTING        0
#define NF_IP_LOCAL_IN        1
#define NF_IP_FORWARD  2
#define NF_IP_LOCAL_OUT         3
#define NF_IP_POST_ROUTING 4

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

/*在ip包头和四层数据之间添加数据结构*/
struct ip_add_hdr
{
  u_int8_t protocol;
  u_int8_t res:7;
  u_int8_t s:1;
  u_int16_t check;
  u_int32_t saddr;
};

u_int16_t
my_re_check (u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
{
  u_int32_t diffs[] = { oldvalinv, newval };
  return
    csum_fold (csum_partial
               ((char *) diffs, sizeof (diffs), oldcheck ^ 0xFFFF));
}

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

  for (sum = 0; nshorts > 0; nshorts--)
    {
      sum += *buf++;
    }

  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);

  return ~sum;
}

/*重新封包*/
struct sk_buff *
ip_mpkt_encapsulate (struct sk_buff *skb, __u32 src)
{
  struct ip_add_hdr *ipahr;
  struct sk_buff *nskb;
  struct iphdr *iph;
/*复制原始数据到新sk_buff*/
  nskb = skb_copy_expand (skb, skb_headroom (skb),
                          skb_tailroom (skb) + sizeof (struct ip_add_hdr),
                          GFP_ATOMIC);
  if (nskb == NULL)
    {
      printk ("Could not allocate new skb\n");
      kfree_skb (skb);
      return NULL;
    }
  if (skb->sk != NULL)
    skb_set_owner_w (nskb, skb->sk);
  iph = (struct iphdr *) skb->network_header;

  skb_put (nskb, sizeof (struct ip_add_hdr));

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

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

  kfree_skb (skb);
  skb = nskb;

  iph = (struct iphdr *) skb->data;
  skb->network_header = skb->data;
/*对添加的数据结构进行赋值*/
  ipahr = (struct ip_add_hdr *) (skb->data + (iph->ihl << 2));
  ipahr->protocol = iph->protocol;
  ipahr->s = 0;
  ipahr->res = 0;
  ipahr->check = 0;
  ipahr->saddr = iph->saddr;
/*修改ip包头*/
  iph->saddr = src;
  iph->protocol = IPPROTO_MIPE;
  iph->tot_len = htons (ntohs (iph->tot_len) + sizeof (struct ip_add_hdr));
  ipahr->check = ip_csum ((unsigned short *) ipahr, 4);
  
  ip_send_check (iph);
  if (iph->id == 0)
    {
      if (skb->dst)
        ip_select_ident (iph, skb->dst, NULL);
    }

  return skb;
}

/*解包*/
struct sk_buff *
ip_mpkt_decapsulate (struct sk_buff *skb)
{
  struct ip_add_hdr *ipahdr;
  struct iphdr *iph = (struct iphdr *) skb->network_header;

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

  iph->protocol = ipahdr->protocol;
  iph->saddr = ipahdr->saddr;

  memmove (skb->data + (iph->ihl << 2),
           skb->data + (iph->ihl << 2) + sizeof (struct ip_add_hdr),
           skb->len - (iph->ihl << 2) - sizeof (struct ip_add_hdr));
  skb_trim (skb, skb->len - sizeof (struct ip_add_hdr));

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

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

  ip_send_check (iph);
  return skb;
}






unsigned int
hook_func (unsigned int hooknum,
           struct sk_buff *skb,
           const struct net_device *in,
           const struct net_device *out, int (*okfn) (struct sk_buff *))
{
  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;
  switch (hooknum)
    {
/*NF_IP_PRE_ROUTING解包处理*/   
case NF_IP_PRE_ROUTING:
      if (iph->protocol == IPPROTO_MIPE && src_ip[0] == 192
          && src_ip[1] == 168 && src_ip[2] == 3 && src_ip[3] == 3)
        {
            ip_mpkt_decapsulate(skb);
          return NF_ACCEPT;
        }
      break;
/*NF_IP_LOCAL_OUT重新封包处理*/       
case NF_IP_LOCAL_OUT:
      if (src_ip[0] == 192 && src_ip[1] == 168 && src_ip[2] == 3
          && src_ip[3] == 3)
        {

                skb = ip_mpkt_encapsulate (skb, iph->saddr);
          
          if (!skb)
            return NF_STOLEN;
          ip_route_me_harder(skb,RTN_LOCAL);
        }
    }
  return NF_ACCEPT;
}


static struct nf_hook_ops hook_ops[] = {
  {
   .hook = hook_func,
   .owner = THIS_MODULE,
   .pf = PF_INET,
   .hooknum = NF_IP_PRE_ROUTING,
   .priority = NF_IP_PRI_FIRST,
   },
  {
   .hook = hook_func,
   .owner = THIS_MODULE,
   .pf = PF_INET,
   .hooknum = NF_IP_LOCAL_OUT,
   .priority = NF_IP_PRI_FILTER,
   },
};



static int __init nat_init (void)
{
  int ret;
  ret = nf_register_hook (&hook_ops[0]);

  if (ret < 0)
    goto cleanup_hook0;

  ret = nf_register_hook (&hook_ops[1]);

  if (ret < 0)
    goto cleanup_hook1;
  return ret;
cleanup_hook1:
  nf_unregister_hook (&hook_ops[1]);
cleanup_hook0:
  nf_unregister_hook (&hook_ops[0]);
  return ret;
}


void __exit nat_exit (void)
{
  nf_unregister_hook (&hook_ops[1]);
  nf_unregister_hook (&hook_ops[0]);
}

module_init(nat_init);
module_exit(nat_exit);

作者: 令人愉悦的忧伤   发布时间: 2010-11-02



QUOTE:
  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 信息吧

作者: Godbach   发布时间: 2010-11-02



QUOTE:
  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;


改成这样,看起来舒服一些


QUOTE:
  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;

作者: Godbach   发布时间: 2010-11-02