use crate::dht::{Key, DHTNode};
use crate::security::{IPv6NodeID, IPDiversityEnforcer, IPDiversityConfig};
use crate::{PeerId, Result, P2PError};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::Ipv6Addr;
use std::time::{Duration, SystemTime};
use tracing::{debug, info, warn};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IPv6DHTNode {
pub base_node: DHTNode,
pub ipv6_identity: IPv6NodeID,
pub ip_analysis: crate::security::IPAnalysis,
pub validated_at: SystemTime,
pub is_verified: bool,
}
#[derive(Debug, Clone)]
pub struct IPv6DHTConfig {
pub diversity_config: IPDiversityConfig,
pub enable_ipv6_verification: bool,
pub enable_ip_diversity: bool,
pub min_ipv6_reputation: f64,
pub identity_refresh_interval: Duration,
pub ip_analysis_cache_ttl: Duration,
pub enable_node_banning: bool,
pub security_ban_duration: Duration,
}
#[derive(Debug)]
pub struct IPv6DHTIdentityManager {
pub config: IPv6DHTConfig,
pub ip_enforcer: IPDiversityEnforcer,
verified_nodes: HashMap<PeerId, IPv6DHTNode>,
identity_cache: HashMap<PeerId, (IPv6NodeID, SystemTime)>,
ip_analysis_cache: HashMap<Ipv6Addr, (crate::security::IPAnalysis, SystemTime)>,
banned_nodes: HashMap<PeerId, SystemTime>,
local_identity: Option<IPv6NodeID>,
}
#[derive(Debug, Clone)]
pub struct IPv6VerificationResult {
pub is_valid: bool,
pub confidence: f64,
pub error_message: Option<String>,
pub ip_diversity_ok: bool,
pub identity_age_secs: u64,
}
#[derive(Debug, Clone)]
pub enum IPv6SecurityEvent {
NodeJoined {
peer_id: PeerId,
ipv6_addr: Ipv6Addr,
verification_confidence: f64,
},
VerificationFailed {
peer_id: PeerId,
ipv6_addr: Ipv6Addr,
reason: String,
},
DiversityViolation {
peer_id: PeerId,
ipv6_addr: Ipv6Addr,
subnet_type: String,
},
NodeBanned {
peer_id: PeerId,
ipv6_addr: Ipv6Addr,
reason: String,
ban_duration: Duration,
},
SuspiciousActivity {
peer_id: PeerId,
ipv6_addr: Ipv6Addr,
activity_type: String,
},
}
impl Default for IPv6DHTConfig {
fn default() -> Self {
Self {
diversity_config: IPDiversityConfig::default(),
enable_ipv6_verification: true,
enable_ip_diversity: true,
min_ipv6_reputation: 0.3,
identity_refresh_interval: Duration::from_secs(3600), ip_analysis_cache_ttl: Duration::from_secs(1800), enable_node_banning: true,
security_ban_duration: Duration::from_secs(7200), }
}
}
impl IPv6DHTIdentityManager {
pub fn new(config: IPv6DHTConfig) -> Self {
let ip_enforcer = IPDiversityEnforcer::new(config.diversity_config.clone());
Self {
config,
ip_enforcer,
verified_nodes: HashMap::new(),
identity_cache: HashMap::new(),
ip_analysis_cache: HashMap::new(),
banned_nodes: HashMap::new(),
local_identity: None,
}
}
pub fn set_local_identity(&mut self, identity: IPv6NodeID) -> Result<()> {
match identity.verify() {
Ok(true) => {
self.local_identity = Some(identity);
info!("Local IPv6 identity set and verified");
Ok(())
}
Ok(false) => {
Err(P2PError::Security("Local IPv6 identity verification failed".to_string()).into())
}
Err(e) => {
Err(P2PError::Security(format!("Identity verification error: {}", e)).into())
}
}
}
pub fn generate_dht_key(ipv6_identity: &IPv6NodeID) -> Key {
Key::from_hash(
ipv6_identity.node_id.as_slice()
.try_into()
.unwrap_or([0u8; 32])
)
}
pub async fn enhance_dht_node(&mut self, node: DHTNode, ipv6_identity: IPv6NodeID) -> Result<IPv6DHTNode> {
let verification_result = self.verify_ipv6_identity(&ipv6_identity).await?;
if !verification_result.is_valid {
return Err(P2PError::Security(format!(
"IPv6 identity verification failed: {}",
verification_result.error_message.unwrap_or_default()
)).into());
}
let ip_analysis = self.analyze_node_ip(ipv6_identity.ipv6_addr).await?;
if self.config.enable_ip_diversity && !self.ip_enforcer.can_accept_node(&ip_analysis) {
return Err(P2PError::Security(
"IP diversity constraints violated".to_string()
).into());
}
if self.config.enable_ip_diversity {
self.ip_enforcer.add_node(&ip_analysis)
.map_err(|e| P2PError::Security(format!("IP diversity error: {}", e)))?;
}
let enhanced_node = IPv6DHTNode {
base_node: node,
ipv6_identity,
ip_analysis,
validated_at: SystemTime::now(),
is_verified: verification_result.is_valid,
};
self.verified_nodes.insert(enhanced_node.base_node.peer_id.clone(), enhanced_node.clone());
info!("Enhanced DHT node with IPv6 identity: {}", enhanced_node.base_node.peer_id);
Ok(enhanced_node)
}
pub async fn verify_ipv6_identity(&mut self, identity: &IPv6NodeID) -> Result<IPv6VerificationResult> {
if let Some((cached_identity, cached_at)) = self.identity_cache.get(&identity.ipv6_addr.to_string()) {
if cached_at.elapsed().unwrap_or(Duration::MAX) < self.config.identity_refresh_interval {
if cached_identity.node_id == identity.node_id {
return Ok(IPv6VerificationResult {
is_valid: true,
confidence: 0.9, error_message: None,
ip_diversity_ok: true,
identity_age_secs: cached_at.elapsed().unwrap_or_default().as_secs(),
});
}
}
}
let signature_valid = match identity.verify() {
Ok(valid) => valid,
Err(e) => {
warn!("IPv6 identity signature verification failed: {}", e);
return Ok(IPv6VerificationResult {
is_valid: false,
confidence: 0.0,
error_message: Some(format!("Signature verification failed: {}", e)),
ip_diversity_ok: false,
identity_age_secs: 0,
});
}
};
if !signature_valid {
return Ok(IPv6VerificationResult {
is_valid: false,
confidence: 0.0,
error_message: Some("Invalid cryptographic signature".to_string()),
ip_diversity_ok: false,
identity_age_secs: 0,
});
}
let identity_age = identity.timestamp_secs;
let now_secs = SystemTime::now().duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default().as_secs();
let age_secs = now_secs.saturating_sub(identity_age);
if age_secs > 86400 {
return Ok(IPv6VerificationResult {
is_valid: false,
confidence: 0.0,
error_message: Some("Identity too old".to_string()),
ip_diversity_ok: false,
identity_age_secs: age_secs,
});
}
let ip_analysis = self.analyze_node_ip(identity.ipv6_addr).await?;
let ip_diversity_ok = !self.config.enable_ip_diversity ||
self.ip_enforcer.can_accept_node(&ip_analysis);
let mut confidence = 1.0;
if age_secs > 3600 { confidence -= (age_secs as f64 - 3600.0) / 86400.0 * 0.3;
}
if ip_analysis.is_hosting_provider {
confidence -= 0.2;
}
if ip_analysis.is_vpn_provider {
confidence -= 0.3;
}
confidence = confidence.max(0.0).min(1.0);
self.identity_cache.insert(
identity.ipv6_addr.to_string(),
(identity.clone(), SystemTime::now())
);
Ok(IPv6VerificationResult {
is_valid: signature_valid && ip_diversity_ok && confidence >= self.config.min_ipv6_reputation,
confidence,
error_message: None,
ip_diversity_ok,
identity_age_secs: age_secs,
})
}
async fn analyze_node_ip(&mut self, ipv6_addr: Ipv6Addr) -> Result<crate::security::IPAnalysis> {
if let Some((cached_analysis, cached_at)) = self.ip_analysis_cache.get(&ipv6_addr) {
if cached_at.elapsed().unwrap_or(Duration::MAX) < self.config.ip_analysis_cache_ttl {
return Ok(cached_analysis.clone());
}
}
let analysis = self.ip_enforcer.analyze_ip(ipv6_addr)
.map_err(|e| P2PError::Security(format!("IP analysis error: {}", e)))?;
self.ip_analysis_cache.insert(ipv6_addr, (analysis.clone(), SystemTime::now()));
Ok(analysis)
}
pub async fn validate_node_join(&mut self, node: &DHTNode, ipv6_identity: &IPv6NodeID) -> Result<IPv6SecurityEvent> {
if let Some(ban_time) = self.banned_nodes.get(&node.peer_id) {
if ban_time.elapsed().unwrap_or(Duration::MAX) < self.config.security_ban_duration {
return Ok(IPv6SecurityEvent::NodeBanned {
peer_id: node.peer_id.clone(),
ipv6_addr: ipv6_identity.ipv6_addr,
reason: "Node still banned".to_string(),
ban_duration: self.config.security_ban_duration,
});
} else {
self.banned_nodes.remove(&node.peer_id);
}
}
let verification_result = self.verify_ipv6_identity(ipv6_identity).await?;
if !verification_result.is_valid {
let event = IPv6SecurityEvent::VerificationFailed {
peer_id: node.peer_id.clone(),
ipv6_addr: ipv6_identity.ipv6_addr,
reason: verification_result.error_message.unwrap_or("Unknown".to_string()),
};
if self.config.enable_node_banning {
self.banned_nodes.insert(node.peer_id.clone(), SystemTime::now());
}
return Ok(event);
}
let ip_analysis = self.analyze_node_ip(ipv6_identity.ipv6_addr).await?;
if self.config.enable_ip_diversity && !self.ip_enforcer.can_accept_node(&ip_analysis) {
return Ok(IPv6SecurityEvent::DiversityViolation {
peer_id: node.peer_id.clone(),
ipv6_addr: ipv6_identity.ipv6_addr,
subnet_type: "IPv6 subnet".to_string(),
});
}
Ok(IPv6SecurityEvent::NodeJoined {
peer_id: node.peer_id.clone(),
ipv6_addr: ipv6_identity.ipv6_addr,
verification_confidence: verification_result.confidence,
})
}
pub fn get_verified_node(&self, peer_id: &PeerId) -> Option<&IPv6DHTNode> {
self.verified_nodes.get(peer_id)
}
pub fn remove_node(&mut self, peer_id: &PeerId) {
if let Some(ipv6_node) = self.verified_nodes.remove(peer_id) {
self.ip_enforcer.remove_node(&ipv6_node.ip_analysis);
debug!("Removed IPv6 node from tracking: {}", peer_id);
}
}
pub fn is_node_banned(&self, peer_id: &PeerId) -> bool {
if let Some(ban_time) = self.banned_nodes.get(peer_id) {
ban_time.elapsed().unwrap_or(Duration::MAX) < self.config.security_ban_duration
} else {
false
}
}
pub fn ban_node(&mut self, peer_id: &PeerId, reason: &str) {
self.banned_nodes.insert(peer_id.clone(), SystemTime::now());
warn!("Banned node {} for: {}", peer_id, reason);
}
pub fn get_ipv6_diversity_stats(&self) -> crate::security::DiversityStats {
self.ip_enforcer.get_diversity_stats()
}
pub fn cleanup_expired(&mut self) {
let _now = SystemTime::now();
self.identity_cache.retain(|_, (_, cached_at)| {
cached_at.elapsed().unwrap_or(Duration::MAX) < self.config.identity_refresh_interval
});
self.ip_analysis_cache.retain(|_, (_, cached_at)| {
cached_at.elapsed().unwrap_or(Duration::MAX) < self.config.ip_analysis_cache_ttl
});
self.banned_nodes.retain(|_, ban_time| {
ban_time.elapsed().unwrap_or(Duration::MAX) < self.config.security_ban_duration
});
self.verified_nodes.retain(|_, node| {
node.validated_at.elapsed().unwrap_or(Duration::MAX) < Duration::from_secs(86400)
});
}
pub fn get_local_identity(&self) -> Option<&IPv6NodeID> {
self.local_identity.as_ref()
}
pub fn update_ipv6_reputation(&mut self, peer_id: &PeerId, positive_behavior: bool) {
if let Some(ipv6_node) = self.verified_nodes.get_mut(peer_id) {
if positive_behavior {
ipv6_node.ip_analysis.reputation_score =
(ipv6_node.ip_analysis.reputation_score + 0.1).min(1.0);
} else {
ipv6_node.ip_analysis.reputation_score =
(ipv6_node.ip_analysis.reputation_score - 0.2).max(0.0);
if ipv6_node.ip_analysis.reputation_score < 0.1 && self.config.enable_node_banning {
self.ban_node(peer_id, "Low IPv6 reputation");
}
}
}
}
}
impl IPv6DHTNode {
pub fn new(base_node: DHTNode, ipv6_identity: IPv6NodeID, ip_analysis: crate::security::IPAnalysis) -> Self {
Self {
base_node,
ipv6_identity,
ip_analysis,
validated_at: SystemTime::now(),
is_verified: false,
}
}
pub fn get_dht_key(&self) -> Key {
IPv6DHTIdentityManager::generate_dht_key(&self.ipv6_identity)
}
pub fn needs_identity_refresh(&self, refresh_interval: Duration) -> bool {
self.validated_at.elapsed().unwrap_or(Duration::MAX) > refresh_interval
}
pub fn get_subnet_info(&self) -> (Ipv6Addr, Ipv6Addr, Ipv6Addr) {
(
self.ipv6_identity.extract_subnet_64(),
self.ipv6_identity.extract_subnet_48(),
self.ipv6_identity.extract_subnet_32(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::security::{IPv6NodeID, IPAnalysis};
use ed25519_dalek::Keypair;
use std::net::Ipv6Addr;
use std::str::FromStr;
use std::time::Duration;
fn create_test_dht_node(peer_id: &str, distance_bytes: [u8; 32]) -> DHTNode {
DHTNode {
peer_id: peer_id.to_string(),
addresses: vec![],
last_seen: std::time::Instant::now(),
distance: Key::from_hash(distance_bytes),
is_connected: false,
}
}
fn create_test_ipv6_identity() -> IPv6NodeID {
let mut csprng = rand::rngs::OsRng {};
let keypair = Keypair::generate(&mut csprng);
let ipv6_addr = Ipv6Addr::from_str("2001:db8::1").unwrap();
IPv6NodeID::generate(ipv6_addr, &keypair).unwrap()
}
fn create_test_ip_analysis() -> IPAnalysis {
IPAnalysis {
subnet_64: Ipv6Addr::from_str("2001:db8::").unwrap(),
subnet_48: Ipv6Addr::from_str("2001:db8::").unwrap(),
subnet_32: Ipv6Addr::from_str("2001:db8::").unwrap(),
asn: Some(64512),
country: Some("US".to_string()),
is_hosting_provider: false,
is_vpn_provider: false,
reputation_score: 1.0,
}
}
#[test]
fn test_ipv6_dht_config_default() {
let config = IPv6DHTConfig::default();
assert!(config.enable_ipv6_verification);
assert!(config.enable_ip_diversity);
assert_eq!(config.min_ipv6_reputation, 0.3);
assert_eq!(config.identity_refresh_interval, Duration::from_secs(3600));
assert_eq!(config.ip_analysis_cache_ttl, Duration::from_secs(1800));
assert!(config.enable_node_banning);
assert_eq!(config.security_ban_duration, Duration::from_secs(7200));
}
#[test]
fn test_ipv6_dht_identity_manager_creation() {
let config = IPv6DHTConfig::default();
let manager = IPv6DHTIdentityManager::new(config);
assert!(manager.verified_nodes.is_empty());
assert!(manager.identity_cache.is_empty());
assert!(manager.ip_analysis_cache.is_empty());
assert!(manager.banned_nodes.is_empty());
assert!(manager.local_identity.is_none());
}
#[test]
fn test_ipv6_dht_identity_manager_set_local_identity() -> Result<()> {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
let identity = create_test_ipv6_identity();
let result = manager.set_local_identity(identity.clone());
assert!(result.is_ok());
assert!(manager.local_identity.is_some());
assert_eq!(manager.local_identity.unwrap().ipv6_addr, identity.ipv6_addr);
Ok(())
}
#[test]
fn test_generate_dht_key() {
let identity = create_test_ipv6_identity();
let dht_key = IPv6DHTIdentityManager::generate_dht_key(&identity);
let dht_key2 = IPv6DHTIdentityManager::generate_dht_key(&identity);
assert_eq!(dht_key, dht_key2);
let expected_key = Key::from_hash(
identity.node_id.as_slice()
.try_into()
.unwrap_or([0u8; 32])
);
assert_eq!(dht_key, expected_key);
}
#[tokio::test]
async fn test_enhance_dht_node() -> Result<()> {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
let base_node = create_test_dht_node("test_peer", [1u8; 32]);
let identity = create_test_ipv6_identity();
let result = manager.enhance_dht_node(base_node.clone(), identity.clone()).await;
match result {
Ok(enhanced_node) => {
assert_eq!(enhanced_node.base_node.peer_id, base_node.peer_id);
assert_eq!(enhanced_node.ipv6_identity.ipv6_addr, identity.ipv6_addr);
assert!(enhanced_node.is_verified);
}
Err(_) => {
}
}
Ok(())
}
#[tokio::test]
async fn test_verify_ipv6_identity() -> Result<()> {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
let identity = create_test_ipv6_identity();
let result = manager.verify_ipv6_identity(&identity).await?;
assert!(result.is_valid);
assert!(result.confidence > 0.0);
assert!(result.error_message.is_none());
Ok(())
}
#[tokio::test]
async fn test_verify_ipv6_identity_caching() -> Result<()> {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
let identity = create_test_ipv6_identity();
let result1 = manager.verify_ipv6_identity(&identity).await?;
let result2 = manager.verify_ipv6_identity(&identity).await?;
assert_eq!(result1.is_valid, result2.is_valid);
Ok(())
}
#[tokio::test]
async fn test_validate_node_join() -> Result<()> {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
let node = create_test_dht_node("test_peer", [1u8; 32]);
let identity = create_test_ipv6_identity();
let event = manager.validate_node_join(&node, &identity).await?;
match event {
IPv6SecurityEvent::NodeJoined { peer_id, ipv6_addr, verification_confidence } => {
assert_eq!(peer_id, node.peer_id);
assert_eq!(ipv6_addr, identity.ipv6_addr);
assert!(verification_confidence > 0.0);
}
IPv6SecurityEvent::VerificationFailed { .. } => {
}
IPv6SecurityEvent::DiversityViolation { .. } => {
}
_ => panic!("Unexpected security event type"),
}
Ok(())
}
#[test]
fn test_node_banning() {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
let peer_id = "test_peer".to_string();
assert!(!manager.is_node_banned(&peer_id));
manager.ban_node(&peer_id, "Test ban");
assert!(manager.is_node_banned(&peer_id));
assert!(manager.banned_nodes.contains_key(&peer_id));
}
#[test]
fn test_get_verified_node() {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
let peer_id = "test_peer".to_string();
assert!(manager.get_verified_node(&peer_id).is_none());
let base_node = create_test_dht_node(&peer_id, [1u8; 32]);
let identity = create_test_ipv6_identity();
let ip_analysis = create_test_ip_analysis();
let ipv6_node = IPv6DHTNode::new(base_node, identity, ip_analysis);
manager.verified_nodes.insert(peer_id.clone(), ipv6_node);
assert!(manager.get_verified_node(&peer_id).is_some());
}
#[test]
fn test_remove_node() {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
let peer_id = "test_peer".to_string();
let base_node = create_test_dht_node(&peer_id, [1u8; 32]);
let identity = create_test_ipv6_identity();
let ip_analysis = create_test_ip_analysis();
let ipv6_node = IPv6DHTNode::new(base_node, identity, ip_analysis);
manager.verified_nodes.insert(peer_id.clone(), ipv6_node);
assert!(manager.get_verified_node(&peer_id).is_some());
manager.remove_node(&peer_id);
assert!(manager.get_verified_node(&peer_id).is_none());
}
#[test]
fn test_update_ipv6_reputation() {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
let peer_id = "test_peer".to_string();
let base_node = create_test_dht_node(&peer_id, [1u8; 32]);
let identity = create_test_ipv6_identity();
let ip_analysis = create_test_ip_analysis();
let ipv6_node = IPv6DHTNode::new(base_node, identity, ip_analysis);
manager.verified_nodes.insert(peer_id.clone(), ipv6_node);
let initial_reputation = manager.verified_nodes[&peer_id].ip_analysis.reputation_score;
manager.update_ipv6_reputation(&peer_id, true);
let new_reputation = manager.verified_nodes[&peer_id].ip_analysis.reputation_score;
assert!(new_reputation >= initial_reputation);
manager.update_ipv6_reputation(&peer_id, false);
let final_reputation = manager.verified_nodes[&peer_id].ip_analysis.reputation_score;
assert!(final_reputation < new_reputation);
}
#[test]
fn test_cleanup_expired() {
let config = IPv6DHTConfig {
identity_refresh_interval: Duration::from_millis(1),
ip_analysis_cache_ttl: Duration::from_millis(1),
security_ban_duration: Duration::from_millis(1),
..Default::default()
};
let mut manager = IPv6DHTIdentityManager::new(config);
let ipv6_addr = Ipv6Addr::from_str("2001:db8::1").unwrap();
let identity = create_test_ipv6_identity();
let ip_analysis = create_test_ip_analysis();
let peer_id = "test_peer".to_string();
manager.identity_cache.insert(
ipv6_addr.to_string(),
(identity, SystemTime::now())
);
manager.ip_analysis_cache.insert(ipv6_addr, (ip_analysis, SystemTime::now()));
manager.banned_nodes.insert(peer_id.clone(), SystemTime::now());
std::thread::sleep(Duration::from_millis(10));
manager.cleanup_expired();
}
#[test]
fn test_get_ipv6_diversity_stats() {
let config = IPv6DHTConfig::default();
let manager = IPv6DHTIdentityManager::new(config);
let stats = manager.get_ipv6_diversity_stats();
assert_eq!(stats.total_64_subnets, 0);
assert_eq!(stats.total_48_subnets, 0);
assert_eq!(stats.total_32_subnets, 0);
}
#[test]
fn test_get_local_identity() {
let config = IPv6DHTConfig::default();
let mut manager = IPv6DHTIdentityManager::new(config);
assert!(manager.get_local_identity().is_none());
let identity = create_test_ipv6_identity();
manager.set_local_identity(identity.clone()).unwrap();
let retrieved_identity = manager.get_local_identity().unwrap();
assert_eq!(retrieved_identity.ipv6_addr, identity.ipv6_addr);
}
#[test]
fn test_ipv6_dht_node_creation() {
let base_node = create_test_dht_node("test_peer", [1u8; 32]);
let identity = create_test_ipv6_identity();
let ip_analysis = create_test_ip_analysis();
let ipv6_node = IPv6DHTNode::new(base_node.clone(), identity.clone(), ip_analysis.clone());
assert_eq!(ipv6_node.base_node.peer_id, base_node.peer_id);
assert_eq!(ipv6_node.ipv6_identity.ipv6_addr, identity.ipv6_addr);
assert_eq!(ipv6_node.ip_analysis.subnet_64, ip_analysis.subnet_64);
assert!(!ipv6_node.is_verified); }
#[test]
fn test_ipv6_dht_node_get_dht_key() {
let base_node = create_test_dht_node("test_peer", [1u8; 32]);
let identity = create_test_ipv6_identity();
let ip_analysis = create_test_ip_analysis();
let ipv6_node = IPv6DHTNode::new(base_node, identity.clone(), ip_analysis);
let dht_key = ipv6_node.get_dht_key();
let expected_key = IPv6DHTIdentityManager::generate_dht_key(&identity);
assert_eq!(dht_key, expected_key);
}
#[test]
fn test_ipv6_dht_node_needs_identity_refresh() {
let base_node = create_test_dht_node("test_peer", [1u8; 32]);
let identity = create_test_ipv6_identity();
let ip_analysis = create_test_ip_analysis();
let ipv6_node = IPv6DHTNode::new(base_node, identity, ip_analysis);
assert!(!ipv6_node.needs_identity_refresh(Duration::from_secs(3600)));
std::thread::sleep(Duration::from_millis(2));
assert!(ipv6_node.needs_identity_refresh(Duration::from_millis(1)));
}
#[test]
fn test_ipv6_security_event_variants() {
let peer_id = "test_peer".to_string();
let ipv6_addr = Ipv6Addr::from_str("2001:db8::1").unwrap();
let joined_event = IPv6SecurityEvent::NodeJoined {
peer_id: peer_id.clone(),
ipv6_addr,
verification_confidence: 0.9,
};
match joined_event {
IPv6SecurityEvent::NodeJoined { verification_confidence, .. } => {
assert_eq!(verification_confidence, 0.9);
}
_ => panic!("Wrong event type"),
}
let failed_event = IPv6SecurityEvent::VerificationFailed {
peer_id: peer_id.clone(),
ipv6_addr,
reason: "Test failure".to_string(),
};
match failed_event {
IPv6SecurityEvent::VerificationFailed { reason, .. } => {
assert_eq!(reason, "Test failure");
}
_ => panic!("Wrong event type"),
}
let violation_event = IPv6SecurityEvent::DiversityViolation {
peer_id: peer_id.clone(),
ipv6_addr,
subnet_type: "IPv6 subnet".to_string(),
};
match violation_event {
IPv6SecurityEvent::DiversityViolation { subnet_type, .. } => {
assert_eq!(subnet_type, "IPv6 subnet");
}
_ => panic!("Wrong event type"),
}
let banned_event = IPv6SecurityEvent::NodeBanned {
peer_id: peer_id.clone(),
ipv6_addr,
reason: "Security violation".to_string(),
ban_duration: Duration::from_secs(3600),
};
match banned_event {
IPv6SecurityEvent::NodeBanned { ban_duration, .. } => {
assert_eq!(ban_duration, Duration::from_secs(3600));
}
_ => panic!("Wrong event type"),
}
let suspicious_event = IPv6SecurityEvent::SuspiciousActivity {
peer_id,
ipv6_addr,
activity_type: "Repeated failed attempts".to_string(),
};
match suspicious_event {
IPv6SecurityEvent::SuspiciousActivity { activity_type, .. } => {
assert_eq!(activity_type, "Repeated failed attempts");
}
_ => panic!("Wrong event type"),
}
}
#[test]
fn test_ipv6_verification_result() {
let result = IPv6VerificationResult {
is_valid: true,
confidence: 0.85,
error_message: None,
ip_diversity_ok: true,
identity_age_secs: 300,
};
assert!(result.is_valid);
assert_eq!(result.confidence, 0.85);
assert!(result.error_message.is_none());
assert!(result.ip_diversity_ok);
assert_eq!(result.identity_age_secs, 300);
}
}