VC++分析数据包实现POP3协议分析


POP3(Post Office Protocol 3)即邮局协议的第3个版本,它是规定个人计算机如何连接到互联网上的邮件服务器进行收发邮件的协议。它是因特网电子邮件的第一个离线协议标准,POP3协议允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时根据客户端的操作删除或保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的。POP3协议是TCP/IP协议族中的一员,,由RFC 1939 定义。本协议主要用于支持使用客户端远程管理在服务器上的电子邮件。
 POP3,全名为“Post Office Protocol - Version 3”,即“邮局协议版本3”。是TCP/IP协议族中的一员,由RFC1939 定义。本协议主要用于支持使用客户端远程管理在服务器上的电子邮件。提供了SSL加密的POP3协议被称为POP3S。
  POP 协议支持“离线”邮件处理。其具体过程是:邮件发送到服务器上,电子邮件客户端调用邮件客户机程序以连接服务器,并下载所有未阅读的电子邮件。这种离线访问模式是一种存储转发服务,将邮件从邮件服务器端送到个人终端机器上,一般是 PC机或 MAC。一旦邮件发送到 PC 机或 MAC上,邮件服务器上的邮件将会被删除。但目前的POP3邮件服务器大都可以“只下载邮件,服务器端并不删除”,也就是改进的POP3协议。


POP3协议的特性


  POP3协议默认端口:110
  POP3协议默认传输协议:TCP
  POP3协议适用的构架结构:C/S
  POP3协议的访问模式:离线访问


命令及工作原理简介


1.适用范围
  POP适用于C/S结构的脱机模型的电子邮件协议,目前已发展到第三版,称POP3。  POP3脱机模型即不能在线操作,POP不支持对服务器邮件进行扩展操作,此过程需要更高级的IMAP4协议来完成。支持POP协议使用ASCII码来传输数据消息,这些数据消息可以是指令,也可以是应答。
2.POP协议
  协议支持离线邮件处理,当邮件发送到服务器后,电子邮件客户端会调用邮件客户端程序,下载所有未阅读的电子邮件(这种离线访问模式是一种存储转发服务).当邮件从邮件服务器发送到个人计算机上,同时邮件服务器会删除该邮件(但是目前很多POP3服务器都支持“下载邮件,服务器并不删除邮件”,也就是说在POP3中改进了POP协议).
3.命令和响应
  POP3客户向POP3服务器发送命令并等待响应,POP3命令采用命令行形式,用ASCII码表示。服务器响应是由一个单独的命令行组成或多个命令行组成,响应第一行以ASCII文本+OK或-ERR(OK指成功,-ERR指失败)指出相应的操作状态是成功还是失败。
4.三种状态
  认证状态,处理状态和更新状态。当客户机与服务器建立连接时,客户机向服务器发送自己身份(这里指的是账户和密码)并由服务器成功确认,即客户端由认可状态转入处理状态,在完成列出未读邮件等相应的操作后客户端发出quit命令,退出处理状态进入更新状态,开始下载未阅读过的邮件到计算机本地之后最后重返认证状态确认身份后断开与服务器的连接。具体原理如下图
  等待连接身份确认quit命令
  C——|认证|—————|处理|——————|更新|----S
  |__________________________________|
  重返认证状态。
5.认证状态的命令语句
  目前大多数POP客户端和服务端都是采用ASCII码来明文发送用户名和密码,在认证状态下服务端等待客户端连接时,客户端发出连接请求,并把由命令构成的user/pass用户身份信息数据明文发送给服务端。
  服务端确认客户端身份以后,连接状态由认证状态转入处理状态,为了避免发送明文口令的安全问题,有一种新的更为安全的认证方法,命名为APOP,使用APOP,口令在传输之前就被加密,当客户端与服务端第一次建立连接时,POP3服务器向客户端发送一个ASCII码文本的问候,这个问候是由遗传字符组成对每个客户机是唯一的,内容一般都是当地时间之类的。然后客户端把它的纯文本口令附加到刚才接受的字符串之后,接着计算出新的字符串的MD5单出函数值的消息数据,最后客户机把用户名和MD5加密后的消息摘要作为APOP命令的参数一起发送到服务器。但是目前大多数windows上的邮件客户端不支持APOP协议。qpopper支持。
6.POP3命令码
  命令参数状态描述  POP3 示意图------------------------------------------
  USERusername认可此命令与下面的pass命令若成功,将导致状态转换
  PASSpassword认可
  APOPName,Digest认可Digest是MD5消息摘要
  ------------------------------------------
  STATNone处理请求服务器发回关于邮箱的统计资料,如邮件总数和总字节数
  UIDL[Msg#]处理返回邮件的唯一标识符,POP3会话的每个标识符都将是唯一的
  LIST[Msg#]处理返回邮件数量和每个邮件的大小
  RETR[Msg#]处理返回由参数标识的邮件的全部文本
  DELE[Msg#]处理服务器将由参数标识的邮件标记为删除,由quit命令执行
  RSETNone处理服务器将重置所有标记为删除的邮件,用于撤消DELE命令
  TOP[Msg#]处理服务器将返回由参数标识的邮件前n行内容,n必须是正整数
  NOOPNone处理服务器返回一个肯定的响应
  ------------------------------------------
  QUITNone更新
  a.客户机希望结束这次会话
  b.如果服务器处于‘处理’状态,那么将进入‘更新’状态以删除任何标记为删除的邮件
  c.导致由处理状态到更新状态,又重返认可状态的转变
  d.如果这个命令发出时服务器处于‘认可’状态,则结束会话,不进行‘更新’状态。
7.等待
  POP3协议在TCP/110端口上等待客户连接请求。[1]
8.监听
  若密码为明文,我如何监听?  POP3下面的命令在服务器运行后在屏幕上显示POP3连接及命令发送的过程:
  #sniffit-a-A.-p110-b-s192.169.11.12
  note:192.168.11.12是客户机IP地址
  你需要事先安装sniffit这个端口监听程序
9.中断
  考虑这种情况,若客户在收取邮件时,假定为15封信等待接收,但由于线路问题,收到第10封时断线了,为什么下次收时仍然从第一封开始,也即为什么前10封没有被从服务器上删除掉?
  任何邮件的删除都必须在quit命令发出后对已标记为删除的邮件执行删除操作,由于中途断线,仍处于处理状态,没有机会执行quit命令以进行状态转换。
10.锁定
  pop3 session is locked by another session,please wait 10 minutes then try again.
  由于非正常操作引起POP3程序内部机制锁住该次会话。
11.不同处理机制
  Foxmail与OE(outlookexpress)的处理机制的不同。
  a.假定服务器上有三封邮件等待客户机接收。用foxmail与OE的不同之处在于
  foxmail每收一封标记删除一封,而OE则等全部接收完后再全部标记为删除最后执行quit命令。
  FoxmailOE
  -------------------------------
  retr1retr1  POP3dele1retr2
  retr2retr3
  dele2dele1
  retr3dele2
  dele3dele3
  quitquit
  b.Foxmail的远程邮件管理是非常优秀的管理工具,假定服务器上有三封信,对第一封,我们不想接收
  想从服务器直接删除;对第二封,想接收但不删除,对第三封,这一次不想接收,分别标记后最后foxmail发出的命令是
  dele1
  retr2
  quit
  c.若没有foxmail,正好有几封很大的信堵住了,我不想接收,想直接删除它,或者想查看这两封是谁发的?
  直接在windows的DOS窗口下用命令行操作,如:
  #telnetmyispnet110
  userusername
  passpassword
  list
  dele3
  dele5
  quit
  --


操作指南


  [2]服务器允许符合POP3(PostOfficeProtocol,Version3邮件投递协议,版本3)的邮件客户端连接Imail服务器。这些邮件客户端软件包括OutlookExpress,Outlook,NetscapeMessenger或Communicator,Eudora,Pegasus,NuPOP,Z-Mail,FoxMail,TheBat,Kmail,和Unixmail。
  POP3客户端通常采用“off-line”离线方式访问邮件服务器,会定时的访问邮件服务器,下载邮件到客户的电脑上,然后和服务器断开。一般的,邮件被临时的存储在服务器上,当客户端下载这些邮件后,它们将被服务器删除,不再保留。对于那些总是在同一台电脑上阅读邮件的用户来说,这种方式是十分适合得。另外一种方式,称为“online”在线方式,即邮件客户端总是和服务器保持连接。邮件被保持在服务器上,客户端不下载邮件到客户机上,用户可以在线的阅读保留在服务器上的邮件。那些经常使用不同电脑的用户适合于这种方式。ImailPOP3服务可以作为Windows NT服务,完全隐藏的运行或者可以以有某些交互的方式运行。该服务将一直运行即使你登出系统。  POP3 操作图IMail同时提供另外一种访问方式IMAP4(InternetMessageAccessProtocolVersion4).IMAP4服务同时提供“在线”和“离线”访问方式。Logging On登入缺省的,POP3服务利用系统账号登入系统。你可以改变这种登入方式:
  [3]POP3
  1、在控制面板,启动Services小程序。
  2、选择IMailPOP3 Server服务然后点击Startup。
  3、(可选)选择您希望的StartupType。
  4、在LogOnAs中,选择正确的登入帐号:IMailServerSystemAccount.如果您有邮件主机采用WindowsNT用户数据库作为Imail用户数据库,那么你需要使用该账号。AllowServicetoInteractwithDesktop.采用该账号时,任何用户登入系统时,桌面上都会有一个Imail的图标。
  ThisAccount.采用这种方式时,如果你的主机中没有采用WindowsNT用户数据库的,你可以输入你希望的用户账号;确认该账号是一个主机管理员。如果您有邮件主机是利用外部数据库的,确认该账号可以访问外部数据库。
  Configuringthe POP3 Server配置POP3服务器如何配置pop3服务器:
  1、在IMailAdministrator中,在左边的面板中选择“localhost”。
  2、选择“Services”目录然后点击POP3.POP3面板出现。
  3、输入以下描述的选项以配置POP3服务。
  4、单击按钮Apply保存设置。
  5、停止服务,等待5-10秒然后重新启动服务。当你单击按钮Stop/Start后,将自动保存设置的改变。






#include "nids.h"   
char ascii_string[10000];   
char *char_to_ascii(char ch)   
{   
    char *string;   
    ascii_string[0] = 0;   
    string = ascii_string;   
    if (isgraph(ch))   
        *string++ = ch;   
    else if (ch == ' ')   
        *string++ = ch;   
    else if (ch == '\n' || ch == '\r')   
        *string++ = ch;   
    else   
        *string++ = '.';   
    *string = 0;   
    return ascii_string;   
}   
/*  
=======================================================================================================================  
下面是分析POP3协议的回调函数  
=======================================================================================================================  
 */   
void pop3_protocol_callback(struct tcp_stream *pop3_connection, void **arg)   
{   
    int i;   
    char address_string[1024];   
    char content[65535];   
    char content_urgent[65535];   
    struct tuple4 ip_and_port = pop3_connection->addr;   
    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.source);   
    strcat(address_string, " <---> ");   
    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.dest);   
    strcat(address_string, "\n");   
    switch (pop3_connection->nids_state)   
    {   
        case NIDS_JUST_EST:   
            if (pop3_connection->addr.dest == 110)   
            {   
                /*POP3客户端和POP3服务器端建立连接 */   
                pop3_connection->client.collect++;   
                /* POP3客户端接收数据 */   
                pop3_connection->server.collect++;   
                /* POP3服务器接收数据 */   
                pop3_connection->server.collect_urg++;   
                /* POP3服务器接收紧急数据 */   
                pop3_connection->client.collect_urg++;   
                /* POP3客户端接收紧急数据 */   
                printf("%sPOP3客户端与POP3服务器建立连接\n", address_string);   
            }   
            return ;   
        case NIDS_CLOSE:   
            /* POP3客户端与POP3服务器端连接正常关闭 */   
            printf("--------------------------------\n");   
            printf("%sPOP3客户端与POP3服务器连接正常关闭\n", address_string);   
            return ;   
        case NIDS_RESET:   
            /* POP3客户端与POP3服务器端连接被RST关闭 */   
            printf("--------------------------------\n");   
            printf("%sPOP3客户端与POP3服务器连接被REST关闭\n", address_string);   
            return ;   
        case NIDS_DATA:   
            {   
                /* POP3协议接收到新的数据 */   
                char status_code[5];   
                struct half_stream *hlf;   
                if (pop3_connection->server.count_new_urg)   
                {   
                    /* POP3服务器接收到新的紧急数据 */   
                    printf("--------------------------------\n");   
                    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
                    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.source);   
                    strcat(address_string, " urgent---> ");   
                    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
                    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.dest);   
                    strcat(address_string, "\n");   
                    address_string[strlen(address_string) + 1] = 0;   
                    address_string[strlen(address_string)] = pop3_connection->server.urgdata;   
                    printf("%s", address_string);   
                    return ;   
                }   
                if (pop3_connection->client.count_new_urg)   
                {   
                    /* POP3服务器接收到新的紧急数据 */   
                    printf("--------------------------------\n");   
                    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
                    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.source);   
                    strcat(address_string, " <--- urgent ");   
                    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
                    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.dest);   
                    strcat(address_string, "\n");   
                    address_string[strlen(address_string) + 1] = 0;   
                    address_string[strlen(address_string)] = pop3_connection->client.urgdata;   
                    printf("%s", address_string);   
                    return ;   
                }   
                if (pop3_connection->client.count_new)   
                {   
                    /* POP3客户端接收到新的数据 */   
                    hlf = &pop3_connection->client;   
                    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
                    sprintf(address_string + strlen(address_string), ":%i", ip_and_port.source);   
                    strcat(address_string, " <--- ");   
                    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
                    sprintf(address_string + strlen(address_string), ":%i", ip_and_port.dest);   
                    strcat(address_string, "\n");   
                    printf("--------------------------------\n");   
                    printf("%s", address_string);   
                    memcpy(content, hlf->data, hlf->count_new);   
                    content[hlf->count_new] = '\0';   
                    if (strstr(strncpy(status_code, content, 4), "+OK"))   
                        printf("操作成功\n");   
                    if (strstr(strncpy(status_code, content, 4), "-ERR"))   
                        printf("操作失败\n");   
                    for (i = 0; i < hlf->count_new; i++)   
                    {   
                        printf("%s", char_to_ascii(content[i]));   
                    }   
                    printf("\n");   
                    if (strstr(content, "\n\r.\n\r"))   
                        printf("数据传输结束\n");   
                }   
                else   
                {   
                    /* POP3服务器接收到新的数据 */   
                    hlf = &pop3_connection->server;   
                    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
                    sprintf(address_string + strlen(address_string), ":%i", ip_and_port.source);   
                    strcat(address_string, " ---> ");   
                    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
                    sprintf(address_string + strlen(address_string), ":%i", ip_and_port.dest);   
                    strcat(address_string, "\n");   
                    printf("--------------------------------\n");   
                    printf("%s", address_string);   
                    memcpy(content, hlf->data, hlf->count_new);   
                    content[hlf->count_new] = '\0';   
                    if (strstr(content, "USER"))   
                        printf("邮件用户名为\n");   
                    if (strstr(content, "PASS"))   
                        printf("用户密码为\n");   
                    if (strstr(content, "STAT"))   
                        printf("返回统计资料\n");   
                    if (strstr(content, "LIST"))   
                        printf("返回邮件数量和大小\n");   
                    if (strstr(content, "RETR"))   
                        printf("获取邮件\n");   
                    if (strstr(content, "DELE"))   
                        printf("删除邮件\n");   
                    if (strstr(content, "QUIT"))   
                        printf("退出连接\n");   
                    for (i = 0; i < hlf->count_new; i++)   
                    {   
                        printf("%s", char_to_ascii(content[i]));   
                    }   
                    printf("\n");   
                }   
            }   
        default:   
            break;   
    }   
    return ;   
}   
/*  
=======================================================================================================================  
主函数  
=======================================================================================================================  
 */   
void main()   
{   
    if (!nids_init())   
     /* Libnids初始化 */   
    {   
        printf("出现错误:%s\n", nids_errbuf);   
        exit(1);   
    }   
    nids_register_tcp(pop3_protocol_callback);   
    /* 注册分析POP3协议的回调函数 */   
    nids_run();   
    /* 进入循环捕获数据包的状态 */   
}   


原文地址:https://www.cnblogs.com/new0801/p/6177685.html