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 intudp_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; }