linux下自己写的网卡数据转发程序

来源:互联网 发布:淘宝的cat是正品吗 编辑:程序博客网 时间:2024/05/17 07:35

static struct nf_hook_ops udp_comp_ops =
{
  .hook = udp_hook,
  .pf = PF_INET,
  .hooknum = 0,
  .priority =  -1,
};

先使用nf_register_hook注册一个hook函数:

nf_register_hook(&udp_comp_ops );

static unsigned int udp_hook(unsigned int hook,

    struct sk_buff *pskb,
    const struct net_device *in,
    const struct net_device *out,

    int (*okfn)(struct sk_buff *))

{

struct iphdr *iph =ip_hdr(pskb);

struct udphdr *udph =(struct udphdr *)(pskb->data+iph->ihl*4);
struct ethhdr *mach = eth_hdr(pskb);


if(iph->protocol != IPPROTO_UDP)  //只转发udp数据
return NF_ACCEPT;
int skb_alloc =0 ;

if (0==memcmp(mach->h_dest,g_local_inside.mac,ETH_ALEN))  //通过目的地址判断数据来源
{
iph->saddr =g_local_outside.addr;    //修改源ip
memcpy(mach->h_source, g_local_outside.mac, ETH_ALEN);//修改源mac地址
memcpy(mach->h_dest, g_outside_net.mac, ETH_ALEN);//修改目的mac地址


struct net_device* pDev = get_other_dev(pskb->dev);  //变换dev为另外一块网卡
if (NULL==pDev)
{
printk("<0>""recv sip,get_other_dev error\n");
return NF_ACCEPT;
}

pskb->dev = pDev;

      int chg_len = 0; 

               ....................    //数据修改


if (chg_len > 0)
{


if(skb_tailroom(pskb) < chg_len) //如果保留数据比增加的长度小,则分配新的sk_buff
{
struct sk_buff * nskb = skb_copy_expand(pskb, skb_headroom(pskb), skb_tailroom(pskb)+64,GFP_ATOMIC);
if(!nskb)
{
printk("<0>""low memory....\n");        
return NF_ACCEPT;
}
   
skb_alloc =1;  //设置分配标志
pskb = nskb; 
iph =ip_hdr(pskb);
udph =(struct udphdr *)(pskb->data+iph->ihl*4);
}
}

                //修改头部长度,重新计算校验和

iph->tot_len = htons(htons(iph->tot_len)+chg_len); 

udph->len = htons(htons(udph->len)+chg_len);
udph->check = 0;
udph->check = csum_tcpudp_magic(iph->saddr,
                                        iph->daddr,
                                        htons(udph->len), IPPROTO_UDP,
                                        csum_partial((char *)udph, htons(udph->len), 0));


iph->check = 0;
iph->check = ip_fast_csum((unsigned char *)iph,iph->ihl); 

//修改skb->data指针,使其指向MAC头部,并且增加skb->len
skb_push(pskb , ETH_HLEN);
//直接调用该函数,将数据包从网卡上发送出去
if (0!=dev_queue_xmit(pskb))
{
printk("<0>""recv sip,trans error\n");
}


if (skb_alloc>0)             //这里关键,如果是分配的要返回NF_DROP
return NF_DROP;
else
return NF_STOLEN;

}

return NF_ACCEPT;
}

原创粉丝点击