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
20pub struct IpInfoHandler {
22 web_client: Client,
23 providers: Vec<IpInfoProvider>,
24 fallback: MmdbConfig,
25}
26
27impl IpInfoHandler {
28 #[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 #[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#[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}