C# 連接 Socks5 代理


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;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM