2022-01-03 21:29:04 +00:00
#![ allow(dead_code) ]
2022-11-30 00:22:33 +00:00
use crate ::* ;
2021-11-22 16:28:30 +00:00
2023-05-29 19:24:57 +00:00
pub async fn get_outbound_relay_peer ( ) -> Option < crate ::routing_table ::PeerInfo > {
2022-04-07 13:55:09 +00:00
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 } ;
2023-08-27 21:39:50 +00:00
use trust_dns_resolver ::error ::ResolveErrorKind ;
2022-07-03 00:40:34 +00:00
} else if #[ cfg(feature= " rt-tokio " ) ] {
2023-07-13 22:52:03 +00:00
use trust_dns_resolver ::{ config , TokioAsyncResolver as AsyncResolver , error ::ResolveError , error ::ResolveErrorKind } ;
2022-07-03 00:40:34 +00:00
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 ( )
}
2023-08-29 20:15:47 +00:00
} else {
compile_error! ( " needs executor implementation " )
2022-07-03 00:40:34 +00:00
}
}
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 )
}
}
2023-07-13 22:52:03 +00:00
async fn reset_resolver ( ) {
let mut resolver_lock = RESOLVER . lock ( ) . await ;
* resolver_lock = None ;
}
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 ;
2023-08-20 01:21:58 +00:00
use windows ::core ::{ PSTR , PCSTR } ;
2023-08-20 15:23:17 +00:00
use std ::ffi ::{ CStr , CString } ;
2022-07-03 00:40:34 +00:00
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 ( ) ;
2023-08-20 15:23:17 +00:00
let host = CString ::new ( host . as_ref ( ) ) . wrap_err ( " invalid host string " ) ? ;
DnsQuery_UTF8 ( PCSTR ::from_raw ( host . as_bytes_with_nul ( ) . as_ptr ( ) ) , DNS_TYPE_TEXT , DNS_QUERY_STANDARD , None , & mut p_query_results as * mut * mut DNS_RECORDA , None ) . wrap_err ( " 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 ( ) {
2023-08-20 01:21:58 +00:00
if ( * p_record ) . wType = = DNS_TYPE_TEXT . 0 {
2022-07-03 00:40:34 +00:00
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 ;
}
2023-08-20 01:21:58 +00:00
DnsFree ( Some ( p_query_results as * const c_void ) , DnsFreeRecordList ) ;
2022-07-03 00:40:34 +00:00
}
Ok ( out )
} else {
let resolver = get_resolver ( ) . await ? ;
2023-07-13 22:52:03 +00:00
let txt_result = match resolver
2022-07-03 00:40:34 +00:00
. txt_lookup ( host . as_ref ( ) )
2023-07-13 22:52:03 +00:00
. await {
Ok ( v ) = > v ,
Err ( e ) = > {
2023-07-14 01:44:34 +00:00
if ! matches! ( e . kind ( ) , ResolveErrorKind ::NoRecordsFound { query :_ , soa :_ , negative_ttl :_ , response_code :_ , trusted :_ } ) {
2023-07-13 22:52:03 +00:00
reset_resolver ( ) . await ;
}
bail! ( " txt_lookup error: {} " , e ) ;
}
} ;
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 ;
2023-08-20 01:21:58 +00:00
use windows ::core ::{ PSTR , PCSTR } ;
2023-08-20 15:23:17 +00:00
use std ::ffi ::{ CStr , CString } ;
2022-07-03 00:40:34 +00:00
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 ( ) ;
2023-08-20 15:23:17 +00:00
let host = CString ::new ( host ) . wrap_err ( " invalid host string " ) ? ;
DnsQuery_UTF8 ( PCSTR ::from_raw ( host . as_bytes_with_nul ( ) . as_ptr ( ) ) , DNS_TYPE_PTR , DNS_QUERY_STANDARD , None , & mut p_query_results as * mut * mut DNS_RECORDA , None ) . wrap_err ( " 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 ( ) {
2023-08-20 01:21:58 +00:00
if ( * p_record ) . wType = = DNS_TYPE_PTR . 0 {
2022-07-03 00:40:34 +00:00
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 ;
}
2023-08-20 01:21:58 +00:00
DnsFree ( Some ( p_query_results as * const c_void ) , DnsFreeRecordList ) ;
2022-07-03 00:40:34 +00:00
}
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
}
}