Skip to main content

MaxMindIntel

Struct MaxMindIntel 

Source
pub struct MaxMindIntel { /* private fields */ }
Available on crate feature maxmind only.
Expand description

Country, city, ASN, network name and anonymizer lookups from MaxMind databases (GeoLite2-City / GeoLite2-Country / GeoIP2-* for the country, and the city with a City edition; GeoLite2-ASN for the autonomous system number and organization name; and optionally GeoIP2-Anonymous-IP, GeoIP-Anonymous-Plus or GeoIP2-IP-Risk for VPNs, proxies and Tor, added with with_anonymizer).

Databases are read into memory once, so lookups on the request path never touch the disk and are lock-free. Unknown addresses and lookup errors yield empty fields.

§Anonymizers

The anonymizer databases are paid GeoIP2 products; there is no GeoLite2 edition. With one loaded, every lookup sets IpInfo::anonymity, which feeds the TorOrProxyEntered and AnonymizerEntered checks. The database’s flags map to the most severe Anonymity that applies:

FlagAnonymity
is_tor_exit_nodeTorExitNode
is_public_proxyPublicProxy
is_residential_proxyResidentialProxy
is_anonymous_vpn, unless anonymizer_confidence is below 50Vpn
is_hosting_providerHostingProvider
none of these, or an address the database does not listDirect

A failed lookup (e.g. an IPv6 address in an IPv4-only database) leaves the anonymity unknown, so it never fires a check. The IP Risk database’s ip_risk score is not used: the guard scores what changed during a session rather than how risky an address is on its own.

use session_guard::MaxMindIntel;

let intel = MaxMindIntel::open("/var/lib/GeoIP/GeoLite2-Country.mmdb", None::<&str>)?
    .with_anonymizer("/var/lib/GeoIP/GeoIP2-Anonymous-IP.mmdb")?;
use session_guard::{Guard, GuardConfig, MaxMindIntel, MemoryStore};

let intel = MaxMindIntel::open(
    "/var/lib/GeoIP/GeoLite2-Country.mmdb",
    Some("/var/lib/GeoIP/GeoLite2-ASN.mmdb"),
)?;
let guard = Guard::builder(MemoryStore::new(), GuardConfig::default()).ip_intel(intel).build();

§Keeping the databases up to date

MaxMind publishes new databases weekly or twice a week, and geoipupdate (as a cron job, a sidecar or a shared volume) replaces the files on disk. Those new files are only used once they are reloaded:

  • spawn_reload (feature tokio) checks the files on an interval and reloads them when they change. This is the usual choice.
  • reload_if_changed does a single check, to drive from your own scheduler or runtime.
  • reload and reload_from_bytes swap the databases unconditionally.

A change is detected from each file’s modification time and size, so it works on every kind of mount, including network file systems and Kubernetes volumes that deliver no file system events. A reload swaps the country and ASN databases at once; in-flight lookups finish on the old ones. The anonymizer database is checked and reloaded on its own, so a failed update of one never holds back the other. reload and reload_from_bytes leave the anonymizer in place; swap it with reload_anonymizer or reload_anonymizer_from_bytes.

To reload a source the guard uses, wrap it in an Arc, pass a clone to GuardBuilder::ip_intel and keep the other:

use std::sync::Arc;
use std::time::Duration;

use session_guard::{Guard, GuardConfig, MaxMindIntel, MemoryStore};

let intel = Arc::new(MaxMindIntel::open(
    "/var/lib/GeoIP/GeoLite2-Country.mmdb",
    Some("/var/lib/GeoIP/GeoLite2-ASN.mmdb"),
)?);
intel.spawn_reload(Duration::from_secs(60 * 60));
let guard = Guard::builder(MemoryStore::new(), GuardConfig::default())
    .ip_intel(Arc::clone(&intel))
    .build();

Implementations§

Source§

impl MaxMindIntel

Source

pub fn open( country_db: impl AsRef<Path>, asn_db: Option<impl AsRef<Path>>, ) -> Result<Self, MaxMindError>

Reads the country database (City or Country edition) and, optionally, the ASN database.

§Errors

Fails when a file cannot be read, is not a valid MMDB file, or is the wrong kind of database.

Source

pub fn from_bytes( country_db: Vec<u8>, asn_db: Option<Vec<u8>>, ) -> Result<Self, MaxMindError>

Like open, from database contents already in memory.

§Errors

Fails when the bytes are not a valid MMDB file or the wrong kind of database.

Source

pub fn with_anonymizer( self, anonymizer_db: impl AsRef<Path>, ) -> Result<Self, MaxMindError>

Adds an Anonymous IP, Anonymous Plus or IP Risk database, so lookups also report the Anonymity of the network; see Anonymizers. reload_if_changed follows its file too.

§Errors

Fails when the file cannot be read, is not a valid MMDB file, or is the wrong kind of database.

Source

pub fn with_anonymizer_bytes( self, anonymizer_db: Vec<u8>, ) -> Result<Self, MaxMindError>

Like with_anonymizer, from database contents already in memory.

§Errors

Fails when the bytes are not a valid MMDB file or the wrong kind of database.

Source

pub fn reload( &self, country_db: impl AsRef<Path>, asn_db: Option<impl AsRef<Path>>, ) -> Result<(), MaxMindError>

Replaces the country and ASN databases with freshly read files, which later reload_if_changed checks follow. In-flight lookups finish on the old databases. On error the current databases and files stay in place. The anonymizer database is left as it is.

§Errors

As for open.

Source

pub fn reload_from_bytes( &self, country_db: Vec<u8>, asn_db: Option<Vec<u8>>, ) -> Result<(), MaxMindError>

Like reload, from database contents already in memory. The databases no longer come from files, so reload_if_changed stops checking them (but still checks the anonymizer database’s file, if it has one).

§Errors

As for from_bytes.

Source

pub fn reload_anonymizer( &self, anonymizer_db: impl AsRef<Path>, ) -> Result<(), MaxMindError>

Replaces (or adds) the anonymizer database with a freshly read file, which later reload_if_changed checks follow. On error the current anonymizer database and file stay in place.

§Errors

As for with_anonymizer.

Source

pub fn reload_anonymizer_from_bytes( &self, anonymizer_db: Vec<u8>, ) -> Result<(), MaxMindError>

Like reload_anonymizer, from database contents already in memory. reload_if_changed then stops checking the anonymizer database.

§Errors

As for with_anonymizer_bytes.

Source

pub fn reload_if_changed(&self) -> Result<bool, MaxMindError>

Reloads the databases if their files changed since they were last read, and returns whether it did.

The files are those given to open or the latest reload, and to with_anonymizer or the latest reload_anonymizer. Each is compared by modification time and size, which costs a stat per file; unchanged files are not read. The country and ASN databases are reloaded together, the anonymizer database on its own. Databases from bytes have no files and are never reloaded here.

This blocks while it reads and parses changed files (tens of megabytes for a City database), so call it off the async runtime, or use spawn_reload.

§Errors

As for open, for example when a file is missing, or only partly written by a tool that does not replace it atomically. The databases that failed then stay in place and the next call tries again; the others are still reloaded. With failures on both sides, the country or ASN error is returned.

Source

pub fn spawn_reload(self: &Arc<Self>, every: Duration) -> JoinHandle<()> ⓘ

Available on crate feature tokio only.

Runs reload_if_changed now and then every every on the tokio runtime, reading files on its blocking pool. Each reload is logged (info, with the databases’ build times) and each failure too (warn), with tracing. A failed check does not stop the task and is retried on the next tick; abort the handle to stop it.

MaxMind releases new databases at most twice a week, so an interval of minutes to an hour is plenty, and a check of unchanged files is cheap.

§Panics

Outside a tokio runtime, or if every is zero.

Trait Implementations§

Source§

impl Debug for MaxMindIntel

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl IpIntel for MaxMindIntel

Source§

fn lookup(&self, ip: IpAddr) -> IpInfo

Looks up ip. Return empty fields for unknown addresses; never panic.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoApi for T

Source§

fn into_api<A>(self) -> UseApi<T, A>
where T: Sized,

into UseApi
Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more