SMTP协议学习笔记

http://blog.csdn.net/wangningyu/article/details/4538120

一、准备工作:

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服务器并验证

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值