smtp协议解析源代码

资料出处:http://my.csdn.net/cclongying1989/code/detail/13010

#include "nids.h"           //包含Libnids头文件
#include <stdio.h>
#include <string.h>           //使用bzero()
#include "iostream"
#include "fstream"
#include "time.h"
#include "Base64.h"         //用来Base64加密解密
using namespace std;
 
#pragma comment( linker, "/subsystem:"windows" /entry:"mainCRTStartup"" ) // 设置入口地址
 
char ascii_string[10000];   //用于存放ASCII明文邮件内容的全局变量
char serverip[16];          //存放服务器IP
bool sendmail = false;      //是否有邮件发送
 
//读取并分析获取的ASCII字符串内容
char* char_to_ascii(char ch)
{
    //初始化
    char* string;
    ascii_string[0] = 0;
    string = ascii_string;
    if(isgraph(ch)) //判断该字符是否是除空格之外可打印的字符(ASCII码33-126之间的字符)
        *string++ = ch;
    else if(ch ==' ')   //空格或其它字符
        *string++ = ch;
    else if(ch == 'n' || ch == 'r') //如果是回车换行
        *string++ = ch;
    else
        *string++ = '.';
    *string = 0;
    return ascii_string;
}
//分析SMTP协议的回调函数
void smtp_protocol_callback(struct tcp_stream* smtp_connection, void** arg)
{
    int i;
    char content[65535];
    char content_urgent[65535];
    char content_temp[65535];
    char content_gb[65535];
    struct tuple4 ip_and_port = smtp_connection->addr;
   
    //打开文件,准备随时写入,保证在return之前关闭文件
    FILE *fp;
    fp = fopen("maillog.txt", "a+");    //可读写打开文件
    fseek(fp, 0L, 2);                   //跳到文件结尾
   
    switch(smtp_connection->nids_state)
    {
    case NIDS_JUST_EST:
        if(smtp_connection->addr.dest == 25)  //SMTP客户端和SMTP服务器端建立连接
        {
            strcpy(serverip, inet_ntoa(*((struct in_addr *) &(ip_and_port.daddr))));    //记录邮件服务器的IP
            smtp_connection->client.collect++;  //SMTP客户端接收数据
            smtp_connection->server.collect++;  //SMTP服务器接收数据
            smtp_connection->server.collect_urg++;  //SMTP服务器接收紧急数据
            smtp_connection->client.collect_urg++;  //SMTP客户端接收紧急数据
            fprintf(fp, "操作:t发送邮件.n");
        }
        fclose(fp);
        return;
    case NIDS_CLOSE:  //SMTP客户端与SMTP服务器连接正常关闭
        time_t datetime;                            //使用time.h中的结构体获取时间
        struct tm *dt;
        time(&datetime);
        dt = localtime(&datetime);
        if(sendmail)
        {
            fprintf(fp, "发送邮件成功!n服务器IP:t%sn", serverip);
            sendmail = false;
        }
        else
        {
            fprintf(fp, "没有邮件可发送!n服务器IP:t%sn", serverip);
        }
        fprintf(fp, "操作时间:t%d.%d.%d %d:%d:%dn", (1900 + dt->tm_year), (1 + dt->tm_mon), dt->tm_mday, dt->tm_hour, dt->tm_min, dt->tm_sec);
        fprintf(fp, "--------------------------n");
        fclose(fp);
        return;
    case NIDS_RESET:  //SMTP客户端与SMTP服务器连接被RST关闭
        time_t datetimer;                           //使用time.h中的结构体获取时间
        struct tm *dtr;
        time(&datetimer);
        dtr = localtime(&datetimer);
        fprintf(fp, "发送邮件失败!n服务器IP:t%sn", serverip);
        fprintf(fp, "操作时间:t%d.%d.%d %d:%d:%dn", (1900 + dtr->tm_year), (1 + dtr->tm_mon), dtr->tm_mday, dtr->tm_hour, dtr->tm_min, dtr->tm_sec);
        fprintf(fp, "--------------------------n");
        fclose(fp); 
        sendmail = false;   //被RESET时也要把该变量置为false
        return;
    case NIDS_DATA:   //SMTP接收到新的数据
        {
            char status_code[4];
            struct half_stream* hlf;
            if(smtp_connection->server.count_new_urg) //SMTP服务器接收到新的紧急数据
            {
                fclose(fp);
                return;
            }
            if(smtp_connection->client.count_new_urg) //SMTP客户端接收到新的紧急数据
            {
                fclose(fp);
                return;
            }
            if(smtp_connection->client.count_new)     //SMTP客户端接收到新的数据
            {
/*              hlf = &smtp_connection->client;
                memcpy(content, hlf->data, hlf->count_new);
                content[hlf->count_new] = '';
                if(strstr(strncpy(status_code, content, 3), "221")) //连接终止
                    fprintf(fp, "连接终止");
                if(strstr(strncpy(status_code, content, 3), "250")) //操作成功
                    fprintf(fp, "操作成功");
                if(strstr(strncpy(status_code, content, 3), "220")) //服务器就绪
                    fprintf(fp, "服务器就绪");
                if(strstr(strncpy(status_code, content, 3), "354")) //开始邮件输入
                    fprintf(fp, "开始邮件输入");
                if(strstr(strncpy(status_code, content, 3), "334")) //服务器响应验证
                    fprintf(fp, "服务器响应验证");
                if(strstr(strncpy(status_code, content, 3), "235")) //认证成功可以发邮件
                    fprintf(fp, "认证成功可以发送");
                for(i = 0; i < hlf->count_new; i++)
                {
                    fprintf(fp, "%s", char_to_ascii(content[i]));
                }
                fprintf(fp, "n");
*/
                fclose(fp);
                return;
            }
            if(smtp_connection->server.count_new)  //SMTP服务器接收到新的数据
            {
                hlf = &smtp_connection->server;
                memcpy(content, hlf->data, hlf->count_new);
                content[hlf->count_new] = '';
 
/*              if(strstr(content, "EHLO"))
                    fprintf(fp, "HELLO命令n");
                if(strstr(content, "QUIT"))
                    fprintf(fp, "退出连接n");
                if(strstr(content, "DATA"))
                    fprintf(fp, "开始传输数据n");
                if(strstr(content, "AUTH"))
                    fprintf(fp, "请求认证n");
                if(strstr(content, "LOGIN"))
                    fprintf(fp, "认证机制为LOGINn");
                if(strstr(content, "n."))
                    fprintf(fp, "数据传输结束n");
 
*/
/*              if(strstr(content, "MAIL FROM"))
                {
                    fprintf(fp, "发送方:");    //"MAIL FROM: "占11字符,i从11开始
                    for(i = 11; i < hlf->count_new; i++)
                    {
                        fprintf(fp, "%s", char_to_ascii(content[i]));
                    }
                }
                if(strstr(content, "RCPT TO"))
                {
                    fprintf(fp, "接收方:");    //"RCPT TO: "占9字符,i从9开始
                    for(i = 9; i < hlf->count_new; i++)
                    {
                        fprintf(fp, "%s", char_to_ascii(content[i]));
                    }
                }*/
                if(strstr(content, "DATA")) //判断是否有可发邮件
                {
                    sendmail = true;        //在连接关闭的时候要把该变量置为false
                }
                //在DATA中提取需要信息
                if(hlf->count_new > 0)
                {
                    //提取From
                    char *pfrom;
                    pfrom = strstr(content, "From: ");
                    if(pfrom)   //如果找到了From:
                    {
                        /*是否是汉字GB2312编码,如果是则分离出=?gb2312?B?到?=之间的字符
                         *发件人是这样的格式"=?gb2312?B?0cfD9w==?= <hitgym@sina.com>"
                         *不仅要提取出汉字,还要把后边的邮件地址输出
                        */
                        strcpy(content_temp, pfrom);
 
                        fprintf(fp, "发件人:t");
                        if(content_temp[6] == 61)   //如果"From: "后是"="
                        {
                            //strcpy(content_temp, pGB2312);
 
                            char gbstring[1000];
                            i = 17; //只捕获=?gb2312?B?后边的字符
                            int j = 0;  //用来记录循环次数,即截取的字符串长度
                            while(!(content_temp[i] == 63 && content_temp[i+1] == 61))
                            {
                                gbstring[j] = content_temp[i];
                                i++;
                                j++;
                            }
                            gbstring[j] = '';
 
                            unsigned long len;
                            string InBase = gbstring;
                            unsigned char OutBase[1000];//存放解密后字符串
                            if(CBase64::Decode(InBase, OutBase, &len))
                            {
                                for(int k=0; k<len; k++)
                                {
                                    fprintf(fp, "%c", OutBase[k]);
                                }
                            }
                            else
                            {
                                fprintf(fp, "解码失败!");
                            }//end if
                             
                            //接下来输出<>之间的地址,ASSCII码"<"为60,">"为62
                            j = i;
                            j+= 2;  //跳到"<"位置
                            while(!(content_temp[j-1] == 62))
                            {
                                fprintf(fp, "%s", char_to_ascii(content_temp[j]));
                                j++;
                            }
                        }
                        else
                        {
                            //strcpy(content_temp, pfrom);
                            i = 6;  //"From: "后边开始输出
                            while(!(content_temp[i-1]==62 && content_temp[i]==13 && content_temp[i+1]==10))
                            {
                                fprintf(fp, "%s", char_to_ascii(content_temp[i]));
                                i++;
                            }
                        }//end if pGB2312
                        fprintf(fp, "n");
                    }//end if pfrom
                    pfrom=NULL;
                    free(pfrom);    //释放指针
 
                    //提取To
                    char *pto;
                    pto = strstr(content, "To: ");
                    if(pto)
                    {
                        strcpy(content_temp, pto);
 
                        fprintf(fp, "收件人:t");
                        if(content_temp[4] == 61)   //如果"To: "后是"="
                        {
                            char gbstring[1000];
                            i = 15; //只捕获=?gb2312?B?后边的字符
                            int j = 0;  //用来记录循环次数,即截取的字符串长度
                            while(!(content_temp[i] == 63 && content_temp[i+1] == 61))
                            {
                                gbstring[j] = content_temp[i];
                                i++;
                                j++;
                            }
                            gbstring[j] = '';
                            unsigned long len;
                            string InBase = gbstring;
                            unsigned char OutBase[1000];//存放解密后字符串
                            if(CBase64::Decode(InBase, OutBase, &len))
                            {
                                for(int k=0; k<len; k++)
                                {
                                    fprintf(fp, "%c", OutBase[k]);
                                }
                            }
                            else
                            {
                                fprintf(fp, "解码失败!");
                            }//end if
                             
                            //接下来输出<>之间的地址,ASSCII码"<"为60,">"为62,","为44
                            j = i;
                            j+= 2;  //跳到"<"位置
                            //while(!(content_temp[j-1] == 62))
                            while(!(content_temp[j-1]==62 && content_temp[j]==13 && content_temp[j+1]==10))
                            {
                                fprintf(fp, "%s", char_to_ascii(content_temp[j]));
                                j++;
                            }
                        }
                        else
                        {
                            i = 4;  //"To: "后边开始输出
                            while(!(content_temp[i-1]==62 && content_temp[i]==13 && content_temp[i+1]==10))
                            {
                                fprintf(fp, "%s", char_to_ascii(content_temp[i]));
                                i++;
                            }
                        }//end if pGB2312
                        fprintf(fp, "n");
                    }//end if pto
                    pto=NULL;
                    free(pto);
 
                    //提取Cc
                    char *pCc;
                    pCc = strstr(content, "Cc: ");
                    if(pCc)
                    {
                        strcpy(content_temp, pCc);
 
                        fprintf(fp, "抄送人:t");
                        if(content_temp[4] == 61)   //如果"Cc: "后是"="
                        {
                            char gbstring[1000];
                            i = 15; //只捕获=?gb2312?B?后边的字符
                            int j = 0;  //用来记录循环次数,即截取的字符串长度
                            while(!(content_temp[i] == 63 && content_temp[i+1] == 61))
                            {
                                gbstring[j] = content_temp[i];
                                i++;
                                j++;
                            }
                            gbstring[j] = '';
 
                            unsigned long len;
                            string InBase = gbstring;
                            unsigned char OutBase[1000];//存放解密后字符串
                            if(CBase64::Decode(InBase, OutBase, &len))
                            {
                                for(int k=0; k<len; k++)
                                {
                                    fprintf(fp, "%c", OutBase[k]);
                                }
                            }
                            else
                            {
                                fprintf(fp, "解码失败!");
                            }//end if
                             
                            //接下来输出<>之间的地址,ASSCII码"<"为60,">"为62
                            j = i;
                            j+= 2;  //跳到"<"位置
                            while(!(content_temp[j-1]==62 && content_temp[j]==13 && content_temp[j+1]==10))
                            {
                                fprintf(fp, "%s", char_to_ascii(content_temp[j]));
                                j++;
                            }
                        }
                        else
                        {
                            i = 4;  //"Cc: "后边开始输出
                            while(!(content_temp[i-1]==62 && content_temp[i]==13 && content_temp[i+1]==10))
                            {
                                fprintf(fp, "%s", char_to_ascii(content_temp[i]));
                                i++;
                            }
                        }//end if pGB2312
                        fprintf(fp, "n");
                    }//end if pCc
                    pCc=NULL;
                    free(pCc);
                     
                    //提取Subject
                    char *psub;
                    psub = strstr(content, "Subject: ");
                    if(psub)
                    {
                        strcpy(content_temp, psub);
                        //是否是汉字GB2312编码,如果是则分离出=?gb2312?B?到?=之间的字符
                        fprintf(fp, "主题:t");
                        if(content_temp[9] == 61)   //如果"Subject: "后是"="
                        {
                            char gbstring[1000];
                            i = 20; //只捕获=?gb2312?B?后边的字符
                            int j = 0;  //用来记录循环次数,即截取的字符串长度
                            while(!(content_temp[i] == 63 && content_temp[i+1] == 61))
                            {
                                gbstring[j] = content_temp[i];
                                i++;
                                j++;
                            }
                            gbstring[j] = '';
 
                            unsigned long len;
                            string InBase = gbstring;
                            unsigned char OutBase[1000];//存放解密后字符串
                            if(CBase64::Decode(InBase, OutBase, &len))
                            {
                                for(int k=0; k<len; k++)
                                {
                                    fprintf(fp, "%c", OutBase[k]);
                                }
                            }
                            else
                            {
                                fprintf(fp, "解码失败!");
                            }//end if
                        }
                        else
                        {
                            i = 9;  //输出"Subject: "后的字符
                            while(!(content_temp[i] == 10 || content_temp[i] == 13))
                            {
                                fprintf(fp, "%s", char_to_ascii(content_temp[i]));
                                i++;
                            }
                        }//end if pGB2312
                        fprintf(fp, "n");
                    }//end if psub
                    psub=NULL;
                    free(psub);
 
                    //提取Date
                    char *pdate;
                    pdate = strstr(content, "Date: ");
                    if(pdate)
                    {
                        strcpy(content_temp, pdate);
                        i = 6;  //截取"Date: "后的字符
                        //fprintf(fp, "日期:t");
                        while(!(content_temp[i] == 13 && content_temp[i+1] == 10))
                        {
                            fprintf(fp, "%s", char_to_ascii(content_temp[i]));
                            i++;
                        }
                        fprintf(fp, "n");
                    }
                    pdate=NULL;
                    free(pdate);
 
                    //提取内容
                    char *pcontent;
                    pcontent = strstr(content, "Content-Type: text/plain;");
                    if(pcontent && strstr(content, "Return-path:"))
                    {
                        strcpy(content_gb, pcontent);
                        char *pbase;
                        pbase = strstr(content_gb, "base64");
                        //fprintf(fp, "邮件内容:n");
                        if(pbase)
                        {
                            fprintf(fp, "邮件内容:n");
                            strcpy(content_temp, pbase);
                            //当内容全部在一个包中时
                            if(strstr(content_temp, "="))
                            {   
                                //内容有可能为空,判定条件是"base64rn"后如果是"rn-"
                                /*//测试
                                for(int m=8; m<20; m++)
                                {
                                    printf("%s", char_to_ascii(content_temp[m]));
                                }
                                //测试*/
 
                                if(content_temp[10]==13 && content_temp[11]==10)    
                                {
                                    fprintf(fp, "t内容为空.");
                                }
                                else
                                {
                                    char gbstring[1600];
                                    i = 10; //只捕获base64rnrn后边的字符
                                    int j = 0;  //用来记录循环次数,即截取的字符串长度
                                    //以该标志结束"rnrn------=","-"的Ascii为45
                                    while(!(content_temp[i+2]==13 && content_temp[i+3]==10 && content_temp[i+4] == 45))
                                    {
                                        gbstring[j] = content_temp[i];
                                        i++;
                                        j++;
                                    }
                                    gbstring[j] = '';
                                     
                                    unsigned long len;
                                    string InBase = gbstring;
                                    unsigned char OutBase[1600];//存放解密后字符串
                                    if(CBase64::Decode(InBase, OutBase, &len))
                                    {
                                        for(int k=0; k<len; k++)
                                        {
                                            fprintf(fp, "%c", OutBase[k]);
                                        }
                                        /*//测试
                                        printf("长度%d字节.n", len);
                                        //测试*/
                                    }
                                    else
                                    {
                                        fprintf(fp, "解码失败!");
                                    }//end if*/
                                }
                            }
                            else
                            {
                                fprintf(fp, "暂时无法显示.");
                            }
                         
                        }//end if(pGB2312)
                        fprintf(fp, "n");
                        pbase = NULL;
                        free(pbase);
                    }//end if(pcontent)
                    pcontent = NULL;
                    free(pcontent);
 
                    //提取附件名字
                    if(strstr(content, "Content-Disposition: attachment"))  //Content-Disposition: attachment
                    {
                        char *pattach;
                        pattach = strstr(content, "filename=");
                        if(pattach)
                        {
                            //是否是汉字GB2312编码,如果是则分离出=?gb2312?B?到?=之间的字符
                            char *pGB2312;
                            pGB2312 = strstr(content, "=?gb2312?B?");
                            if(pGB2312) //含有汉字编码后的字符
                            {
                                strcpy(content_temp, pGB2312);
 
                                char gbstring[1000];
                                i = 11; //只捕获=?gb2312?B?后边的字符
                                int j = 0;  //用来记录循环次数,即截取的字符串长度
                                fprintf(fp, "附件:t");
                                while(!(content_temp[i] == 63 && content_temp[i+1] == 61))
                                {
                                    gbstring[j] = content_temp[i];
                                    i++;
                                    j++;
                                }
                                gbstring[j] = '';
 
                                unsigned long len;
                                string InBase = gbstring;
                                unsigned char OutBase[1000];//存放解密后字符串
                                if(CBase64::Decode(InBase, OutBase, &len))
                                {
                                    for(int k=0; k<len; k++)
                                    {
                                        fprintf(fp, "%c", OutBase[k]);
                                    }
                                }
                                else
                                {
                                    fprintf(fp, "解密失败!");
                                }//end if
                            }
                            else        //否则直接输出英文字符串
                            {
                                strcpy(content_temp, pattach);
                                i = 9;  //输出filename=后的字符
                                fprintf(fp, "附件:t");
                                while(!(content_temp[i] == 10 || content_temp[i] ==13))
                                {
                                    fprintf(fp, "%s", char_to_ascii(content_temp[i]));
                                    i++;
                                }
                            }//end if pGB2312
                            fprintf(fp, "n");
                            pGB2312 = NULL;
                            free(pGB2312);
                        }//end if pattach
 
                        pattach = NULL;
                        free(pattach);
                    }//end if attachment
                }
                fclose(fp);
                return;
            }
        }
    default:
        fclose(fp);
        break;
    }//end switch
    return;
}
 
//主函数
void main()
{
    nids_params.device = "2";   //手选网络适配器,因为默认的是虚拟网卡
    if(!nids_init())                            //Libnids初始化
    {
//      printf("出现错误:%sn", nids_errbuf);
        exit(1);
    }
    nids_register_tcp(smtp_protocol_callback);  //注册分析SMTP协议的回调函数
    nids_run();                                 //进入循环捕获数据包的状态
}


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值