I have couple of questions about the UDP requests in SOCKS5. I've already read this paper https://www.rfc-editor.org/rfc/rfc1928#section-7 and i'm trying to implement it in C++.
Questions:
Do i need to use the "UDP request header" in both sending and receiving?
Can i use something like "WSASendTo" from winsock2 to redirect packets trough the SOCKS5 server?
Do i need to use the "UDP request header" in both sending and receiving?
Yes. This is covered in the document section you linked to:
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:
...
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.
That means that both UDP datagrams sent by you to the SOCKS relay, and UDP datagrams you receive from the SOCKS relay, carry the same header.
Can i use something like "WSASendTo" from winsock2 to redirect packets trough the SOCKS5 server?
You can use WSASendTo() to send your own datagrams to the SOCKS relay, yes.
But, if by redirect you mean to make other applications' UDP sockets send/receive datagarms through the SOCKS relay without their knowledge, then no.
Related
I'm trying to use SOCKS v5 proxy with TIdUDPClient. I'm using C++ Builder 10.3 in Windows x64.
Here is my code so far:
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();
I can connect to my server perfectly without the proxy.
But, it fails to connect with the proxy, so I sniffed the network with wireshark:
The UDP client sends "0.0.0.0" and 0 as the remote info, instead of sending the host and port I set in the code.
Is there anything I can do to fix this?
TIdUDPClient::Connect() will call TIdSocksInfo::OpenUDP() to send a UDP ASSOCIATION request to a SOCKS v5 proxy. TIdUDPClient passes its Host and Port property values as parameters to OpenUDP().
However, TIdSocksInfo::OpenUDP() ignores these Host and Port values that are passed to it. It is hard-coded to send IP 0.0.0.0 (or ::0 for IPv6) and port 0 to the SOCKS proxy. And this is OK, per the SOCKS v5 spec, 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.
So, in a UDP ASSOCIATION request, the specified Host/Port is the local Host/Port that the client will send outgoing datagrams from, or zeros if it does not know that info yet. This lets the proxy's UDP relay know where datagrams will come from when datagrams are being sent from the client to a target peer, and where to send datagrams to when datagrams are being sent from a target peer to the client. If the requested Host/Port is all zeros, the relay should simply use the Host/Port that sent the request.
The Host/Port specified in a UDP ASSOCIATION request is NOT the target peer Host/Port that datagrams are to be forwarded to, like you are thinking. That target info is specified in the individual datagrams that the client will pass to the proxy for forwarding AFTER the association is created. Unlike TCP, UDP is connection-less, so a client can create a single association and then send datagrams to multiple targets, if it wants to.
There is no connection in UDP, so there is nothing for the proxy to send to the target server while processing a UDP ASSOCIATION request. It is simply setting up the proxy's listening port that will then relay subsequent datagrams between the client and the target server.
When sending datagrams for forwarding afterwards, TIdUDPClient::SendBuffer() will call TIdSocksInfo::SendToUDP(), which is also passed the TIdUDPClient's Host and Port property values. SendUDP() will then send a datagram with that target info to the proxy's relay port:
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.
...
So, whatever problem you are having with communicating with your target server, it is likely not related to TIdUDPClient1::Connect() at all, it is more likely related to TIdUDPClient::SendBuffer() and TIdUDPClient::ReceiveBuffer() instead. Either:
the proxy's UDP relay is ignoring the datagrams that TIdUDPClient is requesting be forwarded to the target server, or it is ignoring the server's replies.
datagrams are getting lost in flight on their way to the target server, or on their way back to the proxy.
If you sniff TIdUDPClient's traffic again and see your actual communication datagrams targeting your server properly, then you are going to have to sniff the traffic on the other side of the proxy to make sure those datagrams are actually being forwarded onward. If they are, then the problem has to be on the network or the server itself. If they are not, then the problem has to be on the proxy itself.
I have a UDP server, but I have no UDP capability on client side. Is there a way to send packet via TCP so that UDP server can receive it normally? UDP server cannot be transformed into TCP server.
Reason for wanting to do this is that I'm using a SOCKS5 proxy that does not support UDP associate capability, but I have to use that proxy.
No. The UDP server cannot complete the 3-way handshake required for TCP. If you have IP-raw sockets, it is actually easier to implement UDP on top. However it seems extremely unlikely that you don't have a UDP-stack.
When you talk about "no UDP capability" do you mean the client has no UDP-stack, or is he just behind some firewall that blocks UDP? In the latter case use a proxy.
No, UDP server will not going to accept TCP packets at all (it's a different protocol, so network stack will never propagate those to the application).
If you have to use SOCKS5 proxy, the only way to connect to the said server is by using another proxy-like application, which will stand beyond SOCKS5, accept TCP connections (initiated by app behind SOCKS5 proxy) and retransmit data as UDP.
I have been looking at a lot of Boost.Asio tutorials, especially this one:
TCP daytime server
After a server creates a tcp_connection with a client, it seems like the communication is only one-way between the server and that specific client. How can I make it so a server has the ability to relay client messages to all of the clients connected? Or even choose which clients to send messages to.
TCP create only connexion between the server and a specific client. You can use UDP connexion to broadcast message to several clients.
Like JTejedor says in comments, you can also create a TCP socket for each client.
I know that SOCKS 5 supports UDP and I have been over the structure of the packets that are sent/received in negotiating with a SOCKS proxy.
The one thing I am not clear on is the procedure for setting up to register with a proxy to send/receive UDP packets.
Specifically, my biggest question is, "Is the connection to the SOCKS proxy that is used to negotiate a UDP associate relationship still made with TCP/IP?". In other words, "Do you end up using a TCP/IP socket to receive UDP packets routed through a SOCKS proxy?"
I would imagine that, if you used a TCP/IP connection to establish a pathway for UDP communication, you'd kind of be missing the whole point of establishing UDP communications. However, on the other hand, if the negotiation were made using UDP (and resulted in a UDP socket), then how would the relationship be terminated when your application is shutting down and no longer needs the proxy to "remember" you?
I have been all over the net looking for an example...but can't find anything. Any help (especially an example) would be appreciated.
https://www.rfc-editor.org/rfc/rfc1928
"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"
but
"UDP association terminates when the TCP connection that the UDP
ASSOCIATE request arrived on terminates."
I actually tried using it once, but failed, because many "socks5" proxy
implementations don't actually support the complete protocol.
So I'd suggest to set up a working test case first (find an app which
would support socks5 udp proxy, and a proxy where it would actually work).
Then any network sniffer would tell you how it really works (if it does).
I am writing simple client-server program.
Client send some messages to server using UDP or TCP. Server must be able to support both UDP and TCP.
If client, sends message using UDP, sequence of method calls in client is socket(),bind(),sendto(),recvfrom(),close() and that in server is socket(),bind(),sendto(),recvfrom(),close().
If it uses TCP,
sequence of call in server is
socket(),bind(),listen(),accept(),send(),recv(),close().
and that in client is
socket(),bind(),connect(),send(),recv(),close()
In my program, user/client is given choice in the start to select what he want to use UDP or TCP. So, my main problem is how can I know or differentiate in the server side, if the client is sending message using TCP or UDP. If it uses TCP, I must call listen(),accept(),send(),recv()
and if it uses UDP, I don't call listen(),accept() but call sendto() and recvfrom().
So, how can I differentiate/know this in the beginning so that I can make appropriate function calls.
Thanks.
Before the packet reaches you, you don't know whether it's UDP or TCP.
So you want to bind to both UDP and TCP sockets if you expect requests both ways.
Once you did, you just know which way it came by the socket you received the packet through.
When you create the socket, you pass a type - SOCK_STREAM (TCP) or SOCK_DGRAM (UDP)
So the two kinds of traffic will be on two different sockets.
Just as Henry Troup pointed out, an IP socket is defined as
(transport, interface, port).
(UDP, 127.0.0.1, 80) is not the same IP socket as (TCP, 127.0.0.1, 80) , thus you can safely bind to both of them and listen for incoming traffic.
just let the TCP socket listen on port X, and do the UDP connections through port Y