首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >认证- SOCKS 5

认证- SOCKS 5
EN

Stack Overflow用户
提问于 2018-02-26 18:26:15
回答 1查看 612关注 0票数 0

我正在编写一个SOCKS 5服务器,它与SOCKS 5客户端(maxthon浏览器)对话。我让它在没有认证的情况下工作。但是,当我添加身份验证时,

客户端将用户/pass发送到服务器服务器验证用户/pass

服务器向客户端发送响应

代码语言:javascript
复制
+----+--------+
|VER | STATUS |
+----+--------+
| 1  |   1    |
+----+--------+ 

VER = 0x01 STATUS = 0x00 (成功)

  1. 我认为这是身份验证的结束是正确的吗?

之后我试着从客户端读取数据,

代码语言:javascript
复制
+----+-----+-------+------+----------+----------+
|VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1  |  1  | X'00' |  1   | Variable |    2     |
+----+-----+-------+------+----------+----------+

但是,此时读取的字节并不等于此结构的大小所期望的字节。字节读取== 0。

  1. 有什么问题吗?

如果我取出身份验证,我的服务器就能正常工作。不过,我想让它发挥作用。

编辑

以下是服务器对客户端进行身份验证后的代码:

代码语言:javascript
复制
    socks5_login SOCKS5_Login;
    if (Str::Compare(UserName, PUCHAR("test")) == 0 && Str::Compare(Password, PUCHAR("test")) == 0) {

        SOCKS5_Login.Version = 0x01;
        SOCKS5_Login.Status  = 0x00;
        if (Http::SendProxyData(Settings->Sock, PCHAR(&SOCKS5_Login), sizeof(socks5_login), Settings->Func) != TRUE)
            return FALSE;

        UCHAR Status;
        Settings->Func.Recv(Settings->Sock, PCHAR(Status), sizeof(UCHAR), 0);

        if (Status != NO_ERROR)
            return FALSE;

        /*
            The SOCKS request is formed as follows:
                +----+-----+-------+------+----------+----------+
                |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
                +----+-----+-------+------+----------+----------+
                | 1  |  1  | X'00' |  1   | Variable |    2     |
                +----+-----+-------+------+----------+----------+
        */

        socks5_request Request;
        if (Http::ReadProxyData(Settings->Sock, PCHAR(&Request.SOCKS5_Header), sizeof(socks5_header), Settings->Func) != TRUE)
            return FALSE;

        if (Request.SOCKS5_Header.Command != 1/*CONNECT*/ && 
            Request.SOCKS5_Header.AddressType != 1 /*IPv4*/ &&
            Request.SOCKS5_Header.Version != 5 /*SOCKS Version 5*/)
            return FALSE;

        // ...

读取Request.SOCKS5_Header时,Http::ReadProxyData()函数返回FALSE ( recv()返回0 )。

EN

回答 1

Stack Overflow用户

发布于 2018-02-26 19:57:22

在发送身份验证回复后,您正在读取UCHAR (并且您正在将其未定义的值类型转换为PCHAR,因为您没有使用&地址运算符将其传递给Recv()。因此,您可能会崩溃您的代码!)。客户端不向您的答复发送回复。通过读取该UCHAR,您将读取下一个请求的VER字段,这意味着以后读取完整的Request可能会失败。

你根本不应该读那个UCHAR

更重要的是,您正在将身份验证回复的VER字段设置为0x01而不是0x05。您说正在为下一个请求读取的字节数为0。这意味着客户端正在优雅地关闭连接,如果您发送格式错误的身份验证回复,这是有意义的。

再仔细阅读RFC 1928RFC 1929。图表显示每个字段的字节大小,而不是应该将字段设置为的值(这些值在图表后面的列表中描述)。例如:

代码语言:javascript
复制
+----+--------+
|VER | STATUS |
+----+--------+
| 1  |   1    |
+----+--------+ 

表示VER字段的大小为1字节,STATUS字段的大小为1字节。并不是说您应该将VER字段设置为1。

此外,您展示的代码末尾的if应该使用||运算符而不是&&运算符。尽管如此,您确实不应该以自己的方式验证请求字段,因为不同的条件要求您向客户端发送不同的错误代码,以便它知道请求失败的原因。

尝试更像这样的东西:

代码语言:javascript
复制
socks5_login LoginReply;
LoginReply.Version = 5;

if (Str::Compare(UserName, PUCHAR("test")) == 0 && Str::Compare(Password, PUCHAR("test")) == 0)
    LoginReply.Status = 0; /*success*/
else
    LoginReply.Status = 1; /*failure*/

if (Http::SendProxyData(Settings->Sock, PCHAR(&LoginReply), sizeof(LoginReply), Settings->Func) != TRUE)
{
    // close the connection...
    return FALSE;
}

if (LoginReply.Status != 0)
{
    // close the connection...
    return FALSE;
}

/*
The SOCKS request is formed as follows:
    +----+-----+-------+------+----------+----------+
    |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
    +----+-----+-------+------+----------+----------+
    | 1  |  1  | X'00' |  1   | Variable |    2     |
    +----+-----+-------+------+----------+----------+
*/

socks5_request Request;

// I'm assuming that SOCKS5_Header is only the 1st 4 bytes of the request...
if (Http::ReadProxyData(Settings->Sock, PCHAR(&Request.SOCKS5_Header), sizeof(socks5_header), Settings->Func) != TRUE)
{
    // close the connection...
    return FALSE;
}

if (Request.SOCKS5_Header.Version != 5) /*SOCKS Version 5*/
{
    // I'm assuming you have something like this defined.
    // Adjust this code as needed. What is important is that
    // you need to send back a Reply code before disconnecting...
    socks5_reply Reply;
    UCHAR dst[6] = {0}; // <-- if socks5_reply doesn't have DST.ADDR/DST.PORT fields of its own...

    Reply.SOCKS5_Header.Version = 5;
    Reply.SOCKS5_Header.Status = 1; /*general SOCKS server failure*/
    Reply.SOCKS5_Header.Reserved = 0;
    Reply.SOCKS5_Header.AddressType = 1;

    Http::SendProxyData(Settings->Sock, PCHAR(&Reply.SOCKS5_Header), sizeof(socks5_header), Settings->Func);
    Http::SendProxyData(Settings->Sock, PCHAR(dst), sizeof(dst), Settings->Func);

    // close the connection...
    return FALSE;
}

if (Request.SOCKS5_Header.Command != 1) /*CONNECT*/
{
    // same as above...
    Reply.SOCKS5_Header.Status = 7; /*Command not supported*/
    ...
    return FALSE;
}

if (Request.SOCKS5_Header.AddressType != 1) /*IPv4*/
{
    // same as above...
    Reply.SOCKS5_Header.Status = 8; /*Address type not supported*/
    ...
    return FALSE;
}

// finish reading DST.ADDR and DST.PORT fields into Request...
// use Request as needed...
// send a Reply accordingly...
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48994787

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档