SMTP協議學習筆記

來源:互聯網
上載者:User

這幾天敝人並沒有及時更新部落格,一是由於白天工作中的鎖事比較繁雜,二來連續看了兩個晚上的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:

 

3、先開始抓包,再發送上面的測試郵件,得到的資料包如:

     (要注意Source與Destination,即源地址與目標地址)

 

4、只需要看第20條資料包,其他可以比較容易理解:

 

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檔案:

/************************************************************************/<br />/* main.cpp SMTP協議學習筆記 - 登入驗證<br />/* by Koma 2009.9.10 11:35<br />/* http://blog.csdn.net/wangningyu<br />/************************************************************************/<br />#include "stdio.h"<br />#include "ZBase64.h"<br />#include "winsock2.h"<br />#pragmacomment(lib,"ws2_32.lib") </p><p>int main(int argc, char* argv[])<br />{<br />SOCKADDR_INsaServer;<br />LPHOSTENTlphostent;<br />WSADATAwsadata;<br />SOCKEThsocket;</p><p>intnRet;<br />char* host_name="smtp.tom.com";<br />char* req=<br />// 每發送一行資料服務器都會作出響應<br />"EHLO KOMAWANG/r/n"<br />"AUTH LOGIN/r/n"</p><p>// 兩行是登入使用者與密碼(採用Base64加密)<br />"bm**********20=/r/n"<br />"d2******W4=/r/n"<br />"QUIT/r/n";</p><p>// 初始化通訊端<br />if(WSAStartup(MAKEWORD(2,2),&wsadata))<br />printf("初始化SOCKET出錯!");</p><p>// SMTP連接埠預設是25<br />lphostent=gethostbyname(host_name);<br />if(lphostent==NULL)<br />printf("lphostent為空白!");<br />hsocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);<br />saServer.sin_family = AF_INET;<br />saServer.sin_port = htons(25);<br />saServer.sin_addr = *((LPIN_ADDR)*lphostent->h_addr_list);</p><p>// 利用SOCKET串連<br />nRet = connect(hsocket,(LPSOCKADDR)&saServer,sizeof(SOCKADDR_IN));<br />if(nRet == SOCKET_ERROR)<br />{<br />printf("建立串連時出錯!/n");<br />closesocket(hsocket);<br />return 0;<br />}</p><p>// 利用SOCKET發送<br />nRet = send(hsocket,req,strlen(req),0);<br />if(nRet==SOCKET_ERROR)<br />{<br />printf("發送資料包時出錯!");<br />closesocket(hsocket);<br />}</p><p>char Dest[3000];<br />memset(Dest,0,3000);<br />nRet=1;<br />while(nRet>0)<br />{<br />// 接收返回資料包<br />nRet=recv(hsocket,(LPSTR)Dest,sizeof(Dest),0);<br />if(nRet>0)<br />Dest[nRet]=0;<br />else<br />Dest[0]=0;</p><p>// 顯示返回資料包的大小、內容<br />printf("/n返回資料包大小:%d/n",nRet);<br />printf("返回資料包內容:/n%s",Dest);<br />}<br />return 0;<br />}

 

2、下面是Base64加解密頭與CPP檔案:

/************************************************************************/<br />/* ZBase64.h<br />/************************************************************************/<br />#ifndef _ZBASE64<br />#define _ZBASE64</p><p>#pragma warning(disable:4786)<br />#include <string><br />using namespace std;</p><p>class ZBase64<br />{</p><p>public:</p><p>/*編碼<br />DataByte<br />[in]輸入的資料長度,以位元組為單位<br />*/<br />string Encode(const unsigned char* Data,int DataByte);</p><p>/*解碼<br />DataByte<br />[in]輸入的資料長度,以位元組為單位<br />OutByte<br />[out]輸出的資料長度,以位元組為單位,請不要通過傳回值計算<br />輸出資料的長度<br />*/<br />string Decode(const char* Data,int DataByte,int& OutByte);<br />};<br />#endif

 

/************************************************************************/<br />/* ZBase64.cpp<br />/************************************************************************/<br />#include "ZBase64.h"</p><p>string ZBase64::Encode(const unsigned char* Data,int DataByte)<br />{<br />//編碼錶<br />const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";</p><p>//傳回值<br />string strEncode;</p><p>unsigned char Tmp[3]={0};<br />int LineLength=0;</p><p>for(int i=0;i<(int)(DataByte / 3);i++)<br />{<br /> Tmp[1] = *Data++;<br /> Tmp[2] = *Data++;<br /> Tmp[3] = *Data++;</p><p> strEncode+= EncodeTable[Tmp[1] >> 2];<br /> strEncode+= EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];<br /> strEncode+= EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];<br /> strEncode+= EncodeTable[Tmp[3] & 0x3F];<br />if(LineLength+=4,LineLength==76) {strEncode+="/r/n";LineLength=0;}<br />}</p><p>//對剩餘資料進行編碼<br />int Mod=DataByte % 3;<br />if(Mod==1)<br />{<br /> Tmp[1] = *Data++;<br /> strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];<br /> strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4)];<br /> strEncode+= "==";<br />}<br />else if(Mod==2)<br />{<br />Tmp[1] = *Data++;<br />Tmp[2] = *Data++;<br />strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];<br />strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];<br />strEncode+= EncodeTable[((Tmp[2] & 0x0F) << 2)];<br />strEncode+= "=";<br />}</p><p>return strEncode;<br />}</p><p>string ZBase64::Decode(const char* Data,int DataByte,int& OutByte)<br />{<br />//解碼錶<br />const char DecodeTable[] =<br />{<br />0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,<br />0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,<br />62, // '+'<br />0, 0, 0,<br />63, // '/'<br />52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'<br />0, 0, 0, 0, 0, 0, 0,<br />0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,<br />13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'<br />0, 0, 0, 0, 0, 0,<br />26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,<br />39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'<br />};</p><p>//傳回值<br />string strDecode;</p><p> int nValue;<br /> int i= 0;</p><p> while (i < DataByte)<br /> {<br /> if (*Data != '/r' && *Data!='/n')<br /> {<br /> nValue = DecodeTable[*Data++] << 18;<br /> nValue += DecodeTable[*Data++] << 12;<br />strDecode+=(nValue & 0x00FF0000) >> 16;<br /> OutByte++;</p><p> if (*Data != '=')<br /> {<br /> nValue += DecodeTable[*Data++] << 6;<br />strDecode+=(nValue & 0x0000FF00) >> 8;<br /> OutByte++;</p><p> if (*Data != '=')<br /> {<br /> nValue += DecodeTable[*Data++];<br />strDecode+=nValue & 0x000000FF;<br /> OutByte++;<br /> }<br /> }<br /> i += 4;<br /> }<br /> else// 斷行符號換行,跳過<br /> {<br /> Data++;<br /> i++;<br /> }<br /> }<br />return strDecode;<br />}<br />

 

3、程式運行效果:

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.