通过hook函数获取网桥上的TCP数据包,然后将钩到的数据包修改发现数据有错误,求指导
本帖最后由 ierent168 于 2014-06-28 10:47 编辑通过hook函数获取网桥上的TCP数据包,然后将钩到的数据包源目的MAC地址互换,源目的IP互换,以及TCP端口互换,修改发回去,发现数据有错误而且错误很奇怪。我的钩子位置在PRE_ROUTING,然后修改后直接在接受包的端口发出去,不知道各位兄台有没有遇到过。下面是我的代码?关键是修改TCP以后发现错误了。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/socket.h>/*PF_INET*/
#include <linux/netfilter_ipv4.h>/*NF_IP_PRE_FIRST*/
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/inet.h> /*in_aton()*/
#include <net/ip.h>
#include <net/tcp.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_bridge.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#define ETHALEN 14
#define NF_IP_PRE_ROUTING 0 //netfilter_ipv4.h have
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lyh");
static struct nf_hook_ops nfho;
//static int a = 0;
unsigned int myhook_func(unsigned int hooknum,
struct sk_buff *_skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
// printk(KERN_EMERG "0000000000000000000000000\n");
struct sk_buff *skb;
// struct sk_buff *skbx;
struct net_device *dev;
struct iphdr *iph;
// struct ethernet_header{
// }
int ret;
int tot_len;//定义IP数据报总长度
int iph_len;//IP头部长度
int tcph_len;//TCP头部长度
// int i = 0;
struct tcphdr *tcph;
__u16 midder_var;//rst复位时候交换源端口和目的端口的中间变量
struct ethhdr *ethh;
unsigned char eth_MAC;
int ip_address;
// printk(KERN_EMERG "1111111111111111111111111\n");
// skb = _skb;
skb = skb_copy(_skb,GFP_ATOMIC);
if(skb == NULL)
{
return NF_ACCEPT;
}
iph = ip_hdr(skb);//将skb强制转换成ip结构体型
printk(KERN_EMERG "iph->saddr=%02x\n",iph->saddr);
printk(KERN_EMERG "iph->daddr=%02x\n",iph->daddr);
if(iph == NULL)
{
return NF_ACCEPT;
}
tot_len = ntohs(iph->tot_len);
printk(KERN_EMERG "222222222222222222222222\n");
// 这里假设通过过滤IP地址,如果过滤掉的包是TCP包,那么直接发送一个rst包
// if(iph->daddr == in_aton("192.168.1.7"))
// {
// printk(KERN_EMERG "33333333333333333333333\n");
if(iph->protocol == IPPROTO_TCP)
{
iph_len = ip_hdrlen(skb);
tcph_len = tcp_hdrlen(skb);
//修改MAC部分
{
ethh = eth_hdr(skb);
memcpy(eth_MAC,ethh->h_source,sizeof(ethh->h_source));
memcpy(ethh->h_source,ethh->h_dest,sizeof(ethh->h_dest));
memcpy(ethh->h_dest,eth_MAC,sizeof(ethh->h_source));
/* for(i = 0;i<6;i++)
{
// printk(KERN_EMERG "**************************************************\n");
printk(KERN_EMERG "eth_MAC=%02x;ethh->h_source=%02x;ethh->h_dest=%02x\n",*(eth_MAC+i),*(ethh->h_source+i),*(ethh->h_dest+i));
// printk(KERN_EMERG "**************************************************\n");
}
printk(KERN_EMERG "**************************************************\n");
*/
}
//修改IP部分
{
ip_address = iph->saddr;
iph->saddr = iph->daddr;
iph->daddr = ip_address;
iph->check = 0;
/*
printk(KERN_EMERG "**************************************************\n");
printk(KERN_EMERG "iph->saddr=%02x\n",iph->saddr);
printk(KERN_EMERG "iph->daddr=%02x\n",iph->daddr);
printk(KERN_EMERG "iph->daddr=%02x\n",iph->protocol);
printk(KERN_EMERG "**************************************************\n");
*/
}
//修改TCP部分,使得发送
{
tcph = tcp_hdr(skb);//将skb强制转换成tcp结构体型
midder_var = tcph->source;
tcph->source = tcph->dest;
tcph->dest = midder_var;
tcph->ack_seq = htonl(ntohl(tcph->seq)+1);
tcph->seq = 0;
tcph->ack = 1;
tcph->rst = 1;
tcph->check = 0;
}
{
printk(KERN_EMERG "**************************************************\n");
printk(KERN_EMERG "iph->saddr=%02x\n",iph->saddr);
printk(KERN_EMERG "iph->daddr=%02x\n",iph->daddr);
printk(KERN_EMERG "iph->protocol=%02x\n",iph->protocol);
printk(KERN_EMERG "tcph->source=%02x\n",tcph->source);
printk(KERN_EMERG "tcph->dest=%02x\n",tcph->dest);
printk(KERN_EMERG "tcph->dest=%02x\n",tcph->dest);
printk(KERN_EMERG "tcph->check=%02x\n",tcph->check);
printk(KERN_EMERG "tcph->rst=%02x\n",tcph->rst);
printk(KERN_EMERG "**************************************************\n");
}
skb->pkt_type = PACKET_OTHERHOST;//发给别人的帧(监听模式时会有这种帧)
skb->ip_summed = CHECKSUM_NONE;//需要软件重新计算校验和
skb->csum = csum_partial((unsigned char *)tcph, tot_len-iph_len, 0);
tcph->check = csum_tcpudp_magic(iph->saddr,iph->daddr, tot_len - iph_len, iph->protocol, skb->csum);
iph->check = ip_fast_csum((unsigned char *)iph,iph->ihl);
//测试用
dev = dev_get_by_name(&init_net,"eth7");
if(dev==NULL)
goto out;
skb->dev = dev;
// skb_push(skb, iph_len);
skb_push(skb, ETHALEN);//将skb->data指向l2层,之后将数据包通过dev_queue_xmit()发出
ret = dev_queue_xmit(skb);
// dev_put(skb->dev);
return NF_STOLEN;
}
else
{
return NF_ACCEPT;
}
out:
dev_put(dev);
//free(skb);
printk(KERN_EMERG "send fail\n");
return NF_DROP;
}
static struct nf_hook_ops nfho={
.hook = myhook_func,
.owner = THIS_MODULE,
.pf = PF_BRIDGE,
.hooknum = NF_BR_PRE_ROUTING,
.priority = NF_BR_PRI_FIRST,
};
static int __init myhook_init(void)//__init,表示告诉gcc把该函数放在init这个section;
{
int ret;
ret = nf_register_hook(&nfho);
if(ret < 0)
{
printk(KERN_EMERG "can't modify skb hook!\n");
return ret;
}
return ret;
}
static void myhook_fini(void)
{
nf_unregister_hook(&nfho);
}
module_init(myhook_init);
module_exit(myhook_fini);
我要实现的功能就是将钩到的TCP数据包源目的MAC地址互换,源目的IP互换,以及TCP端口互换,然后RST置1,还有修改序列号,然后再从新发送到接收端口。但是现在程序的情况是这样的,MAC地址可以互换,TCP端口也可以互换,但是源目的IP不能完全互换,只能后两位进行互换,而且用wireshark抓包以后显示,不出是TCP包,也就是原来IP协议标志位也没篡改了就是 iph->protocol值;但是假如把 这几句换注释掉,
tcph->ack_seq = htonl(ntohl(tcph->seq)+1);
tcph->seq = 0;
tcph->ack = 1;
tcph->rst = 1;
tcph->check = 0;
对TCP头只进行端口互换,那么源目的IP就可以正确互换,而且 iph->protocol值不会篡改,但是这样的话功能就实现不了了。不知道为什么?这个问题很奇怪。 有没有人遇到过呢
没有人知道吗? 大家都去HAPPY去了吗 本帖最后由 Godbach 于 2014-07-01 13:24 编辑
回复 1# ierent168
在 IP 层取 tcphdr 不能像你这么做
tcph = tcp_hdr(skb);//将skb强制转换成tcp结构体型
需要你自己通过iphdr 加 ip header 长度的方式转换,类似于下面这样的:
tcph = (struct tcphdr *)((unsigned char*)iph + (iph->ihl << 2))
论坛精华汇总帖中有构造以及发送 skb 的例子,你找一下
回复 4# Godbach 嗯啊 谢谢版主就是这个的原因,tcph = tcp_hdr(skb);//将skb强制转换成tcp结构体型这句改过来 以后就可以了,但是我看linux的源文件里面也是有tcp_hdr(skb)这个函数的,而且我如果只是互换 端口号 那么这个函数的作用就与你那一句一样了,只是要修改后面的话 就会出错,好奇怪啊
回复 5# ierent168
看一下 tcp_hdr 的定义,以及是否有注释说明它的调用时机。
当数据报文从底层传到 IP 层的时候,其更上层的比如 四层以及应用层的数据属于尚未读取的区域。因此你调用 tcp_hdr 得到的结果仍然是 iphdr。因此需要自己通过偏移来读取。
我也想知道如何来修改ip数据内容,看能否和版主合作,请版主收到联系我
页:
[1]