Hi folks,
I'm very new to rust, but hope what I'm trying to achieve isn't too difficult
I want to perform concurrent dns lookups and print the results as json. I'm using trust-dns-resolver to do the lookup
I have managed to query them one after the other, which for a list of ~100 domains took ~6s (on my local machine)
I would like to query them concurrently and then print all results
Here's what I have so far...
Main.rs
use trust_dns_resolver::TokioAsyncResolver;
use trust_dns_resolver::config::{ResolverConfig,ResolverOpts};
use tokio::runtime::Runtime;
use crate::lookup::Result;
mod lookup;
fn main() {
let hosts = vec![String::from("example.org."), String::from("rust-lang.org."), String::from("reddit.com.")];
let io_loop = Runtime::new().unwrap();
let resolver = io_loop.block_on(async {
TokioAsyncResolver::tokio(
ResolverConfig::default(),
ResolverOpts::default())
}).unwrap();
let mut all_results : Vec<Result> = Vec::new();
for host in hosts {
let result : Result = lookup::query(host.clone(), &io_loop, &resolver);
all_results.push(result);
}
println!("{}", serde_json::to_string(&all_results).unwrap());
}
Lookup.rs
use tokio::runtime::Runtime;
use trust_dns_resolver::AsyncResolver;
use trust_dns_resolver::name_server::GenericConnection;
use trust_dns_resolver::name_server::GenericConnectionProvider;
use trust_dns_resolver::proto::xfer::DnsRequestOptions;
use trust_dns_resolver::proto::rr::RecordType;
use serde::{Serialize};
use trust_dns_resolver::name_server::TokioRuntime;
#[derive(Serialize,Clone)]
pub struct Record {
ttl: i32,
#[serde(rename = "type")]
rtype: String,
#[serde(skip_serializing_if = "Option::is_none")]
ip: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
ipv6: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
target: Option<String>,
}
#[derive(Serialize)]
pub struct Result {
host: String,
records: Vec<Record>
}
pub fn query(
target: String,
io_loop: &Runtime,
resolver: &AsyncResolver<GenericConnection, GenericConnectionProvider<TokioRuntime>>
) -> Result {
let lookup_a_future = resolver.lookup_ip(target.clone());
let lookup_aaaa_future = resolver.ipv6_lookup(target.clone());
let lookup_cname_future = resolver.lookup(target.clone(), RecordType::CNAME, DnsRequestOptions::default());
let a_records: Vec<Record> = match io_loop.block_on(lookup_a_future) {
Ok(response) => {response.into_iter().map(|address| {
Record {
ttl: 60, // TODO::FIX ME, get real value
rtype: String::from("A"),
ip: Some(address.to_string()),
ipv6: None,
target: None,
}
}).collect()},
Err(_) => {Vec::new()},
};
let aaaa_records: Vec<Record> = match io_loop.block_on(lookup_aaaa_future) {
Ok(response) => {response.into_iter().map(|address| {
Record {
ttl: 60, // TODO::FIX ME, get real value
rtype: String::from("AAAA"),
ip: None,
ipv6: Some(address.to_string()),
target: None,
}
}).collect()},
Err(_) => {Vec::new()},
};
let cname_records: Vec<Record> = match io_loop.block_on(lookup_cname_future) {
Ok(response) => {response.into_iter().map(|address| {
Record {
ttl: 60, // TODO::FIX ME, get real value
rtype: String::from("CNAME"),
ip: None,
ipv6: None,
target: Some(address.to_string()),
}
}).collect()},
Err(_) => {Vec::new()},
};
let all_records = [
a_records,
aaaa_records,
cname_records
].concat();
Result {
host: target.clone(),
records: all_records
}
}
Many thanks
J.A