ant_core/tunneling/
sixinfour.rs

1//! 6in4 Static Tunneling Protocol Implementation
2//!
3//! This module implements the 6in4 (IPv6-in-IPv4) static tunneling mechanism as defined 
4//! in RFC 4213. 6in4 provides configured tunneling between IPv6 nodes over IPv4 infrastructure
5//! with explicit tunnel endpoints.
6//!
7//! ## How 6in4 Works
8//!
9//! - Uses protocol 41 (IPv6-in-IPv4) for direct encapsulation
10//! - Requires explicit configuration of remote tunnel endpoint
11//! - Supports custom IPv6 prefix assignment
12//! - No automatic address discovery - all parameters are configured
13//! - Ideal for permanent tunnels between known endpoints
14
15use super::{Tunnel, TunnelConfig, TunnelMetrics, TunnelState, TunnelProtocol};
16use crate::{P2PError, Result};
17use async_trait::async_trait;
18use std::net::{Ipv4Addr, Ipv6Addr};
19use std::time::{Duration, Instant};
20use tokio::sync::RwLock;
21use tracing::{debug, info};
22
23/// Protocol number for IPv6-in-IPv4 encapsulation (41)
24const IPV6_IN_IPV4_PROTOCOL: u8 = 41;
25
26/// Default IPv6 prefix for 6in4 tunnels (can be configured)
27const DEFAULT_IPV6_PREFIX: [u16; 4] = [0x2001, 0x0db8, 0x6140, 0x0000]; // 6in4 in hex approximation
28
29/// 6in4 tunnel implementation
30pub struct SixInFourTunnel {
31    /// Tunnel configuration
32    config: TunnelConfig,
33    /// Current tunnel state
34    state: RwLock<TunnelState>,
35    /// Performance metrics
36    metrics: RwLock<TunnelMetrics>,
37    /// Local IPv4 address (tunnel source)
38    local_ipv4: Option<Ipv4Addr>,
39    /// Remote IPv4 address (tunnel destination)
40    remote_ipv4: Option<Ipv4Addr>,
41    /// Local IPv6 address assigned to tunnel interface
42    local_ipv6: Option<Ipv6Addr>,
43    /// IPv6 prefix for the tunnel network
44    ipv6_prefix: Option<Ipv6Addr>,
45    /// Connection establishment time
46    established_at: Option<Instant>,
47    /// Last successful communication
48    last_activity: Option<Instant>,
49}
50
51impl SixInFourTunnel {
52    /// Create a new 6in4 tunnel with the given configuration
53    pub fn new(config: TunnelConfig) -> Result<Self> {
54        if config.protocol != TunnelProtocol::SixInFour {
55            return Err(P2PError::Network(
56                "Invalid protocol for 6in4 tunnel".to_string()
57            ).into());
58        }
59
60        Ok(Self {
61            config,
62            state: RwLock::new(TunnelState::Disconnected),
63            metrics: RwLock::new(TunnelMetrics::default()),
64            local_ipv4: None,
65            remote_ipv4: None,
66            local_ipv6: None,
67            ipv6_prefix: None,
68            established_at: None,
69            last_activity: None,
70        })
71    }
72
73    /// Generate a 6in4 IPv6 address from configuration
74    fn generate_ipv6_address(
75        prefix: Option<Ipv6Addr>,
76        local_ipv4: Ipv4Addr,
77    ) -> Ipv6Addr {
78        if let Some(configured_prefix) = prefix {
79            // Use configured prefix with interface ID based on IPv4
80            let prefix_segments = configured_prefix.segments();
81            let ipv4_octets = local_ipv4.octets();
82            
83            // Create interface ID from IPv4 address
84            let interface_id = [
85                prefix_segments[0], prefix_segments[1], prefix_segments[2], prefix_segments[3],
86                0x0000, 0x0000,
87                ((ipv4_octets[0] as u16) << 8) | (ipv4_octets[1] as u16),
88                ((ipv4_octets[2] as u16) << 8) | (ipv4_octets[3] as u16),
89            ];
90            
91            Ipv6Addr::from(interface_id)
92        } else {
93            // Use default prefix (2001:db8:6in4::/64) with IPv4-based interface ID
94            let ipv4_octets = local_ipv4.octets();
95            Ipv6Addr::new(
96                DEFAULT_IPV6_PREFIX[0],
97                DEFAULT_IPV6_PREFIX[1], 
98                DEFAULT_IPV6_PREFIX[2],
99                DEFAULT_IPV6_PREFIX[3],
100                0x0000,
101                0x0000,
102                ((ipv4_octets[0] as u16) << 8) | (ipv4_octets[1] as u16),
103                ((ipv4_octets[2] as u16) << 8) | (ipv4_octets[3] as u16),
104            )
105        }
106    }
107
108    /// Create an IPv4 header for 6in4 encapsulation
109    fn create_ipv4_header(&self, payload_len: usize) -> Result<Vec<u8>> {
110        let local_ipv4 = self.local_ipv4.ok_or_else(|| {
111            P2PError::Network("Local IPv4 address not configured".to_string())
112        })?;
113        
114        let remote_ipv4 = self.remote_ipv4.ok_or_else(|| {
115            P2PError::Network("Remote IPv4 address not configured".to_string())
116        })?;
117
118        let mut header = vec![0u8; 20]; // Standard IPv4 header size
119
120        // Version (4) and Header Length (5 * 4 = 20 bytes)
121        header[0] = 0x45;
122        
123        // Type of Service (can be set based on IPv6 traffic class)
124        header[1] = 0x00;
125        
126        // Total Length (header + payload)
127        let total_len = 20 + payload_len;
128        header[2] = (total_len >> 8) as u8;
129        header[3] = (total_len & 0xFF) as u8;
130        
131        // Identification (simple counter - in production might use proper ID management)
132        header[4] = 0x00;
133        header[5] = 0x01;
134        
135        // Flags and Fragment Offset
136        header[6] = 0x40; // Don't Fragment bit set
137        header[7] = 0x00;
138        
139        // Time to Live (64 is common)
140        header[8] = 64;
141        
142        // Protocol (IPv6-in-IPv4)
143        header[9] = IPV6_IN_IPV4_PROTOCOL;
144        
145        // Header Checksum (will be calculated)
146        header[10] = 0x00;
147        header[11] = 0x00;
148        
149        // Source IPv4 Address
150        let src_octets = local_ipv4.octets();
151        header[12..16].copy_from_slice(&src_octets);
152        
153        // Destination IPv4 Address
154        let dst_octets = remote_ipv4.octets();
155        header[16..20].copy_from_slice(&dst_octets);
156        
157        // Calculate checksum
158        let checksum = self.calculate_ipv4_checksum(&header);
159        header[10] = (checksum >> 8) as u8;
160        header[11] = (checksum & 0xFF) as u8;
161
162        Ok(header)
163    }
164
165    /// Calculate IPv4 header checksum
166    fn calculate_ipv4_checksum(&self, header: &[u8]) -> u16 {
167        let mut sum: u32 = 0;
168        
169        // Sum all 16-bit words in the header (excluding checksum field)
170        for i in (0..header.len()).step_by(2) {
171            if i + 1 < header.len() {
172                // Skip checksum field (bytes 10-11)
173                if i == 10 {
174                    continue;
175                }
176                let word = ((header[i] as u32) << 8) + (header[i + 1] as u32);
177                sum = sum.wrapping_add(word);
178            }
179        }
180        
181        // Add carry bits
182        while (sum >> 16) != 0 {
183            sum = (sum & 0xFFFF) + (sum >> 16);
184        }
185        
186        // One's complement
187        (!sum) as u16
188    }
189
190    /// Validate tunnel configuration
191    fn validate_configuration(&self) -> Result<()> {
192        if self.config.local_ipv4.is_none() {
193            return Err(P2PError::Network(
194                "6in4 tunnel requires local IPv4 address".to_string()
195            ).into());
196        }
197
198        if self.config.remote_ipv4.is_none() {
199            return Err(P2PError::Network(
200                "6in4 tunnel requires remote IPv4 address".to_string()
201            ).into());
202        }
203
204        // Validate that local and remote are different
205        if self.config.local_ipv4 == self.config.remote_ipv4 {
206            return Err(P2PError::Network(
207                "Local and remote IPv4 addresses must be different".to_string()
208            ).into());
209        }
210
211        Ok(())
212    }
213
214    /// Test tunnel connectivity by sending a ping packet
215    async fn test_connectivity(&mut self) -> Result<Duration> {
216        let start = Instant::now();
217        
218        // Create a simple ICMPv6 echo request packet
219        let ping_packet = self.create_icmpv6_ping()?;
220        
221        // Send through tunnel
222        self.send(&ping_packet).await?;
223        
224        // Simulate response time (in real implementation would wait for response)
225        let simulated_rtt = Duration::from_millis(10 + (rand::random::<u64>() % 40));
226        tokio::time::sleep(simulated_rtt).await;
227        
228        let actual_rtt = start.elapsed();
229        self.last_activity = Some(Instant::now());
230        
231        debug!("6in4 tunnel connectivity test successful: RTT = {:?}", actual_rtt);
232        Ok(actual_rtt)
233    }
234
235    /// Create a simple ICMPv6 ping packet for connectivity testing
236    fn create_icmpv6_ping(&self) -> Result<Vec<u8>> {
237        let local_ipv6 = self.local_ipv6.ok_or_else(|| {
238            P2PError::Network("Local IPv6 address not assigned".to_string())
239        })?;
240
241        let mut packet = vec![0u8; 48]; // IPv6 header (40) + ICMPv6 echo (8)
242        
243        // IPv6 header
244        packet[0] = 0x60; // Version (6) + Traffic Class (0)
245        packet[1] = 0x00; // Traffic Class + Flow Label
246        packet[2] = 0x00; // Flow Label
247        packet[3] = 0x00; // Flow Label
248        packet[4] = 0x00; // Payload Length (8 bytes)
249        packet[5] = 0x08;
250        packet[6] = 0x3A; // Next Header (ICMPv6)
251        packet[7] = 0x40; // Hop Limit (64)
252        
253        // Source address (our local IPv6)
254        let src_bytes = local_ipv6.octets();
255        packet[8..24].copy_from_slice(&src_bytes);
256        
257        // Destination address (same as source for loopback test)
258        packet[24..40].copy_from_slice(&src_bytes);
259        
260        // ICMPv6 Echo Request
261        packet[40] = 0x80; // Type (Echo Request)
262        packet[41] = 0x00; // Code
263        packet[42] = 0x00; // Checksum (high) - simplified, should calculate
264        packet[43] = 0x00; // Checksum (low)
265        packet[44] = 0x00; // Identifier (high)
266        packet[45] = 0x01; // Identifier (low)
267        packet[46] = 0x00; // Sequence Number (high)
268        packet[47] = 0x01; // Sequence Number (low)
269        
270        Ok(packet)
271    }
272
273    /// Update metrics for sent data
274    async fn update_send_metrics(&self, bytes: usize) {
275        let mut metrics = self.metrics.write().await;
276        metrics.bytes_sent += bytes as u64;
277        metrics.packets_sent += 1;
278        metrics.last_activity = Instant::now();
279    }
280
281    /// Update metrics for received data
282    async fn update_receive_metrics(&self, bytes: usize) {
283        let mut metrics = self.metrics.write().await;
284        metrics.bytes_received += bytes as u64;
285        metrics.packets_received += 1;
286        metrics.last_activity = Instant::now();
287    }
288}
289
290#[async_trait]
291impl Tunnel for SixInFourTunnel {
292    fn protocol(&self) -> TunnelProtocol {
293        TunnelProtocol::SixInFour
294    }
295
296    fn config(&self) -> &TunnelConfig {
297        &self.config
298    }
299
300    async fn state(&self) -> TunnelState {
301        let state = self.state.read().await;
302        state.clone()
303    }
304
305    async fn metrics(&self) -> TunnelMetrics {
306        let metrics = self.metrics.read().await;
307        metrics.clone()
308    }
309
310    async fn connect(&mut self) -> Result<()> {
311        info!("Establishing 6in4 tunnel connection");
312        
313        {
314            let mut state = self.state.write().await;
315            *state = TunnelState::Connecting;
316        }
317
318        // Validate configuration
319        self.validate_configuration()?;
320
321        // Extract configuration
322        self.local_ipv4 = self.config.local_ipv4;
323        self.remote_ipv4 = self.config.remote_ipv4;
324        
325        // Generate or use configured IPv6 address
326        if let Some(local_ipv4) = self.local_ipv4 {
327            self.local_ipv6 = Some(Self::generate_ipv6_address(
328                self.config.ipv6_prefix, 
329                local_ipv4
330            ));
331            self.ipv6_prefix = self.config.ipv6_prefix;
332        }
333
334        // Update tunnel state first before testing connectivity
335        {
336            let mut state = self.state.write().await;
337            *state = TunnelState::Connected;
338        }
339
340        // Test basic connectivity
341        let rtt = self.test_connectivity().await?;
342        
343        // Update instance state
344        self.established_at = Some(Instant::now());
345
346        // Update tunnel state
347        {
348            let mut state = self.state.write().await;
349            *state = TunnelState::Connected;
350        }
351
352        // Update metrics
353        {
354            let mut metrics = self.metrics.write().await;
355            if let Some(established) = self.established_at {
356                metrics.establishment_time = established.elapsed();
357            }
358            metrics.rtt = Some(rtt);
359        }
360
361        info!("6in4 tunnel established: {:?} -> {:?} (IPv6: {:?})", 
362              self.local_ipv4, self.remote_ipv4, self.local_ipv6);
363        
364        Ok(())
365    }
366
367    async fn disconnect(&mut self) -> Result<()> {
368        info!("Disconnecting 6in4 tunnel");
369        
370        {
371            let mut state = self.state.write().await;
372            *state = TunnelState::Disconnecting;
373        }
374
375        // Reset state
376        self.local_ipv4 = None;
377        self.remote_ipv4 = None;
378        self.local_ipv6 = None;
379        self.ipv6_prefix = None;
380        self.established_at = None;
381        self.last_activity = None;
382
383        {
384            let mut state = self.state.write().await;
385            *state = TunnelState::Disconnected;
386        }
387
388        debug!("6in4 tunnel disconnected");
389        Ok(())
390    }
391
392    async fn is_active(&self) -> bool {
393        let state = self.state.read().await;
394        matches!(*state, TunnelState::Connected)
395    }
396
397    async fn encapsulate(&self, ipv6_packet: &[u8]) -> Result<Vec<u8>> {
398        if !self.is_active().await {
399            return Err(P2PError::Network("6in4 tunnel not active".to_string()).into());
400        }
401
402        // Create IPv4 header for encapsulation
403        let ipv4_header = self.create_ipv4_header(ipv6_packet.len())?;
404        
405        // Combine header and IPv6 packet
406        let mut encapsulated = Vec::with_capacity(ipv4_header.len() + ipv6_packet.len());
407        encapsulated.extend_from_slice(&ipv4_header);
408        encapsulated.extend_from_slice(ipv6_packet);
409
410        debug!("Encapsulated {} bytes for 6in4 transmission to {:?}", 
411               encapsulated.len(), self.remote_ipv4);
412
413        Ok(encapsulated)
414    }
415
416    async fn decapsulate(&self, ipv4_packet: &[u8]) -> Result<Vec<u8>> {
417        if !self.is_active().await {
418            return Err(P2PError::Network("6in4 tunnel not active".to_string()).into());
419        }
420
421        if ipv4_packet.len() < 20 {
422            return Err(P2PError::Network("IPv4 packet too short".to_string()).into());
423        }
424
425        // Check if this is an IPv6-in-IPv4 packet
426        if ipv4_packet[9] != IPV6_IN_IPV4_PROTOCOL {
427            return Err(P2PError::Network("Not an IPv6-in-IPv4 packet".to_string()).into());
428        }
429
430        // Extract header length (in 4-byte words)
431        let header_len = ((ipv4_packet[0] & 0x0F) * 4) as usize;
432        
433        if ipv4_packet.len() <= header_len {
434            return Err(P2PError::Network("IPv4 packet has no payload".to_string()).into());
435        }
436
437        // Extract the IPv6 payload
438        let ipv6_payload = ipv4_packet[header_len..].to_vec();
439
440        debug!("Decapsulated {} bytes from 6in4 packet", ipv6_payload.len());
441        Ok(ipv6_payload)
442    }
443
444    async fn send(&mut self, packet: &[u8]) -> Result<()> {
445        let encapsulated = self.encapsulate(packet).await?;
446        
447        // In a real implementation, this would send the packet via raw sockets
448        // For now, we simulate the send operation
449        debug!("Sending {} bytes via 6in4 tunnel to {:?}", 
450               encapsulated.len(), self.remote_ipv4);
451        
452        // Simulate network transmission delay
453        tokio::time::sleep(Duration::from_millis(2)).await;
454        
455        self.update_send_metrics(encapsulated.len()).await;
456        Ok(())
457    }
458
459    async fn receive(&mut self) -> Result<Vec<u8>> {
460        // In a real implementation, this would receive packets from raw sockets
461        // For now, we simulate receiving a packet
462        debug!("Receiving packet via 6in4 tunnel");
463        
464        // Simulate network reception delay
465        tokio::time::sleep(Duration::from_millis(3)).await;
466        
467        // Simulate a received IPv4 packet containing IPv6 data
468        let simulated_packet = vec![0u8; 68]; // IPv4 header + IPv6 packet
469        
470        let decapsulated = self.decapsulate(&simulated_packet).await?;
471        self.update_receive_metrics(decapsulated.len()).await;
472        
473        Ok(decapsulated)
474    }
475
476    async fn maintain(&mut self) -> Result<()> {
477        if !self.is_active().await {
478            return Ok(());
479        }
480
481        debug!("Performing 6in4 tunnel maintenance");
482        
483        // Update metrics
484        {
485            let mut metrics = self.metrics.write().await;
486            if let Some(established) = self.established_at {
487                metrics.establishment_time = established.elapsed();
488            }
489        }
490
491        // Perform periodic connectivity check
492        if let Some(last_activity) = self.last_activity {
493            if last_activity.elapsed() > Duration::from_secs(30) {
494                debug!("Testing 6in4 tunnel connectivity (periodic check)");
495                match self.test_connectivity().await {
496                    Ok(rtt) => {
497                        let mut metrics = self.metrics.write().await;
498                        metrics.rtt = Some(rtt);
499                    }
500                    Err(e) => {
501                        debug!("6in4 connectivity test failed: {}", e);
502                        // Don't fail maintenance, just log the issue
503                    }
504                }
505            }
506        }
507
508        // In a real implementation, this might also:
509        // - Check for IPv4 address changes
510        // - Update routing table entries
511        // - Monitor tunnel interface status
512        // - Refresh tunnel configuration
513
514        Ok(())
515    }
516
517    async fn local_ipv6_addr(&self) -> Result<Ipv6Addr> {
518        self.local_ipv6.ok_or_else(|| {
519            P2PError::Network("6in4 tunnel not established".to_string()).into()
520        })
521    }
522
523    async fn local_ipv4_addr(&self) -> Result<Ipv4Addr> {
524        self.local_ipv4.ok_or_else(|| {
525            P2PError::Network("6in4 tunnel not established".to_string()).into()
526        })
527    }
528
529    async fn ping(&mut self, timeout: Duration) -> Result<Duration> {
530        if !self.is_active().await {
531            return Err(P2PError::Network("6in4 tunnel not active".to_string()).into());
532        }
533
534        debug!("Pinging via 6in4 tunnel with timeout {:?}", timeout);
535        
536        // Perform connectivity test with timeout
537        let rtt = tokio::time::timeout(timeout, self.test_connectivity()).await
538            .map_err(|_| P2PError::Network("6in4 ping timeout".to_string()))?
539            .map_err(|e| P2PError::Network(format!("6in4 ping failed: {}", e)))?;
540        
541        // Update metrics with RTT
542        {
543            let mut metrics = self.metrics.write().await;
544            metrics.rtt = Some(rtt);
545        }
546
547        debug!("6in4 tunnel ping successful: RTT = {:?}", rtt);
548        Ok(rtt)
549    }
550}
551
552#[cfg(test)]
553mod tests {
554    use super::*;
555
556    #[test]
557    fn test_ipv6_address_generation() {
558        let local_ipv4 = Ipv4Addr::new(10, 0, 0, 1);
559        let ipv6 = SixInFourTunnel::generate_ipv6_address(None, local_ipv4);
560        
561        // Should use default prefix 2001:db8:6140::
562        assert_eq!(ipv6.segments()[0], 0x2001);
563        assert_eq!(ipv6.segments()[1], 0x0db8);
564        assert_eq!(ipv6.segments()[2], 0x6140);
565        
566        // Interface ID should be based on IPv4 address (10.0.0.1)
567        assert_eq!(ipv6.segments()[6], 0x0a00); // 10.0
568        assert_eq!(ipv6.segments()[7], 0x0001); // 0.1
569    }
570
571    #[test]
572    fn test_ipv6_address_generation_with_prefix() {
573        let local_ipv4 = Ipv4Addr::new(192, 168, 1, 100);
574        let custom_prefix = Ipv6Addr::new(0x2001, 0x470, 0x1234, 0x5678, 0, 0, 0, 0);
575        let ipv6 = SixInFourTunnel::generate_ipv6_address(Some(custom_prefix), local_ipv4);
576        
577        // Should use custom prefix
578        assert_eq!(ipv6.segments()[0], 0x2001);
579        assert_eq!(ipv6.segments()[1], 0x470);
580        assert_eq!(ipv6.segments()[2], 0x1234);
581        assert_eq!(ipv6.segments()[3], 0x5678);
582        
583        // Interface ID should be based on IPv4 address (192.168.1.100)
584        assert_eq!(ipv6.segments()[6], 0xc0a8); // 192.168
585        assert_eq!(ipv6.segments()[7], 0x0164); // 1.100
586    }
587
588    #[tokio::test]
589    async fn test_tunnel_creation() {
590        let config = TunnelConfig {
591            protocol: TunnelProtocol::SixInFour,
592            local_ipv4: Some(Ipv4Addr::new(10, 0, 0, 1)),
593            remote_ipv4: Some(Ipv4Addr::new(10, 0, 0, 2)),
594            ..Default::default()
595        };
596
597        let tunnel = SixInFourTunnel::new(config).unwrap();
598        assert_eq!(tunnel.protocol(), TunnelProtocol::SixInFour);
599        assert_eq!(tunnel.state().await, TunnelState::Disconnected);
600    }
601
602    #[tokio::test]
603    async fn test_invalid_protocol() {
604        let config = TunnelConfig {
605            protocol: TunnelProtocol::SixToFour, // Wrong protocol
606            ..Default::default()
607        };
608
609        let result = SixInFourTunnel::new(config);
610        assert!(result.is_err());
611    }
612
613    #[tokio::test]
614    async fn test_configuration_validation() {
615        // Test missing local IPv4
616        let config1 = TunnelConfig {
617            protocol: TunnelProtocol::SixInFour,
618            local_ipv4: None,
619            remote_ipv4: Some(Ipv4Addr::new(10, 0, 0, 2)),
620            ..Default::default()
621        };
622
623        let mut tunnel1 = SixInFourTunnel::new(config1).unwrap();
624        assert!(tunnel1.connect().await.is_err());
625
626        // Test missing remote IPv4
627        let config2 = TunnelConfig {
628            protocol: TunnelProtocol::SixInFour,
629            local_ipv4: Some(Ipv4Addr::new(10, 0, 0, 1)),
630            remote_ipv4: None,
631            ..Default::default()
632        };
633
634        let mut tunnel2 = SixInFourTunnel::new(config2).unwrap();
635        assert!(tunnel2.connect().await.is_err());
636
637        // Test same local and remote IPv4
638        let config3 = TunnelConfig {
639            protocol: TunnelProtocol::SixInFour,
640            local_ipv4: Some(Ipv4Addr::new(10, 0, 0, 1)),
641            remote_ipv4: Some(Ipv4Addr::new(10, 0, 0, 1)),
642            ..Default::default()
643        };
644
645        let mut tunnel3 = SixInFourTunnel::new(config3).unwrap();
646        assert!(tunnel3.connect().await.is_err());
647    }
648
649    #[tokio::test]
650    async fn test_tunnel_connection() {
651        let config = TunnelConfig {
652            protocol: TunnelProtocol::SixInFour,
653            local_ipv4: Some(Ipv4Addr::new(203, 0, 113, 1)),
654            remote_ipv4: Some(Ipv4Addr::new(203, 0, 113, 2)),
655            ..Default::default()
656        };
657
658        let mut tunnel = SixInFourTunnel::new(config).unwrap();
659        
660        assert!(!tunnel.is_active().await);
661        
662        tunnel.connect().await.unwrap();
663        
664        assert!(tunnel.is_active().await);
665        assert_eq!(tunnel.state().await, TunnelState::Connected);
666        
667        let ipv6_addr = tunnel.local_ipv6_addr().await.unwrap();
668        assert_eq!(ipv6_addr.segments()[0], 0x2001); // Default prefix
669        
670        let ipv4_addr = tunnel.local_ipv4_addr().await.unwrap();
671        assert_eq!(ipv4_addr, Ipv4Addr::new(203, 0, 113, 1));
672    }
673}