dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.04k stars 4.68k forks source link

[API Proposal]: Proxy (HTTP, HTTP tunnel, Socks) support at the Socket level #69595

Open Antonius-S opened 2 years ago

Antonius-S commented 2 years ago

Background and motivation

Now proxies are supported for HTTP requests only but the world obviously is not limited to HTTP protocol. It would be nice to have proxy supported at the lower socket level so that any TCP connection could be proxied.

API Proposal

Current SocksHelper.cs is based on a Stream so we've to use NetworkStream but it requires already connected sockets. Thus proxy feature seems to be only pluggable into TcpClient.

namespace System.Net.Sockets;

TcpClient
{
  public ProxyProps proxyProps;
}

If proxy is set, Connect methods should connect to the proxy host internally and then establish the proxy tunnel.

API Usage

tcpConn.proxyProps.Uri = "socks5://localhost:1080";
await tcpConn.ConnectAsync("example.com:123");

Alternative Designs

Just make SocksHelper and HTTP tunnel helpers public?

Risks

Those who use Socket directly won't get any benefit. Enhance NetworkStream with ability to create and connect a socket?

ghost commented 2 years ago

Tagging subscribers to this area: @dotnet/ncl See info in area-owners.md if you want to be subscribed.

Issue Details
### Background and motivation Now proxies are supported for HTTP requests only but the world obviously is not limited to HTTP protocol. It would be nice to have proxy supported at the lower socket level so that any TCP connection could be proxied. ### API Proposal Current SocksHelper.cs is based on a Stream so we've to use NetworkStream but it requires already connected sockets. Thus proxy feature seems to be only pluggable into TcpClient. ```csharp namespace System.Net.Sockets; TcpClient { public ProxyProps proxyProps; } ``` If proxy is set, `Connect` methods should connect to the proxy host internally and then establish the proxy tunnel. ### API Usage ```csharp tcpConn.proxyProps = "socks5://localhost:1080"; await tcpConn.ConnectAsync("example.com:123"); ``` ### Alternative Designs Just make SocksHelper and HTTP tunnel helpers public? ### Risks Those who use `Socket` directly won't get any benefit. Enhance NetworkStream with ability to create and connect a socket?
Author: Antonius-S
Assignees: -
Labels: `api-suggestion`, `area-System.Net.Http`
Milestone: -
MihaZupan commented 2 years ago

For socks I understand wanting arbitrary connections. But what is your use case for doing things other than http over an http proxy?

Antonius-S commented 2 years ago

For socks I understand wanting arbitrary connections. But what is your use case for doing things other than http over an http proxy?

HTTP tunnel (aka CONNECT) could be used for anything, just like Socks. I personally prefer it over usual HTTP proxy manner (sending request with full remote Uri to proxy host) because of more clear semantic (connect to proxy -> negotiate with proxy -> send request to remote) and unmodified request contents

MihaZupan commented 2 years ago

You already can use CONNECT tunnels for anything - you send a CONNECT http request with SocketsHttpHandler and use the response.Content.ReadAsStreamAsync() as the transport stream. But is it actually commonly used for things other than HTTP to warrant exposing a more convenient API for it?

For the socks part I think it's a reasonable request. We've briefly discussed it when we were adding socks support to the HTTP stack. See https://github.com/dotnet/runtime/pull/48883#issuecomment-790608780. What is your use case for Socks proxies?

I don't think we should be adding anything to TcpClient (see #63162). But we could consider exposing some sort of helper (like what SocksHelper is). Socks also offers more capabilities, like UDP, but I haven't seen any demand for that.

cc: @huoyaoyuan

Antonius-S commented 2 years ago

But is it actually commonly used for things other than HTTP to warrant exposing a more convenient API for it?

Well, I consider HTTP CONNECT option as a Socks analog with similar or even more easy protocol: only one req-resp while Socks requires 2 of them; it's HTTP-like and text-based; server could be written in 10 minutes. And like Socks it could be used for any TCP connection - f.ex., FTP, POP/SMTP/IMAP, SSH and so on. For example, I wrote primitive TLS tunneler exposing HTTP CONNECT interface in Node that occupies only 200 SLOC. However, I don't insist - if there will be only Socks, I'll still be happy.

You already can use CONNECT tunnels for anything - you send a CONNECT http request with SocketsHttpHandler and use the response.Content.ReadAsStreamAsync() as the transport stream.

Yep that's quite usable option for now.

What is your use case for Socks proxies?

Traffic balancing and routing. Running inet-powered apps on multiple hosts through single gateway host, selective accessing blocked domains, tunneling via SSH and many more.

Socks also offers more capabilities, like UDP, but I haven't seen any demand for that.

Me too. I know RDP and RTSP streaming use UDP but I've never needed to proxy them. However, HTTP/3 uses QUIC that is built upon UDP so it likely to have much more attention soon

huoyaoyuan commented 2 years ago

Generally, SOCKS can be used for any TCP and UDP session. UDP case is more complicated since there is bind-receive process.

As #63162 discussed, the TcpClient API is out of date now. We may consider such API on a new designed Tcp API, or we can expose the methods in SocksHelper some way. It can be directly used with NetworkStream.

ghost commented 2 years ago

Tagging subscribers to this area: @dotnet/ncl See info in area-owners.md if you want to be subscribed.

Issue Details
### Background and motivation Now proxies are supported for HTTP requests only but the world obviously is not limited to HTTP protocol. It would be nice to have proxy supported at the lower socket level so that any TCP connection could be proxied. ### API Proposal Current SocksHelper.cs is based on a Stream so we've to use NetworkStream but it requires already connected sockets. Thus proxy feature seems to be only pluggable into TcpClient. ```csharp namespace System.Net.Sockets; TcpClient { public ProxyProps proxyProps; } ``` If proxy is set, `Connect` methods should connect to the proxy host internally and then establish the proxy tunnel. ### API Usage ```csharp tcpConn.proxyProps.Uri = "socks5://localhost:1080"; await tcpConn.ConnectAsync("example.com:123"); ``` ### Alternative Designs Just make SocksHelper and HTTP tunnel helpers public? ### Risks Those who use `Socket` directly won't get any benefit. Enhance NetworkStream with ability to create and connect a socket?
Author: Antonius-S
Assignees: -
Labels: `api-suggestion`, `area-System.Net.Sockets`, `untriaged`
Milestone: -
karelz commented 2 years ago

Triage: As described above, we agree with value for SOCKS support (not via TcpClient, but via some helper API). Not pressing, we will see how many people need it -- if you need it, please uptove top post. Thanks!