feat(nat): add None Natresolver (#834)

This commit is contained in:
Matthias Seitz
2023-01-12 16:56:43 +01:00
committed by GitHub
parent db24d3ae9e
commit 429cd69ed4
3 changed files with 71 additions and 3 deletions

1
Cargo.lock generated
View File

@ -3961,6 +3961,7 @@ dependencies = [
"pin-project-lite",
"public-ip",
"reth-tracing",
"thiserror",
"tokio",
"tracing",
]

View File

@ -22,6 +22,7 @@ igd = { git = "https://github.com/stevefan1999-personal/rust-igd", features = [
tracing = "0.1"
pin-project-lite = "0.2.9"
tokio = { version = "1", features = ["time"] }
thiserror = "1.0"
[dev-dependencies]
reth-tracing = { path = "../../tracing" }

View File

@ -10,9 +10,11 @@
use igd::aio::search_gateway;
use pin_project_lite::pin_project;
use std::{
fmt,
future::{poll_fn, Future},
net::IpAddr,
net::{AddrParseError, IpAddr},
pin::Pin,
str::FromStr,
task::{ready, Context, Poll},
time::Duration,
};
@ -27,7 +29,11 @@ pub enum NatResolver {
/// Resolve via Upnp
Upnp,
/// Resolve external IP via [public_ip::Resolver]
ExternalIp,
PublicIp,
/// Use the given [IpAddr]
ExternalIp(IpAddr),
/// Resolve nothing
None,
}
// === impl NatResolver ===
@ -39,6 +45,52 @@ impl NatResolver {
}
}
impl fmt::Display for NatResolver {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NatResolver::Any => f.write_str("any"),
NatResolver::Upnp => f.write_str("upnp"),
NatResolver::PublicIp => f.write_str("publicip"),
NatResolver::ExternalIp(ip) => write!(f, "extip:{ip}"),
NatResolver::None => f.write_str("none"),
}
}
}
/// Error when parsing a [NatResolver]
#[derive(Debug, thiserror::Error)]
pub enum ParseNatResolverError {
/// Failed to parse provided IP
#[error(transparent)]
AddrParseError(#[from] AddrParseError),
/// Failed to parse due to unknown variant
#[error("Unknown Nat Resolver variant: {0}")]
UnknonwVariant(String),
}
impl FromStr for NatResolver {
type Err = ParseNatResolverError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let r = match s {
"any" => NatResolver::Any,
"upnp" => NatResolver::Upnp,
"none" => NatResolver::None,
"publicip" | "public-ip" => NatResolver::PublicIp,
s => {
if let Some(ip) = s.strip_prefix("extip:") {
NatResolver::ExternalIp(ip.parse::<IpAddr>()?)
} else {
return Err(ParseNatResolverError::UnknonwVariant(format!(
"Unknown Nat Resolver: {s}"
)))
}
}
};
Ok(r)
}
}
/// With this type you can resolve the external public IP address on an interval basis.
#[must_use = "Does nothing unless polled"]
pub struct ResolveNatInterval {
@ -121,7 +173,9 @@ pub async fn external_addr_with(resolver: NatResolver) -> Option<IpAddr> {
.await
}
NatResolver::Upnp => resolve_external_ip_upnp().await,
NatResolver::ExternalIp => resolve_external_ip().await,
NatResolver::PublicIp => resolve_external_ip().await,
NatResolver::ExternalIp(ip) => Some(ip),
NatResolver::None => None,
}
}
@ -193,6 +247,7 @@ async fn resolve_external_ip() -> Option<IpAddr> {
#[cfg(test)]
mod tests {
use super::*;
use std::net::Ipv4Addr;
#[tokio::test]
#[ignore]
@ -213,4 +268,15 @@ mod tests {
let ip = interval.tick().await;
dbg!(ip);
}
#[test]
fn test_from_str() {
assert_eq!(NatResolver::Any, "any".parse().unwrap());
assert_eq!(NatResolver::None, "none".parse().unwrap());
let ip = NatResolver::ExternalIp(IpAddr::V4(Ipv4Addr::UNSPECIFIED));
let s = "extip:0.0.0.0";
assert_eq!(ip, s.parse().unwrap());
assert_eq!(ip.to_string().as_str(), s);
}
}