免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5758 | 回复: 6
打印 上一主题 下一主题

[网络子系统] 通过hook函数获取网桥上的TCP数据包,然后将钩到的数据包修改发现数据有错误,求指导 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-06-28 00:08 |只看该作者 |倒序浏览
本帖最后由 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[6];
        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值不会篡改,但是这样的话功能就实现不了了。不知道为什么?这个问题很奇怪。        有没有人遇到过呢       

论坛徽章:
0
2 [报告]
发表于 2014-06-28 09:37 |只看该作者
没有人知道吗?

论坛徽章:
0
3 [报告]
发表于 2014-06-29 15:16 |只看该作者
大家都去HAPPY去了吗

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
4 [报告]
发表于 2014-07-01 13:24 |只看该作者
本帖最后由 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 的例子,你找一下

论坛徽章:
0
5 [报告]
发表于 2014-07-01 18:49 |只看该作者
回复 4# Godbach   嗯啊 谢谢版主  就是这个的原因,  tcph = tcp_hdr(skb);//将skb强制转换成tcp结构体型这句改过来 以后就可以了,但是我看linux的源文件里面也是有tcp_hdr(skb)这个函数的,而且我如果只是互换 端口号 那么这个函数的作用就与你那一句一样了,只是要修改后面的话 就会出错,好奇怪啊


   

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
6 [报告]
发表于 2014-07-02 09:47 |只看该作者
回复 5# ierent168

看一下 tcp_hdr 的定义,以及是否有注释说明它的调用时机。

当数据报文从底层传到 IP 层的时候,其更上层的比如 四层以及应用层的数据属于尚未读取的区域。因此你调用 tcp_hdr 得到的结果仍然是 iphdr。因此需要自己通过偏移来读取。


   

论坛徽章:
0
7 [报告]
发表于 2016-07-01 09:51 |只看该作者
我也想知道如何来修改ip数据内容,看能否和版主合作,请版主收到联系我
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP