use crate::traceroute::{is_cgnat, is_internal_ip, ClassifiedHopInfo, IspInfo};
use std::net::IpAddr;
pub fn extract_isp_from_path(hops: &[ClassifiedHopInfo]) -> Option<IspInfo> {
for hop in hops {
if let Some(addr) = hop.addr {
if let IpAddr::V4(ipv4) = addr {
if is_internal_ip(&ipv4) || is_cgnat(&ipv4) {
continue;
}
if let Some(ref asn_info) = hop.asn_info {
if asn_info.asn != 0 {
return Some(IspInfo {
public_ip: addr,
asn: asn_info.asn,
name: asn_info.name.clone(),
hostname: hop.hostname.clone(),
});
}
}
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use crate::traceroute::{AsnInfo, SegmentType};
use std::net::Ipv4Addr;
#[test]
fn test_extract_isp_from_path() {
let hops = vec![
ClassifiedHopInfo {
ttl: 1,
segment: SegmentType::Lan,
hostname: Some("router.local".to_string()),
addr: Some(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))),
asn_info: None,
rtt: None,
},
ClassifiedHopInfo {
ttl: 2,
segment: SegmentType::Isp,
hostname: Some("gateway.isp.com".to_string()),
addr: Some(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 1))),
asn_info: Some(AsnInfo {
asn: 12345,
prefix: "203.0.113.0/24".to_string(),
country_code: "US".to_string(),
registry: "ARIN".to_string(),
name: "TEST-ISP".to_string(),
}),
rtt: None,
},
];
let isp = extract_isp_from_path(&hops);
assert!(isp.is_some());
let isp = isp.unwrap();
assert_eq!(isp.asn, 12345);
assert_eq!(isp.name, "TEST-ISP");
assert_eq!(isp.public_ip, IpAddr::V4(Ipv4Addr::new(203, 0, 113, 1)));
assert_eq!(isp.hostname, Some("gateway.isp.com".to_string()));
}
#[test]
fn test_skip_private_ips() {
let hops = vec![
ClassifiedHopInfo {
ttl: 1,
segment: SegmentType::Lan,
hostname: None,
addr: Some(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))),
asn_info: None,
rtt: None,
},
ClassifiedHopInfo {
ttl: 2,
segment: SegmentType::Isp,
hostname: None,
addr: Some(IpAddr::V4(Ipv4Addr::new(100, 64, 0, 1))),
asn_info: Some(AsnInfo {
asn: 12345,
prefix: "100.64.0.0/10".to_string(),
country_code: "US".to_string(),
registry: "ARIN".to_string(),
name: "CGNAT-ISP".to_string(),
}),
rtt: None,
},
ClassifiedHopInfo {
ttl: 3,
segment: SegmentType::Isp,
hostname: None,
addr: Some(IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))),
asn_info: Some(AsnInfo {
asn: 15169,
prefix: "8.8.8.0/24".to_string(),
country_code: "US".to_string(),
registry: "ARIN".to_string(),
name: "GOOGLE".to_string(),
}),
rtt: None,
},
];
let isp = extract_isp_from_path(&hops);
assert!(isp.is_some());
let isp = isp.unwrap();
assert_eq!(isp.asn, 15169);
assert_eq!(isp.name, "GOOGLE");
}
}