iroh-net: provide a way to supply custom TLS connection code for relay
In Delta Chat we have custom code to setup TLS connections that supports built-in DNS cache and various types of proxies: SOCKS5, HTTP(S) proxies and Shadowsocks. This code is used for all IMAP, SMTP and HTTPS connections except for the connection to iroh relay. Because of this relay connection is less reliable, e.g. it will not work if DNS is down and it cannot work over Shadowsocks which is not supported by iroh-net.
If's fine for STUN and P2P QUIC connection to be outside of control for iroh-net library user, but for relay we need some way to provide custom code to establish TLS connections that can reuse existing DNS caches, certificate checking code and so on. iroh can then run HTTP stream on top of generic stream.
This would presumably also need to be enabled for the various HTTPS probes in netcheck?
- captive portal check
- https probe (ping) check
also what about general DNS resolution of the relay urls, and in the discovery service?
what about general DNS resolution of the relay urls
Does iroh resolve relay URLs without the intention to establish a connection to the relay?
For the discovery service I don't know, Delta Chat has it disabled I think, but if it is some HTTPS endpoint accessed via TLS then it should also be possible to proxy it. For DHT I think it's fine if it tries to connect directly, worst case DHT does not work on corporate networks that require that users access the internet via SOCKS5 or HTTP CONNECT proxy.
This would presumably also need to be enabled for the various HTTPS probes in netcheck?
captive portal check
I don't know what captive portal check is for. If it is about public Wi-Fi captive portal, then why does iroh need to know about it? User has to open it in a browser anyway.
https probe (ping) check
This should definitely use the same connection establishment code as actual relay connection code.
In Delta Chat we have custom code to setup TLS connections that supports built-in DNS cache and various types of proxies: SOCKS5, HTTP(S) proxies and Shadowsocks. This code is used for all IMAP, SMTP and HTTPS connections except for the connection to iroh relay.
I assume the reason you went for custom TLS setup code in favor of, say, using reqwest (given it supports SOCKS5, HTTP(s) proxies and DNS resolution customization), is that you want to also use this for IMAP and SMPT, right?
I'm thinking through what it'd mean if we double-down on reqwest in iroh-net, so we get SOCKS5, HTTP(s) proxies, etc. all out of the box for all requests we make in iroh-net, and have them be configurable in one way.
I'm thinking through what it'd mean if we double-down on reqwest in iroh-net, so we get SOCKS5, HTTP(s) proxies, etc. all out of the box for all requests we make in iroh-net, and have them be configurable in one way.
In Delta Chat we have all TCP connection established via single function: https://github.com/deltachat/deltachat-core-rust/blob/800edc6fcefd11cf485b2eb118db012e39e0f5de/src/net.rs#L227-L244
This ensures we use the same DNS resolution, same timeouts, etc. TLS setup is also mostly unified, so we can switch implementation in one place and later enable e.g. ECH for all connections Delta Chat uses: https://github.com/deltachat/deltachat-core-rust/pull/6186
Using reqwest will not help with having the same code for all TCP connections. reqwest still uses its own custom code for DNS resolution, its own implementation of scheduling attempts for IP address connection (Happy Eyeballs algorithm) and only supports SOCKS5 and HTTP(S) proxies with likely not exactly compatible syntax. It does not support Shadowsocks and even if https://github.com/shadowsocks/shadowsocks-rust is added as a dependency for reqwest we may add different protocols in the future and different authentication mechanisms for existing proxies like HTTP(S) digest authentication.
What I want is avoiding situation where some server is reachable over HTTPS, SMTP and IMAP, but connection to relay fails because DNS is down, timeouts are lower, IP addresses are tried in different order or not at all, TLS certificate is considered invalid while we have it in our certificate storage etc.
trait Dialer should probably have just one function dial(hostname, port), similar to https://github.com/NLnetLabs/connectbyname/blob/e6d29baf10b30140a256d59448e68fa0c0407d27/proto9/connectbyname.h#L179-L180 and return Result<impl AsyncRead + AsyncWrite + Unpin + 'static> (maybe also throw + Debug in)
Another example is Outline SDK, interface has a single function that gets a string like "iroh.example.org:1234" and returns a stream: https://github.com/Jigsaw-Code/outline-sdk/blob/dc0a0b0f1af41a29b1000e347b00fbc5b5acc05a/transport/stream.go#L131
Maybe also pass ALPN in, but if you only use HTTP/1.1 connections then it's not needed. Can always be added later with a breaking change if required.
If you add QUIC and WebTransport for relay connection, this will of course change the needed API because there a single AsyncRead + AsyncWrite connection is not enough. Also UDP may be completely unavailable, some proxy protocols only relay TCP (e.g. HTTP CONNECT) so it should be expected that UDP attempts will fail immediately.