Open xljiulang opened 1 month ago
For HTTP, you can generally use the ConnectCallback
@xljiulang. AFAIK This is only one place where DNS would be used and you can completely customize that.
On Socket
there is also API that takes array of IPAddresses
, so doing custom resolution and passing the result there would be trivial IMHO.
Now some improvements around name resolutions are being discussed. This is perhaps related to #19443. But that covers just the API not integration with rest of the .NET
I'm wondering if you can elaborate more on the use cases.
@wfurt I am very pleased that many of these network components support passing in IPAddress directly or indirectly, but it obviously does not conflict with the need to design a DnsClient abstract class and apply it to these network components. For SocketsHttpHandler, although it has a custom connection method of ConnectCallback, without DnsClient, I think many developers cannot handle the following connection method well:
I have implemented the HostResolver function of SocketsHttpHandler in a private project. In order to implement custom host resolution, I wrote a total of about 1,000 lines of cs code.
public static IHttpMessageHandlerBuilder AddHostResolver<THostResolver>(this IHttpMessageHandlerBuilder builder)
where THostResolver : HostResolver
{
builder.Services.TryAddTransient<THostResolver>();
return builder.AddHostResolver(serviceProvider => serviceProvider.GetRequiredService<THostResolver>());
}
http/1.1 and http2 connection
This works fine with ConnectCallback
since it's agnostic about the underlying HTTP2/HTTP3 protocol. The job of ConnectCallback
is to create a Stream
for the communication.
WebProxy connection https WebProxy connection Socks4 and 5 connection
Similarly, I don't see a problem with these. Proxy and tunnel connections are plumbed through ConnectCallback
.
http3 connection
It would be very challanging to integrate msquic with a managed DnsResolver since the code that handles the resolution attempts has to live in msquic to be efficient, see https://github.com/dotnet/runtime/issues/82404#issuecomment-2041023799. It is doable if msquic implemented some sort of callback, but IMHO it is very far on their roadmap (for now the next step is https://github.com/microsoft/msquic/issues/1181). #64449 might enable a sub-optimal implementation on user side.
In order to implement custom host resolution, I wrote a total of about 1,000 lines of cs code.
We plan to eventually address #19443 so users can get rid of that code, however currently we are uncertain if we can land that feature in .NET 9.0. Have you considered using DnsClient.NET?
@antonfirsov Thank you for your answer. The difficulty of my problem is not to implement a DnsClient with complete functions and protocols, but that even with DnsClient, developers still have to write a lot of cs code to integrate it into network components such as SocketsHttpHandler. For example, although it is enough to create a Socks4 and 5 connection as the function's return Stream, developers have to implement the complex connection process of the Socks4 and 5 connection from scratch. Of course, the same is true for other proxy connection methods. Think about what our original needs are? Why did it become a variety of complex connections.
There still may be some value in the proposal IMHO. But again back to my question, why do you need custom resolution to start with @xljiulang? I can see that the ConnectCallback
may be more complicated if you want to cover all the cases above.
One thing developers sometimes struggle with are 3rd party libraries where something happens under the cover. Is that something we should also consider? This is also one case where the callback is problematic.
Since the DNS protocol is insecure, its resolution results are contaminated in some specific areas. In this case, the application needs a more secure Doh protocol or other custom resolution implementation, and the application cannot modify the system. DNS configuration. To be honest, I don't want to know how SocketsHttpHandler's ConnectCallback should work. I just want it to provide a DNS resolver property to set the resolver.
We can keep this as a tracking issue for exposing an easier API to customize DNS resolution than ConnectCallback
assuming #19443 will be implemented. Given that the other issue has priority, I'm triaging this to Future, @wfurt let me know if you disagree.
To be honest, I don't want to know how SocketsHttpHandler's ConnectCallback should work. I just want it to provide a DNS resolver property to set the resolver
If this is blocking you, I think you should give it a try.
although it is enough to create a Socks4 and 5 connection as the function's return Stream, developers have to implement the complex connection process of the Socks4 and 5 connection from scratch
This is not true. ConnectCallback
is a relatively thin abstraction for DNS resolution and TCP connection. SocketsHttpHandler
will deal with the proxy/tunnel establishment for you. The callback could be as simple as:
using SocketsHttpHandler handler = new()
{
ConnectCallback = async (ctx, ct) =>
{
var s = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
try
{
IPAddress[] addresses = await MyCustomResolver.ResolveIPAddressesAsync(ctx.DnsEndPoint.Host, ct);
await s.ConnectAsync(addresses, ctx.DnsEndPoint.Port, ct);
return new NetworkStream(s, ownsSocket: true);
}
catch
{
s.Dispose();
throw;
}
}
};
Background and motivation
Today, network components such as HttpClient directly rely on the Dns static class that is deeply bound to the operating system. This means that if you want to change the DNS resolution of the application, you can only change the Dns configuration of the operating system.
API Proposal
API Usage
Alternative Designs
No response
Risks
No response