Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add blocking reverse DNS lookup #596

Merged
merged 4 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Fixed

- Reverse DNS lookup not working in reports ([#509](https://github.com/fujiapple852/trippy/issues/509))

## [0.8.0] - 2023-05-15

### Added
Expand Down
112 changes: 70 additions & 42 deletions src/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,27 @@ impl DnsResolver {
})
}

/// Resolve a DNS hostname to IP addresses.
/// Perform a blocking DNS hostname lookup and return a vector of IP addresses.
pub fn lookup(&self, hostname: &str) -> anyhow::Result<Vec<IpAddr>> {
self.inner.lookup(hostname)
}

/// Perform a non-blocking reverse DNS lookup of `IpAddr` and return a `DnsEntry`.
/// Perform a blocking reverse DNS lookup of `IpAddr` and return a `DnsEntry`.
///
/// As this method is blocking it will never return a `DnsEntry::Pending`.
pub fn reverse_lookup(&self, addr: IpAddr) -> DnsEntry {
self.inner.reverse_lookup(addr, false, false)
}

/// Perform a blocking reverse DNS lookup of `IpAddr` and return a `DnsEntry` with `AS` information.
///
/// See [`DnsResolver::reverse_lookup`]
#[allow(dead_code)]
pub fn reverse_lookup_with_asinfo(&self, addr: IpAddr) -> DnsEntry {
self.inner.reverse_lookup(addr, true, false)
}

/// Perform a lazy reverse DNS lookup of `IpAddr` and return a `DnsEntry`.
///
/// If the `IpAddr` has already been resolved then `DnsEntry::Resolved` is returned immediately.
///
Expand All @@ -129,15 +144,15 @@ impl DnsResolver {
/// If the entry exists but is `DnsEntry::Timeout` then it is changed to be `DnsEntry::Pending` and enqueued.
///
/// If enqueuing times out then the entry is changed to be `DnsEntry::Timeout` and returned.
pub fn reverse_lookup(&self, addr: IpAddr) -> DnsEntry {
self.inner.reverse_lookup(addr, false)
pub fn lazy_reverse_lookup(&self, addr: IpAddr) -> DnsEntry {
self.inner.reverse_lookup(addr, false, true)
}

/// Perform a non-blocking reverse DNS lookup of `IpAddr` and return a `DnsEntry` with `AS` information.
/// Perform a lazy reverse DNS lookup of `IpAddr` and return a `DnsEntry` with `AS` information.
///
/// See [`DnsResolver::reverse_lookup`]
pub fn reverse_lookup_with_asinfo(&self, addr: IpAddr) -> DnsEntry {
self.inner.reverse_lookup(addr, true)
/// See [`DnsResolver::lazy_reverse_lookup`]
pub fn lazy_reverse_lookup_with_asinfo(&self, addr: IpAddr) -> DnsEntry {
self.inner.reverse_lookup(addr, true, true)
}

/// Get the `DnsResolverConfig`.
Expand Down Expand Up @@ -252,7 +267,15 @@ mod inner {
}
}

pub fn reverse_lookup(&self, addr: IpAddr, with_asinfo: bool) -> DnsEntry {
pub fn reverse_lookup(&self, addr: IpAddr, with_asinfo: bool, lazy: bool) -> DnsEntry {
if lazy {
self.lazy_reverse_lookup(addr, with_asinfo)
} else {
reverse_lookup(&self.provider, addr, with_asinfo)
}
}

fn lazy_reverse_lookup(&self, addr: IpAddr, with_asinfo: bool) -> DnsEntry {
let mut enqueue = false;

// Check if we have already attempted to resolve this `IpAddr` and return the current `DnsEntry` if so,
Expand Down Expand Up @@ -319,47 +342,52 @@ mod inner {
cache: &Cache,
) {
for DnsResolveRequest { addr, with_asinfo } in rx {
let entry = match &provider {
DnsProvider::DnsLookup => {
// we can't distinguish between a failed lookup or a genuine error and so we just assume all
// failures are `DnsEntry::NotFound`.
match dns_lookup::lookup_addr(&addr) {
Ok(dns) => DnsEntry::Resolved(Resolved::Normal(addr, vec![dns])),
Err(_) => DnsEntry::NotFound(Unresolved::Normal(addr)),
cache
.write()
.insert(addr, reverse_lookup(provider, addr, with_asinfo));
}
}

fn reverse_lookup(provider: &DnsProvider, addr: IpAddr, with_asinfo: bool) -> DnsEntry {
match &provider {
DnsProvider::DnsLookup => {
// we can't distinguish between a failed lookup or a genuine error and so we just assume all
// failures are `DnsEntry::NotFound`.
match dns_lookup::lookup_addr(&addr) {
Ok(dns) => DnsEntry::Resolved(Resolved::Normal(addr, vec![dns])),
Err(_) => DnsEntry::NotFound(Unresolved::Normal(addr)),
}
}
DnsProvider::TrustDns(resolver) => match resolver.reverse_lookup(addr) {
Ok(name) => {
let hostnames = name
.into_iter()
.map(|mut s| {
s.set_fqdn(false);
s
})
.map(|s| s.to_string())
.collect();
if with_asinfo {
let as_info = lookup_asinfo(resolver, addr).unwrap_or_default();
DnsEntry::Resolved(Resolved::WithAsInfo(addr, hostnames, as_info))
} else {
DnsEntry::Resolved(Resolved::Normal(addr, hostnames))
}
}
DnsProvider::TrustDns(resolver) => match resolver.reverse_lookup(addr) {
Ok(name) => {
let hostnames = name
.into_iter()
.map(|mut s| {
s.set_fqdn(false);
s
})
.map(|s| s.to_string())
.collect();
Err(err) => match err.kind() {
ResolveErrorKind::NoRecordsFound { .. } => {
if with_asinfo {
let as_info = lookup_asinfo(resolver, addr).unwrap_or_default();
DnsEntry::Resolved(Resolved::WithAsInfo(addr, hostnames, as_info))
DnsEntry::NotFound(Unresolved::WithAsInfo(addr, as_info))
} else {
DnsEntry::Resolved(Resolved::Normal(addr, hostnames))
DnsEntry::NotFound(Unresolved::Normal(addr))
}
}
Err(err) => match err.kind() {
ResolveErrorKind::NoRecordsFound { .. } => {
if with_asinfo {
let as_info = lookup_asinfo(resolver, addr).unwrap_or_default();
DnsEntry::NotFound(Unresolved::WithAsInfo(addr, as_info))
} else {
DnsEntry::NotFound(Unresolved::Normal(addr))
}
}
ResolveErrorKind::Timeout => DnsEntry::Timeout(addr),
_ => DnsEntry::Failed(addr),
},
ResolveErrorKind::Timeout => DnsEntry::Timeout(addr),
_ => DnsEntry::Failed(addr),
},
};
cache.write().insert(addr, entry);
},
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/frontend/render/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ pub fn render<B: Backend>(f: &mut Frame<'_, B>, app: &mut TuiApp, rect: Rect) {

/// Render the source address of the trace.
fn render_source(app: &mut TuiApp) -> String {
let src_hostname = app.resolver.reverse_lookup(app.tracer_config().source_addr);
let src_hostname = app
.resolver
.lazy_reverse_lookup(app.tracer_config().source_addr);
let src_addr = app.tracer_config().source_addr;
match app.tracer_config().port_direction {
PortDirection::None => {
Expand Down
12 changes: 6 additions & 6 deletions src/frontend/render/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,19 +234,19 @@ fn format_address(
AddressMode::IP => addr.to_string(),
AddressMode::Host => {
if config.lookup_as_info {
let entry = dns.reverse_lookup_with_asinfo(*addr);
let entry = dns.lazy_reverse_lookup_with_asinfo(*addr);
format_dns_entry(entry, true, config.as_mode)
} else {
let entry = dns.reverse_lookup(*addr);
let entry = dns.lazy_reverse_lookup(*addr);
format_dns_entry(entry, false, config.as_mode)
}
}
AddressMode::Both => {
let hostname = if config.lookup_as_info {
let entry = dns.reverse_lookup_with_asinfo(*addr);
let entry = dns.lazy_reverse_lookup_with_asinfo(*addr);
format_dns_entry(entry, true, config.as_mode)
} else {
let entry = dns.reverse_lookup(*addr);
let entry = dns.lazy_reverse_lookup(*addr);
format_dns_entry(entry, false, config.as_mode)
};
format!("{hostname} ({addr})")
Expand Down Expand Up @@ -360,7 +360,7 @@ fn format_details(
let geoip = geoip_lookup.lookup(*addr).unwrap_or_default();

if config.lookup_as_info {
let dns_entry = dns.reverse_lookup_with_asinfo(*addr);
let dns_entry = dns.lazy_reverse_lookup_with_asinfo(*addr);
match dns_entry {
DnsEntry::Pending(addr) => {
let details = fmt_details_with_asn(addr, index, count, None, None, geoip);
Expand Down Expand Up @@ -388,7 +388,7 @@ fn format_details(
| DnsEntry::NotFound(Unresolved::Normal(_)) => unreachable!(),
}
} else {
let dns_entry = dns.reverse_lookup(*addr);
let dns_entry = dns.lazy_reverse_lookup(*addr);
match dns_entry {
DnsEntry::Pending(addr) => {
let details = fmt_details_no_asn(addr, index, count, None, geoip);
Expand Down