nullnet_libipinfo/
lib.rs

1#![doc = include_str!("../README.md")]
2
3pub use crate::api::api_fields::ApiFields;
4use crate::bogon::is_bogon;
5pub use crate::ip_info::IpInfo;
6pub use crate::ip_info_provider::IpInfoProvider;
7use crate::mmdb::mmdb_config::MmdbConfig;
8use crate::web_client::new_web_client;
9use nullnet_liberror::Error;
10use reqwest::Client;
11use std::net::IpAddr;
12
13mod api;
14mod bogon;
15mod ip_info;
16mod ip_info_provider;
17mod mmdb;
18mod web_client;
19
20/// The main struct for handling IP information lookups.
21pub struct IpInfoHandler {
22    web_client: Client,
23    providers: Vec<IpInfoProvider>,
24    fallback: MmdbConfig,
25}
26
27impl IpInfoHandler {
28    /// Returns a new `IpInfoHandler` with the given providers.
29    ///
30    /// Even if no providers are given, the handler will still use a fallback provider
31    /// (free databases from [dp-ip.com](https://db-ip.com)).
32    #[allow(clippy::missing_errors_doc)]
33    pub fn new(providers: Vec<IpInfoProvider>) -> Result<Self, Error> {
34        let web_client = new_web_client()?;
35
36        let fallback = MmdbConfig::new(
37            "https://download.db-ip.com/free/dbip-city-lite-{%Y-%m}.mmdb.gz",
38            "https://download.db-ip.com/free/dbip-asn-lite-{%Y-%m}.mmdb.gz",
39            "",
40            31,
41        );
42
43        Ok(Self {
44            web_client,
45            providers,
46            fallback,
47        })
48    }
49
50    /// Looks up the IP information for the given IP address.
51    #[allow(clippy::missing_errors_doc)]
52    pub async fn lookup(&self, ip: &str) -> Result<IpInfo, Error> {
53        for provider in &self.providers {
54            let ip_info = provider.lookup_ip(&self.web_client, ip).await;
55            if ip_info.is_ok() {
56                return ip_info;
57            }
58        }
59        self.fallback.lookup_ip(ip)
60    }
61}
62
63/// Returns the IP address to use for the lookup.
64///
65/// In other words, this method determines which address of the pair isn't from a private or reserved IP range.
66#[must_use]
67pub fn get_ip_to_lookup(source: IpAddr, dest: IpAddr) -> Option<IpAddr> {
68    if is_bogon(source).is_none() {
69        Some(source)
70    } else if is_bogon(dest).is_none() {
71        Some(dest)
72    } else {
73        None
74    }
75}