Skip to content

Commit

Permalink
add bgpkit as2rel dataset access
Browse files Browse the repository at this point in the history
  • Loading branch information
digizeph committed Jun 26, 2024
1 parent 42285f1 commit 92059e7
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 4 deletions.
38 changes: 36 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ println!(

`asnames` is a module for Autonomous System (AS) names and country lookup

Data source:
#### Data sources
- RIPE NCC asnames: <https://ftp.ripe.net/ripe/asnames/asn.txt>
- CAIDA as-to-organization mapping: <https://www.caida.org/catalog/datasets/as-organizations/>
- APNIC AS population data: <https://stats.labs.apnic.net/cgi-bin/aspop>
Expand Down Expand Up @@ -161,7 +161,7 @@ assert_eq!(countries.lookup_by_name("united states").len(), 2);
assert_eq!(countries.lookup_by_name("united kingdom").len(), 1);
```

### RPKI utilities
### RPKI Utilities

#### Data sources

Expand Down Expand Up @@ -225,6 +225,40 @@ assert!(bogons.is_bogon_prefix(&"2001::/24".parse().unwrap()));
assert!(bogons.is_bogon_asn(65535));
```

### AS-level relationship

`bgpkit-commons` provides access to AS-level relationship data generated by BGPKIT.

#### Data sources

* Raw data files available at: <https://data.bgpkit.com/as2rel/>

#### Data Structure

```rust
pub enum AsRelationship {
ProviderCustomer,
CustomerProvider,
PeerPeer,
}

pub struct As2relBgpkitData {
pub rel: AsRelationship,
pub peers_count: u32,
pub max_peer_count: u32,
}
```

#### Usage Examples

```rust
let bgpkit = bgpkit_commons::as2rel::As2relBgpkit::new().unwrap();
let (v4_data, v6_data) = bgpkit.lookup_pair(400644, 54825);
assert!(v4_data.is_none());
assert!(v6_data.is_some());
assert_eq!(v6_data.unwrap().rel, bgpkit_commons::as2rel::AsRelationship::CustomerProvider);
```

### Feature Flags

- `rustls`: use rustls instead of native-tls for the underlying HTTPS requests
Expand Down
161 changes: 161 additions & 0 deletions src/as2rel/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
//! AS-level relationship generated by BGPKIT
//!
//! Raw data files available at: <https://data.bgpkit.com/as2rel/>
//! * [as2rel-latest.json.bz2](https://data.bgpkit.com/as2rel/as2rel-latest.json.bz2): latest combined
//! * [as2rel-v4-latest.json.bz2](https://data.bgpkit.com/as2rel/as2rel-v4-latest.json.bz2): latest IPv4 relationship
//! * [as2rel-v6-latest.json.bz2](https://data.bgpkit.com/as2rel/as2rel-v6-latest.json.bz2): latest IPv6 relationship
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[allow(dead_code)]
const AS2REL_LATEST_COMBINED: &str = "https://data.bgpkit.com/as2rel/as2rel-latest.json.bz2";

const AS2REL_LATEST_V4: &str = "https://data.bgpkit.com/as2rel/as2rel-v4-latest.json.bz2";
const AS2REL_LATEST_V6: &str = "https://data.bgpkit.com/as2rel/as2rel-v6-latest.json.bz2";

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AsRelationship {
ProviderCustomer,
CustomerProvider,
PeerPeer,
}

impl Serialize for AsRelationship {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
AsRelationship::ProviderCustomer => serializer.serialize_str("pc"),
AsRelationship::CustomerProvider => serializer.serialize_str("cp"),
AsRelationship::PeerPeer => serializer.serialize_str("pp"),
}
}
}

impl<'de> Deserialize<'de> for AsRelationship {
fn deserialize<D>(deserializer: D) -> Result<AsRelationship, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = i8::deserialize(deserializer)?;
match s {
-1 | 1 => Ok(AsRelationship::ProviderCustomer),
0 => Ok(AsRelationship::PeerPeer),
_ => Err(serde::de::Error::custom("invalid relationship")),
}
}
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
struct As2relEntry {
asn1: u32,
asn2: u32,
paths_count: u32,
peers_count: u32,
rel: AsRelationship,
}

impl As2relEntry {
fn reverse(&self) -> Self {
Self {
asn1: self.asn2,
asn2: self.asn1,
paths_count: self.paths_count,
peers_count: self.peers_count,
rel: match self.rel {
AsRelationship::ProviderCustomer => AsRelationship::CustomerProvider,
AsRelationship::CustomerProvider => AsRelationship::ProviderCustomer,
AsRelationship::PeerPeer => AsRelationship::PeerPeer,
},
}
}
}

pub struct As2relBgpkit {
v4_rels_map: HashMap<(u32, u32), As2relEntry>,
v6_rels_map: HashMap<(u32, u32), As2relEntry>,
v4_max_peer_count: u32,
v6_max_peer_count: u32,
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct As2relBgpkitData {
pub rel: AsRelationship,
pub peers_count: u32,
pub max_peer_count: u32,
}

impl As2relBgpkit {
pub fn new() -> Result<Self> {
let v4_rels = parse_as2rel_data(AS2REL_LATEST_V4)?;
let v6_rels = parse_as2rel_data(AS2REL_LATEST_V6)?;
let mut v4_rels_map = HashMap::new();
let mut v6_rels_map = HashMap::new();
let mut v4_max_peer_count = 0;
let mut v6_max_peer_count = 0;
for entry in v4_rels {
v4_rels_map.insert((entry.asn1, entry.asn2), entry);
v4_rels_map.insert((entry.asn2, entry.asn1), entry.reverse());

v4_max_peer_count = v4_max_peer_count.max(entry.peers_count);
}
for entry in v6_rels {
v6_rels_map.insert((entry.asn1, entry.asn2), entry);
v6_rels_map.insert((entry.asn2, entry.asn1), entry.reverse());
v6_max_peer_count = v6_max_peer_count.max(entry.peers_count);
}
Ok(Self {
v4_rels_map,
v6_rels_map,
v4_max_peer_count,
v6_max_peer_count,
})
}

pub fn lookup_pair(
&self,
asn1: u32,
asn2: u32,
) -> (Option<As2relBgpkitData>, Option<As2relBgpkitData>) {
let v4_entry = self.v4_rels_map.get(&(asn1, asn2));
let v6_entry = self.v6_rels_map.get(&(asn1, asn2));

(
v4_entry.map(|entry| As2relBgpkitData {
rel: entry.rel,
peers_count: entry.peers_count,
max_peer_count: self.v4_max_peer_count,
}),
v6_entry.map(|entry| As2relBgpkitData {
rel: entry.rel,
peers_count: entry.peers_count,
max_peer_count: self.v6_max_peer_count,
}),
)
}
}

fn parse_as2rel_data(url: &str) -> Result<Vec<As2relEntry>> {
let data: Vec<As2relEntry> = oneio::read_json_struct(url)?;
Ok(data)
}

#[cfg(test)]
mod tests {

#[test]
fn test_loading_raw_data() {
let bgpkit = crate::as2rel::As2relBgpkit::new().unwrap();
let (v4_data, v6_data) = bgpkit.lookup_pair(400644, 54825);
assert!(v4_data.is_none());
assert!(v6_data.is_some());
assert_eq!(
v6_data.unwrap().rel,
crate::as2rel::AsRelationship::CustomerProvider
);
dbg!(v6_data);
}
}
39 changes: 37 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
//!
//! `asnames` is a module for Autonomous System (AS) names and country lookup
//!
//! Data source:
//! ### Data sources
//! - RIPE NCC asnames: <https://ftp.ripe.net/ripe/asnames/asn.txt>
//! - CAIDA as-to-organization mapping: <https://www.caida.org/catalog/datasets/as-organizations/>
//! - APNIC AS population data: <https://stats.labs.apnic.net/cgi-bin/aspop>
Expand Down Expand Up @@ -152,7 +152,7 @@
//! assert_eq!(countries.lookup_by_name("united kingdom").len(), 1);
//! ```
//!
//! ## RPKI utilities
//! ## RPKI Utilities
//!
//! ### Data sources
//!
Expand Down Expand Up @@ -216,6 +216,40 @@
//! assert!(bogons.is_bogon_asn(65535));
//! ```
//!
//! ## AS-level relationship
//!
//! `bgpkit-commons` provides access to AS-level relationship data generated by BGPKIT.
//!
//! ### Data sources
//!
//! * Raw data files available at: <https://data.bgpkit.com/as2rel/>
//!
//! ### Data Structure
//!
//! ```rust
//! pub enum AsRelationship {
//! ProviderCustomer,
//! CustomerProvider,
//! PeerPeer,
//! }
//!
//! pub struct As2relBgpkitData {
//! pub rel: AsRelationship,
//! pub peers_count: u32,
//! pub max_peer_count: u32,
//!}
//! ```
//!
//! ### Usage Examples
//!
//!```rust
//! let bgpkit = bgpkit_commons::as2rel::As2relBgpkit::new().unwrap();
//! let (v4_data, v6_data) = bgpkit.lookup_pair(400644, 54825);
//! assert!(v4_data.is_none());
//! assert!(v6_data.is_some());
//! assert_eq!(v6_data.unwrap().rel, bgpkit_commons::as2rel::AsRelationship::CustomerProvider);
//! ```
//!
//! ## Feature Flags
//!
//! - `rustls`: use rustls instead of native-tls for the underlying HTTPS requests
Expand Down Expand Up @@ -259,6 +293,7 @@
html_favicon_url = "https://raw.githubusercontent.com/bgpkit/assets/main/logos/favicon.ico"
)]

pub mod as2rel;
pub mod asnames;
pub mod bogons;
pub mod collectors;
Expand Down

0 comments on commit 92059e7

Please sign in to comment.