getip/
gip.rs

1//! Implementations of `Provider` that receive global IP addresses from online services.
2//! This is an asynchronous rewrite of dalance/gip.
3//
4//  Copyright (C) 2018 dalance
5//  Copyright (C) 2021 Zhang Maiyun <myzhang1029@hotmail.com>
6//
7//  This file is part of DNS updater.
8//
9//  DNS updater is free software: you can redistribute it and/or modify
10//  it under the terms of the GNU Affero General Public License as published by
11//  the Free Software Foundation, either version 3 of the License, or
12//  (at your option) any later version.
13//
14//  DNS updater is distributed in the hope that it will be useful,
15//  but WITHOUT ANY WARRANTY; without even the implied warranty of
16//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17//  GNU Affero General Public License for more details.
18//
19//  You should have received a copy of the GNU Affero General Public License
20//  along with DNS updater.  If not, see <https://www.gnu.org/licenses/>.
21//
22
23use crate::{Error, IpType, Provider, Result};
24use async_trait::async_trait;
25use derive_deref::Deref;
26use log::{debug, trace};
27use reqwest::{Client, Proxy};
28use serde::Deserialize;
29use serde_json::Value;
30use std::default::Default;
31use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
32use std::str::FromStr;
33use std::time::Duration;
34use thiserror::Error as ErrorDerive;
35use trust_dns_resolver::{
36    config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts},
37    error::ResolveError,
38    TokioAsyncResolver,
39};
40
41/// Method with which a global `Provider` retrieves addresses.
42#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
43pub enum ProviderMethod {
44    /// Plain text HTTP request.
45    #[serde(rename = "plain")]
46    Plain,
47    /// HTTP JSON response.
48    #[serde(rename = "json")]
49    Json,
50    /// DNS queries.
51    #[serde(rename = "dns")]
52    Dns,
53}
54
55/// Information and configuration of a `Provider`.
56#[derive(Clone, Debug, Deserialize, PartialEq)]
57pub struct ProviderInfo {
58    /// Provider name.
59    name: String,
60    /// Provider type of its address.
61    #[serde(rename = "type")]
62    addr_type: IpType,
63    /// Method used by this provider.
64    method: ProviderMethod,
65    url: String,
66    key: Option<String>,
67}
68
69impl Default for ProviderInfo {
70    fn default() -> Self {
71        Self {
72            name: String::default(),
73            addr_type: IpType::Ipv4,
74            method: ProviderMethod::Plain,
75            url: String::default(),
76            key: None,
77        }
78    }
79}
80
81/// Error type of global IP providers.
82#[derive(Debug, ErrorDerive)]
83pub enum GlobalIpError {
84    /// Error because of a `reqwest` request.
85    #[error(transparent)]
86    ReqwestError(#[from] reqwest::Error),
87    /// Error during JSON deserialization.
88    #[error(transparent)]
89    JsonParseError(#[from] serde_json::Error),
90    /// Specified JSON field does not exist in the response.
91    #[error("field `{0}' does not exist in response")]
92    JsonNotFoundError(String),
93    /// Specified JSON field cannot be decoded.
94    #[error("field `{0}' in response can't be decoded")]
95    JsonDecodeError(String),
96    /// DNS queries failed.
97    #[error(transparent)]
98    DnsError(#[from] Box<ResolveError>),
99    /// Cannot resolve the address of the DNS server itself.
100    #[error("specified DNS server `{0}' has no address")]
101    DnsNoServerError(String),
102}
103
104macro_rules! make_get_type {
105    () => {
106        /// Get the `IPType` that this provider returns.
107        fn get_type(&self) -> IpType {
108            self.info.addr_type
109        }
110    };
111}
112
113macro_rules! make_new {
114    ($name: ident) => {
115        impl $name {
116            /// Create a new $name.
117            fn new(info: &ProviderInfo, timeout: u64, proxy: &Option<String>) -> Self {
118                Self(AbstractProvider {
119                    info: info.clone(),
120                    timeout,
121                    proxy: proxy.clone(),
122                })
123            }
124        }
125    };
126}
127
128/// Shared fields among all providers.
129#[derive(Clone, Debug)]
130pub struct AbstractProvider {
131    /// Definition of this provider.
132    pub info: ProviderInfo,
133    /// DNS query or HTTP request timeout.
134    pub timeout: u64,
135    /// Proxy for HTTP requests.
136    pub proxy: Option<String>,
137}
138
139impl Default for AbstractProvider {
140    fn default() -> Self {
141        Self {
142            info: ProviderInfo::default(),
143            timeout: 1000,
144            proxy: None,
145        }
146    }
147}
148
149/// Build a new client with `timeout` and `proxy`.
150fn build_client(timeout: u64, proxy: &Option<String>) -> reqwest::Result<Client> {
151    let client = match (timeout, proxy) {
152        (0, None) => Client::new(),
153        (0, Some(proxy)) => Client::builder().proxy(Proxy::all(proxy)?).build()?,
154        (_, None) => Client::builder()
155            .timeout(Duration::from_millis(timeout))
156            .build()?,
157        (_, Some(proxy)) => Client::builder()
158            .proxy(Proxy::all(proxy)?)
159            .timeout(Duration::from_millis(timeout))
160            .build()?,
161    };
162    Ok(client)
163}
164
165/// Build a new GET request to `url` with `timeout` and `proxy` and return the response.
166async fn build_client_get(url: &str, timeout: u64, proxy: &Option<String>) -> Result<String> {
167    Ok((async {
168        let client = build_client(timeout, proxy)?;
169        debug!("Reqwesting {:?} through proxy {:?}", url, proxy);
170        client
171            .get(url)
172            .send()
173            .await?
174            .error_for_status()?
175            .text()
176            .await
177    })
178    .await
179    .map_err(GlobalIpError::ReqwestError)?)
180}
181
182/// Create a `getip::Result` containing the IP address.
183fn create_ipaddr(addr: &str, addr_type: IpType) -> Result<IpAddr> {
184    Ok(match addr_type {
185        IpType::Ipv4 => IpAddr::V4(Ipv4Addr::from_str(addr).map_err(Error::AddrParseError)?),
186        IpType::Ipv6 => IpAddr::V6(Ipv6Addr::from_str(addr).map_err(Error::AddrParseError)?),
187    })
188}
189
190/// Plain text provider.
191#[derive(Clone, Debug, Deref)]
192pub struct ProviderPlain(AbstractProvider);
193
194make_new! {ProviderPlain}
195
196#[async_trait]
197impl Provider for ProviderPlain {
198    async fn get_addr(&self) -> Result<IpAddr> {
199        let addr = build_client_get(&self.info.url, self.timeout, &self.proxy).await?;
200        debug!("Plain provider {:?} returned {:?}", self.info, addr);
201        create_ipaddr(&addr, self.info.addr_type)
202    }
203
204    make_get_type! {}
205}
206
207/// JSON provider.
208#[derive(Clone, Debug, Deref)]
209pub struct ProviderJson(AbstractProvider);
210
211make_new! {ProviderJson}
212
213#[async_trait]
214impl Provider for ProviderJson {
215    async fn get_addr(&self) -> Result<IpAddr> {
216        let resp = build_client_get(&self.info.url, self.timeout, &self.proxy).await?;
217        trace!("Provider got response {:?}", resp);
218        // Try to parse the response as JSON
219        let json: Value = serde_json::from_str(&resp).map_err(GlobalIpError::JsonParseError)?;
220        let key = self
221            .info
222            .key
223            .clone()
224            .expect("`key' should exist for JSON providers");
225        // Extract ip from response
226        let addr = json
227            .get(&key)
228            .ok_or_else(|| GlobalIpError::JsonNotFoundError(key.clone()))?
229            .as_str()
230            .ok_or(GlobalIpError::JsonDecodeError(key))?;
231        debug!("JSON provider {:?} returned {:?}", self.info, addr);
232        create_ipaddr(addr, self.info.addr_type)
233    }
234
235    make_get_type! {}
236}
237
238/// DNS provider.
239#[derive(Clone, Debug, Deref)]
240pub struct ProviderDns(AbstractProvider);
241
242make_new! {ProviderDns}
243
244/// Resolve host to address with a resolver.
245async fn host_to_addr(
246    resolver: TokioAsyncResolver,
247    host: &str,
248    addr_type: IpType,
249) -> std::result::Result<Option<IpAddr>, ResolveError> {
250    Ok(match addr_type {
251        IpType::Ipv4 => {
252            let srv = resolver.ipv4_lookup(host).await?;
253            // Trick to unpack None
254            (|| Some(IpAddr::V4(*srv.iter().next()?)))()
255        }
256        IpType::Ipv6 => {
257            let srv = resolver.ipv6_lookup(host).await?;
258            (|| Some(IpAddr::V6(*srv.iter().next()?)))()
259        }
260    })
261}
262
263#[async_trait]
264impl Provider for ProviderDns {
265    async fn get_addr(&self) -> Result<IpAddr> {
266        let (query, server) = self
267            .info
268            .url
269            .split_once('@')
270            .expect("DNS Provider URL should be like query@server");
271        let mut opts = ResolverOpts::default();
272        opts.timeout = Duration::from_millis(self.timeout);
273        let opts = opts;
274        // First get the address of the DNS server
275        let resolver = TokioAsyncResolver::tokio(ResolverConfig::new(), opts)
276            .map_err(|e| GlobalIpError::DnsError(Box::new(e)))?;
277        debug!("Resolving {:?} on {:?}", server, resolver);
278        // Get Resolver's address
279        let server_addr = host_to_addr(resolver, server, self.info.addr_type)
280            .await
281            // Deal with errors
282            .map_err(|e| GlobalIpError::DnsError(Box::new(e)))?
283            // Deal with Nones
284            .ok_or_else(|| GlobalIpError::DnsNoServerError(server.to_string()))?;
285        // Construct Resolve config
286        let ns = NameServerConfig {
287            socket_addr: std::net::SocketAddr::new(server_addr, 53),
288            protocol: Protocol::Udp,
289            tls_dns_name: None,
290            trust_nx_responses: false,
291            bind_addr: None,
292        };
293        let mut config = ResolverConfig::new();
294        config.add_name_server(ns);
295        // Create new resolver
296        let resolver = TokioAsyncResolver::tokio(config, opts)
297            .map_err(|e| GlobalIpError::DnsError(Box::new(e)))?;
298        debug!("Resolving {:?} on {:?}", query, resolver);
299        let addr = host_to_addr(resolver, query, self.info.addr_type)
300            .await
301            .map_err(|e| GlobalIpError::DnsError(Box::new(e)))?
302            // Deal with Nones
303            .ok_or_else(|| GlobalIpError::DnsNoServerError(server.to_string()))?;
304        debug!("DNS provider {:?} returned {:?}", self.info, addr);
305        Ok(addr)
306    }
307
308    make_get_type! {}
309}
310
311/// Try multiple providers until anyone succeeds
312#[derive(Debug)]
313pub struct ProviderMultiple {
314    providers: Vec<ProviderInfo>,
315    addr_type: IpType,
316    timeout: u64,
317    proxy: Option<String>,
318}
319
320impl Default for ProviderMultiple {
321    fn default() -> Self {
322        let providers: Vec<ProviderInfo> = serde_json::from_str(DEFAULT_PROVIDERS).unwrap();
323        Self {
324            providers,
325            addr_type: IpType::Ipv4,
326            timeout: 1000,
327            proxy: None,
328        }
329    }
330}
331
332impl ProviderMultiple {
333    /// A default IPv6 provider
334    #[must_use]
335    pub fn default_v6() -> Self {
336        Self {
337            addr_type: IpType::Ipv6,
338            ..ProviderMultiple::default()
339        }
340    }
341}
342
343#[async_trait]
344impl Provider for ProviderMultiple {
345    async fn get_addr(&self) -> Result<IpAddr> {
346        let mut result: Result<IpAddr> = Err(crate::Error::NoAddress);
347        trace!("Registered providers: {:?}", self.providers);
348        for info in &self.providers {
349            if info.addr_type != self.addr_type {
350                continue;
351            }
352            let this_result = match info.method {
353                ProviderMethod::Plain => {
354                    let provider = ProviderPlain::new(info, self.timeout, &self.proxy);
355                    provider.get_addr().await
356                }
357                ProviderMethod::Json => {
358                    let provider = ProviderJson::new(info, self.timeout, &self.proxy);
359                    provider.get_addr().await
360                }
361                ProviderMethod::Dns => {
362                    let provider = ProviderDns::new(info, self.timeout, &self.proxy);
363                    provider.get_addr().await
364                }
365            };
366            if this_result.is_ok() {
367                debug!("Using result {:?} from provider {:?}", this_result, info);
368                result = this_result;
369                break;
370            }
371        }
372        result
373    }
374
375    fn get_type(&self) -> IpType {
376        self.addr_type
377    }
378}
379
380/// JSON list of default providers that `ProviderDefault` uses.
381pub const DEFAULT_PROVIDERS: &str = r#"[
382  {
383    "method": "plain",
384    "name": "ipify",
385    "type": "IPv4",
386    "url": "https://api.ipify.org/"
387  },
388  {
389    "method": "plain",
390    "name": "ipify",
391    "type": "IPv6",
392    "url": "https://api6.ipify.org/"
393  },
394  {
395    "method": "plain",
396    "name": "ipv6-test",
397    "type": "IPv4",
398    "url": "https://v4.ipv6-test.com/api/myip.php"
399  },
400  {
401    "method": "plain",
402    "name": "ipv6-test",
403    "type": "IPv6",
404    "url": "https://v6.ipv6-test.com/api/myip.php"
405  },
406  {
407    "method": "plain",
408    "name": "ident.me",
409    "type": "IPv4",
410    "url": "https://v4.ident.me/"
411  },
412  {
413    "method": "plain",
414    "name": "ident.me",
415    "type": "IPv6",
416    "url": "https://v6.ident.me/"
417  },
418  {
419    "key": "ip",
420    "method": "json",
421    "name": "test-ipv6",
422    "padding": "callback",
423    "type": "IPv4",
424    "url": "https://ipv4.test-ipv6.com/ip/"
425  },
426  {
427    "key": "ip",
428    "method": "json",
429    "name": "test-ipv6",
430    "padding": "callback",
431    "type": "IPv6",
432    "url": "https://ipv6.test-ipv6.com/ip/"
433  },
434  {
435    "method": "dns",
436    "name": "opendns.com",
437    "type": "IPv4",
438    "url": "myip.opendns.com@resolver1.opendns.com"
439  },
440  {
441    "method": "dns",
442    "name": "opendns.com",
443    "type": "IPv6",
444    "url": "myip.opendns.com@resolver1.opendns.com"
445  },
446  {
447    "method": "dns",
448    "name": "akamai.com",
449    "type": "IPv4",
450    "url": "whoami.akamai.com@ns1-1.akamaitech.net"
451  },
452  {
453    "method": "plain",
454    "name": "akamai.com",
455    "type": "IPv4",
456    "url": "http://whatismyip.akamai.com"
457  },
458  {
459    "method": "plain",
460    "name": "akamai.com",
461    "type": "IPv6",
462    "url": "http://ipv6.whatismyip.akamai.com"
463  }
464]"#;