diff options
| author | mat <github@matdoes.dev> | 2021-12-15 23:10:55 -0600 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2021-12-15 23:10:55 -0600 |
| commit | 9642558f8f8d983a7087f15d68be8cf07a85f0c2 (patch) | |
| tree | 5f0a967f005cd5db510a13ab290c8ad6669b25aa /azalea-protocol/src/resolver.rs | |
| parent | 72aefe871ca4983431b1a0b707b472e73ffea836 (diff) | |
| download | azalea-drasl-9642558f8f8d983a7087f15d68be8cf07a85f0c2.tar.xz | |
azalea
Diffstat (limited to 'azalea-protocol/src/resolver.rs')
| -rw-r--r-- | azalea-protocol/src/resolver.rs | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/azalea-protocol/src/resolver.rs b/azalea-protocol/src/resolver.rs new file mode 100644 index 00000000..24687a6e --- /dev/null +++ b/azalea-protocol/src/resolver.rs @@ -0,0 +1,55 @@ +use std::net::IpAddr; + +use crate::{ServerAddress, ServerIpAddress}; +use async_recursion::async_recursion; +use trust_dns_resolver::{ + config::{ResolverConfig, ResolverOpts}, + TokioAsyncResolver, +}; + +/// Resolve a Minecraft server address into an IP address and port. +/// If it's already an IP address, it's returned as-is. +#[async_recursion] +pub async fn resolve_address(address: &ServerAddress) -> Result<ServerIpAddress, String> { + // If the address.host is already in the format of an ip address, return it. + if let Ok(ip) = address.host.parse::<IpAddr>() { + return Ok(ServerIpAddress { + ip, + port: address.port, + }); + } + + // we specify Cloudflare instead of the default resolver because trust_dns_resolver has an issue on Windows where it's really slow using the default resolver + let resolver = + TokioAsyncResolver::tokio(ResolverConfig::cloudflare(), ResolverOpts::default()).unwrap(); + + // first, we do a srv lookup for _minecraft._tcp.<host> + let srv_redirect_result = resolver + .srv_lookup(format!("_minecraft._tcp.{}", address.host).as_str()) + .await; + + // if it resolves that means it's a redirect so we call resolve_address again with the new host + if let Ok(redirect_result) = srv_redirect_result { + let redirect_srv = redirect_result + .iter() + .next() + .ok_or_else(|| "No SRV record found".to_string())?; + let redirect_address = ServerAddress { + host: redirect_srv.target().to_utf8(), + port: redirect_srv.port(), + }; + + println!("redirecting to {:?}", redirect_address); + + return resolve_address(&redirect_address).await; + } + + // there's no redirect, try to resolve this as an ip address + let lookup_ip_result = resolver.lookup_ip(address.host.clone()).await; + let lookup_ip = lookup_ip_result.map_err(|_| "No IP found".to_string())?; + + Ok(ServerIpAddress { + ip: lookup_ip.iter().next().unwrap(), + port: address.port, + }) +} |
