bgpkit_commons/bogons/
mod.rs

1//! # Module: bogons
2//!
3//! This module provides functions to detect whether some given prefix or ASN is a bogon ASN.
4//!
5//! We obtain the bogon ASN and prefixes data from IANA's special registries:
6//! * IPv4: <https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml>
7//! * IPv6: <https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml>
8//! * ASN: <https://www.iana.org/assignments/iana-as-numbers-special-registry/iana-as-numbers-special-registry.xhtml>
9//!
10//! The simplest way to check bogon is to provide a &str:
11//! ```
12//! let bogons = bgpkit_commons::bogons::Bogons::new().unwrap();
13//! assert!(bogons.matches_str("10.0.0.0/9"));
14//! assert!(bogons.matches_str("112"));
15//! assert!(bogons.is_bogon_prefix(&"2001::/24".parse().unwrap()));
16//! assert!(bogons.is_bogon_asn(65535));
17//! ```
18mod asn;
19mod prefix;
20mod utils;
21
22use crate::bogons::asn::load_bogon_asns;
23use crate::bogons::prefix::load_bogon_prefixes;
24use crate::errors::{data_sources, load_methods, modules};
25use crate::{BgpkitCommons, BgpkitCommonsError, LazyLoadable, Result};
26pub use asn::BogonAsn;
27use ipnet::IpNet;
28pub use prefix::BogonPrefix;
29use serde::{Deserialize, Serialize};
30
31#[derive(Clone, Debug, Serialize, Deserialize)]
32pub struct Bogons {
33    pub prefixes: Vec<BogonPrefix>,
34    pub asns: Vec<BogonAsn>,
35}
36
37impl Bogons {
38    pub fn new() -> Result<Self> {
39        Ok(Bogons {
40            prefixes: load_bogon_prefixes()?,
41            asns: load_bogon_asns()?,
42        })
43    }
44
45    /// Check if a given string matches a bogon prefix or ASN.
46    pub fn matches_str(&self, s: &str) -> bool {
47        match s.parse::<IpNet>() {
48            Ok(ip) => self.is_bogon_prefix(&ip),
49            Err(_) => match s.parse::<u32>() {
50                Ok(asn) => self.is_bogon_asn(asn),
51                Err(_) => false,
52            },
53        }
54    }
55
56    /// Check if a given IP prefix is a bogon prefix.
57    pub fn is_bogon_prefix(&self, prefix: &IpNet) -> bool {
58        self.prefixes
59            .iter()
60            .any(|bogon_prefix| bogon_prefix.matches(prefix))
61    }
62
63    /// Check if a given ASN is a bogon ASN.
64    pub fn is_bogon_asn(&self, asn: u32) -> bool {
65        self.asns.iter().any(|bogon_asn| bogon_asn.matches(asn))
66    }
67}
68
69impl LazyLoadable for Bogons {
70    fn reload(&mut self) -> Result<()> {
71        *self = Bogons::new().map_err(|e| {
72            BgpkitCommonsError::data_source_error(data_sources::IANA, e.to_string())
73        })?;
74        Ok(())
75    }
76
77    fn is_loaded(&self) -> bool {
78        !self.prefixes.is_empty() && !self.asns.is_empty()
79    }
80
81    fn loading_status(&self) -> &'static str {
82        if self.is_loaded() {
83            "Bogons data loaded"
84        } else {
85            "Bogons data not loaded"
86        }
87    }
88}
89
90impl BgpkitCommons {
91    pub fn bogons_match(&self, s: &str) -> Result<bool> {
92        match &self.bogons {
93            Some(b) => Ok(b.matches_str(s)),
94            None => Err(BgpkitCommonsError::module_not_loaded(
95                modules::BOGONS,
96                load_methods::LOAD_BOGONS,
97            )),
98        }
99    }
100
101    pub fn bogons_match_prefix(&self, prefix: &str) -> Result<bool> {
102        let prefix: IpNet = prefix.parse().map_err(|e: ipnet::AddrParseError| {
103            BgpkitCommonsError::invalid_format("IP prefix", prefix, e.to_string())
104        })?;
105        match &self.bogons {
106            Some(b) => Ok(b.is_bogon_prefix(&prefix)),
107            None => Err(BgpkitCommonsError::module_not_loaded(
108                modules::BOGONS,
109                load_methods::LOAD_BOGONS,
110            )),
111        }
112    }
113
114    pub fn bogons_match_asn(&self, asn: u32) -> Result<bool> {
115        match &self.bogons {
116            Some(b) => Ok(b.is_bogon_asn(asn)),
117            None => Err(BgpkitCommonsError::module_not_loaded(
118                modules::BOGONS,
119                load_methods::LOAD_BOGONS,
120            )),
121        }
122    }
123
124    /// Get all bogon prefixes.
125    pub fn get_bogon_prefixes(&self) -> Result<Vec<BogonPrefix>> {
126        match &self.bogons {
127            Some(b) => Ok(b.prefixes.clone()),
128            None => Err(BgpkitCommonsError::module_not_loaded(
129                modules::BOGONS,
130                load_methods::LOAD_BOGONS,
131            )),
132        }
133    }
134
135    /// Get all bogon ASNs.
136    pub fn get_bogon_asns(&self) -> Result<Vec<BogonAsn>> {
137        match &self.bogons {
138            Some(b) => Ok(b.asns.clone()),
139            None => Err(BgpkitCommonsError::module_not_loaded(
140                modules::BOGONS,
141                load_methods::LOAD_BOGONS,
142            )),
143        }
144    }
145}