我正在编写一个SOCKS 5服务器,它与SOCKS 5客户端(maxthon浏览器)对话。我让它在没有认证的情况下工作。但是,当我添加身份验证时,
客户端将用户/pass发送到服务器服务器验证用户/pass
服务器向客户端发送响应
+----+--------+
|VER | STATUS |
+----+--------+
| 1 | 1 |
+----+--------+ VER = 0x01 STATUS = 0x00 (成功)
之后我试着从客户端读取数据,
+----+-----+-------+------+----------+----------+
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+但是,此时读取的字节并不等于此结构的大小所期望的字节。字节读取== 0。
如果我取出身份验证,我的服务器就能正常工作。不过,我想让它发挥作用。
编辑
以下是服务器对客户端进行身份验证后的代码:
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 )。
发布于 2018-02-26 19:57:22
在发送身份验证回复后,您正在读取UCHAR (并且您正在将其未定义的值类型转换为PCHAR,因为您没有使用&地址运算符将其传递给Recv()。因此,您可能会崩溃您的代码!)。客户端不向您的答复发送回复。通过读取该UCHAR,您将读取下一个请求的VER字段,这意味着以后读取完整的Request可能会失败。
你根本不应该读那个UCHAR。
更重要的是,您正在将身份验证回复的VER字段设置为0x01而不是0x05。您说正在为下一个请求读取的字节数为0。这意味着客户端正在优雅地关闭连接,如果您发送格式错误的身份验证回复,这是有意义的。
再仔细阅读RFC 1928和RFC 1929。图表显示每个字段的字节大小,而不是应该将字段设置为的值(这些值在图表后面的列表中描述)。例如:
+----+--------+
|VER | STATUS |
+----+--------+
| 1 | 1 |
+----+--------+ 表示VER字段的大小为1字节,STATUS字段的大小为1字节。并不是说您应该将VER字段设置为1。
此外,您展示的代码末尾的if应该使用||运算符而不是&&运算符。尽管如此,您确实不应该以自己的方式验证请求字段,因为不同的条件要求您向客户端发送不同的错误代码,以便它知道请求失败的原因。
尝试更像这样的东西:
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...https://stackoverflow.com/questions/48994787
复制相似问题