免费注册 查看新帖 |

Chinaunix

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

[内核模块] 【求助】利用netfilter进行网络数据加密的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-07-15 23:39 |只看该作者 |倒序浏览
本帖最后由 zhengli85 于 2014-07-16 01:46 编辑

在CentOS 5.6 x86_64中利用Netfilter对TCP、UDP数据进行加密,但出现一点问题,还请各位帮忙看一下:

一、问题描述
1、该代码在5.2 i386环境下是正常的,所以不知道是不是64位的问题;
2、流入的数据能够正常识别并解密,但是流出的数据出现问题,打印输出后发现从skb获取的数据指向并不是真正需要数据

二、系统环境
[root@localhost ~]# lsb_release -a
LSB Version:    :core-4.0-amd64:core-4.0-ia32:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-ia32:graphics-4.0-noarch:printing-4.0-

amd64:printing-4.0-ia32:printing-4.0-noarch
Distributor ID: CentOS
Description:    CentOS release 5.6 (Final)
Release:        5.6
Codename:       Final

[root@localhost ~]# uname -a
Linux localhost.local5.6 2.6.18-238.el5 #1 SMP Thu Jan 13 15:51:15 EST 2011 x86_64 x86_64 x86_64 GNU/Linux

三、问题代码
/*******************************************************************************************************
*根据sk_buff、加密类型、数据方向进行加密
*******************************************************************************************************/
static void crypt_ip_data_skb(struct sk_buff *skb,unsigned int crypt_type,int watch_flag)
{
        char  *        data=NULL;       
        unsigned short data_len=0;
        __u8        protocol_type=0;
        struct tcphdr *tcphead=NULL;
        struct udphdr *udphead=NULL;

        int         ip_head_len=0;
        int        tcp_udp_len=0;

#ifdef DEBUG_MODE
        printk(KERN_EMERG"crypt_ip_data_skb\tcrypt_type:%d\twatch_flag:%d\n",crypt_type,watch_flag);
#endif

        if (!skb )return;
        if (!(skb->nh.iph)) return;

        protocol_type=skb->nh.iph->protocol;
        ip_head_len=(skb->nh.iph->ihl * 4);

        switch(protocol_type)
        {
                case        IPPROTO_TCP:
                {
                        tcphead= (struct tcphdr *)(skb->data  + ip_head_len);
                        tcp_udp_len=tcphead->doff*4;
                        data=(unsigned char *)tcphead+tcp_udp_len;
                        data_len=ntohs(skb->nh.iph->tot_len)-ip_head_len-tcp_udp_len;
                        break;
                }
                case        IPPROTO_UDP:
                {
                        udphead= (struct udphdr *)(skb->data  + ip_head_len);       
                        data=(unsigned char *)udphead+8;//sizeof(udphdr)=8
                        data_len=ntohs(udphead->len)-8;
                        break;
                }
                default:
                {
                        return ;
                }
        }

        //根据数据方向进行加减密
        if(watch_flag==fliter_watch_in)
        {
        #ifdef DEBUG_MODE
                printk(KERN_EMERG"fliter_watch_in\tdata:0x%08x\n",(int)data);
        #endif
                decrypt_data_raw(data,data_len,crypt_type);
        }

        if(watch_flag==fliter_watch_out)
        {

        #ifdef DEBUG_MODE
                printk(KERN_EMERG"fliter_watch_out\tdata:0x%08x\n",(int)data);
        #endif

        #ifdef DEBUG_MODE
                printk(KERN_EMERG"%02x%02x%02x%02x\n",data[0],data[1],data[2],data[3]);
        #endif       

                encrypt_data_raw(data,data_len,crypt_type);

        #ifdef DEBUG_MODE
                printk(KERN_EMERG"%02x%02x%02x%02x\n",data[0],data[1],data[2],data[3]);
        #endif
       
        }

        return;
}

四、hook点

   pre_hook.hook     = watch_in;
   pre_hook.pf       = PF_INET;
   pre_hook.priority = NF_IP_PRI_LAST;
   pre_hook.hooknum  = NF_IP_LOCAL_IN;
   
   post_hook.hook     = watch_out;
   post_hook.pf       = PF_INET;
   post_hook.priority = NF_IP_PRI_LAST;
   post_hook.hooknum  = NF_IP_LOCAL_OUT;
   
   nf_register_hook(&pre_hook);
   nf_register_hook(&post_hook);

论坛徽章:
0
2 [报告]
发表于 2014-07-16 01:43 |只看该作者
本帖最后由 zhengli85 于 2014-07-16 01:45 编辑

对代码部分代码更改如下,进行数据输出显示,发现:
1、在5.2 i386下,通过sk_buff的data字段进行数据获取,根据ip头+tcp/udp头+传输数据的组包方式可获取传输数据
2、在5.6  x86_64下,通过sk_buff的data字段进行数据获取,数据只有ip头+tcp/udp头,传输数据没有紧跟其后,因此根据ip头+tcp/udp头+传输数据的组包方式无法正确获取传输数据,因此造成加密不正常
3、5.2 i386下的内核版本是
[root@localhost kernel]# uname -a
Linux localhost.localdomain 2.6.18-92.el5xen #1 SMP Tue Apr 29 13:45:57 EDT 2008 i686 i686 i386 GNU/Linux
4、初步怀疑是由于内核版本升级,sk_buff结构组织变化导致


        if(watch_flag==fliter_watch_out)
        {
        //#ifdef DEBUG_MODE
                printk(KERN_EMERG"fliter_watch_out\n");
                printk(KERN_EMERG"data:0x%08x\n",data);
                printk(KERN_EMERG"skb_head:0x%08x\tskb_data:0x%08x\tskb_tail:0x%08x\tskb_end:0x%08x\n",skb->head,skb->data,skb->tail,skb->end);

                for(i=0;i<30;i++)//取30这个数,纯粹是跟测试数据相关,由于调试用的
                {
                        printk(KERN_EMERG"skb_data:%02x%02x%02x%02x\n",skb->data[i*4],skb->data[i*4+1],skb->data[i*4+2],skb->data[i*4+3]);
                }
        //#endif               

                //encrypt_data_raw(data,data_len,crypt_type);
        }

论坛徽章:
0
3 [报告]
发表于 2014-07-16 02:01 |只看该作者
同一通信过程:
IP头:20字节
TCP头:32字节
数据:13字节

输出sk_buff的几个字段进行验证
unsigned char                *head,
                        *data,
                        *tail,
                        *end

1、5.2 i386下
skb_head:0xeb7edc00     skb_data:0xeb7edccc     skb_tail:0xeb7edd0d     skb_end:0xeb7ede00
skb_data+20+32+13=skb_tail

ip头+tcp/udp头+传输数据

2、在5.6  x86_64下
skb_head:0x12b21000     skb_data:0x12b210cc     skb_tail:0x12b21100     skb_end:0x12b21100
skb_data+20+32=skb_tail

ip头+tcp/udp头

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
4 [报告]
发表于 2014-07-16 12:41 |只看该作者
请看看end之后是否放了你的数据?
如果使用了sg,那么数据是放在skb_shared_info中的。
另外,对于包头或相关数据的解析,建议使用内核提供的标准接口,新版本中32和64位中skb中的数据解析是不一样的。

论坛徽章:
0
5 [报告]
发表于 2014-07-16 15:35 |只看该作者
回复 4# humjb_1983


多谢您的提示与建议
见笑了,对Linux不熟悉,只是做个应急的东西,参考网上的文章依葫芦画瓢写的。

1、关于“请看看end之后是否放了你的数据?”

在测试里,多打印了一部分end之后的数据,并未发现有我的数据。


2、关于“如果使用了sg,那么数据是放在skb_shared_info中的。”

正在看skb_shared_info的信息,请问是否使用sg是如何判断的?


3、关于“另外,对于包头或相关数据的解析,建议使用内核提供的标准接口,新版本中32和64位中skb中的数据解析是不一样的。”

一开始做,以为网络数据是标准的,就按协议自己解析了,在5.2 i386里没发现问题,也就没改动,解决上述问题后一并再修改。

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
6 [报告]
发表于 2014-07-16 16:24 |只看该作者
zhengli85 发表于 2014-07-16 15:35
回复 4# humjb_1983

ethtool -k ethx
可以看到指定网卡是否开启了sg。

论坛徽章:
0
7 [报告]
发表于 2014-07-16 16:43 |只看该作者
回复 6# humjb_1983

这是没有开启sg选项吧?
[root@localhost ~]# ethtool -k ethxOffload parameters for ethx:
Cannot get device rx csum settings: No such device
Cannot get device tx csum settings: No such device
Cannot get device scatter-gather settings: No such device
Cannot get device tcp segmentation offload settings: No such device
Cannot get device udp large send offload settings: No such device
Cannot get device generic segmentation offload settings: No such device
Cannot get device GRO settings: No such device
no offload info available


论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
8 [报告]
发表于 2014-07-16 17:57 |只看该作者
呵呵,要把ethx换成实际的网卡名,比如eth0

论坛徽章:
0
9 [报告]
发表于 2014-07-16 21:30 |只看该作者
回复 8# humjb_1983


   呵呵
[root@localhost ~]# ethtool -k eth0
Offload parameters for eth0:
Cannot get device udp large send offload settings: Operation not supported
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp segmentation offload: on
udp fragmentation offload: off
generic segmentation offload: off
generic-receive-offload: off


论坛徽章:
0
10 [报告]
发表于 2014-07-17 11:45 |只看该作者
本帖最后由 zhengli85 于 2014-07-21 21:04 编辑

回复 4# humjb_1983


   多谢指教,通过skb_shared_info确实能够获取数据部分===================================================================================

        printk(KERN_EMERG"the skb have fragment counts:%d\n",skb_shinfo(skb)->nr_frags);
        if(skb_shinfo(skb)->nr_frags>0)//本skb中其他页中的数据部分
        {
                printk(KERN_EMERG"skb_shinfo(skb)->nr_frags>0\n" ) ;
                for(i=0;i< skb_shinfo(skb)->nr_frags;i++)
                {
                        printk(KERN_EMERG"the skb frags[%d] page_offset is:%d\n",i,skb_shinfo(skb)->frags[ i ].page_offset);
                        printk(KERN_EMERG"the skb frags[%d] size is:%d\n",i,skb_shinfo(skb)->frags[ i ].size);
                        vaddr=kmap_skb_frag(&skb_shinfo(skb)->frags);
                        print_data_raw(vaddr + skb_shinfo(skb)->frags[ i ].page_offset,skb_shinfo(skb)->frags[ i ].size);//自己的二进制输出函数
                }
       }

        if(skb_shinfo(skb)->frag_list)//其他碎片skb中的数据部分
                printk(KERN_EMERG"the skb have frag list\n" ) ;


===================================================================================

另:用skb_linearize(skb)将skb合并成一个,也能获取其数据部分,然后对数据部分进行加密,但发送出去的还是未加密数据,而加密后输出内存数据显示是加密了的,这是因为我获取的只是一个副本的原因吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP