找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
广告投放联系QQ68610888
查看: 2137|回复: 0

Openwrt使用layer7获取邮件内容

[复制链接]
发表于 2016-11-4 15:54 | 显示全部楼层 |阅读模式
本帖最后由 karl_marx_1818 于 2016-11-5 14:15 编辑

1、扩展nf_conn对layer7的数据结构:
hope@ubuntu:~/barrier_breaker/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/linux-3.10.49/include/net/netfilter$ vi nf_conntrack.h

在数据结构nf_coon中增加蓝色部分:

#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || \
    defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE)
        struct {
                /*
                 * e.g. "http". NULL before decision. "unknown" after decision
                 * if no match.
                 */
                char *app_proto;
                /*
                 * application layer data so far. NULL after match decision.
                 */
                char *app_data;
                char *original_app_data;
                unsigned int app_data_len;
                unsigned int original_app_data_len;
        } layer7;
#endif

 
2、由于layer7将payload都转换为小写,因此在进行base64解码时,无法获取原有邮件原始数据。
   需要将payload的原始数据放到nf_coon新扩展的变量中。
hope@ubuntu:~/barrier_breaker/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/linux-3.10.49/net/netfilter$ vi xt_layer7.c

(1)修改__init xt_layer7_init中的包大小判断
        /* This is not a hard limit.  It's just here to prevent people from
        bringing their slow machines to a grinding halt. */
        else if(maxdatalen > 1024*128) {
                printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, "
                        "using 65536\n");
                maxdatalen = 1024*128;

(2)增大组装包的数量和payload的长度
    (根据CPU、内存和邮件大小等调整变量,同时调整设备的最大并发,测试最大并发时的内存)
     static int num_packets = 30;
     static int maxdatalen = 1024*128;
     
(3)在match函数中增加蓝色部分:
        /* On the first packet of a connection, allocate space for app data */
        if(total_acct_packets(master_conntrack) == 1 && !skb->cb[0] &&
           !master_conntrack->layer7.app_data && !master_conntrack->layer7.original_app_data){
                master_conntrack->layer7.app_data =
                        kmalloc(maxdatalen, GFP_ATOMIC);
                master_conntrack->layer7.original_app_data =
                        kmalloc(maxdatalen, GFP_ATOMIC);
                if(!master_conntrack->layer7.app_data && !master_conntrack->layer7.original_app_data){
                        if (net_ratelimit())
                                printk(KERN_ERR "layer7: out of memory in "
                                                "match, bailing.\n");
                        spin_unlock_bh(&l7_lock);
                        return info->invert;
                }
                master_conntrack->layer7.app_data[0] = '\0';
                master_conntrack->layer7.original_app_data[0] = '\0';
        }
      
        /* Can be here, but unallocated, if numpackets is increased near
        the beginning of a connection */
        if(master_conntrack->layer7.app_data == NULL && master_conntrack->layer7.original_app_data == NULL){
                spin_unlock_bh(&l7_lock);
                return info->invert; /* unmatched */
        }

(4)match函数中增加蓝色部分,如果命中,将文件正文打印到/var/layer7.log中:
     
        /* If looking for "unknown", then never match.  "Unknown" means that
        we've given up; we're still trying with these packets. */
        if(!strcmp(info->protocol, "unknown")) {
                pattern_result = 0;
        /* If looking for "unset", then always match. "Unset" means that we
        haven't yet classified the connection. */
        } else if(!strcmp(info->protocol, "unset")) {
                pattern_result = 2;
                DPRINTK("layer7: matched unset: not yet classified "
                        "(%d/%d packets)\n",
                        total_acct_packets(master_conntrack), num_packets);
        /* If the regexp failed to compile, don't bother running it */
        } else if(comppattern &&
                regexec(comppattern, master_conntrack->layer7.app_data)){
                DPRINTK("layer7: matched %s\n", info->protocol);

                // Gxxie modify begin: Output payload to /var/layer7.log
                DPRINTK("====================================== Layer7 payload begin ======================================\nLayer7 protocol is:%s\n%s\n====================================== Layer7 payload end   ======================================\n", info->protocol, master_conntrack->layer7.original_app_data);
                // Gxxie modify end
                pattern_result = 1;
        } else pattern_result = 0; } else pattern_result = 0;

(5)在match_no_append函数中增加释放layer7.app_data代码
     kfree(master_conntrack->layer7.app_data);
     master_conntrack->layer7.app_data = NULL; /* don't free again */
     kfree(master_conntrack->layer7.original_app_data);
     master_conntrack->layer7.original_app_data = NULL; /* don't free again */
 
3、增加释放nf_coon扩展字段的内存,增加蓝色部分:
hope@ubuntu:~/barrier_breaker/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/linux-3.10.49/net/netfilter$ vi nf_conntrack_core.c

#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE)
        if(ct->layer7.app_proto)
                kfree(ct->layer7.app_proto);
        if(ct->layer7.app_data)
                kfree(ct->layer7.app_data);
                kfree(ct->layer7.original_app_data);
#endif

4、修改 #define LOG_LINE_MAX,增大DPRINTK的单行大小
hope@ubuntu:~/barrier_breaker/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/linux-3.10.49/kernel$ vi printk.c
#define LOG_LINE_MAX                1024*128 - PREFIX_MAX

5、修改 #define CONFIG_LOG_BUF_SHIFT扩大dmesg的buffer
  (或者通过make kernel_menuconfig中General setup --> Kernel log buffer size设置)
hope@ubuntu:~/barrier_breaker/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/linux-3.10.49/include/generated$ vi autoconf.h
#define CONFIG_LOG_BUF_SHIFT 20

6、编辑pop3特征
root@Shanty:/usr/shanty/script# cat /etc/l7-protocols/mail_content.pat
mail_content
Subject:.*(html|221 Bye)

 
7、增加iptables规则
iptables -N LAYER7
iptables -A FORWARD -p tcp --dport 25 -j LAYER7
iptables -A FORWARD -p tcp --sport 25 -j LAYER7
iptables -A FORWARD -p tcp --dport 110 -j LAYER7
iptables -A FORWARD -p tcp --sport 110 -j LAYER7
iptables -A LAYER7 -m layer7 --l7proto mail_content -j ACCEPT
python /usr/shanty/script/mail_collector.py start &


6、创建python脚本(这个脚本比较粗略,主要是说明一下如何读取数据)
#!/usr/bin/python
# -*- coding:utf-8 -*-

import sys,os,time,commands,pexpect,base64

def start():
    # open("/etc/sysctl.conf.new", "w").write(''.join(map(lambda x: "net.netfilter.nf_conntrack_max" in x and "net.netfilter.nf_conntrack_max=1000\n" or x, open("/etc/sysctl.conf", "r"))))
    # os.system("rm /etc/sysctl.conf")
    # os.system("mv /etc/sysctl.conf.new /etc/sysctl.conf")
    # os.system("sysctl -p >/dev/null 2>&1")

    while True:
        # ================================== Encryption Begin ==================================
        if (os.path.exists(r'/usr/shanty/log/mail.log')):
            try:
                (status, result) = commands.getstatusoutput("ls -al /usr/shanty/log/mail.log | awk {'print $5'}")
            except:
                os.system('echo "Error: execute [ ls -al /usr/shanty/log/mail.log ] failed. error in mail.py" >> /usr/shanty/error_log')
                result = 0     
            if ( int(result) > 500000 ):  
                (status, result) = commands.getstatusoutput('date "+%Y-%m-%d-%H-%M-%S"')
                try:   
                          child = pexpect.spawn('openssl enc -aes-128-cbc -in /usr/shanty/log/mail.log -out /mnt/m.sec.' + result)
                          child.expect ('enter aes-128-cbc encryption password:')            
                          child.sendline ('CAFE*1981')                                       
                          child.expect ('Verifying - enter aes-128-cbc encryption password:')            
                          child.sendline ('CAFE*1981')                                                   
                          child.expect ('root@')                                                                 
                          os.system('rm /usr/shanty/log/mail.log')
                except:
                    os.system('echo "Error: encryption /usr/shanty/log/mail.log failed. error in mail.py" >> /usr/shanty/error_log')
            else:
                # File mail.log is small, no need encrypt.
                pass
        else:
            # /usr/shanty/log/mail.log is not exist.
            pass
        # ================================== Encryption End ==================================

        os.system('dmesg -c >/usr/shanty/log/layer7.log')
        time.sleep(60)
        try:
            f = open(r'/usr/shanty/log/layer7.log','r')
        except:
            print('Error: open file /usr/shanty/log/layer7.log failed.')
            os.system('echo "Error: open file /usr/shanty/log/layer7.log failed. error in mail.py" >> /usr/shanty/error_log')
            continue
        while True:
            line = f.readline()
            if not line:
                break
            if( 'Layer7 protocol is:' in line and 'mail' in line):
                username  = 'null'
                password  = 'null'
                mail_from = 'null'
                mail_to   = 'null'
                mail_cc   = 'null'
                mail_date = 'null'
                mail_subject = 'null'
                mail_content = 'null'
            if   ( 'USER' in line ):
                username = line.split('USER ')[1].replace('\n','')
            elif ( 'PASS' in line ):
                password = line.split('PASS ')[1].replace('\n','')
            elif ( 'From:' in line ):
                mail_from = line.split('From: ')[1]  
            elif ( 'To: "' in line ):
                mail_to = line.split('To: ')[1].replace("'",'')
            elif ( 'Cc:' in line ):
                mail_cc = line.split('Cc: ')[1].replace("'",'')
            elif ( 'Date:' in line ):
                mail_date = line.split('Date: ')[1]
            elif ( 'Subject:' in line ):
                mail_subject = line.split('?')[3]
                try:
                    mail_subject = base64.decodestring(mail_subject)
                except:
                    print("Except: decoding base64 from mail_subject error.")
            elif ( 'Content-Transfer-Encoding: base64' in line ):
                f.readline()  # Read the following line which is \r\n\
                mail_content = ''
                while True:
                    tmp = f.readline()
                    if ( tmp == '\r\n' ):
                        break
                    else:
                        mail_content += tmp.replace('\r\n','')
                try:
                    mail_content = base64.decodestring(mail_content)
                except:
                    print("Except: decoding base64 from mail_contend error.")
            elif ( 'Layer7 payload end' in line ):
                if ( mail_content != 'null' ):
                    print ("获得一封内容完整的邮件")
                else:
                    print ("获得一封内容不完整的邮件")
                    mail_content = "Got a large mail, ignore content."
                if ( mail_subject != 'null' ):
                    try:
                        fd = open(r'/usr/shanty/log/mail.log','a')
                        fd.write("\n"+"="*80+"\nUsername:{0}\nPassword:{1}\nFrom    :{2}To      :{3}Cc      :{4}Date    :{5}Subject :{6}\n{7}".format(username, password, mail_from, mail_to, mail_cc, mail_date, mail_subject, mail_content))
                        fd.close()
                    except:
                        print("Except: open and write to /usr/shanty/log/mail.log error.")
                else:
                    os.system('echo "Error: Get a mail but mail_subject is null. error in mail.py" >> /usr/shanty/error_log')
            else:
                pass

        f.close()
               

        

def stop():
    # open("/etc/sysctl.conf.new", "w").write(''.join(map(lambda x: "net.netfilter.nf_conntrack_max" in x and "net.netfilter.nf_conntrack_max=16000\n" or x, open("/etc/sysctl.conf", "r"))))
    # os.system("rm /etc/sysctl.conf")
    # os.system("mv /etc/sysctl.conf.new /etc/sysctl.conf")
    # os.system("sysctl -p >/dev/null 2>&1")
    # os.system("ps aux | grep mail | awk '{system(\"kill \"$2)}' >/dev/null 2>&1")
    pass

if __name__ == '__main__':

    if (sys.argv[1] == "start"):
        start()
    elif (sys.argv[1] == "stop"):
        stop()

7、测试。发送邮件后下载mail.log并查看结果(通过shell查看可能会有乱码)
root@Shanty:~# sz /usr/shanty/log/mail.log

评分

参与人数 1恩山币 +1 收起 理由
netsnake + 1 强大的恩山!(以下重复1万次)

查看全部评分

只谈技术、莫论政事!(点击见详情) | 恩山无线论坛欢迎您的来访,请互相尊重、友善交流,建议保持一颗平常心看待网友的评论,切勿过度反应。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

欢迎大家光临恩山无线论坛上一条 /1 下一条

有疑问请添加管理员QQ86788181|手机版|小黑屋|Archiver|恩山无线论坛(常州市恩山计算机开发有限公司版权所有) ( 苏ICP备05084872号 )

GMT+8, 2024-9-23 14:33

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

| 江苏省互联网有害信息举报中心 举报信箱:js12377 | @jischina.com.cn 举报电话:025-88802724 本站不良内容举报信箱:68610888@qq.com

快速回复 返回顶部 返回列表