利用netfilter进行TCP数据包的源IP地址修改,修改TCP数据包内容。

  代码是在别个基础上修改的,不过还是花了不少时间调试通过。

想实现的功能是,client的IP地址是192.168.1.187,但是server发现跟自己建立链接的是192.169.1.188,实现了IP地址的隐藏。

在server端内核进行数据修改,server也无法发现自己的数据被修改了。例如192.168.1.187的client给192.168.1.111的server发送数据0x11,但是对于server来说,收到的是192.168.1.188的0xFF。

  client是windows是的普通TCP客户端,server是中标麒麟上的普通TCP服务端。

  win7上利用wireshark进行TCP数据分析。

  中标麒麟(linux系统)上加载in.ko模块后,利用dmesg进行数据的打印分析,或者利用tcpdump进行数据抓取打印分析。

刚开始发现TCP三次握手不成功,client发送数据后,通过wireshark抓取数据发现TCP校验和不对,但是server端能够收到tcp三次握手第1包,而且in.ko模块还发送了第2包三次握手包,但是wireshark抓取不到。此时感到无从下手,因为自己网络编程内核编程知识严重不足。

  然后尝试用windows的client给本机虚拟机的unbuntu,现象不一致了,wireshark能够抓取到server发送过来的三次握手第2包,但是没有回第三包,通过分析数据体,发现校验和不对,而且每次相差固定值,然后对server端的校验和进行转换,三次握手成功,数据发送成功。虽然没有从根本解决问题,但是实现了功能,后面还得多多深入学习。路漫漫其修远兮,吾将上下而求索。

 还有一个需要注意的地方是,虽然client的IP地址是192.168.1.187,但是得通过网络添加一个192.168.1.188的IP地址,一个网口对应两个IP地址,因为这样192.168.1.111的ARP才知道192.168.1.188的网络可达,否则LOCAL_OUT的路由选择时,就会把数据报丢了。

  知识有限,有不足的地方希望大家指正指教。

  

 

/ in.c /
#include <linux/time.h>
#include <linux/init.h>
#include <linux/netfilter>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/netfilter_ipv4.h>
#include <linux/net.h>
#include <net/ip.h>
#include <linux/if_ether.h>
#include <net/protocol.h>
#include <net/icmp.h>
#include <net/tcp.h>
#include <linux/if_vlan.h>

#define CHECKSUM_HW 1
#define SWITICH 1
#define T_SWITICH 1

static inline int printk_hex(const char* name,unsigned char *buff,int length)
{
	unsigned char *string_tmp = buff;
	int i;
	int count = 0;
	printk("==========%s start ==========\n",name);
	for(i=0;i<length;i++,count++)
	{
		if(count < 16)
		{
			printk("%02x ",string_tmp[i]);
		}
		else
		{
			count = 0;
			printk("\n%02x ",string_tmp[i]);
			continue;
		}
	}
	printk("\n");
	printk("==========%s end ==========\n",name);
	return 0;
}

unsigned int my_func_in(unsigned int hooknum,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *))
{   
	struct iphdr *iph=ip_hdr(skb);
    struct tcphdr *tcph;
    struct udphdr *udph;
    struct icmphdr *icmph;
    struct net_device   *master;
    
    int i=0,ret=-1;
    int header=0;
    int index=0;
    unsigned char *data=NULL;
    int length=0;
    
    if(likely(iph->protocol==IPPROTO_TCP))
    {
    	///IP hook钩子函数都在ip层,skb指向mac头和ip头的成员,都是有效的,可以直接使用接口API获取。
    	///获取TCP/UDP头时,skb中的成员是无效的,所以需要自己实现获取API。
        tcph=(struct tcphdr*)((unsigned char*)iph->ihl*4);
        data=skb->data+iph->ihl*4+tcph->doff*4;
        header=iph->ihl*4+tcph->doff*4;
        length=skb->len-iph->ihl*4-tcph->doff*4;
        if(skb->len-header>0)
        {
        	///说明有数据,在TCP三次握手时只有数据头无数据体。
            printk("**************now_start_in_data*****************\n");

            if(skb->data_len!=0)///非线性数据区
            {           
                if(skb_linearize(skb))
                {
                    printk("error line skb\r\n");
                    printk("skb->data_len %d\r\n",skb->data_len);
                    return NF_DROP;
                }
            }
            data[0]=0xFF;///此时可以修改数据体数据,但是记得将skb->ip_summed = CHECKSUM_HW,否则应用层收不到修改后的数据。
            printk_hex("data",data,length);///打印数据体
            #ifdef SWITICH
            iph->saddr = 0bc01a8c0///源IP地址修改,从而隐藏地址。
            skb->ip_summed = CHECKSUM_HW;
            #endif

            iph->check=0;
            iph->check=ip_fast_csum((unsigned char*)iph, iph->ihl);
            ///只要skb->ip_summed = CHECKSUM_HW,TCP头校验和校验就不会出错,后面的计算校验和可有可无。
            ///如果只要skb->ip_summed为0,计算了下面的TCP校验和,应用层也收不到数据,说明可能校验和校验出错。
            if(skb->ip_summed == CHECKSUM_HW)
            {
                tcph->check=csum_tcpudp_magic(iph->saddr,iph->daddr,(ntohs(iph ->tot_len)-iph->ihl*4), IPPROTO_TCP,csum_partial(tcph,(ntohs(iph ->tot_len)-iph->ihl*4),0)); 
                skb->csum = offsetof(struct tcphdr,check);      
            }
        }
    }
    else if(likely(iph->protocol==IPPROTO_UDP))
    {
        udph=udp_hdr(skb);
        data=skb->data+iph->ihl*4+sizeof(struct udphdr);
        header=iph->ihl*4+sizeof(struct udphdr);
        length=ntohs(iph->tot_len)-iph->ihl*4-sizeof(struct udphdr);
        if(skb->len-header>0)
        {
	        printk("header length is %d",header);
	        printk("\r\n");
	        printk("len -header is  %d",skb->len-header);
	        printk("\r\n");
	        printk("data length is %d",length);
	        printk("\r\n");
	        for(i=0;i<length;i++)
	        {
	            printk(" %02x",data[i]);
	            if((i+1)%16==0)
	            printk("\r\n");
	        }
	        if(skb->data_len!=0)
	        {           
	            if(skb_linearize(skb))
	            {
	                printk("error line skb\r\n");
	                printk("skb->data_len %d\r\n",skb->data_len);
	                return NF_DROP;

	            }

	        }
	        for(i=0;i<length;i++)
	        {
	            printk("%c",data[i]);           
	        }
	        iph->check=0;
	        iph->check=ip_fast_csum((unsigned char*)iph, iph->ihl);
	        if(skb->ip_summed == CHECKSUM_HW)
	        {
	            udph->check=csum_tcpudp_magic(iph->saddr,iph->daddr,(ntohs(iph ->tot_len)-iph->ihl*4), IPPROTO_UDP,csum_partial(udph, (ntohs(iph ->tot_len)-iph->ihl*4), 0));
	        }
	        printk("*********************UDPend********************\n");
	    }
    }
    else if(likely(iph->protocol==IPPROTO_ICMP))
    {
        icmph=icmp_hdr(skb);
        data=skb->data+iph->ihl*4+sizeof(struct icmphdr);
        header=iph->ihl*4+sizeof(struct icmphdr);   
        length=ntohs(iph->tot_len)-iph->ihl*4-sizeof(struct icmphdr);
        if(skb->len-header>0)
        {
	        printk("header length is %d",header);
	        printk("\r\n");
	        printk("len - header is %d",skb->len-header);
	        printk("\r\n");
	        printk("data length is  %d",length);
	        printk("\r\n");
	        if(skb->data_len!=0)
	        {           
	            if(skb_linearize(skb))
	            {
	                printk("error line skb\r\n");
	                printk("skb->data_len %d\r\n",skb->data_len);
	                return NF_DROP;
	            }

	        }
	        for(i=0;i<length;i++)
	        {
	            printk("%c",data[i]);           
	        }
	        printk("\r\n");

	        iph->check=0;
	        iph->check=ip_fast_csum((unsigned char*)iph, iph->ihl);
	        if(skb->ip_summed == CHECKSUM_HW)
	        {
	            icmph->checksum=ip_compute_csum(icmph, (ntohs(iph ->tot_len)-iph->ihl*4));
	        }
	        printk("*********************ICMPend********************\n");
        }
    }
    return NF_ACCEPT;

}

unsigned int my_func_out(unsigned int hooknum,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *))
{   
	struct iphdr *iph=ip_hdr(skb);
    struct tcphdr *tcph;
    struct udphdr *udph;
    struct icmphdr *icmph;
    struct net_device   *master;
    static int jason_flag = 0;
    
    int i=0,ret=-1;
    int header=0;
    int index=0;
    unsigned char *data=NULL;
    int length=0;
    
    if(likely(iph->protocol==IPPROTO_TCP))
    {
    	///IP hook钩子函数都在ip层,skb指向mac头和ip头的成员,都是有效的,可以直接使用接口API获取。
    	///获取TCP/UDP头时,skb中的成员是无效的,所以需要自己实现获取API。
        tcph=(struct tcphdr*)((unsigned char*)iph->ihl*4);
        data=skb->data+iph->ihl*4+tcph->doff*4;
        header=iph->ihl*4+tcph->doff*4;
        length=skb->len-iph->ihl*4-tcph->doff*4;
        if(skb->len-header>0)
        {
        	///说明有数据,在TCP三次握手时只有数据头无数据体。
            printk("**************now_start_in_data*****************\n");

            if(skb->data_len!=0)///非线性数据区
            {           
                if(skb_linearize(skb))
                {
                    printk("error line skb\r\n");
                    printk("skb->data_len %d\r\n",skb->data_len);
                    return NF_DROP;
                }
            }
            data[0]=0xFF;///此时可以修改数据体数据,但是记得将skb->ip_summed = CHECKSUM_HW,否则应用层收不到修改后的数据。
            printk_hex("data",data,length);///打印数据体
            #ifdef SWITICH
        	iph->daddr = 0bb01a8c0///源IP地址修改,从而隐藏地址。
        	skb->ip_summed = CHECKSUM_HW;
            #endif

            iph->check=0;
            iph->check=ip_fast_csum((unsigned char*)iph, iph->ihl);
            ///只要skb->ip_summed = CHECKSUM_HW,TCP头校验和校验就不会出错,后面的计算校验和可有可无。
            ///如果只要skb->ip_summed为0,计算了下面的TCP校验和,应用层也收不到数据,说明可能校验和校验出错。
            if(skb->ip_summed == CHECKSUM_HW)
            {
                tcph->check=csum_tcpudp_magic(iph->saddr,iph->daddr,(ntohs(iph ->tot_len)-iph->ihl*4), IPPROTO_TCP,csum_partial(tcph,(ntohs(iph ->tot_len)-iph->ihl*4),0)); 
                skb->csum = offsetof(struct tcphdr,check);      
            }
        }
        else
        {
        	#ifdef T_SWITICH
        	iph->daddr = 0xbb01a8c0;
        	skb->ip_summed = 0;
        	tcph->check = tcph->check+0x100;///无法完成三次握手,用wireshark抓包发现
        	///校验和不对,按照固定相差的值进行转换后,三次握手成功,从而TCP收发数据成功。
        	#endif
        }
    }
    else if(likely(iph->protocol==IPPROTO_UDP))
    {
        udph=udp_hdr(skb);
        data=skb->data+iph->ihl*4+sizeof(struct udphdr);
        header=iph->ihl*4+sizeof(struct udphdr);
        length=ntohs(iph->tot_len)-iph->ihl*4-sizeof(struct udphdr);
        if(skb->len-header>0)
        {
	        printk("header length is %d",header);
	        printk("\r\n");
	        printk("len -header is  %d",skb->len-header);
	        printk("\r\n");
	        printk("data length is %d",length);
	        printk("\r\n");
	        for(i=0;i<length;i++)
	        {
	            printk(" %02x",data[i]);
	            if((i+1)%16==0)
	            printk("\r\n");
	        }
	        if(skb->data_len!=0)
	        {           
	            if(skb_linearize(skb))
	            {
	                printk("error line skb\r\n");
	                printk("skb->data_len %d\r\n",skb->data_len);
	                return NF_DROP;

	            }

	        }
	        for(i=0;i<length;i++)
	        {
	            printk("%c",data[i]);           
	        }
	        iph->check=0;
	        iph->check=ip_fast_csum((unsigned char*)iph, iph->ihl);
	        if(skb->ip_summed == CHECKSUM_HW)
	        {
	            udph->check=csum_tcpudp_magic(iph->saddr,iph->daddr,(ntohs(iph ->tot_len)-iph->ihl*4), IPPROTO_UDP,csum_partial(udph, (ntohs(iph ->tot_len)-iph->ihl*4), 0));
	        }
	        printk("*********************UDPend********************\n");
	    }
    }
    else if(likely(iph->protocol==IPPROTO_ICMP))
    {
        icmph=icmp_hdr(skb);
        data=skb->data+iph->ihl*4+sizeof(struct icmphdr);
        header=iph->ihl*4+sizeof(struct icmphdr);   
        length=ntohs(iph->tot_len)-iph->ihl*4-sizeof(struct icmphdr);
        if(skb->len-header>0)
        {
	        printk("header length is %d",header);
	        printk("\r\n");
	        printk("len - header is %d",skb->len-header);
	        printk("\r\n");
	        printk("data length is  %d",length);
	        printk("\r\n");
	        if(skb->data_len!=0)
	        {           
	            if(skb_linearize(skb))
	            {
	                printk("error line skb\r\n");
	                printk("skb->data_len %d\r\n",skb->data_len);
	                return NF_DROP;
	            }

	        }
	        for(i=0;i<length;i++)
	        {
	            printk("%c",data[i]);           
	        }
	        printk("\r\n");

	        iph->check=0;
	        iph->check=ip_fast_csum((unsigned char*)iph, iph->ihl);
	        if(skb->ip_summed == CHECKSUM_HW)
	        {
	            icmph->checksum=ip_compute_csum(icmph, (ntohs(iph ->tot_len)-iph->ihl*4));
	        }
	        printk("*********************ICMPend********************\n");
        }
    }
    return NF_ACCEPT;

}

static struct nf_hook_ops nfho_out = {  
    .hook = my_func_in,  
    .pf = PF_INET,  
    .hooknum =NF_INET_PRE_ROUTING,  
    .priority = NF_IP_PRI_FIRST,  
    .owner = THIS_MODULE,  
}; 

static struct nf_hook_ops nfho_out = {  
    .hook = my_func_out,  
    .pf = PF_INET,  
    .hooknum =NF_INET_LOCAL_OUT,  
    .priority = NF_IP_PRI_FIRST,  
    .owner = THIS_MODULE,  
}; 

static int __init http_init(void)  
{  
    if (nf_register_hook(&nfho_in)) 
    {  
        printk(KERN_ERR"nf_register_hook_in() failed\n");  
    	return -1;  
    } 
    if (nf_register_hook(&nfho_out)) 
    {  
        printk(KERN_ERR"nf_register_hook_out() failed\n");  
    	return -1;  
    }  
    return 0;  
}  
static void __exit http_exit(void)  
{  
    nf_unregister_hook(&nfho_in);
    nf_unregister_hook(&nfho_out);
}  

module_init(http_init);  
module_exit(http_exit);  
MODULE_AUTHOR("JASON");  
MODULE_LICENSE("GPL"); 

 

 

###########Makefile
ifneq ($(KERNELRELEASE),)
	obj-m += in.o
else
	PWD := $(shell pwd)
	KVER := $(shell uname -r)
	KDIR := /lib/modules/$(KVER)/build
default:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	rm -rf *.o *.ko *.mod.c *.symvers *.order *.makers
#endif 

 

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值