当前位置: 移动技术网 > IT编程>开发语言>.net > C# 连接 Socks5 代理

C# 连接 Socks5 代理

2019年06月13日  | 移动技术网IT编程  | 我要评论

焦作旅游网,纠缠不清 柠檬火焰,idea945

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网