use crate::helpers::{split_to_string_vec, string_to_binary};
#[derive(Debug)]
pub struct CFIPs {
pub ipsv4: Vec<String>,
pub ipsv6: Vec<String>,
}
impl CFIPs {
pub async fn load() -> Result<Self, Box<dyn std::error::Error>> {
let ipsv4 = Self::load_ips("https://www.cloudflare.com/ips-v4").await?;
let ipsv6 = Self::load_ips("https://www.cloudflare.com/ips-v6").await?;
Ok(Self { ipsv4, ipsv6 })
}
async fn load_ips(url: &str) -> Result<Vec<String>, Box<dyn std::error::Error>> {
Ok(split_to_string_vec(
reqwest::get(url).await?.text().await?,
"\n",
))
}
}
impl CFIPs {
pub fn check_ip_v4(&self, ip: &str) -> bool {
self.ipsv4
.iter()
.any(|cidr| CFIPs::check_ip_in_cidr(ip, cidr))
}
pub fn check_ip_in_cidr(ip: &str, cidr_range: &str) -> bool {
let ip_parts: Vec<&str> = ip.split(".").collect();
let cidr_parts: Vec<&str> = cidr_range.split("/").collect();
let mask_size: u8 = cidr_parts[1].parse().unwrap_or(0);
if ip_parts.len() != 4 || cidr_parts[0].split(".").collect::<Vec<&str>>().len() != 4 {
return false;
}
let ip_bin = ip_parts
.iter()
.map(|x| string_to_binary(x))
.collect::<String>();
let cidr_bin = cidr_parts[0]
.split(".")
.map(|x| string_to_binary(x))
.collect::<String>();
if ip_bin[0..mask_size as usize] == cidr_bin[0..mask_size as usize] {
return true;
}
false
}
}