Giter Site home page Giter Site logo

DNS resolution about futures-rs HOT 24 CLOSED

rust-lang avatar rust-lang commented on June 12, 2024
DNS resolution

from futures-rs.

Comments (24)

alexcrichton avatar alexcrichton commented on June 12, 2024 1

Ok I'm going to close this for now in favor of https://github.com/sbstp/tokio-dns now that it exists.

from futures-rs.

alexcrichton avatar alexcrichton commented on June 12, 2024

Yeah I would love to have asynchronous DNS resolution, it's definitely a missing feature! Right now you can actually do this on stable Rust via to_socket_addrs and the SOCKSv5 proxy has an example of this. That example also does the work on a thread pool.

In general the pieces should be there in the sense of:

  • The futures-cpupool crate provides a thread pool to perform resolution on
  • The standard library provides to_socket_addrs to perform resolution

In the future though I'd love to integrate with something like rotor-dns or c-ares, as they'd slot in very nicely!

from futures-rs.

sbstp avatar sbstp commented on June 12, 2024

Gee, I feel stupid, I totally forgot about the ToSocketAddr trait. I haven't been using it because it may return addresses that don't work, and you have to try many addresses and figure out which one works. It would be nice if that process could be implemented to the futures crate too.

from futures-rs.

alexcrichton avatar alexcrichton commented on June 12, 2024

It's true yeah, although I'm not actually sure what the best practice is for a DNS query that returns multiple addresses. If that happens should we issue a bunch of parallel TCP connects and select the first one that returns? Or should we try each one in series with a particular timeout?

from futures-rs.

sbstp avatar sbstp commented on June 12, 2024

Sequential could be slow (although it is the current behavior of std::net), and parallel could "spam" the server if all the addresses end up working. Perhaps the loop could have a setting describing how it should try to connect, and the user could pick the appropriate one for their use. Perhaps use sequential as a default, and if the users need performance, they can choose parallel.

from futures-rs.

MarkusJais avatar MarkusJais commented on June 12, 2024

I agree with sbstp. Best to have an option to pick the appropriate strategy. It depends on the individual requirements of an application, network settings, etc.
If a call "spams" the server some network security tools might block access completely.

from futures-rs.

carllerche avatar carllerche commented on June 12, 2024

Whatever the DNS solution turns out to be, I would like to try to coordinate w/ Tokio as there is a need there as well.

from futures-rs.

alexcrichton avatar alexcrichton commented on June 12, 2024

Indeed! To me this is sort of a "quest issue" right now where it's less so about how to expose it but moreso how to implement it. First we need to find an appropriate implementation!

from futures-rs.

sbstp avatar sbstp commented on June 12, 2024

Here's a draft of what the API could look like.

I would create a futurs-dns crate that offers a variety of resolvers. For now we can provide a thread-pool based resolver, and eventually use rotor-dns or c-ares to provide an asynchronous resolver, as Alex mentionned.

Obviously the various resolvers would have to conform to an interface, which might look like this:

trait Resolver {
  fn resolve(&self, hostname: &str) -> BoxFuture<Vec<IpAddr>, io::Error>
}

A trait similar to ToSocketAddrs will be needed to allow various representations of an endpoint. However, unlike ToSocketAddrs, this trait will not perform DNS resolution. It will simply indicate (via the Endpoint enum) that a hostname was used and that DNS resolution should be performed on it.

trait ToEndpoint {
    fn to_endpoint() -> io::Result<(Endpoint, u16)>;
}

enum Endpoint<'a> {
    Hostname(&'a str),
    SocketAddr(SocketAddr),
}

If to_endpoint() returns the Hostname variant, DNS resolution has to be performed. Otherwsie, the socket can connect instantly to the SocketAddr. Here's what tcp_connect might look like with the new interface.

fn <T>tcp_connect(endpoint: T) -> IoFuture<TcpSocket> where T: ToEndpoint {
    match endpoint.to_endpoint() {
        Endpoint::Hostname(host) => {
            // perform dns resolution
            // try to connect to the addresses returned by `resolve`
        }
        Endpoint::SocketAddr(addr) => {
            // connect directly
        }
    }
}

Finally, the futures-mio loop should have settings regarding which resolver to use and how to perform connection (sequential / parallel).

Thoughts?

from futures-rs.

alexcrichton avatar alexcrichton commented on June 12, 2024

Sounds pretty reasonable to me! I agree that the event loop would likely have a global resolver for functions like handle.tcp_connect, and then that'd be swappable to allow for various kinds of resolvers.

Now we just need some implementations :)

from futures-rs.

sbstp avatar sbstp commented on June 12, 2024

I'd love to write a PR for this. Just wanted some feedback before starting.

from futures-rs.

alexcrichton avatar alexcrichton commented on June 12, 2024

Perhaps we can start out with a simple implementation of just using futures-cpupool with the to_socket_addrs trait? We may want to avoid adding traits to futures-mio just yet but we could at least get "make a TCP connection to this hostname" methods up and running pretty soon.

That is, we could provide a concrete resolver, and that resolver could have tcp_connect methods as well as extension traits for types like UdpSocket to work with hostnames as well as socket addresses.

from futures-rs.

sbstp avatar sbstp commented on June 12, 2024

Yeah I'll use futures-cpupool + to_socket_addrs. I would add the structs/traits/enums in a futures-dns and have the mio crate depend on it. That way people can use the resolver without mio.

I'm not sure if an extension trait can be used, because we need to keep the CpuPool object around.

from futures-rs.

alexcrichton avatar alexcrichton commented on June 12, 2024

For now we may want the dependency the other way (dns depending on mio) so eventually we can implement dns with UDP in mio itself

from futures-rs.

sbstp avatar sbstp commented on June 12, 2024

If it's done this way, it won't be possible for the mio loop to use an arbitrary resolver via the Resolver trait.
If futures-mio depends on futures-dns the UDP resolver can be implemented in the futures-mio crate.

from futures-rs.

alexcrichton avatar alexcrichton commented on June 12, 2024

Indeed! I'm thinking we should prototype support outside of the futures-mio crate first, and then when we're happy with it we can move it in.

from futures-rs.

carllerche avatar carllerche commented on June 12, 2024

I would suggest making the trait take an associated type for the return value. This would allow it to be more globally usable. You could define the loop global version to have a boxed return type.

from futures-rs.

bluejekyll avatar bluejekyll commented on June 12, 2024

I'm working on adding futures/streams to trust-dns. I have some thoughts that i'd love some feedback on.

  1. we want to support more than just A record lookup, definitely need AAAA as well, for the "basic" ip lookup.

  2. in addition, we need to support other record types, like SRV for instance.

  3. CNAME records are obviously very common usage, should we support implicit chained lookups to resolve CNAME, probably yes.

  4. I want to support a secure version for my own needs that will support client side DNSSec validation.

Given these requirements, does anyone have a strong preference for what this generic resolver trait would look like?

from futures-rs.

sbstp avatar sbstp commented on June 12, 2024

I don't know if the Resolve trait should have an API this low level. 1) and 3) should definitely be supported, but they can be implemented using the current API.

from futures-rs.

bluejekyll avatar bluejekyll commented on June 12, 2024

I think 3 is probably straight forward. I can give people an internal interface for 2&4.

But for 1, how should we do AAAA and A? In my client code I am planning on establishing connections based on the IP of the server, i.e. if the IpAddr for the NameServer is v4, establish a udp_client for v4, if v6 use v6 (obviously).

We could do the same with A vs. AAAA, i.e. base it off the NameServer address, but this might not be correct given that some NameServers may only be working over ipv4. I know many OSes first query AAAA and then fall back to A. I guess, how much logic do we want in the resolver, vs. requiring the consumer of the interface to make some of these decisions.

from futures-rs.

sbstp avatar sbstp commented on June 12, 2024

Right now, the Resolver can return multiple IpAddrs. It's up to the connection code to find one that works. Currently my tokio-dns crate offers both parallel and sequential algorithms. It up to the user to use the connection mode they prefer.

I think that the resolver should follow CNAMEs, then request AAAA & A records. Returning multiple IpAddrs is an appropriate way of doing things, and is similar to getaddrinfo.

from futures-rs.

alexcrichton avatar alexcrichton commented on June 12, 2024

@bluejekyll those requirements definitely sound good to me for a robust dns crate, but the tokio-dns crate that @sbstp is pioneering is a little different I think. Rather I think that tokio-dns is intended to be DNS resolution "for the masses" in the sense that it contains the functionality necessary for 90% of requests, which is typically just "I'd like to connect to this hostname/port" or "I'd like to resolve this hostname to some IP addresses".

For the remaining functionality, which I'm sure will actually be quite common in some circumstances, I'd expect the trustdns bindings to provide far more granular configuration and APIs. An implementation of a trait in tokio-dns could be layered on top, but it would also provide a suite of other functionality (like you mentioned in 2/4).

Unfortunately the maximum for tokio-dns is probably about what to_socket_addrs can give us right now. That is, we probably need to always be able to implement that trait with the standard library's to_socket_addrs, but that doesn't meant that more flavorful implementations can't exist!

I was talking with @aturon yesterday about how we might integrate DNS resolution with the event loop itself, and we're still a little up in the air.

from futures-rs.

bluejekyll avatar bluejekyll commented on June 12, 2024

@sbstp agree.

@alexcrichton, yeah, I've been looking at the nuts and bolts so long, I've almost forgotten how most people use DNS ;) All of this makes sense, I just want to make sure that I have the right context such that I can provide a similar interface for people to use.

I think it would be interesting (at least for me) to give people some options on how DNS is used in to_socket_addrs or tokio-dns. Things like being able to add an in process cache rather than relying on external resolvers for example could be really powerful.

from futures-rs.

alexcrichton avatar alexcrichton commented on June 12, 2024

Oh yeah I think we definitely want pluggable backends at a bare minimum. It'd be cool to then have a number of "dns middleware" layers like process caches or the like!

Also to be clear, currently tokio-core doesn't do any DNS resolution. It's still deferred to the user to figure out how to do that, but I'd very much like that to change!

from futures-rs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.