v2
This commit is contained in:
@@ -0,0 +1,632 @@
|
||||
use crate::context::config::Config;
|
||||
use crate::context::nat::{MyNatInfo, PunchBackoff};
|
||||
use crate::nat::SubnetExternalRoute;
|
||||
use crate::protocol::client_message::PunchInfo;
|
||||
use crate::protocol::control_message::{ClientSimpleInfo, ClientSimpleInfoList};
|
||||
use crate::tunnel_core::p2p::route_table::RouteTable;
|
||||
use crate::tunnel_core::server::transport::config::ProtocolAddress;
|
||||
use ipnet::Ipv4Net;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use rust_p2p_core::nat::NatInfo;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
#[derive(Default)]
|
||||
struct PingStats {
|
||||
sent: u64,
|
||||
received: u64,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TrafficCounter {
|
||||
tx_bytes: u64,
|
||||
rx_bytes: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct TrafficStats {
|
||||
inner: Arc<RwLock<HashMap<Ipv4Addr, Arc<Mutex<TrafficCounter>>>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct TrafficInfo {
|
||||
pub ip: Ipv4Addr,
|
||||
pub tx_bytes: u64,
|
||||
pub rx_bytes: u64,
|
||||
}
|
||||
|
||||
impl TrafficStats {
|
||||
fn get_or_create(&self, ip: Ipv4Addr) -> Arc<Mutex<TrafficCounter>> {
|
||||
{
|
||||
let read = self.inner.read();
|
||||
if let Some(counter) = read.get(&ip) {
|
||||
return counter.clone();
|
||||
}
|
||||
}
|
||||
let mut write = self.inner.write();
|
||||
write
|
||||
.entry(ip)
|
||||
.or_insert_with(|| Arc::new(Mutex::new(TrafficCounter::default())))
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn record_tx(&self, ip: Ipv4Addr, bytes: u64) {
|
||||
let counter = self.get_or_create(ip);
|
||||
counter.lock().tx_bytes += bytes;
|
||||
}
|
||||
|
||||
pub fn record_rx(&self, ip: Ipv4Addr, bytes: u64) {
|
||||
let counter = self.get_or_create(ip);
|
||||
counter.lock().rx_bytes += bytes;
|
||||
}
|
||||
|
||||
pub fn get_traffic_info(&self, ip: &Ipv4Addr) -> Option<TrafficInfo> {
|
||||
let read = self.inner.read();
|
||||
read.get(ip).map(|counter| {
|
||||
let guard = counter.lock();
|
||||
TrafficInfo {
|
||||
ip: *ip,
|
||||
tx_bytes: guard.tx_bytes,
|
||||
rx_bytes: guard.rx_bytes,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_all_traffic_info(&self) -> Vec<TrafficInfo> {
|
||||
let read = self.inner.read();
|
||||
read.iter()
|
||||
.map(|(ip, counter)| {
|
||||
let guard = counter.lock();
|
||||
TrafficInfo {
|
||||
ip: *ip,
|
||||
tx_bytes: guard.tx_bytes,
|
||||
rx_bytes: guard.rx_bytes,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn reset(&self, ip: &Ipv4Addr) {
|
||||
let read = self.inner.read();
|
||||
if let Some(counter) = read.get(ip) {
|
||||
*counter.lock() = TrafficCounter::default();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_all(&self) {
|
||||
let read = self.inner.read();
|
||||
for counter in read.values() {
|
||||
*counter.lock() = TrafficCounter::default();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.inner.write().clear();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PacketLossStats {
|
||||
inner: Arc<RwLock<HashMap<Ipv4Addr, Arc<Mutex<PingStats>>>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct PacketLossInfo {
|
||||
pub ip: Ipv4Addr,
|
||||
pub sent: u64,
|
||||
pub received: u64,
|
||||
pub loss_rate: f64,
|
||||
}
|
||||
|
||||
impl PacketLossStats {
|
||||
fn get_or_create(&self, ip: Ipv4Addr) -> Arc<Mutex<PingStats>> {
|
||||
{
|
||||
let read = self.inner.read();
|
||||
if let Some(stats) = read.get(&ip) {
|
||||
return stats.clone();
|
||||
}
|
||||
}
|
||||
let mut write = self.inner.write();
|
||||
write
|
||||
.entry(ip)
|
||||
.or_insert_with(|| Arc::new(Mutex::new(PingStats::default())))
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn record_sent(&self, ip: Ipv4Addr) {
|
||||
let stats = self.get_or_create(ip);
|
||||
stats.lock().sent += 1;
|
||||
}
|
||||
|
||||
pub fn record_received(&self, ip: Ipv4Addr) {
|
||||
let stats = self.get_or_create(ip);
|
||||
stats.lock().received += 1;
|
||||
}
|
||||
|
||||
pub fn get_loss_info(&self, ip: &Ipv4Addr) -> Option<PacketLossInfo> {
|
||||
let read = self.inner.read();
|
||||
read.get(ip).map(|stats| {
|
||||
let guard = stats.lock();
|
||||
let loss_rate = if guard.sent > 0 {
|
||||
1.0 - (guard.received as f64 / guard.sent as f64)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
PacketLossInfo {
|
||||
ip: *ip,
|
||||
sent: guard.sent,
|
||||
received: guard.received,
|
||||
loss_rate,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_all_loss_info(&self) -> Vec<PacketLossInfo> {
|
||||
let read = self.inner.read();
|
||||
read.iter()
|
||||
.map(|(ip, stats)| {
|
||||
let guard = stats.lock();
|
||||
let loss_rate = if guard.sent > 0 {
|
||||
1.0 - (guard.received as f64 / guard.sent as f64)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
PacketLossInfo {
|
||||
ip: *ip,
|
||||
sent: guard.sent,
|
||||
received: guard.received,
|
||||
loss_rate,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn reset(&self, ip: &Ipv4Addr) {
|
||||
let read = self.inner.read();
|
||||
if let Some(stats) = read.get(ip) {
|
||||
*stats.lock() = PingStats::default();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_all(&self) {
|
||||
let read = self.inner.read();
|
||||
for stats in read.values() {
|
||||
*stats.lock() = PingStats::default();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.inner.write().clear();
|
||||
}
|
||||
}
|
||||
|
||||
pub mod config;
|
||||
pub(crate) mod nat;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct AppState {
|
||||
config: Arc<Mutex<Option<Box<Config>>>>,
|
||||
pub(crate) network: SharedNetworkAddr,
|
||||
pub(crate) server_info_collection: ServerInfoCollection,
|
||||
pub(crate) peer_map: PeerInfoMap,
|
||||
pub(crate) route_table: RouteTable,
|
||||
pub(crate) subnet_route: SubnetExternalRoute,
|
||||
pub(crate) nat_info: MyNatInfo,
|
||||
pub(crate) punch_backoff: PunchBackoff,
|
||||
pub(crate) packet_loss_stats: PacketLossStats,
|
||||
pub(crate) traffic_stats: TrafficStats,
|
||||
}
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct SharedNetworkAddr {
|
||||
inner: Arc<Mutex<Option<NetworkAddr>>>,
|
||||
}
|
||||
impl SharedNetworkAddr {
|
||||
pub fn network(&self) -> Option<Ipv4Net> {
|
||||
self.inner.lock().as_ref().map(|v| v.network())
|
||||
}
|
||||
pub fn ip(&self) -> Option<Ipv4Addr> {
|
||||
self.inner.lock().map(|v| v.ip)
|
||||
}
|
||||
pub fn get(&self) -> Option<NetworkAddr> {
|
||||
*self.inner.lock()
|
||||
}
|
||||
pub fn set(&self, addr: NetworkAddr) {
|
||||
*self.inner.lock() = Some(addr);
|
||||
}
|
||||
pub fn clear(&self) {
|
||||
*self.inner.lock() = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// 网络路由封装,包含本地网络信息和子网路由
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct NetworkRoute {
|
||||
pub network: SharedNetworkAddr,
|
||||
pub subnet_route: SubnetExternalRoute,
|
||||
}
|
||||
|
||||
impl NetworkRoute {
|
||||
pub fn new(network: SharedNetworkAddr, subnet_route: SubnetExternalRoute) -> Self {
|
||||
Self {
|
||||
network,
|
||||
subnet_route,
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查 IP 是否在本地网络或子网路由中
|
||||
pub fn network_contains(&self, ip: &Ipv4Addr) -> bool {
|
||||
if let Some(network) = self.network.network()
|
||||
&& network.contains(ip)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
self.subnet_route.route(ip).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct PeerClientInfo {
|
||||
pub nat_info: Option<NatInfo>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct PeerInfoMap {
|
||||
inner: Arc<Mutex<HashMap<Ipv4Addr, PeerClientInfo>>>,
|
||||
}
|
||||
|
||||
impl PeerInfoMap {
|
||||
pub fn get(&self, ip: &Ipv4Addr) -> Option<PeerClientInfo> {
|
||||
self.inner.lock().get(ip).cloned()
|
||||
}
|
||||
|
||||
pub fn update_nat_info(&self, ip: Ipv4Addr, nat_info: NatInfo) {
|
||||
let mut guard = self.inner.lock();
|
||||
if let Some(v) = guard.get_mut(&ip) {
|
||||
v.nat_info = Some(nat_info);
|
||||
return;
|
||||
}
|
||||
guard.insert(
|
||||
ip,
|
||||
PeerClientInfo {
|
||||
nat_info: Some(nat_info),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.inner.lock().clear();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct ServerInfoCollection {
|
||||
client_simple_list: Arc<RwLock<Vec<ClientSimpleInfo>>>,
|
||||
server_node_map: Arc<RwLock<HashMap<u32, ServerNodeInfo>>>,
|
||||
}
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ServerNodeInfo {
|
||||
pub server_id: u32,
|
||||
pub server_addr: ProtocolAddress,
|
||||
pub connected: bool,
|
||||
pub rtt: Option<u32>,
|
||||
pub data_version: u64,
|
||||
pub client_map: HashMap<Ipv4Addr, ClientSimpleInfo>,
|
||||
pub last_connected_time: Option<i64>,
|
||||
pub disconnected_time: Option<i64>,
|
||||
pub server_version: Option<String>,
|
||||
}
|
||||
impl ServerInfoCollection {
|
||||
pub fn server_client_ip_map(&self) -> HashMap<u32, (Vec<Ipv4Addr>, u32)> {
|
||||
self.server_node_map
|
||||
.read()
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
*k,
|
||||
(
|
||||
v.client_map
|
||||
.iter()
|
||||
.filter(|(_, v)| v.online)
|
||||
.map(|(k, _)| *k)
|
||||
.collect(),
|
||||
v.rtt.unwrap_or(500),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
pub fn server_node_list(&self) -> Vec<ServerNodeInfo> {
|
||||
self.server_node_map.read().values().cloned().collect()
|
||||
}
|
||||
pub fn update_server(&self, addr: Vec<(u32, ProtocolAddress)>) {
|
||||
let mut server_node_map_guard = self.server_node_map.write();
|
||||
let mut client_simple_list_guard = self.client_simple_list.write();
|
||||
server_node_map_guard.clear();
|
||||
client_simple_list_guard.clear();
|
||||
for (server_id, server_addr) in addr {
|
||||
let server_node = ServerNodeInfo {
|
||||
server_id,
|
||||
server_addr,
|
||||
..Default::default()
|
||||
};
|
||||
server_node_map_guard.insert(server_id, server_node);
|
||||
}
|
||||
}
|
||||
pub fn find_connected_server(&self, server_ids: &[u32]) -> Option<u32> {
|
||||
let map = self.server_node_map.read();
|
||||
|
||||
server_ids
|
||||
.iter()
|
||||
.filter_map(|id| {
|
||||
let server = map.get(id)?;
|
||||
|
||||
if !server.connected {
|
||||
return None;
|
||||
}
|
||||
|
||||
let rtt = server.rtt.unwrap_or(u32::MAX);
|
||||
|
||||
Some((*id, rtt))
|
||||
})
|
||||
.min_by_key(|(_, rtt)| *rtt)
|
||||
.map(|(id, _)| id)
|
||||
}
|
||||
pub fn find_ip_to_server(&self, server_ids: &[u32], ip: &Ipv4Addr) -> Option<u32> {
|
||||
let map = self.server_node_map.read();
|
||||
|
||||
server_ids
|
||||
.iter()
|
||||
.filter_map(|id| {
|
||||
let server = map.get(id)?;
|
||||
|
||||
if !server.connected {
|
||||
return None;
|
||||
}
|
||||
|
||||
let client = server.client_map.get(ip)?;
|
||||
if !client.online {
|
||||
return None;
|
||||
}
|
||||
|
||||
let rtt = server.rtt.unwrap_or(u32::MAX);
|
||||
|
||||
Some((*id, rtt))
|
||||
})
|
||||
.min_by_key(|(_, rtt)| *rtt)
|
||||
.map(|(id, _)| id)
|
||||
}
|
||||
pub fn client_online_ips(&self) -> Vec<Ipv4Addr> {
|
||||
self.client_simple_list
|
||||
.read()
|
||||
.iter()
|
||||
.filter(|v| v.online)
|
||||
.map(|c| c.ip)
|
||||
.collect()
|
||||
}
|
||||
pub fn client_ips(&self) -> Vec<ClientSimpleInfo> {
|
||||
self.client_simple_list.read().clone()
|
||||
}
|
||||
pub fn data_version(&self, server_id: u32) -> u64 {
|
||||
self.server_node_map
|
||||
.read()
|
||||
.get(&server_id)
|
||||
.map(|v| v.data_version)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
pub fn update_client_simple_list(
|
||||
&self,
|
||||
server_id: u32,
|
||||
self_ip: Ipv4Addr,
|
||||
client_simple_list: ClientSimpleInfoList,
|
||||
now: i64,
|
||||
) {
|
||||
let mut guard = self.server_node_map.write();
|
||||
let server_node = guard.entry(server_id).or_default();
|
||||
if now > client_simple_list.time {
|
||||
server_node.rtt = Some((now - client_simple_list.time) as u32);
|
||||
}
|
||||
server_node.data_version = client_simple_list.data_version;
|
||||
let map: HashMap<Ipv4Addr, ClientSimpleInfo> = client_simple_list
|
||||
.list
|
||||
.into_iter()
|
||||
.filter(|v| v.ip != self_ip)
|
||||
.map(|info| (info.ip, info))
|
||||
.collect();
|
||||
|
||||
if client_simple_list.is_all {
|
||||
server_node.client_map = map;
|
||||
} else {
|
||||
server_node.client_map.extend(map);
|
||||
}
|
||||
let mut client_simple_map = HashMap::<Ipv4Addr, ClientSimpleInfo>::new();
|
||||
for (_, server_node) in guard.iter() {
|
||||
for (_, x) in server_node.client_map.iter() {
|
||||
if let Some(v) = client_simple_map.get_mut(&x.ip) {
|
||||
if x.online {
|
||||
v.online = true;
|
||||
}
|
||||
} else {
|
||||
client_simple_map.insert(x.ip, x.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut guard = self.client_simple_list.write();
|
||||
*guard = client_simple_map.into_values().collect()
|
||||
}
|
||||
pub fn set_server_connected(&self, server_id: u32, val: bool) -> bool {
|
||||
let mut mutex_guard = self.server_node_map.write();
|
||||
let server_node = mutex_guard.entry(server_id).or_default();
|
||||
let old = server_node.connected;
|
||||
server_node.connected = val;
|
||||
old
|
||||
}
|
||||
pub fn is_any_server_connected(&self, server_ids: Option<&[u32]>) -> bool {
|
||||
let guard = self.server_node_map.read();
|
||||
if let Some(server_ids) = server_ids {
|
||||
for id in server_ids {
|
||||
if guard.get(id).map(|v| v.connected).unwrap_or(false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (_, server_node) in guard.iter() {
|
||||
if server_node.connected {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
pub fn is_server_connected(&self, server_id: u32) -> bool {
|
||||
self.server_node_map
|
||||
.read()
|
||||
.get(&server_id)
|
||||
.map(|v| v.connected)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
pub fn set_last_connected_time(&self, server_id: u32, last_connected_time: Option<i64>) {
|
||||
self.server_node_map
|
||||
.write()
|
||||
.entry(server_id)
|
||||
.or_default()
|
||||
.last_connected_time = last_connected_time;
|
||||
}
|
||||
pub fn set_disconnected_time(&self, server_id: u32, last_connected_time: Option<i64>) {
|
||||
self.server_node_map
|
||||
.write()
|
||||
.entry(server_id)
|
||||
.or_default()
|
||||
.disconnected_time = last_connected_time;
|
||||
}
|
||||
pub fn set_server_rtt(&self, server_id: u32, rtt: u32) {
|
||||
if let Some(v) = self.server_node_map.write().get_mut(&server_id) {
|
||||
v.rtt = Some(rtt);
|
||||
}
|
||||
}
|
||||
pub fn set_server_version(&self, server_id: u32, version: String) {
|
||||
if let Some(v) = self.server_node_map.write().get_mut(&server_id) {
|
||||
v.server_version = Some(version);
|
||||
}
|
||||
}
|
||||
pub fn get_server_rtt(&self, ip: &Ipv4Addr) -> Option<u32> {
|
||||
let server_node_map_guard = self.server_node_map.read();
|
||||
for (_, server_node) in server_node_map_guard.iter() {
|
||||
if !server_node.connected {
|
||||
continue;
|
||||
}
|
||||
if let Some(v) = server_node.client_map.get(ip)
|
||||
&& v.online
|
||||
{
|
||||
return server_node.rtt;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn exists_online_client_ip(&self, ip: &Ipv4Addr) -> bool {
|
||||
self.client_simple_list
|
||||
.read()
|
||||
.iter()
|
||||
.any(|v| v.ip == *ip && v.online)
|
||||
}
|
||||
pub fn clear(&self) {
|
||||
self.client_simple_list.write().clear();
|
||||
let mut guard = self.server_node_map.write();
|
||||
for server_node in guard.values_mut() {
|
||||
server_node.connected = false;
|
||||
server_node.rtt = None;
|
||||
server_node.data_version = 0;
|
||||
server_node.client_map.clear();
|
||||
server_node.last_connected_time = None;
|
||||
server_node.disconnected_time = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct NetworkAddr {
|
||||
pub gateway: Ipv4Addr,
|
||||
pub broadcast: Ipv4Addr,
|
||||
pub ip: Ipv4Addr,
|
||||
pub prefix_len: u8,
|
||||
}
|
||||
impl NetworkAddr {
|
||||
pub fn network(&self) -> Ipv4Net {
|
||||
Ipv4Net::new_assert(self.ip, self.prefix_len)
|
||||
}
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn stop_network(&self) {
|
||||
self.network.clear();
|
||||
self.server_info_collection.clear();
|
||||
self.peer_map.clear();
|
||||
// route_table 来自外部 crate,会在任务停止后自动失效
|
||||
self.nat_info.clear();
|
||||
self.punch_backoff.clear();
|
||||
self.packet_loss_stats.clear();
|
||||
self.traffic_stats.clear();
|
||||
}
|
||||
|
||||
fn network(&self) -> Option<Ipv4Net> {
|
||||
self.network.network()
|
||||
}
|
||||
pub fn get_network(&self) -> Option<NetworkAddr> {
|
||||
self.network.get()
|
||||
}
|
||||
fn network_contains(&self, ip: &Ipv4Addr) -> bool {
|
||||
let Some(network) = self.network() else {
|
||||
return false;
|
||||
};
|
||||
if network.contains(ip) {
|
||||
return true;
|
||||
}
|
||||
self.subnet_route.route(ip).is_some()
|
||||
}
|
||||
pub fn client_ips(&self) -> Vec<ClientSimpleInfo> {
|
||||
self.server_info_collection.client_ips()
|
||||
}
|
||||
pub fn get_peer_info(&self, ip: &Ipv4Addr) -> Option<PeerClientInfo> {
|
||||
self.peer_map.get(ip)
|
||||
}
|
||||
|
||||
pub fn set_config(&self, config: Box<Config>) {
|
||||
*self.config.lock() = Some(config);
|
||||
}
|
||||
|
||||
pub fn get_config(&self) -> Option<Box<Config>> {
|
||||
self.config.lock().clone()
|
||||
}
|
||||
pub(crate) fn udp_stun(&self) -> Vec<String> {
|
||||
self.config
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(|v| v.udp_stun.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
pub(crate) fn tcp_stun(&self) -> Vec<String> {
|
||||
self.config
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(|v| v.tcp_stun.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
impl AppState {
|
||||
pub fn get_punch_info(&self) -> Option<PunchInfo> {
|
||||
self.nat_info.get().map(|info| PunchInfo {
|
||||
nat_info: self.filter_ip(info),
|
||||
})
|
||||
}
|
||||
pub fn get_nat_info(&self) -> Option<NatInfo> {
|
||||
self.nat_info.get().map(|info| self.filter_ip(info))
|
||||
}
|
||||
pub fn filter_ip(&self, mut info: NatInfo) -> NatInfo {
|
||||
if self.network_contains(&info.local_ipv4) {
|
||||
info.local_ipv4 = Ipv4Addr::UNSPECIFIED;
|
||||
}
|
||||
info.local_ipv4s.retain(|ip| !self.network_contains(ip));
|
||||
info
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user