2022-01-03 21:29:04 +00:00
|
|
|
#![allow(dead_code)]
|
2021-11-22 16:28:30 +00:00
|
|
|
use crate::xx::*;
|
|
|
|
|
2022-04-07 13:55:09 +00:00
|
|
|
pub async fn get_outbound_relay_peer() -> Option<crate::veilid_api::PeerInfo> {
|
|
|
|
panic!("Native Veilid should never require an outbound relay");
|
|
|
|
}
|
|
|
|
|
2022-07-03 00:40:34 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Resolver
|
|
|
|
//
|
|
|
|
// Uses system resolver on windows and trust-dns-resolver elsewhere
|
|
|
|
// trust-dns-resolver hangs for a long time on Windows building some cache or something
|
|
|
|
// and we really should be using the built-in system resolver when possible
|
|
|
|
|
|
|
|
cfg_if! {
|
|
|
|
if #[cfg(not(target_os = "windows"))] {
|
|
|
|
cfg_if! {
|
|
|
|
if #[cfg(feature="rt-async-std")] {
|
|
|
|
use async_std_resolver::{config, resolver, resolver_from_system_conf, AsyncStdResolver as AsyncResolver};
|
|
|
|
} else if #[cfg(feature="rt-tokio")] {
|
|
|
|
use trust_dns_resolver::{config, TokioAsyncResolver as AsyncResolver, error::ResolveError};
|
|
|
|
|
|
|
|
pub async fn resolver(
|
|
|
|
config: config::ResolverConfig,
|
|
|
|
options: config::ResolverOpts,
|
|
|
|
) -> Result<AsyncResolver, ResolveError> {
|
|
|
|
AsyncResolver::tokio(config, options)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs a new async-std based Resolver with the system configuration.
|
|
|
|
///
|
|
|
|
/// This will use `/etc/resolv.conf` on Unix OSes and the registry on Windows.
|
|
|
|
#[cfg(any(unix, target_os = "windows"))]
|
|
|
|
pub async fn resolver_from_system_conf() -> Result<AsyncResolver, ResolveError> {
|
|
|
|
AsyncResolver::tokio_from_system_conf()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-17 20:55:53 +00:00
|
|
|
|
2022-07-03 00:40:34 +00:00
|
|
|
lazy_static::lazy_static! {
|
|
|
|
static ref RESOLVER: Arc<AsyncMutex<Option<AsyncResolver>>> = Arc::new(AsyncMutex::new(None));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg_if! {
|
|
|
|
if #[cfg(not(target_os = "windows"))] {
|
2022-07-10 21:36:50 +00:00
|
|
|
async fn get_resolver() -> EyreResult<AsyncResolver> {
|
2022-07-03 00:40:34 +00:00
|
|
|
let mut resolver_lock = RESOLVER.lock().await;
|
|
|
|
if let Some(r) = &*resolver_lock {
|
|
|
|
Ok(r.clone())
|
|
|
|
} else {
|
|
|
|
let resolver = match resolver_from_system_conf().await {
|
|
|
|
Ok(v) => v,
|
|
|
|
Err(_) => resolver(
|
|
|
|
config::ResolverConfig::default(),
|
|
|
|
config::ResolverOpts::default(),
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
.expect("failed to connect resolver"),
|
|
|
|
};
|
|
|
|
|
|
|
|
*resolver_lock = Some(resolver.clone());
|
|
|
|
Ok(resolver)
|
|
|
|
}
|
|
|
|
}
|
2022-05-17 20:55:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-10 21:36:50 +00:00
|
|
|
pub async fn txt_lookup<S: AsRef<str>>(host: S) -> EyreResult<Vec<String>> {
|
2022-07-03 00:40:34 +00:00
|
|
|
cfg_if! {
|
|
|
|
if #[cfg(target_os = "windows")] {
|
|
|
|
use core::ffi::c_void;
|
|
|
|
use windows::core::PSTR;
|
|
|
|
use std::ffi::CStr;
|
|
|
|
use windows::Win32::NetworkManagement::Dns::{DnsQuery_UTF8, DnsFree, DNS_TYPE_TEXT, DNS_QUERY_STANDARD, DNS_RECORDA, DnsFreeRecordList};
|
|
|
|
|
|
|
|
let mut out = Vec::new();
|
|
|
|
unsafe {
|
|
|
|
let mut p_query_results: *mut DNS_RECORDA = core::ptr::null_mut();
|
|
|
|
let status = DnsQuery_UTF8(host.as_ref(), DNS_TYPE_TEXT as u16, DNS_QUERY_STANDARD, core::ptr::null_mut(), &mut p_query_results as *mut *mut DNS_RECORDA, core::ptr::null_mut());
|
|
|
|
if status != 0 {
|
2022-07-10 21:36:50 +00:00
|
|
|
bail!("Failed to resolve TXT record");
|
2022-07-03 00:40:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut p_record: *mut DNS_RECORDA = p_query_results;
|
|
|
|
while !p_record.is_null() {
|
|
|
|
if (*p_record).wType == DNS_TYPE_TEXT as u16 {
|
|
|
|
let count:usize = (*p_record).Data.TXT.dwStringCount.try_into().unwrap();
|
|
|
|
let string_array: *const PSTR = &(*p_record).Data.TXT.pStringArray[0];
|
|
|
|
for n in 0..count {
|
|
|
|
let pstr: PSTR = *(string_array.add(n));
|
|
|
|
let c_str: &CStr = CStr::from_ptr(pstr.0 as *const i8);
|
|
|
|
if let Ok(str_slice) = c_str.to_str() {
|
|
|
|
let str_buf: String = str_slice.to_owned();
|
|
|
|
out.push(str_buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p_record = (*p_record).pNext;
|
|
|
|
}
|
|
|
|
DnsFree(p_query_results as *const c_void, DnsFreeRecordList);
|
|
|
|
}
|
|
|
|
Ok(out)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
let resolver = get_resolver().await?;
|
|
|
|
let txt_result = resolver
|
|
|
|
.txt_lookup(host.as_ref())
|
2022-07-10 21:36:50 +00:00
|
|
|
.await?;
|
2022-07-03 00:40:34 +00:00
|
|
|
let mut out = Vec::new();
|
|
|
|
for x in txt_result.iter() {
|
|
|
|
for s in x.txt_data() {
|
2022-07-10 21:36:50 +00:00
|
|
|
out.push(String::from_utf8(s.to_vec()).wrap_err("utf8 conversion error")?);
|
2022-07-03 00:40:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(out)
|
2022-05-17 20:55:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-10 21:36:50 +00:00
|
|
|
pub async fn ptr_lookup(ip_addr: IpAddr) -> EyreResult<String> {
|
2022-07-03 00:40:34 +00:00
|
|
|
cfg_if! {
|
|
|
|
if #[cfg(target_os = "windows")] {
|
|
|
|
use core::ffi::c_void;
|
|
|
|
use windows::core::PSTR;
|
|
|
|
use std::ffi::CStr;
|
|
|
|
use windows::Win32::NetworkManagement::Dns::{DnsQuery_UTF8, DnsFree, DNS_TYPE_PTR, DNS_QUERY_STANDARD, DNS_RECORDA, DnsFreeRecordList};
|
|
|
|
|
|
|
|
let host = match ip_addr {
|
|
|
|
IpAddr::V4(a) => {
|
|
|
|
let oct = a.octets();
|
|
|
|
format!("{}.{}.{}.{}.in-addr.arpa",oct[3],oct[2],oct[1],oct[0])
|
|
|
|
}
|
|
|
|
IpAddr::V6(a) => {
|
|
|
|
let mut s = String::new();
|
|
|
|
for b in hex::encode(a.octets()).as_bytes().iter().rev() {
|
|
|
|
s.push_str(&format!("{}.",b));
|
|
|
|
}
|
|
|
|
format!("{}ip6.arpa",s)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let mut p_query_results: *mut DNS_RECORDA = core::ptr::null_mut();
|
|
|
|
let status = DnsQuery_UTF8(host, DNS_TYPE_PTR as u16, DNS_QUERY_STANDARD, core::ptr::null_mut(), &mut p_query_results as *mut *mut DNS_RECORDA, core::ptr::null_mut());
|
|
|
|
if status != 0 {
|
2022-07-10 21:36:50 +00:00
|
|
|
bail!("Failed to resolve PTR record");
|
2022-07-03 00:40:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut p_record: *mut DNS_RECORDA = p_query_results;
|
|
|
|
while !p_record.is_null() {
|
|
|
|
if (*p_record).wType == DNS_TYPE_PTR as u16 {
|
|
|
|
let p_name_host: PSTR = (*p_record).Data.PTR.pNameHost;
|
|
|
|
let c_str: &CStr = CStr::from_ptr(p_name_host.0 as *const i8);
|
|
|
|
if let Ok(str_slice) = c_str.to_str() {
|
|
|
|
let str_buf: String = str_slice.to_owned();
|
|
|
|
return Ok(str_buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p_record = (*p_record).pNext;
|
|
|
|
}
|
|
|
|
DnsFree(p_query_results as *const c_void, DnsFreeRecordList);
|
|
|
|
}
|
2022-07-10 21:36:50 +00:00
|
|
|
bail!("No records returned");
|
2022-07-03 00:40:34 +00:00
|
|
|
} else {
|
|
|
|
let resolver = get_resolver().await?;
|
|
|
|
let ptr_result = resolver
|
|
|
|
.reverse_lookup(ip_addr)
|
|
|
|
.await
|
2022-07-10 21:36:50 +00:00
|
|
|
.wrap_err("resolver error")?;
|
2022-07-03 00:40:34 +00:00
|
|
|
if let Some(r) = ptr_result.iter().next() {
|
|
|
|
Ok(r.to_string().trim_end_matches('.').to_string())
|
|
|
|
} else {
|
2022-07-10 21:36:50 +00:00
|
|
|
bail!("PTR lookup returned an empty string");
|
2022-07-03 00:40:34 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-17 20:55:53 +00:00
|
|
|
}
|
|
|
|
}
|