1use std::net::IpAddr;
4use std::time::Duration;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[non_exhaustive]
9pub enum Protocol {
10 Dns,
12 Http,
14 Stun,
16}
17
18impl std::fmt::Display for Protocol {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match self {
21 Protocol::Dns => write!(f, "DNS"),
22 Protocol::Http => write!(f, "HTTP"),
23 Protocol::Stun => write!(f, "STUN"),
24 }
25 }
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
30#[non_exhaustive]
31pub enum IpVersion {
32 V4,
34 V6,
36 #[default]
38 Any,
39}
40
41impl IpVersion {
42 pub(crate) fn matches(self, ip: IpAddr) -> bool {
43 match self {
44 Self::V4 => ip.is_ipv4(),
45 Self::V6 => ip.is_ipv6(),
46 Self::Any => true,
47 }
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct ProviderResult {
54 pub ip: IpAddr,
56 pub provider: String,
58 pub protocol: Protocol,
60 pub latency: Duration,
62}
63
64impl ProviderResult {
65 pub fn ipv4(&self) -> Option<std::net::Ipv4Addr> {
67 match self.ip {
68 IpAddr::V4(v4) => Some(v4),
69 _ => None,
70 }
71 }
72
73 pub fn ipv6(&self) -> Option<std::net::Ipv6Addr> {
75 match self.ip {
76 IpAddr::V6(v6) => Some(v6),
77 _ => None,
78 }
79 }
80}
81
82impl std::fmt::Display for ProviderResult {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(
85 f,
86 "{} (via {} over {}, {:?})",
87 self.ip, self.provider, self.protocol, self.latency
88 )
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
97#[non_exhaustive]
98pub enum BuiltinProvider {
99 GoogleStun,
102 GoogleStun1,
104 GoogleStun2,
106 CloudflareStun,
108
109 GoogleDns,
112 CloudflareDns,
114 OpenDns,
116
117 CloudflareHttp,
120 Aws,
122}
123
124impl BuiltinProvider {
125 pub fn protocol(&self) -> Protocol {
127 match self {
128 Self::GoogleStun | Self::GoogleStun1 | Self::GoogleStun2 | Self::CloudflareStun => {
129 Protocol::Stun
130 }
131 Self::GoogleDns | Self::CloudflareDns | Self::OpenDns => Protocol::Dns,
132 Self::CloudflareHttp | Self::Aws => Protocol::Http,
133 }
134 }
135
136 pub const ALL: &'static [BuiltinProvider] = &[
146 Self::CloudflareStun,
148 Self::CloudflareDns,
149 Self::GoogleStun,
150 Self::GoogleStun1,
151 Self::GoogleStun2,
152 Self::GoogleDns,
153 Self::OpenDns,
155 Self::CloudflareHttp,
156 Self::Aws,
157 ];
158
159 pub(crate) fn to_boxed_blocking(self) -> crate::provider::BoxedBlockingProvider {
161 match self {
162 #[cfg(feature = "stun")]
163 Self::GoogleStun => Box::new(crate::stun::providers::google()),
164 #[cfg(feature = "stun")]
165 Self::GoogleStun1 => Box::new(crate::stun::providers::google1()),
166 #[cfg(feature = "stun")]
167 Self::GoogleStun2 => Box::new(crate::stun::providers::google2()),
168 #[cfg(feature = "stun")]
169 Self::CloudflareStun => Box::new(crate::stun::providers::cloudflare()),
170
171 #[cfg(feature = "dns")]
172 Self::GoogleDns => Box::new(crate::dns::providers::google()),
173 #[cfg(feature = "dns")]
174 Self::CloudflareDns => Box::new(crate::dns::providers::cloudflare()),
175 #[cfg(feature = "dns")]
176 Self::OpenDns => Box::new(crate::dns::providers::opendns()),
177
178 #[cfg(feature = "http")]
179 Self::CloudflareHttp => Box::new(crate::http::providers::cloudflare()),
180 #[cfg(feature = "http")]
181 Self::Aws => Box::new(crate::http::providers::aws()),
182
183 #[allow(unreachable_patterns)]
185 other => Box::new(super::provider::DisabledProvider(format!("{:?}", other))),
186 }
187 }
188
189 #[cfg(feature = "tokio")]
191 pub(crate) fn to_boxed(self) -> crate::provider::BoxedProvider {
192 match self {
193 #[cfg(feature = "stun")]
194 Self::GoogleStun => Box::new(crate::stun::providers::google()),
195 #[cfg(feature = "stun")]
196 Self::GoogleStun1 => Box::new(crate::stun::providers::google1()),
197 #[cfg(feature = "stun")]
198 Self::GoogleStun2 => Box::new(crate::stun::providers::google2()),
199 #[cfg(feature = "stun")]
200 Self::CloudflareStun => Box::new(crate::stun::providers::cloudflare()),
201
202 #[cfg(feature = "dns")]
203 Self::GoogleDns => Box::new(crate::dns::providers::google()),
204 #[cfg(feature = "dns")]
205 Self::CloudflareDns => Box::new(crate::dns::providers::cloudflare()),
206 #[cfg(feature = "dns")]
207 Self::OpenDns => Box::new(crate::dns::providers::opendns()),
208
209 #[cfg(feature = "http")]
210 Self::CloudflareHttp => Box::new(crate::http::providers::cloudflare()),
211 #[cfg(feature = "http")]
212 Self::Aws => Box::new(crate::http::providers::aws()),
213
214 #[allow(unreachable_patterns)]
216 other => Box::new(super::provider::DisabledProvider(format!("{:?}", other))),
217 }
218 }
219}
220
221impl std::fmt::Display for BuiltinProvider {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 match self {
224 Self::GoogleStun => write!(f, "Google STUN"),
225 Self::GoogleStun1 => write!(f, "Google STUN 1"),
226 Self::GoogleStun2 => write!(f, "Google STUN 2"),
227 Self::CloudflareStun => write!(f, "Cloudflare STUN"),
228 Self::GoogleDns => write!(f, "Google DNS"),
229 Self::CloudflareDns => write!(f, "Cloudflare DNS"),
230 Self::OpenDns => write!(f, "OpenDNS"),
231 Self::CloudflareHttp => write!(f, "Cloudflare"),
232 Self::Aws => write!(f, "AWS"),
233 }
234 }
235}