From 1da26de01c6889facdc54025b50d1988bc4a04fa Mon Sep 17 00:00:00 2001 From: DaLaw2 Date: Thu, 12 Dec 2024 15:00:22 +0800 Subject: [PATCH] Simplify access_list and delete duplicate APIs --- net-guardia/src/core/control/access_list.rs | 756 ++++-------------- net-guardia/src/model/direction.rs | 8 + net-guardia/src/model/ip_address.rs | 33 + net-guardia/src/model/list_type.rs | 10 + net-guardia/src/model/mod.rs | 3 + .../src/web/api/control/access_list.rs | 202 +---- 6 files changed, 236 insertions(+), 776 deletions(-) create mode 100644 net-guardia/src/model/direction.rs create mode 100644 net-guardia/src/model/ip_address.rs create mode 100644 net-guardia/src/model/list_type.rs diff --git a/net-guardia/src/core/control/access_list.rs b/net-guardia/src/core/control/access_list.rs index d0602a6..e3b2733 100644 --- a/net-guardia/src/core/control/access_list.rs +++ b/net-guardia/src/core/control/access_list.rs @@ -1,8 +1,12 @@ use crate::core::system::System; +use crate::model::direction::Direction; +use crate::model::ip_address::IpAddressType; +use crate::model::list_type::ListType; use crate::utils::ip_address::convert_ports_to_vec; use crate::utils::log_entry::ebpf::EbpfEntry; use crate::utils::log_entry::system::SystemEntry; use aya::maps::{HashMap as AyaHashMap, MapData}; +use aya::Pod; use net_guardia_common::model::ip_address::{IPv4, IPv6, Port}; use net_guardia_common::MAX_RULES_PORT; use std::collections::HashMap as StdHashMap; @@ -14,48 +18,56 @@ use tracing::info; static ACCESS_LIST: OnceLock> = OnceLock::new(); pub struct AccessList { - ipv4_src_white_list: AyaHashMap, - ipv6_src_white_list: AyaHashMap, - ipv4_dst_white_list: AyaHashMap, - ipv6_dst_white_list: AyaHashMap, - ipv4_src_black_list: AyaHashMap, - ipv6_src_black_list: AyaHashMap, - ipv4_dst_black_list: AyaHashMap, - ipv6_dst_black_list: AyaHashMap, + ipv4_maps: StdHashMap<(Direction, ListType), AccessMap>, + ipv6_maps: StdHashMap<(Direction, ListType), AccessMap>, } impl AccessList { + const MAP_CONFIGS: [((Direction, ListType), (&'static str, &'static str)); 4] = [ + ( + (Direction::Source, ListType::White), + ("IPV4_SRC_WHITELIST", "IPV6_SRC_WHITELIST"), + ), + ( + (Direction::Source, ListType::Black), + ("IPV4_SRC_BLACKLIST", "IPV6_SRC_BLACKLIST"), + ), + ( + (Direction::Destination, ListType::White), + ("IPV4_DST_WHITELIST", "IPV6_DST_WHITELIST"), + ), + ( + (Direction::Destination, ListType::Black), + ("IPV4_DST_BLACKLIST", "IPV6_DST_BLACKLIST"), + ), + ]; + pub async fn initialize() -> anyhow::Result<()> { info!("{}", SystemEntry::Initializing); let mut system = System::instance_mut().await; let ebpf = &mut system.ebpf; - let access_list = AccessList { - ipv4_src_white_list: AyaHashMap::try_from( - ebpf.take_map("IPV4_SRC_WHITELIST").unwrap(), - )?, - ipv6_src_white_list: AyaHashMap::try_from( - ebpf.take_map("IPV6_SRC_WHITELIST").unwrap(), - )?, - ipv4_dst_white_list: AyaHashMap::try_from( - ebpf.take_map("IPV4_DST_WHITELIST").unwrap(), - )?, - ipv6_dst_white_list: AyaHashMap::try_from( - ebpf.take_map("IPV6_DST_WHITELIST").unwrap(), - )?, - ipv4_src_black_list: AyaHashMap::try_from( - ebpf.take_map("IPV4_SRC_BLACKLIST").unwrap(), - )?, - ipv6_src_black_list: AyaHashMap::try_from( - ebpf.take_map("IPV6_SRC_BLACKLIST").unwrap(), - )?, - ipv4_dst_black_list: AyaHashMap::try_from( - ebpf.take_map("IPV4_DST_BLACKLIST").unwrap(), - )?, - ipv6_dst_black_list: AyaHashMap::try_from( - ebpf.take_map("IPV6_DST_BLACKLIST").unwrap(), - )?, - }; - ACCESS_LIST.get_or_init(|| RwLock::new(access_list)); + let mut ipv4_maps = StdHashMap::new(); + let mut ipv6_maps = StdHashMap::new(); + for (key, (ipv4_name, ipv6_name)) in Self::MAP_CONFIGS { + ipv4_maps.insert( + key, + AccessMap { + map: AyaHashMap::try_from(ebpf.take_map(ipv4_name).unwrap())?, + }, + ); + ipv6_maps.insert( + key, + AccessMap { + map: AyaHashMap::try_from(ebpf.take_map(ipv6_name).unwrap())?, + }, + ); + } + ACCESS_LIST.get_or_init(|| { + RwLock::new(AccessList { + ipv4_maps, + ipv6_maps, + }) + }); info!("{}", SystemEntry::InitializeComplete); Ok(()) } @@ -72,34 +84,109 @@ impl AccessList { once_lock.write().await } - pub async fn get_ipv4_src_white_list() -> StdHashMap> { + pub async fn get_ipv4_list( + direction: Direction, + list_type: ListType, + ) -> StdHashMap> { let access_list = AccessList::instance().await; access_list - .ipv4_src_white_list - .iter() - .filter_map(Result::ok) - .map(|(key, value)| (Ipv4Addr::from(key), convert_ports_to_vec(value))) - .collect() + .ipv4_maps + .get(&(direction, list_type)) + .map(|map| map.get_list()) + .unwrap() } - pub async fn get_ipv6_src_white_list() -> StdHashMap> { + pub async fn get_ipv6_list( + direction: Direction, + list_type: ListType, + ) -> StdHashMap> { let access_list = AccessList::instance().await; access_list - .ipv6_src_white_list - .iter() - .filter_map(Result::ok) - .map(|(key, value)| (Ipv6Addr::from(key), convert_ports_to_vec(value))) - .collect() + .ipv6_maps + .get(&(direction, list_type)) + .map(|map| map.get_list()) + .unwrap() } - pub async fn add_ipv4_src_white_list(address: SocketAddrV4) -> anyhow::Result<()> { + pub async fn add_ipv4_list( + direction: Direction, + list_type: ListType, + address: SocketAddrV4, + ) -> anyhow::Result<()> { let ip: u32 = (*address.ip()).into(); let port = address.port(); let mut access_list = AccessList::instance_mut().await; + let map = access_list + .ipv4_maps + .get_mut(&(direction, list_type)) + .unwrap(); + map.add(ip, port) + } + + pub async fn add_ipv6_list( + direction: Direction, + list_type: ListType, + address: SocketAddrV6, + ) -> anyhow::Result<()> { + let ip: u128 = (*address.ip()).into(); + let port = address.port(); + let mut access_list = AccessList::instance_mut().await; + let map = access_list + .ipv6_maps + .get_mut(&(direction, list_type)) + .unwrap(); + map.add(ip, port) + } + + pub async fn remove_ipv4_list( + direction: Direction, + list_type: ListType, + address: SocketAddrV4, + ) -> anyhow::Result<()> { + let ip: u32 = (*address.ip()).into(); + let port = address.port(); + let mut access_list = AccessList::instance_mut().await; + let map = access_list + .ipv4_maps + .get_mut(&(direction, list_type)) + .unwrap(); + map.remove(ip, port) + } + + pub async fn remove_ipv6_list( + direction: Direction, + list_type: ListType, + address: SocketAddrV6, + ) -> anyhow::Result<()> { + let ip: u128 = (*address.ip()).into(); + let port = address.port(); + let mut access_list = AccessList::instance_mut().await; + let map = access_list + .ipv6_maps + .get_mut(&(direction, list_type)) + .unwrap(); + map.remove(ip, port) + } +} + +struct AccessMap { + map: AyaHashMap, +} + +impl AccessMap { + fn get_list(&self) -> StdHashMap> { + self.map + .iter() + .filter_map(Result::ok) + .map(|(key, value)| (key.into_native(), convert_ports_to_vec(value))) + .collect() + } + + fn add(&mut self, ip: T, port: Port) -> anyhow::Result<()> { let mut new_ports = [0_u16; MAX_RULES_PORT]; if port == 0 { new_ports[0] = 0; - } else if let Ok(ports) = access_list.ipv4_src_white_list.get(&ip, 0) { + } else if let Ok(ports) = self.map.get(&ip, 0) { if ports[0] == 0 { return Ok(()); } @@ -120,588 +207,33 @@ impl AccessList { } else { new_ports[0] = port; } - access_list - .ipv4_src_white_list + self.map .insert(ip, new_ports, 0) .map_err(|_| EbpfEntry::MapOperationError)?; Ok(()) } - pub async fn add_ipv6_src_white_list(address: SocketAddrV6) -> anyhow::Result<()> { - let ip: u128 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - let mut new_ports = [0_u16; MAX_RULES_PORT]; - if port == 0 { - new_ports[0] = 0; - } else if let Ok(ports) = access_list.ipv6_src_white_list.get(&ip, 0) { - if ports[0] == 0 { - return Ok(()); - } - let mut index = None; - for (i, &value) in ports.iter().enumerate() { - if value == port { - return Ok(()); - } - if index.is_none() && value == 0 { - index = Some(i); - } - } - if index.is_none() { - return Err(EbpfEntry::RuleReachLimit.into()); - } - new_ports.copy_from_slice(&ports); - new_ports[index.unwrap()] = port; - } else { - new_ports[0] = port; - } - access_list - .ipv6_src_white_list - .insert(ip, new_ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - Ok(()) - } - - pub async fn remove_ipv4_src_white_list(address: SocketAddrV4) -> anyhow::Result<()> { - let ip: u32 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - if let Ok(mut ports) = access_list.ipv4_src_white_list.get(&ip, 0) { + fn remove(&mut self, ip: T, port: Port) -> anyhow::Result<()> { + if let Ok(mut ports) = self.map.get(&ip, 0) { if port == 0 { - access_list - .ipv4_src_white_list + self.map .remove(&ip) .map_err(|_| EbpfEntry::MapOperationError)?; return Ok(()); } + if let Some(index) = ports.iter().position(|&x| x == port) { for i in index..(MAX_RULES_PORT - 1) { ports[i] = ports[i + 1]; } ports[MAX_RULES_PORT - 1] = 0; + if ports[0] == 0 { - access_list - .ipv4_src_white_list + self.map .remove(&ip) .map_err(|_| EbpfEntry::MapOperationError)?; } else { - access_list - .ipv4_src_white_list - .insert(ip, ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - } - } - Ok(()) - } else { - Err(EbpfEntry::IpDoesNotExist)? - } - } - - pub async fn remove_ipv6_src_white_list(address: SocketAddrV6) -> anyhow::Result<()> { - let ip: u128 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - if let Ok(mut ports) = access_list.ipv6_src_white_list.get(&ip, 0) { - if port == 0 { - access_list - .ipv6_src_white_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - return Ok(()); - } - if let Some(index) = ports.iter().position(|&x| x == port) { - for i in index..(MAX_RULES_PORT - 1) { - ports[i] = ports[i + 1]; - } - ports[MAX_RULES_PORT - 1] = 0; - if ports[0] == 0 { - access_list - .ipv6_src_white_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - } else { - access_list - .ipv6_src_white_list - .insert(ip, ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - } - } - Ok(()) - } else { - Err(EbpfEntry::IpDoesNotExist)? - } - } - - pub async fn get_ipv4_dst_white_list() -> StdHashMap> { - let access_list = AccessList::instance().await; - access_list - .ipv4_dst_white_list - .iter() - .filter_map(Result::ok) - .map(|(key, value)| (Ipv4Addr::from(key), convert_ports_to_vec(value))) - .collect() - } - - pub async fn get_ipv6_dst_white_list() -> StdHashMap> { - let access_list = AccessList::instance().await; - access_list - .ipv6_dst_white_list - .iter() - .filter_map(Result::ok) - .map(|(key, value)| (Ipv6Addr::from(key), convert_ports_to_vec(value))) - .collect() - } - - pub async fn add_ipv4_dst_white_list(address: SocketAddrV4) -> anyhow::Result<()> { - let ip: u32 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - let mut new_ports = [0_u16; MAX_RULES_PORT]; - if port == 0 { - new_ports[0] = 0; - } else if let Ok(ports) = access_list.ipv4_dst_white_list.get(&ip, 0) { - if ports[0] == 0 { - return Ok(()); - } - let mut index = None; - for (i, &value) in ports.iter().enumerate() { - if value == port { - return Ok(()); - } - if index.is_none() && value == 0 { - index = Some(i); - } - } - if index.is_none() { - return Err(EbpfEntry::RuleReachLimit.into()); - } - new_ports.copy_from_slice(&ports); - new_ports[index.unwrap()] = port; - } else { - new_ports[0] = port; - } - access_list - .ipv4_dst_white_list - .insert(ip, new_ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - Ok(()) - } - - pub async fn add_ipv6_dst_white_list(address: SocketAddrV6) -> anyhow::Result<()> { - let ip: u128 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - let mut new_ports = [0_u16; MAX_RULES_PORT]; - if port == 0 { - new_ports[0] = 0; - } else if let Ok(ports) = access_list.ipv6_dst_white_list.get(&ip, 0) { - if ports[0] == 0 { - return Ok(()); - } - let mut index = None; - for (i, &value) in ports.iter().enumerate() { - if value == port { - return Ok(()); - } - if index.is_none() && value == 0 { - index = Some(i); - } - } - if index.is_none() { - return Err(EbpfEntry::RuleReachLimit.into()); - } - new_ports.copy_from_slice(&ports); - new_ports[index.unwrap()] = port; - } else { - new_ports[0] = port; - } - access_list - .ipv6_dst_white_list - .insert(ip, new_ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - Ok(()) - } - - pub async fn remove_ipv4_dst_white_list(address: SocketAddrV4) -> anyhow::Result<()> { - let ip: u32 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - if let Ok(mut ports) = access_list.ipv4_dst_white_list.get(&ip, 0) { - if port == 0 { - access_list - .ipv4_dst_white_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - return Ok(()); - } - if let Some(index) = ports.iter().position(|&x| x == port) { - for i in index..(MAX_RULES_PORT - 1) { - ports[i] = ports[i + 1]; - } - ports[MAX_RULES_PORT - 1] = 0; - if ports[0] == 0 { - access_list - .ipv4_dst_white_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - } else { - access_list - .ipv4_dst_white_list - .insert(ip, ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - } - } - Ok(()) - } else { - Err(EbpfEntry::IpDoesNotExist)? - } - } - - pub async fn remove_ipv6_dst_white_list(address: SocketAddrV6) -> anyhow::Result<()> { - let ip: u128 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - if let Ok(mut ports) = access_list.ipv6_dst_white_list.get(&ip, 0) { - if port == 0 { - access_list - .ipv6_dst_white_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - return Ok(()); - } - if let Some(index) = ports.iter().position(|&x| x == port) { - for i in index..(MAX_RULES_PORT - 1) { - ports[i] = ports[i + 1]; - } - ports[MAX_RULES_PORT - 1] = 0; - if ports[0] == 0 { - access_list - .ipv6_dst_white_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - } else { - access_list - .ipv6_dst_white_list - .insert(ip, ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - } - } - Ok(()) - } else { - Err(EbpfEntry::IpDoesNotExist)? - } - } - - pub async fn get_ipv4_src_black_list() -> StdHashMap> { - let access_list = AccessList::instance().await; - access_list - .ipv4_src_black_list - .iter() - .filter_map(Result::ok) - .map(|(key, value)| (Ipv4Addr::from(key), convert_ports_to_vec(value))) - .collect() - } - - pub async fn get_ipv6_src_black_list() -> StdHashMap> { - let access_list = AccessList::instance().await; - access_list - .ipv6_src_black_list - .iter() - .filter_map(Result::ok) - .map(|(key, value)| (Ipv6Addr::from(key), convert_ports_to_vec(value))) - .collect() - } - - pub async fn add_ipv4_src_black_list(address: SocketAddrV4) -> anyhow::Result<()> { - let ip: u32 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - let mut new_ports = [0_u16; MAX_RULES_PORT]; - if port == 0 { - new_ports[0] = 0; - } else if let Ok(ports) = access_list.ipv4_src_black_list.get(&ip, 0) { - if ports[0] == 0 { - return Ok(()); - } - let mut index = None; - for (i, &value) in ports.iter().enumerate() { - if value == port { - return Ok(()); - } - if index.is_none() && value == 0 { - index = Some(i); - } - } - if index.is_none() { - return Err(EbpfEntry::RuleReachLimit.into()); - } - new_ports.copy_from_slice(&ports); - new_ports[index.unwrap()] = port; - } else { - new_ports[0] = port; - } - access_list - .ipv4_src_black_list - .insert(ip, new_ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - Ok(()) - } - - pub async fn add_ipv6_src_black_list(address: SocketAddrV6) -> anyhow::Result<()> { - let ip: u128 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - let mut new_ports = [0_u16; MAX_RULES_PORT]; - if port == 0 { - new_ports[0] = 0; - } else if let Ok(ports) = access_list.ipv6_src_black_list.get(&ip, 0) { - if ports[0] == 0 { - return Ok(()); - } - let mut index = None; - for (i, &value) in ports.iter().enumerate() { - if value == port { - return Ok(()); - } - if index.is_none() && value == 0 { - index = Some(i); - } - } - if index.is_none() { - return Err(EbpfEntry::RuleReachLimit.into()); - } - new_ports.copy_from_slice(&ports); - new_ports[index.unwrap()] = port; - } else { - new_ports[0] = port; - } - access_list - .ipv6_src_black_list - .insert(ip, new_ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - Ok(()) - } - - pub async fn remove_ipv4_src_black_list(address: SocketAddrV4) -> anyhow::Result<()> { - let ip: u32 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - if let Ok(mut ports) = access_list.ipv4_src_black_list.get(&ip, 0) { - if port == 0 { - access_list - .ipv4_src_black_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - return Ok(()); - } - if let Some(index) = ports.iter().position(|&x| x == port) { - for i in index..(MAX_RULES_PORT - 1) { - ports[i] = ports[i + 1]; - } - ports[MAX_RULES_PORT - 1] = 0; - if ports[0] == 0 { - access_list - .ipv4_src_black_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - } else { - access_list - .ipv4_src_black_list - .insert(ip, ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - } - } - Ok(()) - } else { - Err(EbpfEntry::IpDoesNotExist)? - } - } - - pub async fn remove_ipv6_src_black_list(address: SocketAddrV6) -> anyhow::Result<()> { - let ip: u128 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - if let Ok(mut ports) = access_list.ipv6_src_black_list.get(&ip, 0) { - if port == 0 { - access_list - .ipv6_src_black_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - return Ok(()); - } - if let Some(index) = ports.iter().position(|&x| x == port) { - for i in index..(MAX_RULES_PORT - 1) { - ports[i] = ports[i + 1]; - } - ports[MAX_RULES_PORT - 1] = 0; - if ports[0] == 0 { - access_list - .ipv6_src_black_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - } else { - access_list - .ipv6_src_black_list - .insert(ip, ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - } - } - Ok(()) - } else { - Err(EbpfEntry::IpDoesNotExist)? - } - } - - pub async fn get_ipv4_dst_black_list() -> StdHashMap> { - let access_list = AccessList::instance().await; - access_list - .ipv4_dst_black_list - .iter() - .filter_map(Result::ok) - .map(|(key, value)| (Ipv4Addr::from(key), convert_ports_to_vec(value))) - .collect() - } - - pub async fn get_ipv6_dst_black_list() -> StdHashMap> { - let access_list = AccessList::instance().await; - access_list - .ipv6_dst_black_list - .iter() - .filter_map(Result::ok) - .map(|(key, value)| (Ipv6Addr::from(key), convert_ports_to_vec(value))) - .collect() - } - - pub async fn add_ipv4_dst_black_list(address: SocketAddrV4) -> anyhow::Result<()> { - let ip: u32 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - let mut new_ports = [0_u16; MAX_RULES_PORT]; - if port == 0 { - new_ports[0] = 0; - } else if let Ok(ports) = access_list.ipv4_dst_black_list.get(&ip, 0) { - if ports[0] == 0 { - return Ok(()); - } - let mut index = None; - for (i, &value) in ports.iter().enumerate() { - if value == port { - return Ok(()); - } - if index.is_none() && value == 0 { - index = Some(i); - } - } - if index.is_none() { - return Err(EbpfEntry::RuleReachLimit.into()); - } - new_ports.copy_from_slice(&ports); - new_ports[index.unwrap()] = port; - } else { - new_ports[0] = port; - } - access_list - .ipv4_dst_black_list - .insert(ip, new_ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - Ok(()) - } - - pub async fn add_ipv6_dst_black_list(address: SocketAddrV6) -> anyhow::Result<()> { - let ip: u128 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - let mut new_ports = [0_u16; MAX_RULES_PORT]; - if port == 0 { - new_ports[0] = 0; - } else if let Ok(ports) = access_list.ipv6_dst_black_list.get(&ip, 0) { - if ports[0] == 0 { - return Ok(()); - } - let mut index = None; - for (i, &value) in ports.iter().enumerate() { - if value == port { - return Ok(()); - } - if index.is_none() && value == 0 { - index = Some(i); - } - } - if index.is_none() { - return Err(EbpfEntry::RuleReachLimit.into()); - } - new_ports.copy_from_slice(&ports); - new_ports[index.unwrap()] = port; - } else { - new_ports[0] = port; - } - access_list - .ipv6_dst_black_list - .insert(ip, new_ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - Ok(()) - } - - pub async fn remove_ipv4_dst_black_list(address: SocketAddrV4) -> anyhow::Result<()> { - let ip: u32 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - if let Ok(mut ports) = access_list.ipv4_dst_black_list.get(&ip, 0) { - if port == 0 { - access_list - .ipv4_dst_black_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - return Ok(()); - } - if let Some(index) = ports.iter().position(|&x| x == port) { - for i in index..(MAX_RULES_PORT - 1) { - ports[i] = ports[i + 1]; - } - ports[MAX_RULES_PORT - 1] = 0; - if ports[0] == 0 { - access_list - .ipv4_dst_black_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - } else { - access_list - .ipv4_dst_black_list - .insert(ip, ports, 0) - .map_err(|_| EbpfEntry::MapOperationError)?; - } - } - Ok(()) - } else { - Err(EbpfEntry::IpDoesNotExist)? - } - } - - pub async fn remove_ipv6_dst_black_list(address: SocketAddrV6) -> anyhow::Result<()> { - let ip: u128 = (*address.ip()).into(); - let port = address.port(); - let mut access_list = AccessList::instance_mut().await; - if let Ok(mut ports) = access_list.ipv6_dst_black_list.get(&ip, 0) { - if port == 0 { - access_list - .ipv6_dst_black_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - return Ok(()); - } - if let Some(index) = ports.iter().position(|&x| x == port) { - for i in index..(MAX_RULES_PORT - 1) { - ports[i] = ports[i + 1]; - } - ports[MAX_RULES_PORT - 1] = 0; - if ports[0] == 0 { - access_list - .ipv6_dst_black_list - .remove(&ip) - .map_err(|_| EbpfEntry::MapOperationError)?; - } else { - access_list - .ipv6_dst_black_list + self.map .insert(ip, ports, 0) .map_err(|_| EbpfEntry::MapOperationError)?; } diff --git a/net-guardia/src/model/direction.rs b/net-guardia/src/model/direction.rs new file mode 100644 index 0000000..03ca084 --- /dev/null +++ b/net-guardia/src/model/direction.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash)] +#[serde(rename_all = "lowercase")] +pub enum Direction { + Source, + Destination, +} diff --git a/net-guardia/src/model/ip_address.rs b/net-guardia/src/model/ip_address.rs new file mode 100644 index 0000000..aa309b9 --- /dev/null +++ b/net-guardia/src/model/ip_address.rs @@ -0,0 +1,33 @@ +use net_guardia_common::model::ip_address::{IPv4, IPv6}; +use std::hash::Hash; +use std::net::{Ipv4Addr, Ipv6Addr}; + +pub trait IpAddressType: Copy { + type Native: Eq + PartialEq + Hash; + fn into_native(self) -> Self::Native; + fn from_native(native: Self::Native) -> Self; +} + +impl IpAddressType for IPv4 { + type Native = Ipv4Addr; + + fn into_native(self) -> Self::Native { + Ipv4Addr::from(self) + } + + fn from_native(native: Self::Native) -> Self { + native.into() + } +} + +impl IpAddressType for IPv6 { + type Native = Ipv6Addr; + + fn into_native(self) -> Self::Native { + Ipv6Addr::from(self) + } + + fn from_native(native: Self::Native) -> Self { + native.into() + } +} diff --git a/net-guardia/src/model/list_type.rs b/net-guardia/src/model/list_type.rs new file mode 100644 index 0000000..310eb54 --- /dev/null +++ b/net-guardia/src/model/list_type.rs @@ -0,0 +1,10 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash)] +#[serde(rename_all = "lowercase")] +pub enum ListType { + #[serde(rename = "white_list")] + White, + #[serde(rename = "black_list")] + Black, +} diff --git a/net-guardia/src/model/mod.rs b/net-guardia/src/model/mod.rs index 8d5e085..76472d6 100644 --- a/net-guardia/src/model/mod.rs +++ b/net-guardia/src/model/mod.rs @@ -1,4 +1,7 @@ pub mod config; +pub mod direction; pub mod flow_stats; pub mod flow_type; pub mod http_method; +pub mod ip_address; +pub mod list_type; diff --git a/net-guardia/src/web/api/control/access_list.rs b/net-guardia/src/web/api/control/access_list.rs index 28a8cba..53d00f0 100644 --- a/net-guardia/src/web/api/control/access_list.rs +++ b/net-guardia/src/web/api/control/access_list.rs @@ -1,194 +1,68 @@ use crate::core::control::access_list::AccessList; +use crate::model::direction::Direction; +use crate::model::list_type::ListType; use actix_web::{delete, get, put, web, HttpResponse, Responder, Scope}; use std::net::{SocketAddrV4, SocketAddrV6}; pub fn initialize() -> Scope { web::scope("/access_list") - .service(get_ipv4_src_white_list) - .service(get_ipv6_src_white_list) - .service(add_ipv4_src_white_list) - .service(add_ipv6_src_white_list) - .service(remove_ipv4_src_white_list) - .service(remove_ipv6_src_white_list) - .service(get_ipv4_src_black_list) - .service(get_ipv6_src_black_list) - .service(add_ipv4_src_black_list) - .service(add_ipv6_src_black_list) - .service(remove_ipv4_src_black_list) - .service(remove_ipv6_src_black_list) + .service(get_ipv4_list) + .service(get_ipv6_list) + .service(add_ipv4_list) + .service(add_ipv6_list) + .service(remove_ipv4_list) + .service(remove_ipv6_list) } -#[get("/ipv4/src_white_list")] -async fn get_ipv4_src_white_list() -> impl Responder { - let list = AccessList::get_ipv4_src_white_list().await; - HttpResponse::Ok().json(web::Json(list)) +#[get("/ipv4/{direction}/{list_type}")] +async fn get_ipv4_list(path: web::Path<(Direction, ListType)>) -> impl Responder { + let (direction, list_type) = path.into_inner(); + let list = AccessList::get_ipv4_list(direction, list_type).await; + HttpResponse::Ok().json(list) } -#[get("/ipv6/src_white_list")] -async fn get_ipv6_src_white_list() -> impl Responder { - let list = AccessList::get_ipv6_src_white_list().await; - HttpResponse::Ok().json(web::Json(list)) +#[get("/ipv6/{direction}/{list_type}")] +async fn get_ipv6_list(path: web::Path<(Direction, ListType)>) -> impl Responder { + let (direction, list_type) = path.into_inner(); + let list = AccessList::get_ipv6_list(direction, list_type).await; + HttpResponse::Ok().json(list) } -#[put("/ipv4/src_white_list")] -async fn add_ipv4_src_white_list(ip_addr: web::Json) -> impl Responder { - match AccessList::add_ipv4_src_white_list(ip_addr.into_inner()).await { +#[put("/ipv4/{direction}/{list_type}")] +async fn add_ipv4_list(address: web::Json, path: web::Path<(Direction, ListType)>) -> impl Responder { + let address = address.into_inner(); + let (direction, list_type) = path.into_inner(); + match AccessList::add_ipv4_list(direction, list_type, address).await { Ok(_) => HttpResponse::Ok().finish(), Err(e) => HttpResponse::InternalServerError().body(e.to_string()), } } -#[put("/ipv6/src_white_list")] -async fn add_ipv6_src_white_list(ip_addr: web::Json) -> impl Responder { - match AccessList::add_ipv6_src_white_list(ip_addr.into_inner()).await { +#[put("/ipv6/{direction}/{list_type}")] +async fn add_ipv6_list(address: web::Json, path: web::Path<(Direction, ListType)>) -> impl Responder { + let address = address.into_inner(); + let (direction, list_type) = path.into_inner(); + match AccessList::add_ipv6_list(direction, list_type, address).await { Ok(_) => HttpResponse::Ok().finish(), Err(e) => HttpResponse::InternalServerError().body(e.to_string()), } } -#[delete("/ipv4/src_white_list")] -async fn remove_ipv4_src_white_list(ip_addr: web::Json) -> impl Responder { - match AccessList::remove_ipv4_src_white_list(ip_addr.into_inner()).await { +#[delete("/ipv4/{direction}/{list_type}")] +async fn remove_ipv4_list(address: web::Json, path: web::Path<(Direction, ListType)>) -> impl Responder { + let address = address.into_inner(); + let (direction, list_type) = path.into_inner(); + match AccessList::remove_ipv4_list(direction, list_type, address).await { Ok(_) => HttpResponse::Ok().finish(), Err(e) => HttpResponse::InternalServerError().body(e.to_string()), } } -#[delete("/ipv6/src_white_list")] -async fn remove_ipv6_src_white_list(ip_addr: web::Json) -> impl Responder { - match AccessList::remove_ipv6_src_white_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[get("/ipv4/dst_white_list")] -async fn get_ipv4_dst_white_list() -> impl Responder { - let list = AccessList::get_ipv4_dst_white_list().await; - HttpResponse::Ok().json(web::Json(list)) -} - -#[get("/ipv6/dst_white_list")] -async fn get_ipv6_dst_white_list() -> impl Responder { - let list = AccessList::get_ipv6_dst_white_list().await; - HttpResponse::Ok().json(web::Json(list)) -} - -#[put("/ipv4/dst_white_list")] -async fn add_ipv4_dst_white_list(ip_addr: web::Json) -> impl Responder { - match AccessList::add_ipv4_dst_white_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[put("/ipv6/dst_white_list")] -async fn add_ipv6_dst_white_list(ip_addr: web::Json) -> impl Responder { - match AccessList::add_ipv6_dst_white_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[delete("/ipv4/dst_white_list")] -async fn remove_ipv4_dst_white_list(ip_addr: web::Json) -> impl Responder { - match AccessList::remove_ipv4_dst_white_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[delete("/ipv6/dst_white_list")] -async fn remove_ipv6_dst_white_list(ip_addr: web::Json) -> impl Responder { - match AccessList::remove_ipv6_dst_white_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[get("/ipv4/src_black_list")] -async fn get_ipv4_src_black_list() -> impl Responder { - let list = AccessList::get_ipv4_src_black_list().await; - HttpResponse::Ok().json(web::Json(list)) -} - -#[get("/ipv6/src_black_list")] -async fn get_ipv6_src_black_list() -> impl Responder { - let list = AccessList::get_ipv6_src_black_list().await; - HttpResponse::Ok().json(web::Json(list)) -} - -#[put("/ipv4/src_black_list")] -async fn add_ipv4_src_black_list(ip_addr: web::Json) -> impl Responder { - match AccessList::add_ipv4_src_black_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[put("/ipv6/src_black_list")] -async fn add_ipv6_src_black_list(ip_addr: web::Json) -> impl Responder { - match AccessList::add_ipv6_src_black_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[delete("/ipv4/src_black_list")] -async fn remove_ipv4_src_black_list(ip_addr: web::Json) -> impl Responder { - match AccessList::remove_ipv4_src_black_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[delete("/ipv6/src_black_list")] -async fn remove_ipv6_src_black_list(ip_addr: web::Json) -> impl Responder { - match AccessList::remove_ipv6_src_black_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[get("/ipv4/dst_black_list")] -async fn get_ipv4_dst_black_list() -> impl Responder { - let list = AccessList::get_ipv4_dst_black_list().await; - HttpResponse::Ok().json(web::Json(list)) -} - -#[get("/ipv6/dst_black_list")] -async fn get_ipv6_dst_black_list() -> impl Responder { - let list = AccessList::get_ipv6_dst_black_list().await; - HttpResponse::Ok().json(web::Json(list)) -} - -#[put("/ipv4/dst_black_list")] -async fn add_ipv4_dst_black_list(ip_addr: web::Json) -> impl Responder { - match AccessList::add_ipv4_dst_black_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[put("/ipv6/dst_black_list")] -async fn add_ipv6_dst_black_list(ip_addr: web::Json) -> impl Responder { - match AccessList::add_ipv6_dst_black_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[delete("/ipv4/dst_black_list")] -async fn remove_ipv4_dst_black_list(ip_addr: web::Json) -> impl Responder { - match AccessList::remove_ipv4_dst_black_list(ip_addr.into_inner()).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), - } -} - -#[delete("/ipv6/dst_black_list")] -async fn remove_ipv6_dst_black_list(ip_addr: web::Json) -> impl Responder { - match AccessList::remove_ipv6_dst_black_list(ip_addr.into_inner()).await { +#[delete("/ipv6/{direction}/{list_type}")] +async fn remove_ipv6_list(address: web::Json, path: web::Path<(Direction, ListType)>) -> impl Responder { + let address = address.into_inner(); + let (direction, list_type) = path.into_inner(); + match AccessList::remove_ipv6_list(direction, list_type, address).await { Ok(_) => HttpResponse::Ok().finish(), Err(e) => HttpResponse::InternalServerError().body(e.to_string()), }