免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4990 | 回复: 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
19 [报告]
发表于 2014-07-20 21:39 |只看该作者
回复 18# wan3610425


   感谢您的关注与指点
1、在10楼里提到了,通过skb_shared_info直接在分片里获取数据并加密,但是发送出去的也是明文。

2、后面提到的用skb_linearize(skb)将分散片拷贝到线性区然后加密,您说的有道理,实际也是不行的,贴出代码只是对11楼的回应。

再次感谢,还在继续分析。

论坛徽章:
1
摩羯座
日期:2014-05-07 11:21:33
18 [报告]
发表于 2014-07-18 14:48 |只看该作者
不好意思,我理解错了,以为是ip分段导致的,然后又误以为ip分段是在LOCAL_OUT点完成的。就建议你改优先级了

刚才看了下这个聚合分散,有点想法,不知道对你有用没。首先这个skb_linearize(skb)是在将分散片拷贝到线性区,你对线性区进行加密,底层发送的时候是否还是对分散片发送呢?
然后既然选择了利用这种GSO机制,你对每个报文又重新拷贝到线性区,这个工作有点相违背吧,我觉得可以直接访问到分片中,对分片进行加密。

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

回复 13# wan3610425

单纯的把hook点LOCAL_OUT的优先级设为NF_IP_PRI_FIRST,并没有解决问题,反而是回到问题的原点,传输的数据在其他分页里

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_FIRST;
post_hook.hooknum  = NF_IP_LOCAL_OUT;

nf_register_hook(&pre_hook);
nf_register_hook(&post_hook);

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


   嗯,我再看看,看这么长的函数体没晕到你吧?

论坛徽章:
0
15 [报告]
发表于 2014-07-17 21:09 |只看该作者
回复 13# wan3610425


   感谢,我试试看

论坛徽章:
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
14 [报告]
发表于 2014-07-17 17:00 |只看该作者
“用skb_linearize(skb)将skb合并成一个,也能获取其数据部分,然后对数据部分进行加密,但发送出去的还是未加密数据,而加密后输出内存数据显示是加密了”
----如果这个能确认的话,那就应该不是这个流程的问题了,应该是后面发送流程的问题了,可以打点跟一下后面的发送流程中的数据是否是从“加密后的数据”中取的。。。

论坛徽章:
1
摩羯座
日期:2014-05-07 11:21:33
13 [报告]
发表于 2014-07-17 16:17 |只看该作者
可以把hook点LOCAL_OUT的优先级提高为最高NF_IP_PRI_FIRST,直接按照你改之前的代码试下,,

论坛徽章:
0
12 [报告]
发表于 2014-07-17 15:18 |只看该作者
回复 11# humjb_1983


if(skb_shinfo(skb)->nr_frags>0)//在一个页里为0{
                if (0 != skb_linearize(skb))//对于多个fragment的情况,将其合并
                {
                //#ifdef DEBUG_MODE
                        printk(KERN_EMERG"skb_linearize(sb) failed\n");
                //#endif
                                return NF_ACCEPT;
                }
}

crypt_ip_data_skb(skb,crypt_type,watch_flag);


/*******************************************************************************************************
*根据sk_buff、加密类型、数据方向进行加密
*******************************************************************************************************/
static void crypt_ip_data_skb(struct sk_buff *skb,unsigned int crypt_type,int watch_flag)
{
  unsigned        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\tskb_data:0x%08x\n",data,skb->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\n");
                printk(KERN_EMERG"the skb have fragment counts:%d\n",skb_shinfo(skb)->nr_frags);//测试中skb_shinfo(skb)->nr_frags=0,合并成功
                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);

                printk(KERN_EMERG"tcp_udp_len:%d\tdata_len:%d\n",tcp_udp_len,data_len);               
                printk(KERN_EMERG"skb_len:%d\tskb_data_len:%d\n",skb->len,skb->data_len);

        //#endif
                print_data_raw(skb->data+ip_head_len+tcp_udp_len,data_len);//输出明文
               
                encrypt_data_raw(skb->data+ip_head_len+tcp_udp_len,data_len,crypt_type);
               
                print_data_raw(skb->data+ip_head_len+tcp_udp_len,data_len);//输出密文
        }
       
        return;
}

论坛徽章:
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
11 [报告]
发表于 2014-07-17 14:03 |只看该作者
用skb_linearize(skb)将skb合并成一个,也能获取其数据部分,然后对数据部分进行加密,但发送出去的还是未加密数据,而加密后输出内存数据显示是加密了的,这是因为我获取的只是一个副本的原因吗?
---能把相关代码贴来看看么?谢谢!
  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP