ip_discovery/lib.rs
1//! # ip-discovery
2//!
3//! A lightweight, high-performance Rust library for detecting public IP addresses
4//! via DNS, HTTP, and STUN protocols with fallback support.
5//!
6//! ## Features
7//!
8//! - **Multi-protocol support**: DNS, HTTP/HTTPS, STUN (RFC 5389)
9//! - **Trusted providers**: Google, Cloudflare, AWS, OpenDNS
10//! - **Fallback mechanism**: Automatic retry with different providers
11//! - **Flexible strategies**: First success, race (fastest), or consensus
12//! - **Zero-dependency protocols**: DNS and STUN use raw UDP sockets
13//! - **Async-first**: Built on tokio for high performance
14//!
15//! ## Quick Start
16//!
17//! ```rust,no_run
18//! use ip_discovery::{get_ip, get_ipv4, get_ipv6};
19//!
20//! #[tokio::main]
21//! async fn main() {
22//! // Get any IP address (IPv4 or IPv6)
23//! if let Ok(result) = get_ip().await {
24//! println!("Public IP: {} (via {})", result.ip, result.provider);
25//! }
26//!
27//! // Get IPv4 specifically
28//! if let Ok(result) = get_ipv4().await {
29//! println!("IPv4: {}", result.ip);
30//! }
31//! }
32//! ```
33//!
34//! ## Custom Configuration
35//!
36//! ```rust,no_run
37//! use ip_discovery::{Config, Strategy, Protocol, BuiltinProvider, get_ip_with};
38//! use std::time::Duration;
39//!
40//! #[tokio::main]
41//! async fn main() {
42//! // Use only DNS providers with race strategy
43//! let config = Config::builder()
44//! .protocols(&[Protocol::Dns])
45//! .strategy(Strategy::Race)
46//! .timeout(Duration::from_secs(5))
47//! .build();
48//!
49//! if let Ok(result) = get_ip_with(config).await {
50//! println!("IP: {} (latency: {:?})", result.ip, result.latency);
51//! }
52//!
53//! // Or pick specific providers
54//! let config = Config::builder()
55//! .providers(&[
56//! BuiltinProvider::CloudflareDns,
57//! BuiltinProvider::GoogleStun,
58//! ])
59//! .build();
60//!
61//! if let Ok(result) = get_ip_with(config).await {
62//! println!("IP: {}", result.ip);
63//! }
64//! }
65//! ```
66
67#![warn(missing_docs)]
68
69mod config;
70mod error;
71mod provider;
72mod resolver;
73mod types;
74
75#[cfg(feature = "dns")]
76pub mod dns;
77
78#[cfg(feature = "http")]
79pub mod http;
80
81#[cfg(feature = "stun")]
82pub mod stun;
83
84pub use config::{Config, ConfigBuilder, Strategy};
85pub use error::{Error, ProviderError};
86pub use provider::Provider;
87pub use resolver::Resolver;
88pub use types::{BuiltinProvider, IpVersion, Protocol, ProviderResult};
89
90/// Get public IP address using default configuration.
91///
92/// Uses all available protocols with the [`Strategy::First`] fallback strategy
93/// and a 10-second per-provider timeout.
94///
95/// # Errors
96///
97/// Returns [`Error::AllProvidersFailed`] if every provider fails.
98pub async fn get_ip() -> Result<ProviderResult, Error> {
99 let config = Config::default();
100 get_ip_with(config).await
101}
102
103/// Get public IPv4 address using default configuration.
104///
105/// # Errors
106///
107/// Returns [`Error::AllProvidersFailed`] if no provider returns an IPv4 address.
108pub async fn get_ipv4() -> Result<ProviderResult, Error> {
109 let config = Config::builder().version(IpVersion::V4).build();
110 get_ip_with(config).await
111}
112
113/// Get public IPv6 address using default configuration.
114///
115/// # Errors
116///
117/// Returns [`Error::NoProvidersForVersion`] if no provider supports IPv6.
118pub async fn get_ipv6() -> Result<ProviderResult, Error> {
119 let config = Config::builder().version(IpVersion::V6).build();
120 get_ip_with(config).await
121}
122
123/// Get public IP address with a custom [`Config`].
124///
125/// # Errors
126///
127/// Returns an [`Error`] variant depending on the strategy and provider results.
128pub async fn get_ip_with(config: Config) -> Result<ProviderResult, Error> {
129 let resolver = Resolver::new(config);
130 resolver.resolve().await
131}