diff --git a/ethers-providers/src/rpc/provider.rs b/ethers-providers/src/rpc/provider.rs index 2cd918e64..13ec96c86 100644 --- a/ethers-providers/src/rpc/provider.rs +++ b/ethers-providers/src/rpc/provider.rs @@ -13,6 +13,7 @@ use crate::{ #[cfg(not(target_arch = "wasm32"))] use crate::{HttpRateLimitRetryPolicy, RetryClient}; +use std::net::Ipv4Addr; #[cfg(feature = "celo")] pub use crate::CeloMiddleware; @@ -40,7 +41,7 @@ use std::{ }; use tracing::trace; use tracing_futures::Instrument; -use url::{ParseError, Url}; +use url::{Host, ParseError, Url}; /// Node Clients #[derive(Copy, Clone)] @@ -1443,11 +1444,30 @@ impl ProviderExt for Provider { /// ``` /// use ethers_providers::is_local_endpoint; /// assert!(is_local_endpoint("http://localhost:8545")); +/// assert!(is_local_endpoint("http://169.254.0.0:8545")); /// assert!(is_local_endpoint("http://127.0.0.1:8545")); +/// assert!(!is_local_endpoint("http://206.71.50.230:8545")); +/// assert!(!is_local_endpoint("http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]")); +/// assert!(is_local_endpoint("http://[::1]")); +/// assert!(!is_local_endpoint("havenofearlucishere")); /// ``` #[inline] -pub fn is_local_endpoint(url: &str) -> bool { - url.contains("127.0.0.1") || url.contains("localhost") +pub fn is_local_endpoint(endpoint: &str) -> bool { + if let Ok(url) = Url::parse(endpoint) { + if let Some(host) = url.host() { + match host { + Host::Domain(domain) => return domain.contains("localhost"), + Host::Ipv4(ipv4) => { + return ipv4 == Ipv4Addr::LOCALHOST || + ipv4.is_link_local() || + ipv4.is_loopback() || + ipv4.is_private() + } + Host::Ipv6(ipv6) => return ipv6.is_loopback(), + } + } + } + false } #[cfg(test)]