Skip to main content

p2p_foundation/tunneling/
map.rs

1//! MAP-E and MAP-T (Mapping of Address and Port) Implementation
2//!
3//! This module implements MAP-E (RFC 7597) and MAP-T (RFC 7599) protocols
4//! for modern ISP IPv4/IPv6 transition mechanisms. These protocols enable
5//! ISPs to provide IPv4 services over IPv6 infrastructure using deterministic
6//! address and port mapping.
7//!
8//! ## Supported Protocols
9//!
10//! - **MAP-E**: IPv4-in-IPv6 encapsulation with mapping rules
11//! - **MAP-T**: Stateless IPv4/IPv6 translation with mapping rules
12//!
13//! ## Key Features
14//!
15//! - Deterministic port set allocation per subscriber
16//! - IPv4 address sharing across multiple customers
17//! - Stateless operation suitable for high-performance ISP deployments
18//! - Support for both encapsulation and translation modes
19//! - Algorithmic mapping rule processing
20
21use crate::tunneling::{Tunnel, TunnelConfig, TunnelState, TunnelMetrics, TunnelProtocol};
22use crate::{Result, P2PError};
23use async_trait::async_trait;
24use std::net::{Ipv4Addr, Ipv6Addr, IpAddr, SocketAddr};
25use std::time::{Duration, Instant};
26use std::collections::HashMap;
27use tracing::{info, warn, debug};
28use tokio::net::UdpSocket;
29use serde::{Serialize, Deserialize};
30
31/// MAP protocol variant
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33pub enum MapProtocol {
34    /// MAP-E: IPv4-in-IPv6 encapsulation
35    MapE,
36    /// MAP-T: IPv4/IPv6 stateless translation
37    MapT,
38}
39
40/// MAP rule configuration
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct MapRule {
43    /// IPv6 prefix for this MAP domain
44    pub ipv6_prefix: Ipv6Addr,
45    /// IPv6 prefix length
46    pub ipv6_prefix_len: u8,
47    /// IPv4 prefix for address sharing
48    pub ipv4_prefix: Ipv4Addr,
49    /// IPv4 prefix length
50    pub ipv4_prefix_len: u8,
51    /// Port parameters
52    pub port_params: PortParameters,
53    /// Border Relay IPv6 address (MAP-E only)
54    pub border_relay: Option<Ipv6Addr>,
55    /// Forward Mapping Rule (FMR) vs Basic Mapping Rule (BMR)
56    pub is_fmr: bool,
57}
58
59/// Port set parameters for MAP
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct PortParameters {
62    /// Port Set Identifier (PSID) offset
63    pub psid_offset: u8,
64    /// Port Set Identifier length
65    pub psid_length: u8,
66    /// Excluded ports (well-known ports)
67    pub excluded_ports: u16,
68}
69
70/// Calculated port set for a MAP customer
71#[derive(Debug, Clone)]
72pub struct PortSet {
73    /// Port Set Identifier
74    pub psid: u16,
75    /// Starting port in the set
76    pub start_port: u16,
77    /// Number of ports in the set
78    pub port_count: u16,
79    /// List of available ports
80    pub available_ports: Vec<u16>,
81}
82
83/// MAP tunnel implementation supporting both MAP-E and MAP-T
84pub struct MapTunnel {
85    /// MAP protocol variant (MAP-E or MAP-T)
86    protocol_variant: MapProtocol,
87    /// Tunnel configuration
88    config: TunnelConfig,
89    /// Current tunnel state
90    state: TunnelState,
91    /// Performance metrics
92    metrics: TunnelMetrics,
93    /// Active MAP rules
94    map_rules: Vec<MapRule>,
95    /// Calculated port set for this CE
96    port_set: Option<PortSet>,
97    /// Local IPv4 address (customer side)
98    local_ipv4: Option<Ipv4Addr>,
99    /// Assigned IPv6 address
100    assigned_ipv6: Option<Ipv6Addr>,
101    /// UDP socket for communication
102    socket: Option<UdpSocket>,
103    /// Border Relay address (MAP-E)
104    border_relay: Option<Ipv6Addr>,
105    /// NAT translation table (MAP-T)
106    translation_table: HashMap<(Ipv4Addr, u16), (Ipv6Addr, u16)>,
107}
108
109impl MapTunnel {
110    /// Create a new MAP tunnel
111    pub fn new(config: TunnelConfig, protocol_variant: MapProtocol) -> Result<Self> {
112        match config.protocol {
113            TunnelProtocol::MapE if protocol_variant != MapProtocol::MapE => {
114                return Err(P2PError::Config("Protocol mismatch: expected MAP-E".to_string()));
115            }
116            TunnelProtocol::MapT if protocol_variant != MapProtocol::MapT => {
117                return Err(P2PError::Config("Protocol mismatch: expected MAP-T".to_string()));
118            }
119            TunnelProtocol::MapE | TunnelProtocol::MapT => {
120                // Correct protocol match
121            }
122            _ => {
123                return Err(P2PError::Config("Invalid protocol for MAP tunnel".to_string()));
124            }
125        }
126
127        info!("Creating MAP tunnel: {:?}", protocol_variant);
128
129        Ok(Self {
130            protocol_variant,
131            config,
132            state: TunnelState::Disconnected,
133            metrics: TunnelMetrics::default(),
134            map_rules: Vec::new(),
135            port_set: None,
136            local_ipv4: None,
137            assigned_ipv6: None,
138            socket: None,
139            border_relay: None,
140            translation_table: HashMap::new(),
141        })
142    }
143
144    /// Add a MAP rule to the configuration
145    pub fn add_map_rule(&mut self, rule: MapRule) {
146        info!("Adding MAP rule: IPv6 prefix: {}/{}, IPv4 prefix: {}/{}", 
147              rule.ipv6_prefix, rule.ipv6_prefix_len,
148              rule.ipv4_prefix, rule.ipv4_prefix_len);
149        
150        if rule.border_relay.is_some() && self.protocol_variant == MapProtocol::MapE {
151            self.border_relay = rule.border_relay;
152        }
153        
154        self.map_rules.push(rule);
155    }
156
157    /// Calculate IPv6 address from IPv4 address and MAP rule
158    pub fn calculate_ipv6_address(&self, ipv4_addr: Ipv4Addr, rule: &MapRule) -> Result<Ipv6Addr> {
159        // Extract the interface identifier from IPv4 address
160        let ipv4_bytes = ipv4_addr.octets();
161        let ipv4_suffix = u32::from_be_bytes(ipv4_bytes);
162        
163        // Calculate PSID from IPv4 address
164        let host_bits = 32 - rule.ipv4_prefix_len;
165        let psid_bits = rule.port_params.psid_length;
166        
167        if host_bits < psid_bits {
168            return Err(P2PError::Config("Invalid MAP rule: insufficient host bits for PSID".to_string()));
169        }
170        
171        // Extract PSID from IPv4 address
172        let psid_mask = (1u32 << psid_bits) - 1;
173        let psid_shift = host_bits - psid_bits;
174        let psid = (ipv4_suffix >> psid_shift) & psid_mask;
175        
176        // Construct IPv6 address: prefix + IPv4 + PSID
177        let prefix_bytes = rule.ipv6_prefix.octets();
178        let mut ipv6_bytes = [0u8; 16];
179        
180        // Copy IPv6 prefix
181        let prefix_len = rule.ipv6_prefix_len as usize / 8;
182        ipv6_bytes[..prefix_len].copy_from_slice(&prefix_bytes[..prefix_len]);
183        
184        // Embed IPv4 address
185        ipv6_bytes[prefix_len..prefix_len + 4].copy_from_slice(&ipv4_bytes);
186        
187        // Embed PSID
188        if psid_bits > 0 {
189            let psid_bytes = (psid as u16).to_be_bytes();
190            ipv6_bytes[prefix_len + 4..prefix_len + 6].copy_from_slice(&psid_bytes);
191        }
192        
193        Ok(Ipv6Addr::from(ipv6_bytes))
194    }
195
196    /// Calculate port set for a given PSID
197    pub fn calculate_port_set(&self, psid: u16, rule: &MapRule) -> PortSet {
198        let port_params = &rule.port_params;
199        
200        // Calculate port range
201        let total_ports = 65536u32;
202        let excluded_ports = port_params.excluded_ports as u32;
203        let ports_per_set = if port_params.psid_length > 0 {
204            ((total_ports - excluded_ports) >> port_params.psid_length) as u16
205        } else {
206            (total_ports - excluded_ports) as u16
207        };
208        
209        let start_port = port_params.excluded_ports + (psid * ports_per_set);
210        
211        // Generate available ports in the set
212        let mut available_ports = Vec::new();
213        for i in 0..ports_per_set {
214            let port = start_port + i;
215            if port > 0 && port < 65535 {
216                available_ports.push(port);
217            }
218        }
219        
220        PortSet {
221            psid,
222            start_port,
223            port_count: ports_per_set,
224            available_ports,
225        }
226    }
227
228    /// Extract PSID from IPv4 address using MAP rule
229    pub fn extract_psid(&self, ipv4_addr: Ipv4Addr, rule: &MapRule) -> u16 {
230        let ipv4_bytes = ipv4_addr.octets();
231        let ipv4_u32 = u32::from_be_bytes(ipv4_bytes);
232        
233        let host_bits = 32 - rule.ipv4_prefix_len;
234        let psid_bits = rule.port_params.psid_length;
235        
236        if psid_bits == 0 {
237            return 0;
238        }
239        
240        let psid_mask = (1u32 << psid_bits) - 1;
241        let psid_shift = host_bits - psid_bits;
242        
243        ((ipv4_u32 >> psid_shift) & psid_mask) as u16
244    }
245
246    /// Initialize local IPv4 address and generate ISATAP address (public for testing)
247    pub async fn initialize_addresses(&mut self) -> Result<()> {
248        self.initialize_map().await
249    }
250
251    /// Initialize MAP configuration
252    async fn initialize_map(&mut self) -> Result<()> {
253        if self.map_rules.is_empty() {
254            return Err(P2PError::Config("No MAP rules configured".to_string()));
255        }
256
257        // Use the first rule for initialization (in practice, would select best rule)
258        let rule = &self.map_rules[0].clone();
259        
260        // Get local IPv4 address
261        let local_ipv4 = self.get_local_ipv4().await?;
262        self.local_ipv4 = Some(local_ipv4);
263        
264        // Calculate IPv6 address
265        let ipv6_addr = self.calculate_ipv6_address(local_ipv4, rule)?;
266        self.assigned_ipv6 = Some(ipv6_addr);
267        
268        // Calculate port set
269        let psid = self.extract_psid(local_ipv4, rule);
270        let port_set = self.calculate_port_set(psid, rule);
271        self.port_set = Some(port_set);
272        
273        info!("MAP initialization complete: IPv4={}, IPv6={}, PSID={}", 
274              local_ipv4, ipv6_addr, psid);
275        
276        Ok(())
277    }
278
279    /// Get local IPv4 address
280    async fn get_local_ipv4(&self) -> Result<Ipv4Addr> {
281        if let Some(addr) = self.config.local_ipv4 {
282            return Ok(addr);
283        }
284
285        // Auto-detect local IPv4 address
286        match tokio::net::UdpSocket::bind("0.0.0.0:0").await {
287            Ok(socket) => {
288                if socket.connect("8.8.8.8:53").await.is_ok() {
289                    if let Ok(local_addr) = socket.local_addr() {
290                        if let IpAddr::V4(ipv4) = local_addr.ip() {
291                            return Ok(ipv4);
292                        }
293                    }
294                }
295            }
296            Err(e) => {
297                warn!("Failed to detect local IPv4 address: {}", e);
298            }
299        }
300
301        Err(P2PError::Network("Could not determine local IPv4 address".to_string()))
302    }
303
304    /// Create UDP socket for MAP communication
305    async fn create_socket(&mut self) -> Result<()> {
306        let local_ipv4 = self.local_ipv4.ok_or_else(|| {
307            P2PError::Config("Local IPv4 address not initialized".to_string())
308        })?;
309
310        let bind_addr = SocketAddr::new(IpAddr::V4(local_ipv4), 0);
311        let socket = UdpSocket::bind(bind_addr).await
312            .map_err(|e| P2PError::Network(format!("Failed to create MAP socket: {}", e)))?;
313
314        info!("Created MAP socket on: {}", socket.local_addr().unwrap());
315        self.socket = Some(socket);
316        Ok(())
317    }
318
319    /// Encapsulate IPv4 packet in IPv6 for MAP-E
320    pub fn encapsulate_ipv4_in_ipv6(&self, ipv4_packet: &[u8]) -> Result<Vec<u8>> {
321        if self.protocol_variant != MapProtocol::MapE {
322            return Err(P2PError::Transport("MAP-E encapsulation requires MAP-E protocol".to_string()));
323        }
324
325        if ipv4_packet.len() < 20 {
326            return Err(P2PError::Transport("IPv4 packet too short".to_string()));
327        }
328
329        let local_ipv6 = self.assigned_ipv6.ok_or_else(|| {
330            P2PError::Network("Local IPv6 address not available".to_string())
331        })?;
332
333        let border_relay = self.border_relay.ok_or_else(|| {
334            P2PError::Config("Border relay not configured".to_string())
335        })?;
336
337        // Create IPv6 header for encapsulation
338        let mut ipv6_packet = Vec::with_capacity(40 + ipv4_packet.len());
339        
340        // IPv6 header (40 bytes)
341        ipv6_packet.push(0x60); // Version=6, Traffic Class=0
342        ipv6_packet.extend_from_slice(&[0x00, 0x00, 0x00]); // Traffic Class + Flow Label
343        ipv6_packet.extend_from_slice(&((ipv4_packet.len()) as u16).to_be_bytes()); // Payload Length
344        ipv6_packet.push(4); // Next Header = IPv4
345        ipv6_packet.push(64); // Hop Limit
346        ipv6_packet.extend_from_slice(&local_ipv6.octets()); // Source Address
347        ipv6_packet.extend_from_slice(&border_relay.octets()); // Destination Address
348
349        // Append IPv4 payload
350        ipv6_packet.extend_from_slice(ipv4_packet);
351
352        Ok(ipv6_packet)
353    }
354
355    /// Translate IPv4 packet to IPv6 for MAP-T
356    pub fn translate_ipv4_to_ipv6(&mut self, ipv4_packet: &[u8]) -> Result<Vec<u8>> {
357        if self.protocol_variant != MapProtocol::MapT {
358            return Err(P2PError::Transport("MAP-T translation requires MAP-T protocol".to_string()));
359        }
360
361        if ipv4_packet.len() < 20 {
362            return Err(P2PError::Transport("IPv4 packet too short".to_string()));
363        }
364
365        // Parse IPv4 header
366        let src_ipv4 = Ipv4Addr::from(<[u8; 4]>::try_from(&ipv4_packet[12..16]).unwrap());
367        let dst_ipv4 = Ipv4Addr::from(<[u8; 4]>::try_from(&ipv4_packet[16..20]).unwrap());
368        
369        // Get port information if TCP/UDP
370        let protocol = ipv4_packet[9];
371        let (src_port, _dst_port) = if protocol == 6 || protocol == 17 { // TCP or UDP
372            if ipv4_packet.len() >= 24 {
373                let src_port = u16::from_be_bytes([ipv4_packet[20], ipv4_packet[21]]);
374                let dst_port = u16::from_be_bytes([ipv4_packet[22], ipv4_packet[23]]);
375                (src_port, dst_port)
376            } else {
377                (0, 0)
378            }
379        } else {
380            (0, 0)
381        };
382
383        // Calculate corresponding IPv6 addresses using MAP rules
384        let rule = &self.map_rules[0]; // Use first rule
385        let src_ipv6 = self.calculate_ipv6_address(src_ipv4, rule)?;
386        let dst_ipv6 = self.calculate_ipv6_address(dst_ipv4, rule)?;
387
388        // Store translation for return traffic
389        self.translation_table.insert((src_ipv4, src_port), (src_ipv6, src_port));
390
391        // Create IPv6 packet
392        let payload_len = ipv4_packet.len() - 20; // Remove IPv4 header
393        let mut ipv6_packet = Vec::with_capacity(40 + payload_len);
394        
395        // IPv6 header
396        ipv6_packet.push(0x60); // Version=6
397        ipv6_packet.extend_from_slice(&[0x00, 0x00, 0x00]); // Traffic Class + Flow Label
398        ipv6_packet.extend_from_slice(&(payload_len as u16).to_be_bytes()); // Payload Length
399        ipv6_packet.push(protocol); // Next Header (same as IPv4 protocol)
400        ipv6_packet.push(64); // Hop Limit
401        ipv6_packet.extend_from_slice(&src_ipv6.octets()); // Source Address
402        ipv6_packet.extend_from_slice(&dst_ipv6.octets()); // Destination Address
403
404        // Append payload (everything after IPv4 header)
405        ipv6_packet.extend_from_slice(&ipv4_packet[20..]);
406
407        Ok(ipv6_packet)
408    }
409
410    /// Validate port against assigned port set
411    pub fn is_port_allowed(&self, port: u16) -> bool {
412        if let Some(ref port_set) = self.port_set {
413            port_set.available_ports.contains(&port)
414        } else {
415            false
416        }
417    }
418}
419
420#[async_trait]
421impl Tunnel for MapTunnel {
422    fn protocol(&self) -> TunnelProtocol {
423        match self.protocol_variant {
424            MapProtocol::MapE => TunnelProtocol::MapE,
425            MapProtocol::MapT => TunnelProtocol::MapT,
426        }
427    }
428
429    fn config(&self) -> &TunnelConfig {
430        &self.config
431    }
432
433    async fn state(&self) -> TunnelState {
434        self.state.clone()
435    }
436
437    async fn metrics(&self) -> TunnelMetrics {
438        self.metrics.clone()
439    }
440
441    async fn connect(&mut self) -> Result<()> {
442        info!("Connecting MAP tunnel: {:?}", self.protocol_variant);
443        self.state = TunnelState::Connecting;
444
445        // Initialize MAP configuration
446        if let Err(e) = self.initialize_map().await {
447            self.state = TunnelState::Failed(format!("MAP initialization failed: {}", e));
448            return Err(e);
449        }
450
451        // Create communication socket
452        if let Err(e) = self.create_socket().await {
453            self.state = TunnelState::Failed(format!("Socket creation failed: {}", e));
454            return Err(e);
455        }
456
457        self.state = TunnelState::Connected;
458        info!("MAP tunnel connected successfully: {:?}", self.protocol_variant);
459        Ok(())
460    }
461
462    async fn is_active(&self) -> bool {
463        matches!(self.state, TunnelState::Connected)
464    }
465
466    async fn disconnect(&mut self) -> Result<()> {
467        info!("Disconnecting MAP tunnel");
468        
469        if let Some(socket) = self.socket.take() {
470            drop(socket);
471        }
472
473        self.state = TunnelState::Disconnected;
474        self.translation_table.clear();
475        info!("MAP tunnel disconnected");
476        Ok(())
477    }
478
479    async fn encapsulate(&self, ipv4_packet: &[u8]) -> Result<Vec<u8>> {
480        if !self.is_active().await {
481            return Err(P2PError::Network("MAP tunnel not connected".to_string()));
482        }
483
484        match self.protocol_variant {
485            MapProtocol::MapE => self.encapsulate_ipv4_in_ipv6(ipv4_packet),
486            MapProtocol::MapT => {
487                // For MAP-T, we need mutable access for translation table
488                Err(P2PError::Transport("MAP-T encapsulation requires mutable access".to_string()))
489            }
490        }
491    }
492
493    async fn decapsulate(&self, packet: &[u8]) -> Result<Vec<u8>> {
494        if !self.is_active().await {
495            return Err(P2PError::Network("MAP tunnel not connected".to_string()));
496        }
497
498        match self.protocol_variant {
499            MapProtocol::MapE => {
500                // For MAP-E, extract IPv4 from IPv6
501                if packet.len() < 40 {
502                    return Err(P2PError::Transport("IPv6 packet too short".to_string()));
503                }
504                if packet[6] != 4 { // Next Header must be IPv4
505                    return Err(P2PError::Transport("Not an IPv4-in-IPv6 packet".to_string()));
506                }
507                Ok(packet[40..].to_vec())
508            }
509            MapProtocol::MapT => {
510                // For MAP-T, this would be IPv6-to-IPv4 translation
511                Err(P2PError::Transport("MAP-T decapsulation not implemented in immutable context".to_string()))
512            }
513        }
514    }
515
516    async fn send(&mut self, packet: &[u8]) -> Result<()> {
517        let socket = self.socket.as_ref().ok_or_else(|| {
518            P2PError::Network("MAP socket not available".to_string())
519        })?;
520
521        // For MAP, determine destination based on protocol variant
522        let dest_addr = match self.protocol_variant {
523            MapProtocol::MapE => {
524                // Send to border relay
525                let br = self.border_relay.ok_or_else(|| {
526                    P2PError::Config("Border relay not configured".to_string())
527                })?;
528                SocketAddr::new(IpAddr::V6(br), 0)
529            }
530            MapProtocol::MapT => {
531                // For MAP-T, destination depends on packet content
532                return Err(P2PError::Transport("MAP-T send not implemented".to_string()));
533            }
534        };
535
536        socket.send_to(packet, dest_addr).await
537            .map_err(|e| P2PError::Network(format!("Failed to send MAP packet: {}", e)))?;
538
539        self.metrics.packets_sent += 1;
540        self.metrics.bytes_sent += packet.len() as u64;
541        Ok(())
542    }
543
544    async fn receive(&mut self) -> Result<Vec<u8>> {
545        let socket = self.socket.as_ref().ok_or_else(|| {
546            P2PError::Network("MAP socket not available".to_string())
547        })?;
548
549        let mut buffer = vec![0u8; 1500];
550        let (size, _) = socket.recv_from(&mut buffer).await
551            .map_err(|e| P2PError::Network(format!("Failed to receive MAP packet: {}", e)))?;
552
553        buffer.truncate(size);
554        self.metrics.packets_received += 1;
555        self.metrics.bytes_received += size as u64;
556        Ok(buffer)
557    }
558
559    async fn maintain(&mut self) -> Result<()> {
560        // MAP protocols are generally stateless, minimal maintenance needed
561        debug!("MAP tunnel maintenance: translation table size: {}", 
562               self.translation_table.len());
563        
564        // Clean old translation entries (simple timeout-based cleanup)
565        if self.translation_table.len() > 10000 {
566            warn!("MAP translation table growing large, consider cleanup");
567            // In production, implement proper LRU or timeout-based cleanup
568        }
569        
570        Ok(())
571    }
572
573    async fn local_ipv6_addr(&self) -> Result<Ipv6Addr> {
574        self.assigned_ipv6.ok_or_else(|| {
575            P2PError::Network("Local IPv6 address not available".to_string())
576        })
577    }
578
579    async fn local_ipv4_addr(&self) -> Result<Ipv4Addr> {
580        self.local_ipv4.ok_or_else(|| {
581            P2PError::Network("Local IPv4 address not available".to_string())
582        })
583    }
584
585    async fn ping(&mut self, _timeout: Duration) -> Result<Duration> {
586        // For MAP protocols, ping would go through the mapping mechanism
587        let start = Instant::now();
588        
589        match self.protocol_variant {
590            MapProtocol::MapE => {
591                if self.border_relay.is_none() {
592                    return Err(P2PError::Network("No border relay configured for ping".to_string()));
593                }
594                // Would implement actual ping to border relay
595            }
596            MapProtocol::MapT => {
597                // For MAP-T, ping would be translated and sent
598                // Would implement actual translated ping
599            }
600        }
601        
602        // Simulated ping response
603        tokio::time::sleep(Duration::from_millis(20)).await;
604        Ok(start.elapsed())
605    }
606}
607