这个 SOCKS 代理请求出了啥问题?

Posted

技术标签:

【中文标题】这个 SOCKS 代理请求出了啥问题?【英文标题】:What's going wrong with this SOCKS proxy request?这个 SOCKS 代理请求出了什么问题? 【发布时间】:2011-01-18 01:11:26 【问题描述】:

我目前正在尝试在我的 C++ 程序中实现 SOCKS 4/5 功能(即,如果需要,可以通过给定的 SOCKS 代理重定向对任意协议和主机的请求)。我纯粹为 Windows 开发,所以使用 Winsock 2。

不过,我的问题比简单的“这是如何工作的”要抽象一些。我已经阅读了 SOCKS 4 的 RFC(我决定首先实现 SOCKS 4,因为它的请求中要处理的字节更少)但我正在努力创建我需要 send() 的 C 字符串强>。

目前,我定义了一个名为 Socks4Msg 的结构,如下所示:

struct Socks4Msg 
const static uint8_t version = 0x04; //SOCKS version 4 (obviously)
const static uint8_t command = 0x01; //1 is TCP CONNECT command
const static uint8_t nullbyte = 0x00; //null byte sent at message end

uint16_t port; //16 bit/2 byte port (network order)
uint32_t ip; //32 bit/4 byte IP address (network order)
Socks4Msg(uint16_t p, uint32_t i) : port(p), ip(i)  
;

创建实际套接字并完成工作的函数在这里(其中 p 和 h 保存端口和主机以测试 通过代理 -- p 是一个字符串以保持与 HttpProxy 的兼容性我已经实现了)。 port 和 addr 是类的一部分,分别是 int 和 string;它们是代理服务器的详细信息。

int Socks4Proxy::test(std::string p, std::string h) const 
uint16_t network_port = htons(str_to_numt<uint16_t>(p));
uint32_t network_ip = hostname_to_ip(h);
Socks4Msg msg_struct(network_port,network_ip);

SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
int last_error;
if(s == INVALID_SOCKET) 
              last_error = WSAGetLastError();
              std::cerr << "Failed to initialise socket! Error code: " << last_error << std::endl; 
              return 2;


sockaddr_in st_addr;
st_addr.sin_family = AF_INET;
st_addr.sin_port = htons(port);
ipaddr_t ip = inet_addr(addr.c_str());
st_addr.sin_addr.S_un.S_addr = ip;

if(connect(s,(sockaddr*)&st_addr,sizeof(st_addr))!=0) 
                                                      last_error = WSAGetLastError();
                                                      std::cerr << "Socket failed to connect. Error code: " << last_error << std::endl;
                                                      return 2;  


uint8_t message[13];
uint8_t* message_ptr;
memset(message, 0, 13);
message_ptr = message;
*message_ptr = msg_struct.version;
message_ptr++;
*message_ptr = msg_struct.command;
message_ptr++;
*message_ptr = msg_struct.port;
message_ptr += 2;
*message_ptr = msg_struct.ip;
message_ptr += 4;
*message_ptr = 'b'; message_ptr++; *message_ptr = 'o'; message_ptr++; *message_ptr = 'b'; message_ptr++;
*message_ptr = msg_struct.nullbyte;
message_ptr++;
*message_ptr = 0x00;
char smessage[13];
memcpy(smessage, message, 13);

int return_val;
while(return_val = send(s, smessage, strlen(smessage), 0)) 
                       if(return_val == SOCKET_ERROR) 
                                     last_error = WSAGetLastError();
                                     std::cerr << "Writing data failed. Error code: " << last_error << std::endl;
                                     return 2;
                       
                       //implement return_val < strlen(message) here
                       else break;

//remainder of function

在 C 字符串操作开始之前,我已经测试并验证了 msg_struct 的成员包含正确的数据(并且以正确的字节顺序)。

我尝试使用 memcpy()(例如 memcpy(message_ptr, &msg_struct.port, 2)) 代替分配,但我就是不明白为什么 Wireshack 总是引用发送数据的字节长度为 2(即版本和命令),但仅此而已。 (我知道我对 C 字符串的了解——因此当时的代码——有点粗糙,但我无法解释为什么它不起作用)

任何建议将不胜感激!

【问题讨论】:

【参考方案1】:

首先message_ptruint8_t**message_ptr = msg_struct.ip; 是错误的。您应该将message_ptr 转换为uint_32t* 然后分配数据,如* ((uint32_t*)message_ptr) = msg_struct.ip; 否则 msg_struct.ip 将转换为 uint8_t 然后分配。其他领域也有同样的问题。

检查一下,让我知道它是否再次工作:)

顺便说一句。我认为 Wireshark 网络流量分析器可以帮助您解决此类问题。

更新

可能更好的主意是创建一个结构来表示您要发送的消息并将message_ptr 转换为该结构上的指针。但是不要忘记告诉你的编译器不要添加任何填充。

更新 2

网络和主机字节顺序。

不要忘记您应该使用 hton、ntoh、htonl 或 ntohl 函数更改字节顺序。

【讨论】:

感谢您的建议。好的,我分别为端口和 IP 添加了强制转换 *((uint16_t*)message_ptr) 和 *((uint32_t*)message_ptr)。不过没有变化。 Wireshark 报告消息正文是 0x04 0x01,这很好,因为它是正确的,只是被严重截断。非常均匀。 :P 检查 strlen(smessage) 值。它可能非常小,因为您的文本中可能有 '\0',而协议消息不是文本;)据我所知,由于*message_ptr = msg_struct.nullbyte;,它至少比您预期的少 1 个字节 关于将整个东西放在一个结构中的想法:这根本不是一个坏主意。可能几个小时前就应该想到它并保存了我的一些头发,但至少还剩下一些。 :) 干杯,我会这样做,看看会发生什么。 我看到你是新来的。只是一个小建议 - 不要忘记单击 + 并接受解决方案以感谢其他 ppl 的帮助。祝你好运;) 结果! strlen() 返回 2。而 that 将是我的问题!坐在那里盯着每一行看了一会儿,我从来没有想过。谢谢,会的。

以上是关于这个 SOCKS 代理请求出了啥问题?的主要内容,如果未能解决你的问题,请参考以下文章

DNS 的 SOCKS5 代理如何在浏览器中工作?

是否存在支持 SSL 的 SOCKS 代理服务器?

删除 SOCKS 4/5 代理

JSch 是不是支持 SOCKS5 代理?

通过 Java 中的 SOCKS 代理进行 SOAP 调用

使用 Charles Proxy Socks 功能调试 iPhone 流量?