如何正确使用带有 TIdUDPClient 的 SOCKS 5 代理

How to use SOCKS 5 proxy with TIdUDPClient properly

我正在尝试将 SOCKS v5 代理与 TIdUDPClient 一起使用。我在 Windows x64.

中使用 C++ Builder 10.3

到目前为止,这是我的代码:

TIdSocksInfo* socksInfo = new TIdSocksInfo();
socksInfo->Host = "ip address of the proxy server";
socksInfo->Port = proxyPort;
socksInfo->Version = svSocks5;
socksInfo->Authentication = saNoAuthentication;

IdUDPClient1->Host = "ip address of my udp server";
IdUDPClient1->Port = port;
IdUDPClient1->TransparentProxy = socksInfo;
IdUDPClient1->Connect();

我可以在没有代理的情况下完美地连接到我的服务器。

但是,它无法连接到代理,所以我用 wireshark 嗅探了网络:

UDP 客户端发送“0.0.0.0”和 0 作为远程信息,而不是发送我在代码中设置的主机和端口。

我能做些什么来解决这个问题吗?

TIdUDPClient::Connect() 将调用 TIdSocksInfo::OpenUDP() 向 SOCKS v5 代理发送 UDP 关联请求。 TIdUDPClient 将其 HostPort 属性 值作为参数传递给 OpenUDP().

但是,TIdSocksInfo::OpenUDP() 会忽略传递给它的这些主机和端口值。将 IP 0.0.0.0(或 ::0 用于 IPv6)和端口 0 发送到 SOCKS 代理是硬编码的。这没关系,根据 SOCKS v5 规范,RFC 1928:

UDP ASSOCIATE

The UDP ASSOCIATE request is used to establish an association within the UDP relay process to handle UDP datagrams. The DST.ADDR and DST.PORT fields contain the address and port that the client expects to use to send UDP datagrams on for the association. The server MAY use this information to limit access to the association. If the client is not in possesion of the information at the time of the UDP ASSOCIATE, the client MUST use a port number and address of all zeros.

A UDP association terminates when the TCP connection that the UDP ASSOCIATE request arrived on terminates.

In the reply to a UDP ASSOCIATE request, the BND.PORT and BND.ADDR fields indicate the port number/address where the client MUST send UDP request messages to be relayed.

因此,在 UDP ASSOCIATION 请求中,指定的 Host/Port 是 local Host/Port,客户端将从中发送传出数据报,或者如果它还不知道该信息。这让代理的 UDP 中继知道当数据报从客户端发送到目标对等点时数据报将来自何处,以及当数据报从目标对等点发送到客户端时将数据报发送到哪里。如果请求的Host/Port全为零,中继应该简单地使用发送请求的Host/Port。

UDP ASSOCIATION 请求中指定的 Host/Port 是 NOT 数据报要转发到的目标对等点 Host/Port,如您所想。该目标信息在单独的数据报中指定,客户端将传递给代理以进行转发 AFTER 关联已创建。与 TCP 不同,UDP 是无连接的,因此客户端可以创建单个关联,然后根据需要将数据报发送到多个目标。

UDP 中没有连接,因此代理在处理 UDP 关联请求时没有任何内容可以发送到目标服务器。它只是设置代理的侦听端口,然后在客户端和目标服务器之间中继后续数据报。

之后发送数据报进行转发时,TIdUDPClient::SendBuffer()会调用TIdSocksInfo::SendToUDP(),也是通过TIdUDPClientHostPort属性 值。 SendUDP() 然后将包含该目标信息的数据报发送到代理的中继端口:

A UDP-based client MUST send its datagrams to the UDP relay server at the UDP port indicated by BND.PORT in the reply to the UDP ASSOCIATE request. If the selected authentication method provides encapsulation for the purposes of authenticity, integrity, and/or confidentiality, the datagram MUST be encapsulated using the appropriate encapsulation. Each UDP datagram carries a UDP request header with it:

... [request header, containing DST.ADDR and DST.PORT in it] ...

When a UDP relay server decides to relay a UDP datagram, it does so silently, without any notification to the requesting client. Similarly, it will drop datagrams it cannot or will not relay. When a UDP relay server receives a reply datagram from a remote host, it MUST encapsulate that datagram using the above UDP request header, and any authentication-method-dependent encapsulation.

The UDP relay server MUST acquire from the SOCKS server the expected IP address of the client that will send datagrams to the BND.PORT given in the reply to UDP ASSOCIATE. It MUST drop any datagrams arriving from any source IP address other than the one recorded for the particular association.

...

因此,无论您在与目标服务器通信时遇到什么问题,它很可能根本与 TIdUDPClient1::Connect() 无关,更可能与 TIdUDPClient::SendBuffer()TIdUDPClient::ReceiveBuffer() 有关反而。或者:

  • 代理的 UDP 中继忽略了 TIdUDPClient 请求转发到目标服务器的数据报,或者忽略了服务器的回复。

  • 数据报在前往目标服务器或返回代理的途中丢失。

如果您再次嗅探 TIdUDPClient 的流量并正确地看到以您的服务器为目标的实际通信数据报,那么您将不得不嗅探代理另一端的流量以确保这些数据报实际上正在转发。如果是,则问题必须出在网络或服务器本身上。如果不是,则问题必须出在代理本身上。