mirror of
https://github.com/jht5945/rust_util.git
synced 2025-12-27 15:40:03 +08:00
feat: v0.6.31
This commit is contained in:
@@ -19,6 +19,7 @@ pub mod util_term;
|
||||
pub mod util_git;
|
||||
#[cfg(feature = "use_clap")]
|
||||
pub mod util_clap;
|
||||
pub mod util_tlv;
|
||||
|
||||
/// iff!(condition, result_when_true, result_when_false)
|
||||
#[macro_export] macro_rules! iff {
|
||||
|
||||
158
src/util_net.rs
158
src/util_net.rs
@@ -2,9 +2,64 @@ use std::fmt::{self, Display, Formatter};
|
||||
use std::result::Result;
|
||||
use std::net::SocketAddr;
|
||||
use crate::XResult;
|
||||
use std::collections::HashSet;
|
||||
|
||||
const DEFAULT_LISTEN_ADDR: [u8; 4] = [127, 0, 0, 1];
|
||||
|
||||
pub struct IpAndIpMaskMatcher {
|
||||
min_mask_len: u8,
|
||||
ip_and_ip_mask_set: HashSet<u64>,
|
||||
}
|
||||
|
||||
impl IpAndIpMaskMatcher {
|
||||
pub fn new() -> Self {
|
||||
IpAndIpMaskMatcher {
|
||||
min_mask_len: 32,
|
||||
ip_and_ip_mask_set: HashSet::with_capacity(128),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_ip_address_mask(&mut self, ip_address: &IpAddress, mask_len: u8) -> bool {
|
||||
if mask_len > 32 {
|
||||
return false;
|
||||
}
|
||||
if mask_len < self.min_mask_len {
|
||||
self.min_mask_len = mask_len;
|
||||
}
|
||||
let mask_n_ip = Self::get_mask_n_ip(ip_address.to_u32() as u64, mask_len);
|
||||
self.ip_and_ip_mask_set.insert(mask_n_ip);
|
||||
true
|
||||
}
|
||||
|
||||
pub fn add_ip_address(&mut self, ip_address: &IpAddress) -> bool {
|
||||
self.add_ip_address_mask(ip_address, 32)
|
||||
}
|
||||
|
||||
pub fn contains_ip_address(&self, ip_address: &IpAddress) -> bool {
|
||||
self.contains_ip_address_mask(ip_address, 32)
|
||||
}
|
||||
|
||||
pub fn contains_ip_address_mask(&self, ip_address: &IpAddress, mask_len: u8) -> bool {
|
||||
if mask_len > 32 {
|
||||
return false;
|
||||
}
|
||||
let ip_addr_as_u64 = ip_address.to_u32() as u64;
|
||||
for i_mask_len in (self.min_mask_len..=mask_len).rev() {
|
||||
let mask_n_ip = Self::get_mask_n_ip(ip_addr_as_u64, i_mask_len);
|
||||
if self.ip_and_ip_mask_set.contains(&mask_n_ip) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn get_mask_n_ip(ip_addr_as_u64: u64, mask_len: u8) -> u64 {
|
||||
let mask = u64::from_be_bytes([0x00, 0x00, 0x00, mask_len, 0x00, 0x00, 0x00, 0x00]);
|
||||
let ip_mask_bits = get_ipv4_mask(mask_len);
|
||||
mask + (ip_addr_as_u64 & ip_mask_bits as u64)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq)]
|
||||
pub enum IpAddress {
|
||||
Ipv4([u8; 4]),
|
||||
@@ -21,6 +76,14 @@ impl IpAddress {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_u32(&self) -> u32 {
|
||||
match self {
|
||||
IpAddress::Ipv4(ipv4) => {
|
||||
u32::from_be_bytes(ipv4.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_matches(&self, socket_addr: &SocketAddr) -> bool {
|
||||
match self {
|
||||
IpAddress::Ipv4(self_ipv4_octets) => IpAddressMask::Ipv4(*self_ipv4_octets, 32).is_matches(socket_addr),
|
||||
@@ -60,7 +123,7 @@ impl IpAddressMask {
|
||||
match self {
|
||||
IpAddressMask::Ipv4(ipv4, mask) => {
|
||||
format!("{}/{}", ipv4.iter().map(|p| p.to_string()).collect::<Vec<_>>().join("."), mask)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +137,9 @@ impl IpAddressMask {
|
||||
let addr_ipv4_u32 = ipv4_to_u32(&socket_addr_v4_octets);
|
||||
let mask_u32 = ipv4_mask(*mask);
|
||||
self_ipv4_u32 & mask_u32 == addr_ipv4_u32 & mask_u32
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
SocketAddr::V6(_) => false,
|
||||
}
|
||||
}
|
||||
@@ -163,14 +226,16 @@ fn parse_ip_and_port(listen: &str) -> Option<([u8; 4], u16)> {
|
||||
None => DEFAULT_LISTEN_ADDR,
|
||||
Some(addr) if addr.is_empty() => DEFAULT_LISTEN_ADDR,
|
||||
Some(addr) => match parse_ipv4_addr(addr) {
|
||||
Some(parsed_ip_address) => parsed_ip_address, None => return None,
|
||||
Some(parsed_ip_address) => parsed_ip_address,
|
||||
None => return None,
|
||||
},
|
||||
};
|
||||
|
||||
let listen_port = match listen.split(':').nth(1) {
|
||||
None => return None,
|
||||
Some(port) => match port.parse::<u16>() {
|
||||
Ok(port) => port, Err(_) => return None,
|
||||
Ok(port) => port,
|
||||
Err(_) => return None,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -189,12 +254,25 @@ fn ipv4_mask(mask: u8) -> u32 {
|
||||
r
|
||||
}
|
||||
|
||||
fn ipv4_to_u32(ipv4: &[u8; 4]) -> u32 {
|
||||
u32::from_be_bytes(*ipv4)
|
||||
// ((ipv4[0] as u32) << (8 * 3)) + ((ipv4[1] as u32) << (8 * 2)) + ((ipv4[2] as u32) << 8) + (ipv4[3] as u32)
|
||||
fn get_ipv4_mask(mask_len: u8) -> u32 {
|
||||
let mut m = 0_u32;
|
||||
let ml = mask_len as usize;
|
||||
for _ in 0..ml {
|
||||
m <<= 1;
|
||||
m |= 1;
|
||||
}
|
||||
let ml_left = 32 - ml;
|
||||
for _ in 0..ml_left {
|
||||
m <<= 1;
|
||||
}
|
||||
m
|
||||
}
|
||||
|
||||
fn parse_ipv4_addr(addr: &str) -> Option<[u8; 4]> {
|
||||
fn ipv4_to_u32(ipv4: &[u8; 4]) -> u32 {
|
||||
u32::from_be_bytes(*ipv4)
|
||||
}
|
||||
|
||||
fn parse_ipv4_addr(addr: &str) -> Option<[u8; 4]> {
|
||||
let addr_parts = addr.split('.').collect::<Vec<_>>();
|
||||
if addr_parts.len() != 4 {
|
||||
return None;
|
||||
@@ -245,3 +323,65 @@ fn test_ip_address_mask_group_is_matches() {
|
||||
let addr = SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::new(10, 0, 1, 2)), 123);
|
||||
assert_eq!(false, group.is_matches(&addr));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_ipv4_mask() {
|
||||
assert_eq!([0, 0, 0, 0], get_ipv4_mask(0).to_be_bytes());
|
||||
assert_eq!([128, 0, 0, 0], get_ipv4_mask(1).to_be_bytes());
|
||||
assert_eq!([192, 0, 0, 0], get_ipv4_mask(2).to_be_bytes());
|
||||
assert_eq!([224, 0, 0, 0], get_ipv4_mask(3).to_be_bytes());
|
||||
assert_eq!([240, 0, 0, 0], get_ipv4_mask(4).to_be_bytes());
|
||||
assert_eq!([248, 0, 0, 0], get_ipv4_mask(5).to_be_bytes());
|
||||
assert_eq!([252, 0, 0, 0], get_ipv4_mask(6).to_be_bytes());
|
||||
assert_eq!([254, 0, 0, 0], get_ipv4_mask(7).to_be_bytes());
|
||||
assert_eq!([255, 0, 0, 0], get_ipv4_mask(8).to_be_bytes());
|
||||
assert_eq!([255, 128, 0, 0], get_ipv4_mask(9).to_be_bytes());
|
||||
assert_eq!([255, 192, 0, 0], get_ipv4_mask(10).to_be_bytes());
|
||||
assert_eq!([255, 224, 0, 0], get_ipv4_mask(11).to_be_bytes());
|
||||
assert_eq!([255, 240, 0, 0], get_ipv4_mask(12).to_be_bytes());
|
||||
assert_eq!([255, 248, 0, 0], get_ipv4_mask(13).to_be_bytes());
|
||||
assert_eq!([255, 252, 0, 0], get_ipv4_mask(14).to_be_bytes());
|
||||
assert_eq!([255, 254, 0, 0], get_ipv4_mask(15).to_be_bytes());
|
||||
assert_eq!([255, 255, 255, 254], get_ipv4_mask(31).to_be_bytes());
|
||||
assert_eq!([255, 255, 255, 255], get_ipv4_mask(32).to_be_bytes());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ip_and_ip_mask_matcher() {
|
||||
{
|
||||
let mut matcher = IpAndIpMaskMatcher::new();
|
||||
matcher.add_ip_address(&IpAddress::Ipv4([127, 0, 0, 1]));
|
||||
assert!(matcher.contains_ip_address(&IpAddress::Ipv4([127, 0, 0, 1])));
|
||||
assert!(!matcher.contains_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 31));
|
||||
}
|
||||
{
|
||||
let mut matcher = IpAndIpMaskMatcher::new();
|
||||
matcher.add_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 24);
|
||||
assert!(matcher.contains_ip_address(&IpAddress::Ipv4([127, 0, 0, 1])));
|
||||
assert!(matcher.contains_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 31));
|
||||
assert!(matcher.contains_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 30));
|
||||
assert!(matcher.contains_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 24));
|
||||
assert!(!matcher.contains_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 23));
|
||||
}
|
||||
{
|
||||
let mut matcher = IpAndIpMaskMatcher::new();
|
||||
matcher.add_ip_address_mask(&IpAddress::Ipv4([0, 0, 0, 0]), 0);
|
||||
assert!(matcher.contains_ip_address(&IpAddress::Ipv4([127, 0, 0, 1])));
|
||||
assert!(matcher.contains_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 31));
|
||||
assert!(matcher.contains_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 30));
|
||||
assert!(matcher.contains_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 24));
|
||||
assert!(matcher.contains_ip_address_mask(&IpAddress::Ipv4([127, 0, 0, 0]), 23));
|
||||
}
|
||||
{
|
||||
let mut matcher = IpAndIpMaskMatcher::new();
|
||||
matcher.add_ip_address_mask(&IpAddress::Ipv4([192, 168, 1, 2]), 32);
|
||||
assert!(matcher.contains_ip_address(&IpAddress::Ipv4([192, 168, 1, 2])));
|
||||
assert!(!matcher.contains_ip_address_mask(&IpAddress::Ipv4([192, 168, 1, 2]), 31));
|
||||
}
|
||||
{
|
||||
let mut matcher = IpAndIpMaskMatcher::new();
|
||||
matcher.add_ip_address_mask(&IpAddress::Ipv4([192, 168, 1, 2]), 16);
|
||||
assert!(matcher.contains_ip_address(&IpAddress::Ipv4([192, 168, 1, 2])));
|
||||
assert!(matcher.contains_ip_address_mask(&IpAddress::Ipv4([192, 168, 1, 2]), 31));
|
||||
}
|
||||
}
|
||||
|
||||
92
src/util_tlv.rs
Normal file
92
src/util_tlv.rs
Normal file
@@ -0,0 +1,92 @@
|
||||
use std::io::{Write, Read};
|
||||
use crate::XResult;
|
||||
|
||||
pub struct Tlv {
|
||||
pub r#type: u16,
|
||||
pub length: u32,
|
||||
pub value: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Tlv {
|
||||
pub fn new_empty(ty: u16) -> Self {
|
||||
Self {
|
||||
r#type: ty,
|
||||
length: 0,
|
||||
value: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(ty: u16, value: Vec<u8>) -> Self {
|
||||
assert!(value.len() < u32::MAX as usize, "Value too huge");
|
||||
Self {
|
||||
r#type: ty,
|
||||
length: value.len() as u32,
|
||||
value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compose(&self) -> Vec<u8> {
|
||||
let cap = self.value.len() + 4 + 2;
|
||||
let mut v = Vec::with_capacity(cap);
|
||||
v.extend_from_slice(&self.r#type.to_be_bytes());
|
||||
v.extend_from_slice(&self.length.to_be_bytes());
|
||||
v.extend_from_slice(self.value.as_slice());
|
||||
v
|
||||
}
|
||||
|
||||
pub fn write<T>(&self, mut w: T) -> XResult<usize> where T: Write {
|
||||
let mut len = w.write(&self.r#type.to_be_bytes())?;
|
||||
len += w.write(&self.length.to_be_bytes())?;
|
||||
len += w.write(self.value.as_slice())?;
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
pub fn read<T>(mut r: T) -> XResult<Self> where T: Read {
|
||||
let mut r#type = [0_u8; 2];
|
||||
r.read_exact(&mut r#type)?;
|
||||
let mut length = [0_u8; 4];
|
||||
r.read_exact(&mut length)?;
|
||||
let len = u32::from_be_bytes(length);
|
||||
let mut value = vec![0_u8; len as usize];
|
||||
r.read_exact(&mut value)?;
|
||||
Ok(Self {
|
||||
r#type: u16::from_be_bytes(r#type),
|
||||
length: len,
|
||||
value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tlv() {
|
||||
{
|
||||
let tlv = Tlv::new_empty(0);
|
||||
assert_eq!([0, 0, 0, 0, 0, 0], tlv.compose().as_slice());
|
||||
}
|
||||
{
|
||||
let tlv = Tlv::new_empty(1);
|
||||
assert_eq!([0, 1, 0, 0, 0, 0], tlv.compose().as_slice());
|
||||
}
|
||||
{
|
||||
let tlv = Tlv::new_empty(256);
|
||||
assert_eq!([1, 0, 0, 0, 0, 0], tlv.compose().as_slice());
|
||||
}
|
||||
{
|
||||
let tlv = Tlv::new(1, vec![0]);
|
||||
assert_eq!([0, 1, 0, 0, 0, 1, 0], tlv.compose().as_slice());
|
||||
}
|
||||
{
|
||||
let tlv = Tlv::new(2, vec![1, 2]);
|
||||
assert_eq!([0, 2, 0, 0, 0, 2, 1, 2], tlv.compose().as_slice());
|
||||
}
|
||||
{
|
||||
let tlv = Tlv::new(2, vec![1, 2]);
|
||||
let bs = tlv.compose().clone();
|
||||
let tlv2 = Tlv::read(bs.as_slice()).unwrap();
|
||||
assert_eq!(bs, tlv2.compose());
|
||||
assert_eq!(2, tlv2.r#type);
|
||||
assert_eq!(2, tlv2.length);
|
||||
assert_eq!([1, 2], tlv2.value.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user