假期的時候把socks5代理的RFC全部讀完了,有些體會不敢獨享,在這裡寫出來大家一起評論評論,如有錯誤敬請提出。
下面假設使用TCP連接方式。首先需要和代理服務器之間建立連接,這裡沒什麼復雜的,簡單的connect(serverIP, serverPort)就可以了。連接成功之後,需要使用send()發送命令字,以便確定是否需要驗證,下面是RFC裡面的命令字格式:
項目 版本 方式數目 連接方式 … 項目長度 1 1 1-255 …首先"版本"這一項固定是 X"05"(socks version 5),方式數目告訴server究竟提交了幾種連接方式的請求,至於連接方式則可以有多個。下面就是方式列表:
連接方式 含義 X’00’ 無需驗證,直接繼續 X’01’ GSSAPI X’02’ 需要用戶名/密碼 X’03’ to X’7F’ IANA ASSIGNED X’80’ to X’FE’ 保留方式,可以自己靈活選用 X’FF’ 未包含符合要求的方式接下來是server的回應:
項目 版本 允許的連接方式 項目長度 1 1版本不必說,仍然固定是 X"05",允許的連接方式則是在你提交的眾多連接方式中,由server選出一個可以接受的,然後返回來;如果沒有,那麼返回就是 X"FF"。其中一般用到的就是 X"00"和 X"02"了。它們之間的區別就在於 X"02"方式需要發送用戶名/密碼,驗證通過後的過程則和 X"00"方式沒有任何區別。
客戶端識別到server返回 X"02"之後,發送下列格式驗證字串:
項目 VER 用戶名長度 用戶名 密碼長度 密碼 項目長度 1 1 1-255 1 1-255注意:這裡的VER有別於上邊,固定是 X"01"。用戶名/密碼最大長度是255。
server端驗證完畢後返回結果:
項目 VER 驗證結果 項目長度 1 1驗證結果是 X"00"的話,就表示驗證通過,否則都是不過…
接下來的過程一樣,就是發送請求命令字了:
項目 版本 命令字 保留 地址類型 地址 端口 項目長度 1 1 X"00" 1 不固定 2版本固定 X"05";命令字分三種: CONNECT X"01",BIND X"02",UDP X"03"。CONNECT就是普通的TCP連接;BIND要求你的client支持接受server的連接請求(FTP協議就是一個典型的例子);UDP則是一個特例,我還沒有完全理解… 保留項固定是 X"00"。
地址類型有三種:X"01"、X"03"、X"04",分別對應IP-V4、DOMAINNAME、IP-V6,而接下來的地址長度也根據地址類型的不同而變化。IP-V4的長度是4位,DOMAINNAME的長度則根據實際情況變化,但是地址的第一位的內容要設成域名字符串的長度,IP-V6就是16位。
端口長度固定兩位,沒什麼可說的。
而server返回的內容格式也大致相同
項目 版本 返回值 保留 地址類型 地址(BND) 端口 項目長度 1 1 X"00" 1 不固定 2返回值可能是下列值中的一個:
連接方式 含義 X’00’ 成功 X’01’ general SOCKS server failure X’02’ 連接不符合server規格 X’03’ 目標網絡無法到達 X’04’ 目標主機無法到達 X’05’ 連接拒絕 X’06’ TTL expired X’07’ 命令不支持 X’08’ 地址格式不支持 X’09 to X’FF’ 保留
估計各位看完上面的解讀之後仍然是一頭霧水,那麼我就來貼一段代碼,大家就明白了
///////////////////////////////////////////////////////////////////
//
// socks 5 范例
//
//
unsigned char command[10];//准備連接命令字
memset(command,0,10);
command[0]=5;//版本號 05
command[1]=m_bUseSocks5Logon?2:1;//如果需要驗證的話,要發送兩位方式字
command[2]=m_bUseSocks5Logon?2:0;
TRY
{
Send(command,m_bUseSocks5Logon?4:3,0);
int num=Receive(command,2);
if (num!=2)
{
m_nProxyError=PROXYERROR_REQUESTFAILED;
return FALSE;
}
}
CATCH_ALL(e)
{
m_nProxyError=PROXYERROR_REQUESTFAILED;
return FALSE;
}
END_CATCH_ALL
if (command[1]==0xFF)
{
m_nProxyError=PROXYERROR_AUTHREQUIRED;// 0xFF表示失敗,沒有合適的連接方式
return FALSE;
}
if (command[1])
{
if (command[1]!=2)
{
m_nProxyError=PROXYERROR_AUTHTYPEUNKNOWN;// 驗證方式未知
return FALSE;
}
if (m_bUseSocks5Logon)
{
unsigned char *buffer=new unsigned
char[3+m_ProxyUser.GetLength()+m_ProxyPass.GetLength()];
sprintf((char *)buffer," %s %s",m_ProxyUser,m_ProxyPass);//分配用戶名密碼緩沖區
buffer[0]=5;
buffer[1]=m_ProxyUser.GetLength();
buffer[2+m_ProxyUser.GetLength()]=m_ProxyPass.GetLength();
TRY
{
Send(buffer,3+m_ProxyUser.GetLength()+m_ProxyPass.GetLength(),0);
//Get auth response
int num=Receive(command,2);
if (num!=2)
{
delete [] buffer;
m_nProxyError=PROXYERROR_AUTHFAILED;
return FALSE;
}
}
CATCH_ALL(e)
{
delete [] buffer;
m_nProxyError=PROXYERROR_AUTHFAILED;
return FALSE;
}
END_CATCH_ALL
if (command[1]!=0x00)
{
delete [] buffer;
m_nProxyError=PROXYERROR_AUTHFAILED;
return FALSE;
}
delete [] buffer;
}
else
{
m_nProxyError=PROXYERROR_AUTHNOLOGON;
return FALSE;
}
}
//構建請求
memset(command,0,10);
command[0]=5;
command[1]=1;
command[2]=0;
command[3]=1;
memcpy(&command[4],&sockAddr->sin_addr.S_un.S_addr,4);
memcpy(&command[8],&sockAddr->sin_port,2);
//上面只提供了IP-4地址方式,其他的可以自行更改代碼
TRY
{
Send(command,10,0);
int num=Receive(command,10);
if (num!=10)
{
m_nProxyError=PROXYERROR_REQUESTFAILED;
return FALSE;
}
}
CATCH_ALL(e)
{
m_nProxyError=PROXYERROR_REQUESTFAILED;
return FALSE;
}
END_CATCH_ALL
if (command[1]!=0x00)
{
m_nProxyError=PROXYERROR_REQUESTFAILED;
return FALSE;
}
總之就是這個樣子了,如果還有不明白的地方.