1use crate::tunneling::{Tunnel, TunnelConfig, TunnelState, TunnelMetrics, TunnelProtocol};
18use crate::{Result, P2PError};
19use async_trait::async_trait;
20use std::net::{Ipv4Addr, Ipv6Addr, IpAddr, SocketAddr};
21use std::time::{Duration, Instant, SystemTime};
22use tracing::{info, warn, debug};
23use tokio::net::UdpSocket;
24use serde::{Serialize, Deserialize};
25
26const ISATAP_IID_PREFIX: u64 = 0x00005EFE;
28
29const DEFAULT_ROUTER_DISCOVERY_INTERVAL: Duration = Duration::from_secs(300); const MAX_PRL_SIZE: usize = 10;
34
35pub struct IsatapTunnel {
40 config: TunnelConfig,
42 state: TunnelState,
44 metrics: TunnelMetrics,
46 local_ipv4: Option<Ipv4Addr>,
48 isatap_ipv6: Option<Ipv6Addr>,
50 socket: Option<UdpSocket>,
52 potential_router_list: Vec<IsatapRouter>,
54 last_router_discovery: Option<Instant>,
56 active_router: Option<IsatapRouter>,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct IsatapRouter {
63 pub ipv4_addr: Ipv4Addr,
65 pub ipv6_prefix: Option<Ipv6Addr>,
67 pub priority: u8,
69 pub last_seen: Option<SystemTime>,
71 pub reachable: bool,
73 pub rtt: Option<Duration>,
75}
76
77#[derive(Debug, Clone)]
79pub enum RouterDiscoveryMethod {
80 DnsWellKnown(String),
82 ConfiguredList(Vec<Ipv4Addr>),
84 Dhcp,
86 Manual(Vec<IsatapRouter>),
88}
89
90impl IsatapTunnel {
91 pub fn new(config: TunnelConfig) -> Result<Self> {
93 if config.protocol != TunnelProtocol::Isatap {
94 return Err(P2PError::Config(
95 "Invalid protocol for ISATAP tunnel".to_string()
96 ));
97 }
98
99 info!("Creating ISATAP tunnel for enterprise IPv6 connectivity");
100
101 Ok(Self {
102 config,
103 state: TunnelState::Disconnected,
104 metrics: TunnelMetrics::default(),
105 local_ipv4: None,
106 isatap_ipv6: None,
107 socket: None,
108 potential_router_list: Vec::new(),
109 last_router_discovery: None,
110 active_router: None,
111 })
112 }
113
114 pub fn generate_isatap_address(ipv4_addr: Ipv4Addr, prefix: Option<Ipv6Addr>) -> Ipv6Addr {
119 let prefix = prefix.unwrap_or_else(|| "fe80::".parse().unwrap());
120
121 let ipv4_bytes = ipv4_addr.octets();
123 let ipv4_u32 = u32::from_be_bytes(ipv4_bytes);
124
125 let iid_high = ISATAP_IID_PREFIX;
127 let prefix_bytes = prefix.octets();
131 let mut addr_bytes = [0u8; 16];
132
133 addr_bytes[..8].copy_from_slice(&prefix_bytes[..8]);
135
136 addr_bytes[8..12].copy_from_slice(&iid_high.to_be_bytes()[4..]);
138 addr_bytes[12..16].copy_from_slice(&ipv4_u32.to_be_bytes());
139
140 Ipv6Addr::from(addr_bytes)
141 }
142
143 pub fn is_isatap_address(addr: Ipv6Addr) -> bool {
145 let segments = addr.segments();
146 segments[4] == 0x0000 && segments[5] == 0x5EFE
148 }
149
150 pub fn extract_ipv4_from_isatap(addr: Ipv6Addr) -> Option<Ipv4Addr> {
152 if !Self::is_isatap_address(addr) {
153 return None;
154 }
155
156 let segments = addr.segments();
157 let ipv4_bytes = [
158 ((segments[6] >> 8) & 0xFF) as u8,
159 (segments[6] & 0xFF) as u8,
160 ((segments[7] >> 8) & 0xFF) as u8,
161 (segments[7] & 0xFF) as u8,
162 ];
163
164 Some(Ipv4Addr::from(ipv4_bytes))
165 }
166
167 pub async fn discover_routers(&mut self, method: RouterDiscoveryMethod) -> Result<Vec<IsatapRouter>> {
169 info!("Discovering ISATAP routers using: {:?}", method);
170
171 let discovered_routers = match method {
172 RouterDiscoveryMethod::DnsWellKnown(domain) => {
173 self.discover_routers_dns(&domain).await?
174 }
175 RouterDiscoveryMethod::ConfiguredList(addresses) => {
176 self.create_routers_from_addresses(addresses)
177 }
178 RouterDiscoveryMethod::Manual(routers) => routers,
179 RouterDiscoveryMethod::Dhcp => {
180 warn!("DHCP router discovery not yet implemented");
181 Vec::new()
182 }
183 };
184
185 self.update_potential_router_list(discovered_routers.clone());
187 self.last_router_discovery = Some(Instant::now());
188
189 info!("Discovered {} ISATAP routers", discovered_routers.len());
190 Ok(discovered_routers)
191 }
192
193 async fn discover_routers_dns(&self, domain: &str) -> Result<Vec<IsatapRouter>> {
195 let isatap_hostname = format!("isatap.{}", domain);
196 debug!("Looking up ISATAP router at: {}", isatap_hostname);
197
198 match tokio::net::lookup_host(format!("{}:80", isatap_hostname)).await {
199 Ok(addrs) => {
200 let mut routers = Vec::new();
201 for addr in addrs {
202 if let IpAddr::V4(ipv4) = addr.ip() {
203 routers.push(IsatapRouter {
204 ipv4_addr: ipv4,
205 ipv6_prefix: None,
206 priority: 10, last_seen: None,
208 reachable: false,
209 rtt: None,
210 });
211 }
212 }
213 Ok(routers)
214 }
215 Err(e) => {
216 warn!("Failed to resolve ISATAP router '{}': {}", isatap_hostname, e);
217 Ok(Vec::new())
218 }
219 }
220 }
221
222 fn create_routers_from_addresses(&self, addresses: Vec<Ipv4Addr>) -> Vec<IsatapRouter> {
224 addresses.into_iter().enumerate().map(|(i, addr)| {
225 IsatapRouter {
226 ipv4_addr: addr,
227 ipv6_prefix: None,
228 priority: i as u8,
229 last_seen: None,
230 reachable: false,
231 rtt: None,
232 }
233 }).collect()
234 }
235
236 fn update_potential_router_list(&mut self, new_routers: Vec<IsatapRouter>) {
238 for new_router in new_routers {
240 if !self.potential_router_list.iter().any(|r| r.ipv4_addr == new_router.ipv4_addr) {
241 self.potential_router_list.push(new_router);
242 }
243 }
244
245 self.potential_router_list.sort_by_key(|r| r.priority);
247 self.potential_router_list.truncate(MAX_PRL_SIZE);
248
249 debug!("Updated PRL with {} routers", self.potential_router_list.len());
250 }
251
252 pub async fn test_router_reachability(&self, router: &IsatapRouter) -> Result<Duration> {
254 let target = format!("{}:80", router.ipv4_addr);
255 let start = Instant::now();
256
257 match tokio::time::timeout(Duration::from_secs(5), tokio::net::TcpStream::connect(&target)).await {
258 Ok(Ok(_)) => {
259 let rtt = start.elapsed();
260 debug!("ISATAP router {} reachable, RTT: {:?}", router.ipv4_addr, rtt);
261 Ok(rtt)
262 }
263 Ok(Err(e)) => {
264 debug!("ISATAP router {} unreachable: {}", router.ipv4_addr, e);
265 Err(P2PError::Network(format!("Router unreachable: {}", e)))
266 }
267 Err(_) => {
268 debug!("ISATAP router {} timeout", router.ipv4_addr);
269 Err(P2PError::Network("Router reachability timeout".to_string()))
270 }
271 }
272 }
273
274 pub async fn select_router(&mut self) -> Result<IsatapRouter> {
276 if self.potential_router_list.is_empty() {
277 return Err(P2PError::Config("No ISATAP routers available".to_string()));
278 }
279
280 info!("Selecting best ISATAP router from {} candidates", self.potential_router_list.len());
281
282 let mut best_router = None;
284 let mut best_rtt = Duration::from_secs(u64::MAX);
285
286 let mut test_results = Vec::new();
288 for (i, router) in self.potential_router_list.iter().enumerate() {
289 let rtt_result = self.test_router_reachability(router).await;
290 test_results.push((i, rtt_result));
291 }
292
293 for (i, rtt_result) in test_results {
295 let router = &mut self.potential_router_list[i];
296 match rtt_result {
297 Ok(rtt) => {
298 router.reachable = true;
299 router.rtt = Some(rtt);
300 router.last_seen = Some(SystemTime::now());
301
302 if rtt < best_rtt {
303 best_rtt = rtt;
304 best_router = Some(router.clone());
305 }
306 }
307 Err(_) => {
308 router.reachable = false;
309 router.rtt = None;
310 }
311 }
312 }
313
314 match best_router {
315 Some(router) => {
316 info!("Selected ISATAP router: {} (RTT: {:?})", router.ipv4_addr, router.rtt);
317 self.active_router = Some(router.clone());
318 Ok(router)
319 }
320 None => Err(P2PError::Network("No reachable ISATAP routers found".to_string()))
321 }
322 }
323
324 pub async fn initialize_addresses(&mut self) -> Result<()> {
326 let local_ipv4 = self.get_local_ipv4().await?;
328 self.local_ipv4 = Some(local_ipv4);
329
330 let prefix = self.get_ipv6_prefix();
332 let isatap_addr = Self::generate_isatap_address(local_ipv4, prefix);
333 self.isatap_ipv6 = Some(isatap_addr);
334
335 info!("Initialized ISATAP addresses: IPv4={}, IPv6={}", local_ipv4, isatap_addr);
336 Ok(())
337 }
338
339 async fn get_local_ipv4(&self) -> Result<Ipv4Addr> {
341 if let Some(addr) = self.config.local_ipv4 {
343 return Ok(addr);
344 }
345
346 match tokio::net::UdpSocket::bind("0.0.0.0:0").await {
348 Ok(socket) => {
349 if socket.connect("8.8.8.8:53").await.is_ok() {
351 if let Ok(local_addr) = socket.local_addr() {
352 if let IpAddr::V4(ipv4) = local_addr.ip() {
353 return Ok(ipv4);
354 }
355 }
356 }
357 }
358 Err(e) => {
359 warn!("Failed to auto-detect local IPv4: {}", e);
360 }
361 }
362
363 Err(P2PError::Network("Could not determine local IPv4 address".to_string()))
364 }
365
366 fn get_ipv6_prefix(&self) -> Option<Ipv6Addr> {
368 self.config.ipv6_prefix.or_else(|| {
369 Some("fe80::".parse().unwrap())
371 })
372 }
373
374 async fn create_socket(&mut self) -> Result<()> {
376 let local_ipv4 = self.local_ipv4.ok_or_else(|| {
377 P2PError::Config("Local IPv4 address not initialized".to_string())
378 })?;
379
380 let bind_addr = SocketAddr::new(IpAddr::V4(local_ipv4), 0);
381 let socket = UdpSocket::bind(bind_addr).await
382 .map_err(|e| P2PError::Network(format!("Failed to create ISATAP socket: {}", e)))?;
383
384 info!("Created ISATAP socket on: {}", socket.local_addr().unwrap());
385 self.socket = Some(socket);
386 Ok(())
387 }
388
389 pub fn encapsulate_ipv6_in_ipv4(&self, ipv6_packet: &[u8], dest_ipv4: Ipv4Addr) -> Result<Vec<u8>> {
391 if ipv6_packet.len() < 40 {
392 return Err(P2PError::Transport("IPv6 packet too short".to_string()));
393 }
394
395 if (ipv6_packet[0] & 0xF0) != 0x60 {
397 return Err(P2PError::Transport("Not an IPv6 packet".to_string()));
398 }
399
400 let local_ipv4 = self.local_ipv4.ok_or_else(|| {
401 P2PError::Network("Local IPv4 address not available".to_string())
402 })?;
403
404 let mut ipv4_packet = Vec::with_capacity(20 + ipv6_packet.len());
406
407 ipv4_packet.push(0x45); ipv4_packet.push(0x00); ipv4_packet.extend_from_slice(&((20 + ipv6_packet.len()) as u16).to_be_bytes()); ipv4_packet.extend_from_slice(&[0x00, 0x00]); ipv4_packet.extend_from_slice(&[0x40, 0x00]); ipv4_packet.push(64); ipv4_packet.push(41); ipv4_packet.extend_from_slice(&[0x00, 0x00]); ipv4_packet.extend_from_slice(&local_ipv4.octets()); ipv4_packet.extend_from_slice(&dest_ipv4.octets()); let checksum = Self::calculate_ipv4_checksum(&ipv4_packet);
421 ipv4_packet[10..12].copy_from_slice(&checksum.to_be_bytes());
422
423 ipv4_packet.extend_from_slice(ipv6_packet);
425
426 Ok(ipv4_packet)
427 }
428
429 pub fn decapsulate_ipv4_to_ipv6(&self, ipv4_packet: &[u8]) -> Result<Vec<u8>> {
431 if ipv4_packet.len() < 20 {
432 return Err(P2PError::Transport("IPv4 packet too short".to_string()));
433 }
434
435 if (ipv4_packet[0] & 0xF0) != 0x40 {
437 return Err(P2PError::Transport("Not an IPv4 packet".to_string()));
438 }
439
440 if ipv4_packet[9] != 41 {
442 return Err(P2PError::Transport("IPv4 packet does not contain IPv6".to_string()));
443 }
444
445 let ihl = (ipv4_packet[0] & 0x0F) as usize * 4;
447 if ipv4_packet.len() <= ihl {
448 return Err(P2PError::Transport("IPv4 header length invalid".to_string()));
449 }
450
451 let ipv6_packet = ipv4_packet[ihl..].to_vec();
453
454 if ipv6_packet.is_empty() || (ipv6_packet[0] & 0xF0) != 0x60 {
456 return Err(P2PError::Transport("Invalid IPv6 payload".to_string()));
457 }
458
459 Ok(ipv6_packet)
460 }
461
462 fn calculate_ipv4_checksum(header: &[u8]) -> u16 {
464 let mut sum: u32 = 0;
465
466 for i in (0..20).step_by(2) {
468 if i == 10 { continue; } let word = if i + 1 < header.len() {
471 u16::from_be_bytes([header[i], header[i + 1]])
472 } else {
473 u16::from_be_bytes([header[i], 0])
474 };
475 sum += word as u32;
476 }
477
478 while (sum >> 16) != 0 {
480 sum = (sum & 0xFFFF) + (sum >> 16);
481 }
482
483 !sum as u16
485 }
486}
487
488#[async_trait]
489impl Tunnel for IsatapTunnel {
490 fn protocol(&self) -> TunnelProtocol {
491 TunnelProtocol::Isatap
492 }
493
494 fn config(&self) -> &TunnelConfig {
495 &self.config
496 }
497
498 async fn state(&self) -> TunnelState {
499 self.state.clone()
500 }
501
502 async fn metrics(&self) -> TunnelMetrics {
503 self.metrics.clone()
504 }
505
506 async fn connect(&mut self) -> Result<()> {
507 info!("Connecting ISATAP tunnel for enterprise IPv6 connectivity");
508 self.state = TunnelState::Connecting;
509
510 if let Err(e) = self.initialize_addresses().await {
512 self.state = TunnelState::Failed(format!("Address initialization failed: {}", e));
513 return Err(e);
514 }
515
516 let discovery_method = if let Some(domain) = std::env::var("ISATAP_DOMAIN").ok() {
518 RouterDiscoveryMethod::DnsWellKnown(domain)
519 } else {
520 RouterDiscoveryMethod::ConfiguredList(vec![
522 "192.168.1.1".parse().unwrap(),
523 "10.0.0.1".parse().unwrap(),
524 ])
525 };
526
527 if let Err(e) = self.discover_routers(discovery_method).await {
528 warn!("Router discovery failed: {}", e);
529 }
530
531 if self.select_router().await.is_err() {
533 warn!("No ISATAP router available, operating in host-to-host mode");
534 }
535
536 if let Err(e) = self.create_socket().await {
538 self.state = TunnelState::Failed(format!("Socket creation failed: {}", e));
539 return Err(e);
540 }
541
542 self.state = TunnelState::Connected;
543 info!("ISATAP tunnel connected successfully");
544 Ok(())
545 }
546
547 async fn is_active(&self) -> bool {
548 matches!(self.state, TunnelState::Connected)
549 }
550
551 async fn disconnect(&mut self) -> Result<()> {
552 info!("Disconnecting ISATAP tunnel");
553
554 if let Some(socket) = self.socket.take() {
555 drop(socket);
556 }
557
558 self.state = TunnelState::Disconnected;
559 self.active_router = None;
560 info!("ISATAP tunnel disconnected");
561 Ok(())
562 }
563
564 async fn encapsulate(&self, ipv6_packet: &[u8]) -> Result<Vec<u8>> {
565 if !self.is_active().await {
566 return Err(P2PError::Network("ISATAP tunnel not connected".to_string()));
567 }
568
569 let dest_ipv4 = if let Some(router) = &self.active_router {
571 router.ipv4_addr
572 } else {
573 if ipv6_packet.len() >= 40 {
575 let dest_ipv6_bytes = &ipv6_packet[24..40];
576 let dest_ipv6 = Ipv6Addr::from(<[u8; 16]>::try_from(dest_ipv6_bytes).unwrap());
577
578 if let Some(ipv4) = Self::extract_ipv4_from_isatap(dest_ipv6) {
579 ipv4
580 } else {
581 return Err(P2PError::Network("No route to IPv6 destination".to_string()));
582 }
583 } else {
584 return Err(P2PError::Transport("IPv6 packet too short".to_string()));
585 }
586 };
587
588 self.encapsulate_ipv6_in_ipv4(ipv6_packet, dest_ipv4)
589 }
590
591 async fn decapsulate(&self, ipv4_packet: &[u8]) -> Result<Vec<u8>> {
592 if !self.is_active().await {
593 return Err(P2PError::Network("ISATAP tunnel not connected".to_string()));
594 }
595
596 self.decapsulate_ipv4_to_ipv6(ipv4_packet)
597 }
598
599 async fn send(&mut self, packet: &[u8]) -> Result<()> {
600 let socket = self.socket.as_ref().ok_or_else(|| {
601 P2PError::Network("ISATAP socket not available".to_string())
602 })?;
603
604 if packet.len() < 20 {
606 return Err(P2PError::Transport("Packet too short".to_string()));
607 }
608
609 let dest_bytes = &packet[16..20];
611 let dest_addr = Ipv4Addr::from(<[u8; 4]>::try_from(dest_bytes).unwrap());
612 let dest_port = 41; socket.send_to(packet, (dest_addr, dest_port)).await
615 .map_err(|e| P2PError::Network(format!("Failed to send packet: {}", e)))?;
616
617 self.metrics.packets_sent += 1;
618 self.metrics.bytes_sent += packet.len() as u64;
619 Ok(())
620 }
621
622 async fn receive(&mut self) -> Result<Vec<u8>> {
623 let socket = self.socket.as_ref().ok_or_else(|| {
624 P2PError::Network("ISATAP socket not available".to_string())
625 })?;
626
627 let mut buffer = vec![0u8; 1500]; let (size, _) = socket.recv_from(&mut buffer).await
629 .map_err(|e| P2PError::Network(format!("Failed to receive packet: {}", e)))?;
630
631 buffer.truncate(size);
632 self.metrics.packets_received += 1;
633 self.metrics.bytes_received += size as u64;
634 Ok(buffer)
635 }
636
637 async fn maintain(&mut self) -> Result<()> {
638 if let Some(last_discovery) = self.last_router_discovery {
640 if last_discovery.elapsed() > DEFAULT_ROUTER_DISCOVERY_INTERVAL {
641 debug!("Performing periodic ISATAP router discovery");
642
643 let discovery_method = RouterDiscoveryMethod::DnsWellKnown(
644 std::env::var("ISATAP_DOMAIN").unwrap_or_else(|_| "corp.local".to_string())
645 );
646
647 if let Err(e) = self.discover_routers(discovery_method).await {
648 warn!("Periodic router discovery failed: {}", e);
649 }
650 }
651 }
652
653 if let Some(router) = &self.active_router {
655 if let Err(_) = self.test_router_reachability(router).await {
656 warn!("Active ISATAP router {} became unreachable", router.ipv4_addr);
657 self.active_router = None;
658
659 if let Err(e) = self.select_router().await {
661 warn!("Failed to select new ISATAP router: {}", e);
662 }
663 }
664 }
665
666 Ok(())
667 }
668
669 async fn local_ipv6_addr(&self) -> Result<Ipv6Addr> {
670 self.isatap_ipv6.ok_or_else(|| {
671 P2PError::Network("ISATAP IPv6 address not available".to_string())
672 })
673 }
674
675 async fn local_ipv4_addr(&self) -> Result<Ipv4Addr> {
676 self.local_ipv4.ok_or_else(|| {
677 P2PError::Network("Local IPv4 address not available".to_string())
678 })
679 }
680
681 async fn ping(&mut self, _timeout: Duration) -> Result<Duration> {
682 let router = self.active_router.as_ref().ok_or_else(|| {
683 P2PError::Network("No active ISATAP router for ping".to_string())
684 })?;
685
686 self.test_router_reachability(router).await
687 }
688}