• SMTP协议学习笔记


    这几天敝人并没有及时更新博客,一是由于白天工作中的锁事比较繁杂,二来连续看了两个晚上的SMTP协议。

    我比较喜欢用实践来证明一切,这样才会加深自己的理解!

    一、准备工作:

    1、本机环境:Windows XP SP3、ADSL 10M光纤

    2、开发工具:WildPackets OmniPeek V5.1.4

                        Visual C++ 6.0

                        Outlook Express6.0

                        FlexEdit V2.3.1871

    二、SMTP命令:

    1、HELO 向服务器标识用户身份
    2、MAIL 初始化邮件传输mail from: <xxx>
    3、RCPT 标识单个的邮件接收人;常在MAIL命令后面可有多个rcpt to: <xxx>
    4、DATA 在单个或多个RCPT命令后,表示所有的邮件接收人已标识,初始化数据传输,以.结束
    5、NOOP 无操作,服务器应响应OK
    6、RSET 重置会话,当前传输被取消
    7、QUIT 结束会话

    三、分析数据包:

    1、打开Outlook Express6.0,创建新邮件,内容如下:

    测试邮件

    2、打开OmniPeek,选择SMTP:

    选择滤镜/SMTP

    3、先开始抓包,再发送上面的测试邮件,得到的数据包如下图:

         (要注意Source与Destination,即源地址与目标地址)

    SMTP Packets

    4、只需要看第20条数据包,其他可以比较容易理解:

    SMTP

    5、其他小技巧

         <CR> <LF>即对应C/C++中的"/r /n"

         比如 Line 8: charset="gb2312"<CR><LF>,因为需要用到转义字符

         所以对应的字符串应该为char * sData = "charset=/"gb2312/"/r/n";

    四、相关代码:

    1、以下代码通过socket与SMTP服务器建立连接并验证身份。打开Visual C++,新建一个控制台工程、并添加一个CPP文件:

    1. /************************************************************************/  
    2. /* main.cpp  SMTP协议学习笔记 - 登录验证 
    3. /* by Koma 2009.9.10 11:35 
    4. /* http://blog.csdn.net/wangningyu 
    5. /************************************************************************/  
    6. #include "stdio.h"    
    7. #include "ZBase64.h"   
    8. #include "winsock2.h"      
    9. #pragma comment(lib,"ws2_32.lib")      
    10.   
    11. int main(int argc, char* argv[])  
    12. {  
    13.     SOCKADDR_IN saServer;  
    14.     LPHOSTENT   lphostent;  
    15.     WSADATA     wsadata;  
    16.     SOCKET      hsocket;  
    17.   
    18.     int     nRet;  
    19.     char*   host_name="smtp.tom.com";  
    20.     char*   req=  
    21.         // 每发送一行数据服务器都会作出响应   
    22.         "EHLO KOMAWANG/r/n"  
    23.         "AUTH LOGIN/r/n"  
    24.   
    25.         // 两行是登录用户与密码(采用Base64加密)   
    26.         "bm**********20=/r/n"  
    27.         "d2******W4=/r/n"  
    28.         "QUIT/r/n";  
    29.   
    30.     // 初始化套接字   
    31.     if(WSAStartup(MAKEWORD(2,2),&wsadata))     
    32.         printf("初始化SOCKET出错!");  
    33.   
    34.     // SMTP端口默认是25   
    35.     lphostent=gethostbyname(host_name);     
    36.     if(lphostent==NULL)     
    37.         printf("lphostent为空!");  
    38.     hsocket   =   socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);     
    39.     saServer.sin_family = AF_INET;     
    40.     saServer.sin_port = htons(25);     
    41.     saServer.sin_addr = *((LPIN_ADDR)*lphostent->h_addr_list);  
    42.   
    43.     // 利用SOCKET连接   
    44.     nRet = connect(hsocket,(LPSOCKADDR)&saServer,sizeof(SOCKADDR_IN));     
    45.     if(nRet == SOCKET_ERROR)     
    46.     {     
    47.         printf("建立连接时出错!/n");     
    48.         closesocket(hsocket);     
    49.         return 0;     
    50.     }  
    51.   
    52.     // 利用SOCKET发送   
    53.     nRet = send(hsocket,req,strlen(req),0);  
    54.     if(nRet==SOCKET_ERROR)  
    55.     {  
    56.         printf("发送数据包时出错!");  
    57.         closesocket(hsocket);  
    58.     }  
    59.   
    60.     char   Dest[3000];  
    61.     memset(Dest,0,3000);  
    62.     nRet=1;     
    63.     while(nRet>0)     
    64.     {  
    65.         // 接收返回数据包   
    66.         nRet=recv(hsocket,(LPSTR)Dest,sizeof(Dest),0);     
    67.         if(nRet>0)     
    68.             Dest[nRet]=0;     
    69.         else     
    70.             Dest[0]=0;  
    71.   
    72.         // 显示返回数据包的大小、内容   
    73.         printf("/n返回数据包大小:%d/n",nRet);     
    74.         printf("返回数据包内容:/n%s",Dest);     
    75.     }  
    76.     return 0;  
    77. }  

    2、下面是Base64加解密头与CPP文件:

    1. /************************************************************************/  
    2. /* ZBase64.h 
    3. /************************************************************************/  
    4. #ifndef _ZBASE64   
    5. #define _ZBASE64   
    6.   
    7. #pragma warning(disable:4786)    
    8. #include <string>   
    9. using namespace std;  
    10.   
    11. class ZBase64  
    12. {  
    13.   
    14. public:  
    15.   
    16.     /*编码 
    17.     DataByte 
    18.         [in]输入的数据长度,以字节为单位 
    19.     */  
    20.     string Encode(const unsigned char* Data,int DataByte);  
    21.   
    22.     /*解码 
    23.     DataByte 
    24.         [in]输入的数据长度,以字节为单位 
    25.     OutByte 
    26.         [out]输出的数据长度,以字节为单位,请不要通过返回值计算 
    27.         输出数据的长度 
    28.     */  
    29.     string Decode(const char* Data,int DataByte,int& OutByte);  
    30. };  
    31. #endif  

    1. /************************************************************************/  
    2. /* ZBase64.cpp 
    3. /************************************************************************/  
    4. #include "ZBase64.h"   
    5.   
    6. string ZBase64::Encode(const unsigned char* Data,int DataByte)  
    7. {  
    8.     //编码表   
    9.     const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  
    10.   
    11.     //返回值   
    12.     string strEncode;  
    13.   
    14.     unsigned char Tmp[3]={0};  
    15.     int LineLength=0;  
    16.   
    17.     for(int i=0;i<(int)(DataByte / 3);i++)  
    18.     {  
    19.         Tmp[1] = *Data++;  
    20.         Tmp[2] = *Data++;  
    21.         Tmp[3] = *Data++;  
    22.   
    23.         strEncode+= EncodeTable[Tmp[1] >> 2];  
    24.         strEncode+= EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];  
    25.         strEncode+= EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];  
    26.         strEncode+= EncodeTable[Tmp[3] & 0x3F];  
    27.         if(LineLength+=4,LineLength==76) {strEncode+="/r/n";LineLength=0;}  
    28.     }  
    29.   
    30.     //对剩余数据进行编码   
    31.     int Mod=DataByte % 3;  
    32.     if(Mod==1)  
    33.     {  
    34.         Tmp[1] = *Data++;  
    35.         strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];  
    36.         strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4)];  
    37.         strEncode+= "==";  
    38.     }  
    39.     else if(Mod==2)  
    40.     {  
    41.         Tmp[1] = *Data++;  
    42.         Tmp[2] = *Data++;  
    43.         strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];  
    44.         strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];  
    45.         strEncode+= EncodeTable[((Tmp[2] & 0x0F) << 2)];  
    46.         strEncode+= "=";  
    47.     }  
    48.       
    49.     return strEncode;  
    50. }  
    51.   
    52. string ZBase64::Decode(const char* Data,int DataByte,int& OutByte)  
    53. {  
    54.     //解码表   
    55.     const char DecodeTable[] =  
    56.     {  
    57.         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
    58.         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
    59.         62, // '+'   
    60.         0, 0, 0,  
    61.         63, // '/'   
    62.         52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'   
    63.         0, 0, 0, 0, 0, 0, 0,  
    64.         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,  
    65.         13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'   
    66.         0, 0, 0, 0, 0, 0,  
    67.         26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  
    68.         39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'   
    69.     };  
    70.   
    71.     //返回值   
    72.     string strDecode;  
    73.   
    74.     int nValue;  
    75.     int i= 0;  
    76.    
    77.     while (i < DataByte)  
    78.     {  
    79.         if (*Data != '/r' && *Data!='/n')  
    80.         {  
    81.             nValue = DecodeTable[*Data++] << 18;  
    82.             nValue += DecodeTable[*Data++] << 12;  
    83.             strDecode+=(nValue & 0x00FF0000) >> 16;  
    84.             OutByte++;  
    85.    
    86.             if (*Data != '=')  
    87.             {  
    88.                 nValue += DecodeTable[*Data++] << 6;  
    89.                 strDecode+=(nValue & 0x0000FF00) >> 8;  
    90.                 OutByte++;  
    91.    
    92.                 if (*Data != '=')  
    93.                 {  
    94.                     nValue += DecodeTable[*Data++];  
    95.                     strDecode+=nValue & 0x000000FF;  
    96.                     OutByte++;  
    97.                 }  
    98.             }  
    99.             i += 4;  
    100.         }  
    101.         else// 回车换行,跳过   
    102.         {  
    103.             Data++;  
    104.             i++;  
    105.         }  
    106.      }  
    107.     return strDecode;  
    108. }  

    3、程序运行效果:

     登录SMTP服务器并验证

  • 相关阅读:
    添加事件(jquery)
    闭包导致的问题
    学习之js绑定事件
    第二条 一个类如果有多个参数,考虑用Builder构造者模式
    用Intellij IDEA 创建第一个maven项目!
    OrderSessionHelper查看订单在session是否存在的辅助类
    css——overflow
    css——盒子
    css——外部样式
    css——权重叠加
  • 原文地址:https://www.cnblogs.com/hehehaha/p/6332957.html
Copyright © 2020-2023  润新知