public class Socks5ProxyHelp
{
private Socks5ProxyHelp() { }
public static string[] errorMsgs = {
"Operation completed successfully.",//操作成功完成
"General SOCKS server failure.",//常規服務器失敗
"Connection not allowed by ruleset.",//連接不被允許
"Network unreachable.",//網絡不能到達
"Host unreachable.",//主機不能到達
"Connection refused.",//連接被拒絕
"TTL expired.",//TTL期滿
"Command not supported.",//不支持的命令
"Address type not supported.",//不被支持的地址類型
"Unknown error."//未名的錯誤
};
// <summary>
// 連接到socks5代理
// </summary>
// <param name="proxyAdress">代理服務期地址</param>
// <param name="proxyPort">代理服務器端口</param>
// <param name="destAddress">目標地址 Destination: 目的地,UDP命令時是本機的地址</param>
// <param name="destPort">目標端口,UDP命令時是本機的UDP端口</param>
// <param name="userName">用戶名</param>
// <param name="password">密碼</param>
// <returns>用於TCP連接的SOCKET</returns>
public static void ConnectToSocks5Proxy(string proxyAdress, int proxyPort, string userName, string password, out string ErrorMsg)
{
ErrorMsg = "";
IPAddress proxyIP = null;
byte[] request = new byte[257]; //請求
byte[] response = new byte[257];//應答
ushort nIndex;
try
{
proxyIP = IPAddress.Parse(proxyAdress);
}
catch (FormatException)
{
proxyIP = Dns.GetHostEntry(proxyAdress).AddressList[0];
}
// 解析 destAddress (要求是類似 "212.116.65.112" 的string),否則是類似 "www.microsoft.com"的地址
IPEndPoint proxyEndPoint = new IPEndPoint(proxyIP, proxyPort);
Socket s = null;
try
{
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s.Connect(proxyEndPoint);//客戶端連到服務器后,然后就發送請求來協商版本和認證方法:
nIndex = 0;
request[nIndex++] = 0x05; // V 5. [版本]
request[nIndex++] = 0x02; // 2種驗證方式 [方法的數目]
request[nIndex++] = 0x00; // X'00' 不需要認證 [方法1]
request[nIndex++] = 0x02; // X'02' 用戶名/密碼[方法2]
s.Send(request, nIndex, SocketFlags.None);
// 收到2個字節的應答,填充到response中,如果不是兩個字節,則拋出異常
int nGot = s.Receive(response, 2, SocketFlags.None);
if (nGot != 2) throw new Exception("從 proxy server 返回錯誤的應答.");
// 當前定義的方法有:
// X'00' 不需要認證
// X'01' GSSAPI
// X'02' 用戶名/密碼
// X'03' -- X'7F' 由IANA分配
// X'80' -- X'FE' 為私人方法所保留的
// X'FF' 沒有可以接受的方法
switch (response[1])
{
case 0xFF:
沒有可以接受的方法(s);
break;
case 0x02:
用戶名密碼驗證(s, userName, password);
break;
}
}
catch (Exception ex)
{
ErrorMsg = ex.Message;
}
finally
{
if (s != null)
{
s.Close();
s.Dispose();
s = null;
}
}
//SendUDP.UDP命令(s);
}
static void 沒有可以接受的方法(Socket s)
{
// 客戶端沒有一中驗證方式能被服務器接受,則關閉該socket.
s.Close();
throw new Exception("客戶端沒有一中驗證方式能被代理服務器接受.");
}
static bool 用戶名密碼驗證(Socket s, string userName, string password)
{
byte[] request = new byte[257]; //請求
byte[] response = new byte[257];//應答
ushort nIndex;
byte[] rawBytes;
nIndex = 0;
request[nIndex++] = 0x05; // Version 5. 不清楚為什么報文的首字節是0x01(按照慣例應當是0x05)
// 加入 user name
request[nIndex++] = (byte)userName.Length; //一個字節,放UserName的長度
rawBytes = Encoding.Default.GetBytes(userName);
rawBytes.CopyTo(request, nIndex); //將userName 加入
nIndex += (ushort)rawBytes.Length;
// 加入 password
request[nIndex++] = (byte)password.Length; //一個字節,放PassWord的長度
rawBytes = Encoding.Default.GetBytes(password);
rawBytes.CopyTo(request, nIndex);
nIndex += (ushort)rawBytes.Length;
// 發送 Username/Password 請求
s.Send(request, nIndex, SocketFlags.None);
int nGot = s.Receive(response, 2, SocketFlags.None);
if (nGot != 2)
{
throw new Exception("從 proxy server 返回錯誤的應答.");
}
if (response[1] != 0x00) //返回如下的報文字節序列映像為:0x01 | 驗證結果標志-->0x00 驗證通過,其余均表示有故障
{
throw new Exception("賬號或密碼錯誤!");
}
Console.WriteLine("okpass");
return true;
}
}