[GH-ISSUE #1259] Reverselookup Slooooow #634

Closed
opened 2026-03-15 23:33:03 +03:00 by kerem · 13 comments
Owner

Originally created by @JRAndreassen on GitHub (Oct 20, 2020).
Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/1259

Describe the bug
The reverse lookup is extremely slow
As are the SOA queries at times...
It appears it misses the responses some times...

To Reproduce
See attached code...
Adapted from async global example

Expected behavior
Well... faster

System:

  • OS: Windows 10
  • Architecture: x86_64
  • Version Microsoft Windows [Version 10.0.18363.1139]
  • rustc version:
    stable-x86_64-pc-windows-msvc - Up to date : 1.47.0 (18bf6b4f0 2020-10-07)
    stable-x86_64-unknown-linux-gnu - Up to date : 1.47.0 (18bf6b4f0 2020-10-07)

Version:
Crate: trust-dns-resolver
Version: "0.20.0"

cargo.toml

trust-dns-resolver = { version = "*", git = "https://github.com/bluejekyll/trust-dns.git" }
futures-util = { version = "0.3.5", default-features = false, features = ["std"] }
tokio = { version = "0.2", features = ["full"]}
lazy_static = "*"
futures = "*"

main.rs

use std::{
    task::{
        Poll
    },
    io,
    net::{
        SocketAddr,
        IpAddr,
    },
    fmt::{
        Display,
    }
};


use lazy_static::{
    lazy_static
};

use tokio;

use futures::Future;
use futures_util::future;
use trust_dns_resolver;
use trust_dns_resolver::{
    TokioAsyncResolver, 
    IntoName, TryParseIp,
    lookup::Lookup,
    proto::{
        rr::{
            Name, Record, 
            RecordType, 
        },
        xfer::DnsRequestOptions,        
    },
};

pub fn await_future<F: Future>(f: F) -> F::Output {
    futures::executor::block_on( async { f.await})
}

lazy_static! {
    // First we need to setup the global Resolver
    static ref GLOBAL_DNS_RESOLVER: TokioAsyncResolver = {
        use std::sync::{Arc, Mutex, Condvar};
        use std::thread;

        // We'll be using this condvar to get the Resolver from the thread...
        let pair = Arc::new((Mutex::new(None::<TokioAsyncResolver>), Condvar::new()));
        let pair2 = pair.clone();
        #[allow(unused_assignments,unused_variables)] 

        // Spawn the runtime to a new thread...
        //
        // This thread will manage the actual resolution runtime
        thread::spawn(move || {
            // A runtime for this new thread
            let mut runtime = tokio::runtime::Runtime::new().expect("failed to launch Runtime");
            // our platform independent future, result, see next blocks
            let resolver = {

                // To make this independent, if targeting macOS, BSD, Linux, or Windows, we can use the system's configuration:
                #[cfg(any(unix, windows))]
                {
                    // use the system resolver configuration
                    TokioAsyncResolver::from_system_conf(runtime.handle().clone())
                }

                // For other operating systems, we can use one of the preconfigured definitions
                #[cfg(not(any(unix, windows)))]
                {
                    // Directly reference the config types
                    use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};

                    // Get a new resolver with the google nameservers as the upstream recursive resolvers
                    TokioAsyncResolver::new(ResolverConfig::quad9(), ResolverOpts::default(), runtime.handle().clone())
                }
            };

            let &(ref lock, ref cvar) = &*pair2;
            let mut started = lock.lock().unwrap();

            // let resolver = current_handle.block_on(resolver).expect("failed to create trust-dns-resolver");
            let resolver = resolver.expect("failed to create trust-dns-resolver");

            *started = Some(resolver);
            cvar.notify_one();
            drop(started);

            runtime.block_on(future::poll_fn(|_cx| Poll::<()>::Pending))
        });

        // Wait for the thread to start up.
        let &(ref lock, ref cvar) = &*pair;
        let mut resolver = lock.lock().unwrap();
        while resolver.is_none() {
            resolver = cvar.wait(resolver).unwrap();
        }

        // take the started resolver
        let resolver = std::mem::replace(&mut *resolver, None);

        // set the global resolver
        resolver.expect("resolver should not be none")
    };
}

pub async fn resolve_socket<N: IntoName + Display + TryParseIp + 'static>(
    host: N,
    port: u16,
) -> io::Result<Vec<SocketAddr>> {
    // Now we use the global resolver to perform a lookup_ip.
    let name = host.to_string();
    let result = GLOBAL_DNS_RESOLVER.lookup_ip(host).await;
    // map the result into what we want...
    result
        .map_err(move |err| {
            // we transform the error into a standard IO error for convenience
            io::Error::new(
                io::ErrorKind::AddrNotAvailable,
                format!("dns resolution error for {}: {}", name, err),
            )
        })
        .map(move |lookup_ip| {
            // we take all the IPs returned, and then send back the set of IPs
            lookup_ip
                .iter()
                .map(|ip| SocketAddr::new(ip, port))
                .collect::<Vec<_>>()
        })
}

pub async fn resolve<N: IntoName + Display + TryParseIp + 'static>(
    host: N,
    record_type: RecordType,
    options: Option<DnsRequestOptions>,
) -> io::Result<Lookup> {
    // Now we use the global resolver to perform a lookup_ip.
    let name = host.to_string();
    let opts  =
      if let Some(iopt) = options {
        iopt
      } else {DnsRequestOptions::default()};

    let result = 
        GLOBAL_DNS_RESOLVER.lookup(host, record_type, opts).await;
    // map the result into what we want...
    result
        .map_err(move |err| {
            // we transform the error into a standard IO error for convenience
            io::Error::new(
                io::ErrorKind::AddrNotAvailable,
                format!("dns resolution error for {}: {}", name, err),
            )
        })
}

pub fn resolve_sync<N: IntoName + Display + TryParseIp + 'static>(
    host: N,
    record_type: RecordType,
    options: Option<DnsRequestOptions>,
) -> io::Result<Lookup> {
    await_future(resolve(host, record_type, options))
}

pub async fn resolve_ip<N: IntoName + Display + TryParseIp>(
    host: N
) -> io::Result<Vec<IpAddr>> {
    // Now we use the global resolver to perform a lookup_ip.
    let name = host.to_string();
    let result = GLOBAL_DNS_RESOLVER.lookup_ip(host).await;
    // map the result into what we want...
    result
        .map_err(move |err| {
            // we transform the error into a standard IO error for convenience
            io::Error::new(
                io::ErrorKind::AddrNotAvailable,
                format!("dns resolution error for {}: {}", name, err),
            )
        })
        .map(move |lookup_ip| {
            // we take all the IPs returned, and then send back the set of IPs
            lookup_ip
                .iter()
                .collect::<Vec<_>>()
        })
}

pub fn resolve_ip_sync(host: &str) -> io::Result<Vec<IpAddr>> {

    // Lookup the IP addresses associated with a name.
    // The final dot forces this to be an FQDN, otherwise the search rules as specified
    //  in `ResolverOpts` will take effect. FQDN's are generally cheaper queries.
    await_future(resolve_ip(host))

}

pub async fn reverse_lookup(
    ip_addr: IpAddr
) -> io::Result<Vec<String>> {
    // Now we use the global resolver to perform a lookup_ip.
    //let name = host.to_string();
    let result = GLOBAL_DNS_RESOLVER.reverse_lookup(ip_addr).await;
    // map the result into what we want...
    result
        .map_err(move |err| {
            // we transform the error into a standard IO error for convenience
            io::Error::new(
                io::ErrorKind::AddrNotAvailable,
                format!("rdns resolution error for {}: {}", ip_addr, err),
            )
        })
        .map(move |lookup_name| {
            // we take all the IPs returned, and then send back the set of IPs
            lookup_name
                .iter()
                .map(|s| s.to_string() )
                .collect::<Vec<String>>()
        })
}

pub fn reverse_lookup_sync(ip_addr: IpAddr) -> io::Result<Vec<String>> {

    // Lookup the IP addresses associated with a name.
    // The final dot forces this to be an FQDN, otherwise the search rules as specified
    //  in `ResolverOpts` will take effect. FQDN's are generally cheaper queries.
    await_future(reverse_lookup(ip_addr))

}

pub fn test_validate_all(host: &'static str)
{
	println!("----------- {} -----------", host);
	let val = resolve_sync(host, RecordType::SOA, None).unwrap();
	println!("Resolved[SOA]: {:?}", val);
	let val = resolve_sync(host, RecordType::MX, None).unwrap();
	println!("Resolved[MX]: {:?}", val);
}
	
#[tokio::main]
async fn main() {
    
    std::thread::yield_now();
    let val = resolve_ip_sync("localhost").unwrap();
    println!("Resolved: {:?}", val);
    let val_gw = resolve_ip_sync("204.65.230.1").unwrap();
    println!("Resolved: {:?}", val_gw);
    let val = resolve_ip_sync("rackspace.com").unwrap();
    println!("Resolved: {:?}", val);
    let val = resolve_ip_sync("google.com").unwrap();
    println!("Resolved: {:?}", val);

  // Sloooow
    let val = reverse_lookup_sync(val_gw[0]).unwrap();
    println!("Reverse: {:?}", val);
/*
     No.	Time	Source	Destination	Protocol	Length	Info
     15	3.920132	172.20.40.25	9.9.9.9	DNS	96	Standard query 0xaba6 PTR 1.230.65.204.in-addr.arpa OPT
     16	3.981643	9.9.9.9	172.20.40.25	DNS	164	Standard query response 0xaba6 No such name PTR 1.230.65.204.in-addr.arpa SOA ns.capnet.state.tx.us OPT
     43	54.055271	8.8.8.8	172.20.40.25	TCP	60	53 → 65047 [ACK] Seq=1 Ack=57 Win=65536 Len=0
     44	54.059747	172.20.41.15	172.20.40.25	TCP	60	53 → 65046 [ACK] Seq=1 Ack=3 Win=65536 Len=0
     45	54.059784	172.20.40.25	172.20.41.15	DNS	108	Standard query 0xd7cf PTR 1.230.65.204.in-addr.arpa OPT
     46	54.060410	172.20.41.15	172.20.40.25	DNS	178	Standard query response 0xd7cf No such name PTR 1.230.65.204.in-addr.arpa SOA ns.capnet.state.tx.us OPT
     47	54.080447	8.8.8.8	172.20.40.25	DNS	178	Standard query response 0xbbf2 No such name PTR 1.230.65.204.in-addr.arpa SOA ns.capnet.state.tx.us OPT
*/    
  // Also Sloooow
	test_validate_all("google.com");
/*  No.	Time	Source	Destination	Protocol	Length	Info
    1	0.000000	172.20.40.25	172.20.41.15	DNS	74	Standard query 0x3420 A 4.sophosxl.net
    2	0.000845	172.20.41.15	172.20.40.25	DNS	202	Standard query response 0x3420 A 4.sophosxl.net A 52.205.94.43 A 3.224.96.206 A 34.193.178.220 A 52.0.151.141 A 34.231.106.102 A 52.204.13.73 A 3.224.253.17 A 34.227.137.252
    3	1.776129	172.20.40.25	172.20.41.15	DNS	81	Standard query 0xa04a SOA google.com OPT
    4	1.776193	172.20.40.25	8.8.8.8	DNS	81	Standard query 0x3b00 SOA google.com OPT
    5	1.799151	8.8.8.8	172.20.40.25	DNS	131	Standard query response 0x3b00 SOA google.com SOA ns1.google.com OPT
    6	1.801309	172.20.40.25	9.9.9.9	DNS	81	Standard query 0x28b8 MX google.com OPT
    7	1.852966	9.9.9.9	172.20.40.25	DNS	189	Standard query response 0x28b8 MX google.com MX 20 alt1.aspmx.l.google.com MX 30 alt2.aspmx.l.google.com MX 10 aspmx.l.google.com MX 40 alt3.aspmx.l.google.com MX 50 alt4.aspmx.l.google.com OPT
    8	1.871566	172.20.41.15	172.20.40.25	DNS	175	Standard query response 0xa04a SOA google.com SOA ns1.google.com A 216.239.32.10 AAAA 2001:4860:4802:32::a OPT

----------- google.com -----------
Resolved[SOA]: Lookup { query: Query { name: Name { is_fqdn: false, labels: [google, com] }, query_type: SOA, query_class: IN }, records: [Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: SOA, dns_class: IN, ttl: 58, rdata: SOA(SOA { mname: Name { is_fqdn: true, labels: [ns1, google, com] }, rname: Name { is_fqdn: true, labels: [dns-admin, google, com] }, serial: 338027060, refresh: 900, retry: 900, expire: 1800, minimum: 60 }) }], valid_until: Instant { t: 609715.6056302s } }
Resolved[MX]: Lookup { query: Query { name: Name { is_fqdn: false, labels: [google, com] }, query_type: MX, query_class: IN }, records: [Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 20, exchange: Name { is_fqdn: true, labels: [alt1, aspmx, l, google, com] } }) }, Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 30, exchange: Name { is_fqdn: true, labels: [alt2, aspmx, l, google, com] } }) }, Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 10, exchange: Name { is_fqdn: true, labels: [aspmx, l, google, com] } }) }, Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 40, exchange: Name { is_fqdn: true, labels: [alt3, aspmx, l, google, com] } }) }, Record { name_labels: Name { is_fqdn: true, labels: [google, 
com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 50, exchange: Name { is_fqdn: true, labels: [alt4, aspmx, l, google, com] } }) }], valid_until: Instant { t: 610257.6597085s } }

*/
test_validate_all("otava.com");
/*  No.	Time	Source	Destination	Protocol	Length	Info
    19	21.861545	172.20.40.25	172.20.41.15	DNS	80	Standard query 0x4d5b SOA otava.com OPT
    20	22.038869	172.20.41.15	172.20.40.25	DNS	271	Standard query response 0x4d5b SOA otava.com SOA fred.ns.cloudflare.com A 173.245.59.113 A 172.64.33.113 A 108.162.193.113 AAAA 2606:4700:58::adf5:3b71 AAAA 2803:f800:50::6ca2:c171 AAAA 2a06:98c1:50::ac40:2171 OPT
    25	67.061575	172.20.40.25	8.8.8.8	DNS	80	Standard query 0xdd16 MX otava.com OPT
    26	67.061660	172.20.40.25	9.9.9.9	DNS	80	Standard query 0x099d MX otava.com OPT
    27	67.108718	8.8.8.8	172.20.40.25	DNS	130	Standard query response 0xdd16 MX otava.com MX 0 otava-com.mail.protection.outlook.com OPT
    28	67.110079	9.9.9.9	172.20.40.25	DNS	130	Standard query response 0x099d MX otava.com MX 0 otava-com.mail.protection.outlook.com OPT

----------- otava.com -----------
Resolved[SOA]: Lookup { query: Query { name: Name { is_fqdn: false, labels: [otava, com] }, query_type: SOA, query_class: IN }, records: [Record { name_labels: Name { is_fqdn: true, labels: [otava, com] }, rr_type: SOA, dns_class: IN, ttl: 3599, rdata: SOA(SOA { mname: Name { is_fqdn: true, labels: [fred, ns, cloudflare, com] }, rname: Name { is_fqdn: true, labels: [dns, cloudflare, com] }, serial: 2035487922, refresh: 10000, retry: 2400, expire: 604800, minimum: 3600 }) }], valid_until: Instant { t: 613276.8453371s } }   
Resolved[MX]: Lookup { query: Query { name: Name { is_fqdn: false, labels: [otava, com] }, query_type: MX, query_class: IN }, records: [Record { name_labels: Name { is_fqdn: true, labels: [otava, com] }, rr_type: MX, dns_class: IN, ttl: 299, rdata: MX(MX { preference: 0, exchange: Name { is_fqdn: true, labels: [otava-com,     
*/    
}

	

Originally created by @JRAndreassen on GitHub (Oct 20, 2020). Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/1259 **Describe the bug** The reverse lookup is extremely slow As are the SOA queries at times... It appears it misses the responses some times... **To Reproduce** See attached code... Adapted from async global example **Expected behavior** Well... faster **System:** - OS: Windows 10 - Architecture: x86_64 - Version Microsoft Windows [Version 10.0.18363.1139] - rustc version: stable-x86_64-pc-windows-msvc - Up to date : 1.47.0 (18bf6b4f0 2020-10-07) stable-x86_64-unknown-linux-gnu - Up to date : 1.47.0 (18bf6b4f0 2020-10-07) **Version:** Crate: trust-dns-resolver Version: "0.20.0" cargo.toml ```toml trust-dns-resolver = { version = "*", git = "https://github.com/bluejekyll/trust-dns.git" } futures-util = { version = "0.3.5", default-features = false, features = ["std"] } tokio = { version = "0.2", features = ["full"]} lazy_static = "*" futures = "*" ``` main.rs ```rust use std::{ task::{ Poll }, io, net::{ SocketAddr, IpAddr, }, fmt::{ Display, } }; use lazy_static::{ lazy_static }; use tokio; use futures::Future; use futures_util::future; use trust_dns_resolver; use trust_dns_resolver::{ TokioAsyncResolver, IntoName, TryParseIp, lookup::Lookup, proto::{ rr::{ Name, Record, RecordType, }, xfer::DnsRequestOptions, }, }; pub fn await_future<F: Future>(f: F) -> F::Output { futures::executor::block_on( async { f.await}) } lazy_static! { // First we need to setup the global Resolver static ref GLOBAL_DNS_RESOLVER: TokioAsyncResolver = { use std::sync::{Arc, Mutex, Condvar}; use std::thread; // We'll be using this condvar to get the Resolver from the thread... let pair = Arc::new((Mutex::new(None::<TokioAsyncResolver>), Condvar::new())); let pair2 = pair.clone(); #[allow(unused_assignments,unused_variables)] // Spawn the runtime to a new thread... // // This thread will manage the actual resolution runtime thread::spawn(move || { // A runtime for this new thread let mut runtime = tokio::runtime::Runtime::new().expect("failed to launch Runtime"); // our platform independent future, result, see next blocks let resolver = { // To make this independent, if targeting macOS, BSD, Linux, or Windows, we can use the system's configuration: #[cfg(any(unix, windows))] { // use the system resolver configuration TokioAsyncResolver::from_system_conf(runtime.handle().clone()) } // For other operating systems, we can use one of the preconfigured definitions #[cfg(not(any(unix, windows)))] { // Directly reference the config types use trust_dns_resolver::config::{ResolverConfig, ResolverOpts}; // Get a new resolver with the google nameservers as the upstream recursive resolvers TokioAsyncResolver::new(ResolverConfig::quad9(), ResolverOpts::default(), runtime.handle().clone()) } }; let &(ref lock, ref cvar) = &*pair2; let mut started = lock.lock().unwrap(); // let resolver = current_handle.block_on(resolver).expect("failed to create trust-dns-resolver"); let resolver = resolver.expect("failed to create trust-dns-resolver"); *started = Some(resolver); cvar.notify_one(); drop(started); runtime.block_on(future::poll_fn(|_cx| Poll::<()>::Pending)) }); // Wait for the thread to start up. let &(ref lock, ref cvar) = &*pair; let mut resolver = lock.lock().unwrap(); while resolver.is_none() { resolver = cvar.wait(resolver).unwrap(); } // take the started resolver let resolver = std::mem::replace(&mut *resolver, None); // set the global resolver resolver.expect("resolver should not be none") }; } pub async fn resolve_socket<N: IntoName + Display + TryParseIp + 'static>( host: N, port: u16, ) -> io::Result<Vec<SocketAddr>> { // Now we use the global resolver to perform a lookup_ip. let name = host.to_string(); let result = GLOBAL_DNS_RESOLVER.lookup_ip(host).await; // map the result into what we want... result .map_err(move |err| { // we transform the error into a standard IO error for convenience io::Error::new( io::ErrorKind::AddrNotAvailable, format!("dns resolution error for {}: {}", name, err), ) }) .map(move |lookup_ip| { // we take all the IPs returned, and then send back the set of IPs lookup_ip .iter() .map(|ip| SocketAddr::new(ip, port)) .collect::<Vec<_>>() }) } pub async fn resolve<N: IntoName + Display + TryParseIp + 'static>( host: N, record_type: RecordType, options: Option<DnsRequestOptions>, ) -> io::Result<Lookup> { // Now we use the global resolver to perform a lookup_ip. let name = host.to_string(); let opts = if let Some(iopt) = options { iopt } else {DnsRequestOptions::default()}; let result = GLOBAL_DNS_RESOLVER.lookup(host, record_type, opts).await; // map the result into what we want... result .map_err(move |err| { // we transform the error into a standard IO error for convenience io::Error::new( io::ErrorKind::AddrNotAvailable, format!("dns resolution error for {}: {}", name, err), ) }) } pub fn resolve_sync<N: IntoName + Display + TryParseIp + 'static>( host: N, record_type: RecordType, options: Option<DnsRequestOptions>, ) -> io::Result<Lookup> { await_future(resolve(host, record_type, options)) } pub async fn resolve_ip<N: IntoName + Display + TryParseIp>( host: N ) -> io::Result<Vec<IpAddr>> { // Now we use the global resolver to perform a lookup_ip. let name = host.to_string(); let result = GLOBAL_DNS_RESOLVER.lookup_ip(host).await; // map the result into what we want... result .map_err(move |err| { // we transform the error into a standard IO error for convenience io::Error::new( io::ErrorKind::AddrNotAvailable, format!("dns resolution error for {}: {}", name, err), ) }) .map(move |lookup_ip| { // we take all the IPs returned, and then send back the set of IPs lookup_ip .iter() .collect::<Vec<_>>() }) } pub fn resolve_ip_sync(host: &str) -> io::Result<Vec<IpAddr>> { // Lookup the IP addresses associated with a name. // The final dot forces this to be an FQDN, otherwise the search rules as specified // in `ResolverOpts` will take effect. FQDN's are generally cheaper queries. await_future(resolve_ip(host)) } pub async fn reverse_lookup( ip_addr: IpAddr ) -> io::Result<Vec<String>> { // Now we use the global resolver to perform a lookup_ip. //let name = host.to_string(); let result = GLOBAL_DNS_RESOLVER.reverse_lookup(ip_addr).await; // map the result into what we want... result .map_err(move |err| { // we transform the error into a standard IO error for convenience io::Error::new( io::ErrorKind::AddrNotAvailable, format!("rdns resolution error for {}: {}", ip_addr, err), ) }) .map(move |lookup_name| { // we take all the IPs returned, and then send back the set of IPs lookup_name .iter() .map(|s| s.to_string() ) .collect::<Vec<String>>() }) } pub fn reverse_lookup_sync(ip_addr: IpAddr) -> io::Result<Vec<String>> { // Lookup the IP addresses associated with a name. // The final dot forces this to be an FQDN, otherwise the search rules as specified // in `ResolverOpts` will take effect. FQDN's are generally cheaper queries. await_future(reverse_lookup(ip_addr)) } pub fn test_validate_all(host: &'static str) { println!("----------- {} -----------", host); let val = resolve_sync(host, RecordType::SOA, None).unwrap(); println!("Resolved[SOA]: {:?}", val); let val = resolve_sync(host, RecordType::MX, None).unwrap(); println!("Resolved[MX]: {:?}", val); } #[tokio::main] async fn main() { std::thread::yield_now(); let val = resolve_ip_sync("localhost").unwrap(); println!("Resolved: {:?}", val); let val_gw = resolve_ip_sync("204.65.230.1").unwrap(); println!("Resolved: {:?}", val_gw); let val = resolve_ip_sync("rackspace.com").unwrap(); println!("Resolved: {:?}", val); let val = resolve_ip_sync("google.com").unwrap(); println!("Resolved: {:?}", val); // Sloooow let val = reverse_lookup_sync(val_gw[0]).unwrap(); println!("Reverse: {:?}", val); /* No. Time Source Destination Protocol Length Info 15 3.920132 172.20.40.25 9.9.9.9 DNS 96 Standard query 0xaba6 PTR 1.230.65.204.in-addr.arpa OPT 16 3.981643 9.9.9.9 172.20.40.25 DNS 164 Standard query response 0xaba6 No such name PTR 1.230.65.204.in-addr.arpa SOA ns.capnet.state.tx.us OPT 43 54.055271 8.8.8.8 172.20.40.25 TCP 60 53 → 65047 [ACK] Seq=1 Ack=57 Win=65536 Len=0 44 54.059747 172.20.41.15 172.20.40.25 TCP 60 53 → 65046 [ACK] Seq=1 Ack=3 Win=65536 Len=0 45 54.059784 172.20.40.25 172.20.41.15 DNS 108 Standard query 0xd7cf PTR 1.230.65.204.in-addr.arpa OPT 46 54.060410 172.20.41.15 172.20.40.25 DNS 178 Standard query response 0xd7cf No such name PTR 1.230.65.204.in-addr.arpa SOA ns.capnet.state.tx.us OPT 47 54.080447 8.8.8.8 172.20.40.25 DNS 178 Standard query response 0xbbf2 No such name PTR 1.230.65.204.in-addr.arpa SOA ns.capnet.state.tx.us OPT */ // Also Sloooow test_validate_all("google.com"); /* No. Time Source Destination Protocol Length Info 1 0.000000 172.20.40.25 172.20.41.15 DNS 74 Standard query 0x3420 A 4.sophosxl.net 2 0.000845 172.20.41.15 172.20.40.25 DNS 202 Standard query response 0x3420 A 4.sophosxl.net A 52.205.94.43 A 3.224.96.206 A 34.193.178.220 A 52.0.151.141 A 34.231.106.102 A 52.204.13.73 A 3.224.253.17 A 34.227.137.252 3 1.776129 172.20.40.25 172.20.41.15 DNS 81 Standard query 0xa04a SOA google.com OPT 4 1.776193 172.20.40.25 8.8.8.8 DNS 81 Standard query 0x3b00 SOA google.com OPT 5 1.799151 8.8.8.8 172.20.40.25 DNS 131 Standard query response 0x3b00 SOA google.com SOA ns1.google.com OPT 6 1.801309 172.20.40.25 9.9.9.9 DNS 81 Standard query 0x28b8 MX google.com OPT 7 1.852966 9.9.9.9 172.20.40.25 DNS 189 Standard query response 0x28b8 MX google.com MX 20 alt1.aspmx.l.google.com MX 30 alt2.aspmx.l.google.com MX 10 aspmx.l.google.com MX 40 alt3.aspmx.l.google.com MX 50 alt4.aspmx.l.google.com OPT 8 1.871566 172.20.41.15 172.20.40.25 DNS 175 Standard query response 0xa04a SOA google.com SOA ns1.google.com A 216.239.32.10 AAAA 2001:4860:4802:32::a OPT ----------- google.com ----------- Resolved[SOA]: Lookup { query: Query { name: Name { is_fqdn: false, labels: [google, com] }, query_type: SOA, query_class: IN }, records: [Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: SOA, dns_class: IN, ttl: 58, rdata: SOA(SOA { mname: Name { is_fqdn: true, labels: [ns1, google, com] }, rname: Name { is_fqdn: true, labels: [dns-admin, google, com] }, serial: 338027060, refresh: 900, retry: 900, expire: 1800, minimum: 60 }) }], valid_until: Instant { t: 609715.6056302s } } Resolved[MX]: Lookup { query: Query { name: Name { is_fqdn: false, labels: [google, com] }, query_type: MX, query_class: IN }, records: [Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 20, exchange: Name { is_fqdn: true, labels: [alt1, aspmx, l, google, com] } }) }, Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 30, exchange: Name { is_fqdn: true, labels: [alt2, aspmx, l, google, com] } }) }, Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 10, exchange: Name { is_fqdn: true, labels: [aspmx, l, google, com] } }) }, Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 40, exchange: Name { is_fqdn: true, labels: [alt3, aspmx, l, google, com] } }) }, Record { name_labels: Name { is_fqdn: true, labels: [google, com] }, rr_type: MX, dns_class: IN, ttl: 600, rdata: MX(MX { preference: 50, exchange: Name { is_fqdn: true, labels: [alt4, aspmx, l, google, com] } }) }], valid_until: Instant { t: 610257.6597085s } } */ test_validate_all("otava.com"); /* No. Time Source Destination Protocol Length Info 19 21.861545 172.20.40.25 172.20.41.15 DNS 80 Standard query 0x4d5b SOA otava.com OPT 20 22.038869 172.20.41.15 172.20.40.25 DNS 271 Standard query response 0x4d5b SOA otava.com SOA fred.ns.cloudflare.com A 173.245.59.113 A 172.64.33.113 A 108.162.193.113 AAAA 2606:4700:58::adf5:3b71 AAAA 2803:f800:50::6ca2:c171 AAAA 2a06:98c1:50::ac40:2171 OPT 25 67.061575 172.20.40.25 8.8.8.8 DNS 80 Standard query 0xdd16 MX otava.com OPT 26 67.061660 172.20.40.25 9.9.9.9 DNS 80 Standard query 0x099d MX otava.com OPT 27 67.108718 8.8.8.8 172.20.40.25 DNS 130 Standard query response 0xdd16 MX otava.com MX 0 otava-com.mail.protection.outlook.com OPT 28 67.110079 9.9.9.9 172.20.40.25 DNS 130 Standard query response 0x099d MX otava.com MX 0 otava-com.mail.protection.outlook.com OPT ----------- otava.com ----------- Resolved[SOA]: Lookup { query: Query { name: Name { is_fqdn: false, labels: [otava, com] }, query_type: SOA, query_class: IN }, records: [Record { name_labels: Name { is_fqdn: true, labels: [otava, com] }, rr_type: SOA, dns_class: IN, ttl: 3599, rdata: SOA(SOA { mname: Name { is_fqdn: true, labels: [fred, ns, cloudflare, com] }, rname: Name { is_fqdn: true, labels: [dns, cloudflare, com] }, serial: 2035487922, refresh: 10000, retry: 2400, expire: 604800, minimum: 3600 }) }], valid_until: Instant { t: 613276.8453371s } } Resolved[MX]: Lookup { query: Query { name: Name { is_fqdn: false, labels: [otava, com] }, query_type: MX, query_class: IN }, records: [Record { name_labels: Name { is_fqdn: true, labels: [otava, com] }, rr_type: MX, dns_class: IN, ttl: 299, rdata: MX(MX { preference: 0, exchange: Name { is_fqdn: true, labels: [otava-com, */ } ```
kerem closed this issue 2026-03-15 23:33:08 +03:00
Author
Owner

@bluejekyll commented on GitHub (Oct 21, 2020):

is it possible you're being rate-limited? I haven't reviewed your code in depth at the moment, maybe there are some areas where this can be sped up. One thing I notice is that your lookups are probably all happening on a single thread. You may want to read up a little bit on spawning in Tokio to achieve a little more parallelism: https://tokio.rs/tokio/tutorial/spawning

<!-- gh-comment-id:713975028 --> @bluejekyll commented on GitHub (Oct 21, 2020): is it possible you're being rate-limited? I haven't reviewed your code in depth at the moment, maybe there are some areas where this can be sped up. One thing I notice is that your lookups are probably all happening on a single thread. You may want to read up a little bit on spawning in Tokio to achieve a little more parallelism: https://tokio.rs/tokio/tutorial/spawning
Author
Owner

@JRAndreassen commented on GitHub (Oct 21, 2020):

Hi...

They are intentionally on a single thread in the test...
The issue I see is that it is missing some of the replies...
Though, seems to only be happening on the the non host(A) queries ...

<!-- gh-comment-id:713986207 --> @JRAndreassen commented on GitHub (Oct 21, 2020): Hi... They are intentionally on a single thread in the test... The issue I see is that it is missing some of the replies... Though, seems to only be happening on the the non host(A) queries ...
Author
Owner

@JRAndreassen commented on GitHub (Oct 25, 2020):

Hi...

This one works:

/*
trust-dns-resolver = "0.19"
futures-util = { version = "0.3.5", default-features = false, features = ["std"] }
tokio = { version = "0.2", features = ["full"]}
lazy_static = "*"
futures = "*"
log = "*"
*/

pub use log::{debug, error, info, trace, warn};
use std::{
    task::Poll,    io,
    net::{SocketAddr, IpAddr,Ipv4Addr,},
    fmt::Display,
    sync::{Arc,Mutex, },
};
use lazy_static::lazy_static;
use tokio;
use futures::Future;
use trust_dns_resolver::{ 
    TokioAsyncResolver, 
    IntoName, TryParseIp,
};

pub fn await_future<F: Future>(f: F) -> F::Output {
    futures::executor::block_on( async { f.await})
}

fn alloc_async_resolver() -> Result<TokioAsyncResolver, String>
{
    #[cfg(any(unix, windows))]
    let dns_cfg = trust_dns_resolver::config::ResolverConfig::default();
    #[cfg(not(any(unix, windows)))]
    let dns_cfg = trust_dns_resolver::config::ResolverConfig::quad9();

    let resolver = TokioAsyncResolver::tokio(dns_cfg,
        trust_dns_resolver::config::ResolverOpts::default());

    match await_future( resolver)
    {
        Ok(resolv) => Ok(resolv),
        Err(err) => {
            Err(format!("TrustDNS-Resolver[Alloc]: failed to spawn Resolver: {:?}", err))
        },
    }
}
lazy_static!{
    pub static ref GLOBAL_DNS_RESOLVER : Mutex<Vec<Option<Arc<TokioAsyncResolver>>>> = Mutex::new(Vec::new());
}

#[allow(dead_code)]
fn get_trustdns_resolver() -> Result<Arc<TokioAsyncResolver>, io::Error>  {
    if let Ok(mut resolver) = GLOBAL_DNS_RESOLVER.lock() {
        if resolver.len()  < 1 {
            let res = 
             match alloc_async_resolver()
             {
                Ok(val) => 
                    Some(Arc::new(val)),
                Err(err) => {
                    error!("TrustDNS-Resolver: failed to allocate resolver: {:?}", err);
                    let err = io::Error::new(
                        io::ErrorKind::NotConnected, err);
                    return Err(err);
                },
             };
             resolver.push(res);
        }
        if let Some(tpa) = resolver[0].as_ref() {
            Ok(tpa.clone())
        } else {
            trace!("TrustDNS-Resolver: Not available");
            let err = io::Error::new(
                io::ErrorKind::NotConnected,
                "Trust-DNS resolver not available");
            return Err(err);
        }
    }
    else 
    { 
        error!("TrustDNS-Resolver: failed to lock resolver handle");
        let err = io::Error::new(
            io::ErrorKind::TimedOut,
            "Trust-DNS resolver not available");
        return Err(err);
    }
}


pub async fn resolve_ip<N: IntoName + Display + TryParseIp>(
    host: N
) -> io::Result<Vec<IpAddr>> {
    // Now we use the global resolver to perform a lookup_ip.
    let name = host.to_string();
    let resolver = get_trustdns_resolver()?; 
    let result = resolver.lookup_ip(host).await;
    // map the result into what we want...
    result
        .map_err(move |err| {
            // we transform the error into a standard IO error for convenience
            io::Error::new(
                io::ErrorKind::AddrNotAvailable,
                format!("dns resolution error for {}: {}", name, err),
            )
        })
        .map(move |lookup_ip| {
            // we take all the IPs returned, and then send back the set of IPs
            lookup_ip
                .iter()
                .collect::<Vec<_>>()
        })
}

pub fn resolve_ip_sync(host: &str) -> io::Result<Vec<IpAddr>> {
    { // prime the pump before "block_on...", it will cause panic
        let _resolver = get_trustdns_resolver()?;
    }
    await_future(resolve_ip(host))
}

pub async fn reverse_lookup(
    ip_addr: IpAddr
) -> io::Result<Vec<String>> {
    // Now we use the global resolver to perform a lookup_ip.
    //let name = host.to_string();
    let resolver = get_trustdns_resolver()?; 
    let result = resolver.reverse_lookup(ip_addr).await;
    // map the result into what we want...
    result
        .map_err(move |err| {
            // we transform the error into a standard IO error for convenience
            io::Error::new(
                io::ErrorKind::AddrNotAvailable,
                format!("rdns resolution error for {}: {}", ip_addr, err),
            )
        })
        .map(move |lookup_name| {
            // we take all the IPs returned, and then send back the set of IPs
            lookup_name
                .iter()
                .map(|s| s.to_string() )
                .collect::<Vec<String>>()
        })
}

pub fn reverse_lookup_sync(ip_addr: IpAddr) -> io::Result<Vec<String>> {
    { // prime the pump before "block_on...", it will cause panic
        let _resolver = get_trustdns_resolver()?; 
    }
    // Lookup the IP addresses associated with a name.
    // The final dot forces this to be an FQDN, otherwise the search rules as specified
    //  in `ResolverOpts` will take effect. FQDN's are generally cheaper queries.
    await_future(reverse_lookup(ip_addr))

}

pub fn test_dns_mt() -> Vec<IpAddr>
{
    // Create some futures representing name lookups.
    let names = &["www.google.com", "www.reddit.com", "www.wikipedia.org"];
    let futures = names
        .iter()
        .map(|name| resolve_ip(*name))
        .collect::<Vec<_>>();

    let mut  results:Vec<IpAddr> = Vec::new();
    let joinall = 
        await_future(futures::future::join_all(futures));
    // Go through the list of resolution operations and wait for them to complete.
    for lookup in joinall {
        println!("resolved to {:?}", lookup);
        if let Ok(res) = lookup {
            if res.len() > 0 {
                results.push(res[0])
            }
        }
    }
    results
}

pub fn test_rdns_mt(todo: &Vec<IpAddr>)
{
    // Create some futures representing name lookups.
    let names = &["www.google.com", "www.reddit.com", "www.wikipedia.org"];
    let futures = todo
        .iter()
        .map(|ipaddr| reverse_lookup(*ipaddr))
        .collect::<Vec<_>>();

    let joinall = 
        await_future(futures::future::join_all(futures));
    // Go through the list of resolution operations and wait for them to complete.
    for lookup in joinall {
        println!("resolved to {:?}", lookup);
    }
}


#[tokio::main]
async fn main() {
    // prime the pump... to allocate on current RT (otherwise we may get panic)
    let _resolver = get_trustdns_resolver().unwrap(); 
    let mut res = test_dns_mt();
    res.push(IpAddr::V4(Ipv4Addr::new(204, 65, 230, 1)));
    test_rdns_mt(&res);
}

<!-- gh-comment-id:716174060 --> @JRAndreassen commented on GitHub (Oct 25, 2020): Hi... This one works: ```rust /* trust-dns-resolver = "0.19" futures-util = { version = "0.3.5", default-features = false, features = ["std"] } tokio = { version = "0.2", features = ["full"]} lazy_static = "*" futures = "*" log = "*" */ pub use log::{debug, error, info, trace, warn}; use std::{ task::Poll, io, net::{SocketAddr, IpAddr,Ipv4Addr,}, fmt::Display, sync::{Arc,Mutex, }, }; use lazy_static::lazy_static; use tokio; use futures::Future; use trust_dns_resolver::{ TokioAsyncResolver, IntoName, TryParseIp, }; pub fn await_future<F: Future>(f: F) -> F::Output { futures::executor::block_on( async { f.await}) } fn alloc_async_resolver() -> Result<TokioAsyncResolver, String> { #[cfg(any(unix, windows))] let dns_cfg = trust_dns_resolver::config::ResolverConfig::default(); #[cfg(not(any(unix, windows)))] let dns_cfg = trust_dns_resolver::config::ResolverConfig::quad9(); let resolver = TokioAsyncResolver::tokio(dns_cfg, trust_dns_resolver::config::ResolverOpts::default()); match await_future( resolver) { Ok(resolv) => Ok(resolv), Err(err) => { Err(format!("TrustDNS-Resolver[Alloc]: failed to spawn Resolver: {:?}", err)) }, } } lazy_static!{ pub static ref GLOBAL_DNS_RESOLVER : Mutex<Vec<Option<Arc<TokioAsyncResolver>>>> = Mutex::new(Vec::new()); } #[allow(dead_code)] fn get_trustdns_resolver() -> Result<Arc<TokioAsyncResolver>, io::Error> { if let Ok(mut resolver) = GLOBAL_DNS_RESOLVER.lock() { if resolver.len() < 1 { let res = match alloc_async_resolver() { Ok(val) => Some(Arc::new(val)), Err(err) => { error!("TrustDNS-Resolver: failed to allocate resolver: {:?}", err); let err = io::Error::new( io::ErrorKind::NotConnected, err); return Err(err); }, }; resolver.push(res); } if let Some(tpa) = resolver[0].as_ref() { Ok(tpa.clone()) } else { trace!("TrustDNS-Resolver: Not available"); let err = io::Error::new( io::ErrorKind::NotConnected, "Trust-DNS resolver not available"); return Err(err); } } else { error!("TrustDNS-Resolver: failed to lock resolver handle"); let err = io::Error::new( io::ErrorKind::TimedOut, "Trust-DNS resolver not available"); return Err(err); } } pub async fn resolve_ip<N: IntoName + Display + TryParseIp>( host: N ) -> io::Result<Vec<IpAddr>> { // Now we use the global resolver to perform a lookup_ip. let name = host.to_string(); let resolver = get_trustdns_resolver()?; let result = resolver.lookup_ip(host).await; // map the result into what we want... result .map_err(move |err| { // we transform the error into a standard IO error for convenience io::Error::new( io::ErrorKind::AddrNotAvailable, format!("dns resolution error for {}: {}", name, err), ) }) .map(move |lookup_ip| { // we take all the IPs returned, and then send back the set of IPs lookup_ip .iter() .collect::<Vec<_>>() }) } pub fn resolve_ip_sync(host: &str) -> io::Result<Vec<IpAddr>> { { // prime the pump before "block_on...", it will cause panic let _resolver = get_trustdns_resolver()?; } await_future(resolve_ip(host)) } pub async fn reverse_lookup( ip_addr: IpAddr ) -> io::Result<Vec<String>> { // Now we use the global resolver to perform a lookup_ip. //let name = host.to_string(); let resolver = get_trustdns_resolver()?; let result = resolver.reverse_lookup(ip_addr).await; // map the result into what we want... result .map_err(move |err| { // we transform the error into a standard IO error for convenience io::Error::new( io::ErrorKind::AddrNotAvailable, format!("rdns resolution error for {}: {}", ip_addr, err), ) }) .map(move |lookup_name| { // we take all the IPs returned, and then send back the set of IPs lookup_name .iter() .map(|s| s.to_string() ) .collect::<Vec<String>>() }) } pub fn reverse_lookup_sync(ip_addr: IpAddr) -> io::Result<Vec<String>> { { // prime the pump before "block_on...", it will cause panic let _resolver = get_trustdns_resolver()?; } // Lookup the IP addresses associated with a name. // The final dot forces this to be an FQDN, otherwise the search rules as specified // in `ResolverOpts` will take effect. FQDN's are generally cheaper queries. await_future(reverse_lookup(ip_addr)) } pub fn test_dns_mt() -> Vec<IpAddr> { // Create some futures representing name lookups. let names = &["www.google.com", "www.reddit.com", "www.wikipedia.org"]; let futures = names .iter() .map(|name| resolve_ip(*name)) .collect::<Vec<_>>(); let mut results:Vec<IpAddr> = Vec::new(); let joinall = await_future(futures::future::join_all(futures)); // Go through the list of resolution operations and wait for them to complete. for lookup in joinall { println!("resolved to {:?}", lookup); if let Ok(res) = lookup { if res.len() > 0 { results.push(res[0]) } } } results } pub fn test_rdns_mt(todo: &Vec<IpAddr>) { // Create some futures representing name lookups. let names = &["www.google.com", "www.reddit.com", "www.wikipedia.org"]; let futures = todo .iter() .map(|ipaddr| reverse_lookup(*ipaddr)) .collect::<Vec<_>>(); let joinall = await_future(futures::future::join_all(futures)); // Go through the list of resolution operations and wait for them to complete. for lookup in joinall { println!("resolved to {:?}", lookup); } } #[tokio::main] async fn main() { // prime the pump... to allocate on current RT (otherwise we may get panic) let _resolver = get_trustdns_resolver().unwrap(); let mut res = test_dns_mt(); res.push(IpAddr::V4(Ipv4Addr::new(204, 65, 230, 1))); test_rdns_mt(&res); } ```
Author
Owner

@djc commented on GitHub (Oct 26, 2020):

So does that mean your issue has been solved?

<!-- gh-comment-id:716805010 --> @djc commented on GitHub (Oct 26, 2020): So does that mean your issue has been solved?
Author
Owner

@JRAndreassen commented on GitHub (Oct 26, 2020):

@djc ,
I would say so...
It is now only running about 17 threads, besides the 40+ that are left behind for Windows issues...

So, yes...
Thanks you for your assistance...
JR

<!-- gh-comment-id:716810060 --> @JRAndreassen commented on GitHub (Oct 26, 2020): @djc , I would say so... It is now only running about 17 threads, besides the 40+ that are left behind for Windows issues... So, yes... Thanks you for your assistance... JR
Author
Owner

@bluejekyll commented on GitHub (Oct 26, 2020):

@JRAndreassen be aware, that there is a known mio memory leak (the async-io library used by tokio and most of the Rust ecosystem) on Windows. This is fixed in Tokio 0.3, though it's going to be a little bit before we upgrade to Tokio 0.3. You can follow that progress here: #1262

<!-- gh-comment-id:716818502 --> @bluejekyll commented on GitHub (Oct 26, 2020): @JRAndreassen be aware, that there is a known mio memory leak (the async-io library used by tokio and most of the Rust ecosystem) on Windows. This is fixed in Tokio 0.3, though it's going to be a little bit before we upgrade to Tokio 0.3. You can follow that progress here: #1262
Author
Owner

@JRAndreassen commented on GitHub (Oct 27, 2020):

@bluejekyll
Thanks for the tip..

I've not seen a leak, but I do have a runaway future:poll

#[unstable(feature = "gen_future", issue = "50547")]
pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
where
    T: Generator<ResumeTy, Yield = ()>,
{
    #[rustc_diagnostic_item = "gen_future"]
    struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);

    // We rely on the fact that async/await futures are immovable in order to create
    // self-referential borrows in the underlying generator.
    impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {}

    impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> {
        type Output = T::Return;
        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            // SAFETY: Safe because we're !Unpin + !Drop, and this is just a field projection.
            let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };

            // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The
            // `.await` lowering will safely cast that back to a `&mut Context`.
 *>        match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
                GeneratorState::Yielded(()) => Poll::Pending,
                GeneratorState::Complete(x) => Poll::Ready(x),
            }
        }
    }

    GenFuture(gen)
}
<!-- gh-comment-id:717273733 --> @JRAndreassen commented on GitHub (Oct 27, 2020): @bluejekyll Thanks for the tip.. I've not seen a leak, but I do have a runaway future:poll ```rust #[unstable(feature = "gen_future", issue = "50547")] pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return> where T: Generator<ResumeTy, Yield = ()>, { #[rustc_diagnostic_item = "gen_future"] struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T); // We rely on the fact that async/await futures are immovable in order to create // self-referential borrows in the underlying generator. impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {} impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> { type Output = T::Return; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { // SAFETY: Safe because we're !Unpin + !Drop, and this is just a field projection. let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The // `.await` lowering will safely cast that back to a `&mut Context`. *> match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) { GeneratorState::Yielded(()) => Poll::Pending, GeneratorState::Complete(x) => Poll::Ready(x), } } } GenFuture(gen) } ```
Author
Owner

@JRAndreassen commented on GitHub (Oct 28, 2020):

@bluejekyll ...

I've not seen a memory leak, but the runaway process I saw showed up on the trust-dns thread...
2020-10-28T02:33:08.142180800+00:00 WARN tokio-runtime-worker trust_dns_proto::xfer: error notifying wait, possible future leak: Err(ProtoError { kind: Message("requestor canceled"), backtrack: None })
And it's deep in the futures::block_on...

What parts of trust-dns is working under 0.3...
I only use resolver (and dependents).
Thanks
JR

<!-- gh-comment-id:717676580 --> @JRAndreassen commented on GitHub (Oct 28, 2020): @bluejekyll ... I've not seen a memory leak, but the runaway process I saw showed up on the trust-dns thread... 2020-10-28T02:33:08.142180800+00:00 WARN tokio-runtime-worker trust_dns_proto::xfer: error notifying wait, possible future leak: Err(ProtoError { kind: Message("requestor canceled"), backtrack: None }) And it's deep in the futures::block_on... What parts of trust-dns is working under 0.3... I only use resolver (and dependents). Thanks JR
Author
Owner

@bluejekyll commented on GitHub (Oct 28, 2020):

The resolver is probably the most complex component in the entire library, so it's going to be the last thing to be ready on tokio 0.3.

You can follow the effort here, there's currently a bug around UDP: #1262

<!-- gh-comment-id:718082976 --> @bluejekyll commented on GitHub (Oct 28, 2020): The resolver is probably the most complex component in the entire library, so it's going to be the last thing to be ready on tokio 0.3. You can follow the effort here, there's currently a bug around UDP: #1262
Author
Owner

@JRAndreassen commented on GitHub (Oct 28, 2020):

@bluejekyll
Ok...

Keep up the good work...
Thanks for letting me know...
JR

<!-- gh-comment-id:718087753 --> @JRAndreassen commented on GitHub (Oct 28, 2020): @bluejekyll Ok... Keep up the good work... Thanks for letting me know... JR
Author
Owner

@JRAndreassen commented on GitHub (Oct 28, 2020):

@bluejekyll ...
As an aside...

Is there a preferred way to turn off the cache (like setting Cache size to 0) ?
My goal is to time the lookup, not fast cached lookups...
Thanks
JR

<!-- gh-comment-id:718106713 --> @JRAndreassen commented on GitHub (Oct 28, 2020): @bluejekyll ... As an aside... Is there a preferred way to turn off the cache (like setting Cache size to 0) ? My goal is to time the lookup, not fast cached lookups... Thanks JR
Author
Owner

@djc commented on GitHub (Oct 28, 2020):

Yes, you can set the cache size in the ResolverOpts:

https://docs.rs/trust-dns-resolver/0.19.5/trust_dns_resolver/config/struct.ResolverOpts.html#structfield.cache_size

<!-- gh-comment-id:718222521 --> @djc commented on GitHub (Oct 28, 2020): Yes, you can set the cache size in the `ResolverOpts`: https://docs.rs/trust-dns-resolver/0.19.5/trust_dns_resolver/config/struct.ResolverOpts.html#structfield.cache_size
Author
Owner

@JRAndreassen commented on GitHub (Oct 28, 2020):

Cool,
Thanks
JR

<!-- gh-comment-id:718224103 --> @JRAndreassen commented on GitHub (Oct 28, 2020): Cool, Thanks JR
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hickory-dns#634
No description provided.