use once_cell::sync::Lazy;
use std::net::UdpSocket;
use tracing::warn;
pub struct IpUtil;
impl IpUtil {
#[cfg(feature = "server-http")]
pub fn get_ip_addr<Req: crate::tina::server::http::request_ext::RequestExt>(req: &Req) -> std::borrow::Cow<str> {
req.get_remote_ip_address()
}
pub fn internal_ip(ip: &str) -> bool {
if ip == "127.0.0.1" {
return true;
}
let addr = Self::text_to_numeric_format_v_4(ip);
internal_ip(addr.as_slice())
}
pub fn text_to_numeric_format_v_4(text: &str) -> Vec<u8> {
if text.is_empty() {
return vec![];
}
let mut bytes: [u8; 4] = [0, 0, 0, 0];
let elements = text.split('.').collect::<Vec<&str>>();
let mut l: u64;
match elements.len() {
1 => {
l = match elements[0].parse::<u64>() {
Ok(v) => v,
Err(_) => {
warn!("invalid ip v4: {}", text);
return vec![];
}
};
if l > 4294967295 {
return vec![];
}
bytes[0] = (l >> 24 & 0xFF) as u32 as u8;
bytes[1] = ((l & 0xFFFFFF) >> 16 & 0xFF) as u32 as u8;
bytes[2] = ((l & 0xFFFF) >> 8 & 0xFF) as u32 as u8;
bytes[3] = (l & 0xFF) as u32 as u8;
}
2 => {
l = match elements[0].parse::<u64>() {
Ok(v) => v,
Err(_) => {
warn!("invalid ip v4: {}", text);
return vec![];
}
};
if l > 255 {
return vec![];
}
bytes[0] = (l & 0xFF) as u32 as u8;
l = match elements[1].parse::<u64>() {
Ok(v) => v,
Err(_) => {
warn!("invalid ip v4: {}", text);
return vec![];
}
};
if l > 16777215 {
return vec![];
}
bytes[1] = (l >> 16 & 0xFF) as u32 as u8;
bytes[2] = ((l & 0xFFFF) >> 8 & 0xFF) as u32 as u8;
bytes[3] = (l & 0xFF) as u32 as u8;
}
3 => {
for i in 0..2 {
l = match elements[i].parse::<u64>() {
Ok(v) => v,
Err(_) => {
warn!("invalid ip v4: {}", text);
return vec![];
}
};
if l > 255 {
return vec![];
}
bytes[i] = (l & 0xFF) as u32 as u8;
}
l = match elements[2].parse::<u64>() {
Ok(v) => v,
Err(_) => {
warn!("invalid ip v4: {}", text);
return vec![];
}
};
if l > 65535 {
return vec![];
}
bytes[2] = (l >> 8 & 0xFF) as u32 as u8;
bytes[3] = (l & 0xFF) as u32 as u8;
}
4 => {
for i in 0..4 {
l = match elements[i].parse::<u64>() {
Ok(v) => v,
Err(_) => {
warn!("invalid ip v4: {}", text);
return vec![];
}
};
if l > 255 {
return vec![];
}
bytes[i] = (l & 0xFF) as u32 as u8;
}
}
_ => return vec![],
}
Vec::from(bytes)
}
pub fn get_host_ip() -> Option<&'static str> {
static HOST_IP: Lazy<Option<String>> = Lazy::new(|| {
let socket = match UdpSocket::bind("0.0.0.0:0") {
Ok(s) => s,
Err(_) => return None,
};
match socket.connect("8.8.8.8:80") {
Ok(()) => (),
Err(_) => return None,
};
match socket.local_addr() {
Ok(addr) => Some(addr.ip().to_string()),
Err(_) => None,
}
});
HOST_IP.as_ref().map(|s| s.as_str())
}
}
fn internal_ip(addr: &[u8]) -> bool {
if addr.len() < 2 {
return true;
}
let b0 = addr[0];
let b1 = addr[1];
const SECTION_1: u8 = 0x0A;
const SECTION_2: u8 = 0xAC;
const SECTION_3: u8 = 0x10;
const SECTION_4: u8 = 0x1F;
const SECTION_5: u8 = 0xC0;
const SECTION_6: u8 = 0xA8;
match b0 {
SECTION_1 => true,
SECTION_2 => {
if (SECTION_3..=SECTION_4).contains(&b1) {
return true;
}
false
}
SECTION_5 => matches!(b1, SECTION_6),
_ => false,
}
}