ant_core/tunneling/
teredo.rs

1//! Teredo Tunneling Protocol Implementation
2//!
3//! This module implements the Teredo tunneling mechanism as defined in RFC 4380.
4//! Teredo enables IPv6 connectivity for nodes located behind NAT devices by using
5//! UDP encapsulation and relay servers.
6//!
7//! ## How Teredo Works
8//!
9//! - Uses the IPv6 prefix 2001::/32 for Teredo addressing
10//! - Embeds NAT's public IPv4 address and UDP port in the IPv6 address
11//! - Uses UDP encapsulation to traverse NAT devices
12//! - Employs relay servers for initial connectivity and NAT traversal
13//! - Supports direct peer-to-peer communication after initial setup
14
15use super::{Tunnel, TunnelConfig, TunnelMetrics, TunnelState, TunnelProtocol};
16use crate::{P2PError, Result};
17use async_trait::async_trait;
18use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket};
19use std::time::{Duration, Instant};
20use tokio::sync::RwLock;
21use tracing::{debug, info};
22
23/// IPv6 prefix for Teredo tunneling (2001::/32)
24#[allow(dead_code)]
25const TEREDO_PREFIX: u32 = 0x2001_0000;
26
27/// Default Teredo server address (Using a public IPv4 address for testing)
28const DEFAULT_TEREDO_SERVER: &str = "65.55.158.118:3544";
29
30/// Teredo relay discovery multicast address
31#[allow(dead_code)]
32const TEREDO_DISCOVERY_ADDR: &str = "ff02::2:0000";
33
34/// Protocol number for IPv6-in-UDP encapsulation
35#[allow(dead_code)]
36const IPV6_IN_UDP_PROTOCOL: u8 = 41;
37
38/// Teredo packet types
39#[allow(dead_code)]
40#[derive(Debug, Clone, PartialEq)]
41enum TeredoPacketType {
42    /// Router Solicitation for initial setup
43    RouterSolicitation,
44    /// Router Advertisement response
45    RouterAdvertisement,
46    /// IPv6 packet encapsulated in Teredo
47    Data,
48    /// Bubble packet for NAT traversal
49    Bubble,
50}
51
52/// Teredo address components
53#[allow(dead_code)]
54#[derive(Debug, Clone)]
55struct TeredoAddress {
56    /// Server IPv4 address
57    server_ipv4: Ipv4Addr,
58    /// Flags (reserved for future use)
59    flags: u16,
60    /// Obfuscated external UDP port
61    obfuscated_port: u16,
62    /// Obfuscated external IPv4 address
63    obfuscated_ipv4: Ipv4Addr,
64}
65
66/// Teredo tunnel implementation
67pub struct TeredoTunnel {
68    /// Tunnel configuration
69    config: TunnelConfig,
70    /// Current tunnel state
71    state: RwLock<TunnelState>,
72    /// Performance metrics
73    metrics: RwLock<TunnelMetrics>,
74    /// Teredo server address
75    server_addr: SocketAddr,
76    /// Local UDP socket for Teredo communication
77    udp_socket: Option<UdpSocket>,
78    /// Generated Teredo IPv6 address
79    teredo_ipv6: Option<Ipv6Addr>,
80    /// External (public) IPv4 address discovered via Teredo server
81    external_ipv4: Option<Ipv4Addr>,
82    /// External UDP port discovered via Teredo server
83    external_port: Option<u16>,
84    /// Connection establishment time
85    established_at: Option<Instant>,
86    /// Last communication with Teredo server
87    last_server_contact: Option<Instant>,
88}
89
90impl TeredoTunnel {
91    /// Create a new Teredo tunnel with the given configuration
92    pub fn new(config: TunnelConfig) -> Result<Self> {
93        if config.protocol != TunnelProtocol::Teredo {
94            return Err(P2PError::Network(
95                "Invalid protocol for Teredo tunnel".to_string()
96            ).into());
97        }
98
99        // Parse Teredo server address
100        let server_addr = DEFAULT_TEREDO_SERVER.parse()
101            .map_err(|e| P2PError::Network(format!("Invalid Teredo server address: {}", e)))?;
102
103        Ok(Self {
104            config,
105            state: RwLock::new(TunnelState::Disconnected),
106            metrics: RwLock::new(TunnelMetrics::default()),
107            server_addr,
108            udp_socket: None,
109            teredo_ipv6: None,
110            external_ipv4: None,
111            external_port: None,
112            established_at: None,
113            last_server_contact: None,
114        })
115    }
116
117    /// Generate Teredo IPv6 address from discovered external address
118    fn generate_teredo_address(
119        server_ipv4: Ipv4Addr,
120        external_ipv4: Ipv4Addr,
121        external_port: u16,
122    ) -> Ipv6Addr {
123        let server_octets = server_ipv4.octets();
124        let external_octets = external_ipv4.octets();
125        
126        // Obfuscate the external address and port (XOR with 0xFFFF for security)
127        let obfuscated_port = external_port ^ 0xFFFF;
128        let obfuscated_addr = [
129            external_octets[0] ^ 0xFF,
130            external_octets[1] ^ 0xFF,
131            external_octets[2] ^ 0xFF,
132            external_octets[3] ^ 0xFF,
133        ];
134
135        Ipv6Addr::from([
136            0x20, 0x01,                           // Teredo prefix (2001::/32)
137            server_octets[0], server_octets[1],   // Server IPv4 address (high)
138            server_octets[2], server_octets[3],   // Server IPv4 address (low)
139            0x00, 0x00,                           // Flags (reserved)
140            (obfuscated_port >> 8) as u8,         // Obfuscated port (high)
141            (obfuscated_port & 0xFF) as u8,       // Obfuscated port (low)
142            obfuscated_addr[0], obfuscated_addr[1], // Obfuscated IPv4 (high)
143            obfuscated_addr[2], obfuscated_addr[3], // Obfuscated IPv4 (low)
144            0x00, 0x00,                           // Padding to 16 bytes
145        ])
146    }
147
148    /// Parse a Teredo IPv6 address to extract components
149    #[allow(dead_code)]
150    fn parse_teredo_address(ipv6: &Ipv6Addr) -> Option<TeredoAddress> {
151        let segments = ipv6.segments();
152        
153        // Check if this is a Teredo address (prefix 2001::/32)
154        if segments[0] != 0x2001 {
155            return None;
156        }
157
158        let server_ipv4 = Ipv4Addr::new(
159            (segments[1] >> 8) as u8,
160            (segments[1] & 0xFF) as u8,
161            (segments[2] >> 8) as u8,
162            (segments[2] & 0xFF) as u8,
163        );
164
165        let flags = segments[3];
166        let obfuscated_port = segments[4];
167
168        let obfuscated_ipv4 = Ipv4Addr::new(
169            (segments[5] >> 8) as u8,
170            (segments[5] & 0xFF) as u8,
171            (segments[6] >> 8) as u8,
172            (segments[6] & 0xFF) as u8,
173        );
174
175        Some(TeredoAddress {
176            server_ipv4,
177            flags,
178            obfuscated_port,
179            obfuscated_ipv4,
180        })
181    }
182
183    /// Create a Router Solicitation packet for Teredo setup
184    fn create_router_solicitation(&self) -> Vec<u8> {
185        let mut packet = Vec::new();
186        
187        // Teredo encapsulation header (simplified)
188        packet.extend_from_slice(&[0x60, 0x00, 0x00, 0x00]); // IPv6 version + traffic class + flow label
189        packet.extend_from_slice(&[0x00, 0x08]); // Payload length (8 bytes for RS)
190        packet.extend_from_slice(&[0x3A]); // Next header (ICMPv6)
191        packet.extend_from_slice(&[0xFF]); // Hop limit
192        
193        // Source address (unspecified for initial RS)
194        packet.extend_from_slice(&[0; 16]);
195        
196        // Destination address (all-routers multicast)
197        packet.extend_from_slice(&[
198            0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02
200        ]);
201        
202        // ICMPv6 Router Solicitation
203        packet.extend_from_slice(&[0x85]); // Type (Router Solicitation)
204        packet.extend_from_slice(&[0x00]); // Code
205        packet.extend_from_slice(&[0x00, 0x00]); // Checksum (to be calculated)
206        packet.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // Reserved
207        
208        packet
209    }
210
211    /// Create a Teredo bubble packet for NAT traversal
212    fn create_bubble_packet(&self, destination: &Ipv6Addr) -> Vec<u8> {
213        let mut packet = Vec::new();
214        
215        // Minimal IPv6 header for bubble packet
216        packet.extend_from_slice(&[0x60, 0x00, 0x00, 0x00]); // Version + traffic class + flow label
217        packet.extend_from_slice(&[0x00, 0x00]); // Payload length (0 for bubble)
218        packet.extend_from_slice(&[0x3B]); // Next header (no next header)
219        packet.extend_from_slice(&[0x01]); // Hop limit (1 for local)
220        
221        // Source address (our Teredo address)
222        if let Some(src) = self.teredo_ipv6 {
223            packet.extend_from_slice(&src.octets());
224        } else {
225            packet.extend_from_slice(&[0; 16]);
226        }
227        
228        // Destination address
229        packet.extend_from_slice(&destination.octets());
230        
231        packet
232    }
233
234    /// Perform Teredo server qualification to discover external address
235    async fn qualify_with_server(&mut self) -> Result<()> {
236        debug!("Starting Teredo server qualification");
237        
238        // Create UDP socket for communication
239        let socket = UdpSocket::bind("0.0.0.0:0")
240            .map_err(|e| P2PError::Network(format!("Failed to bind UDP socket: {}", e)))?;
241        
242        socket.set_nonblocking(true)
243            .map_err(|e| P2PError::Network(format!("Failed to set socket non-blocking: {}", e)))?;
244        
245        // Send Router Solicitation to Teredo server
246        let rs_packet = self.create_router_solicitation();
247        socket.send_to(&rs_packet, self.server_addr)
248            .map_err(|e| P2PError::Network(format!("Failed to send RS to server: {}", e)))?;
249        
250        debug!("Sent Router Solicitation to Teredo server: {}", self.server_addr);
251        
252        // Wait for Router Advertisement response (simplified simulation)
253        tokio::time::sleep(Duration::from_millis(100)).await;
254        
255        // Simulate successful qualification (in real implementation, would parse RA)
256        self.external_ipv4 = Some(Ipv4Addr::new(203, 0, 113, 100)); // Simulated external IP
257        self.external_port = Some(12345); // Simulated external port
258        self.udp_socket = Some(socket);
259        self.last_server_contact = Some(Instant::now());
260        
261        info!("Teredo qualification successful: external {}:{}", 
262              self.external_ipv4.unwrap(), self.external_port.unwrap());
263        
264        Ok(())
265    }
266
267    /// Perform NAT traversal setup with bubble packets
268    async fn setup_nat_traversal(&mut self) -> Result<()> {
269        debug!("Setting up NAT traversal");
270        
271        // Send bubble packets to establish NAT bindings
272        let bubble = self.create_bubble_packet(&Ipv6Addr::LOCALHOST);
273        
274        if let Some(ref socket) = self.udp_socket {
275            socket.send_to(&bubble, self.server_addr)
276                .map_err(|e| P2PError::Network(format!("Failed to send bubble: {}", e)))?;
277        }
278        
279        debug!("NAT traversal setup completed");
280        Ok(())
281    }
282
283    /// Create Teredo UDP encapsulation header
284    fn create_teredo_header(&self, _ipv6_packet: &[u8]) -> Vec<u8> {
285        let mut header = Vec::new();
286        
287        // Teredo authentication header (optional, simplified here)
288        header.extend_from_slice(&[0x00, 0x01]); // Type: Origin indication
289        header.extend_from_slice(&[0x00, 0x08]); // Length: 8 bytes
290        
291        // Origin indication (our external address)
292        if let (Some(ext_ipv4), Some(ext_port)) = (self.external_ipv4, self.external_port) {
293            header.extend_from_slice(&ext_ipv4.octets());
294            header.extend_from_slice(&ext_port.to_be_bytes());
295        } else {
296            header.extend_from_slice(&[0; 6]);
297        }
298        
299        header
300    }
301
302    /// Extract IPv6 packet from Teredo UDP payload
303    fn extract_ipv6_from_teredo(&self, teredo_packet: &[u8]) -> Result<Vec<u8>> {
304        debug!("Extracting IPv6 from Teredo packet of {} bytes", teredo_packet.len());
305        
306        // Skip Teredo authentication headers (simplified parsing)
307        // In our implementation, we add a 10-byte header (2+2+4+2), so skip it
308        if teredo_packet.len() <= 10 {
309            debug!("Teredo packet too short: {} <= 10", teredo_packet.len());
310            return Err(P2PError::Network("Teredo packet too short".to_string()).into());
311        }
312        
313        // Skip the 10-byte header we added in create_teredo_header
314        let ipv6_start = 10;
315        let ipv6_packet = teredo_packet[ipv6_start..].to_vec();
316        debug!("Extracted IPv6 packet of {} bytes, first byte: {:02x}", 
317               ipv6_packet.len(), 
318               if ipv6_packet.is_empty() { 0 } else { ipv6_packet[0] });
319        
320        // Validate it starts with IPv6 version
321        if !ipv6_packet.is_empty() && (ipv6_packet[0] & 0xF0) == 0x60 {
322            debug!("Valid IPv6 packet extracted");
323            Ok(ipv6_packet)
324        } else {
325            debug!("Invalid IPv6 version in packet: {:02x} (expected 0x6x)", 
326                   if ipv6_packet.is_empty() { 0 } else { ipv6_packet[0] });
327            Err(P2PError::Network("No valid IPv6 packet found in Teredo payload".to_string()).into())
328        }
329    }
330
331    /// Update metrics for sent data
332    async fn update_send_metrics(&self, bytes: usize) {
333        let mut metrics = self.metrics.write().await;
334        metrics.bytes_sent += bytes as u64;
335        metrics.packets_sent += 1;
336        metrics.last_activity = Instant::now();
337    }
338
339    /// Update metrics for received data
340    async fn update_receive_metrics(&self, bytes: usize) {
341        let mut metrics = self.metrics.write().await;
342        metrics.bytes_received += bytes as u64;
343        metrics.packets_received += 1;
344        metrics.last_activity = Instant::now();
345    }
346
347    /// Check if server communication is still active
348    fn is_server_active(&self) -> bool {
349        if let Some(last_contact) = self.last_server_contact {
350            last_contact.elapsed() < Duration::from_secs(300) // 5 minutes timeout
351        } else {
352            false
353        }
354    }
355}
356
357#[async_trait]
358impl Tunnel for TeredoTunnel {
359    fn protocol(&self) -> TunnelProtocol {
360        TunnelProtocol::Teredo
361    }
362
363    fn config(&self) -> &TunnelConfig {
364        &self.config
365    }
366
367    async fn state(&self) -> TunnelState {
368        let state = self.state.read().await;
369        state.clone()
370    }
371
372    async fn metrics(&self) -> TunnelMetrics {
373        let metrics = self.metrics.read().await;
374        metrics.clone()
375    }
376
377    async fn connect(&mut self) -> Result<()> {
378        info!("Establishing Teredo tunnel connection");
379        
380        {
381            let mut state = self.state.write().await;
382            *state = TunnelState::Connecting;
383        }
384
385        // Step 1: Qualify with Teredo server to discover external address
386        self.qualify_with_server().await?;
387        
388        // Step 2: Generate Teredo IPv6 address
389        if let (Some(ext_ipv4), Some(ext_port)) = (self.external_ipv4, self.external_port) {
390            let server_ipv4 = self.server_addr.ip();
391            if let std::net::IpAddr::V4(server_v4) = server_ipv4 {
392                self.teredo_ipv6 = Some(Self::generate_teredo_address(
393                    server_v4, ext_ipv4, ext_port
394                ));
395            } else {
396                return Err(P2PError::Network("Teredo server must have IPv4 address".to_string()).into());
397            }
398        }
399        
400        // Step 3: Setup NAT traversal
401        self.setup_nat_traversal().await?;
402        
403        // Update instance state
404        self.established_at = Some(Instant::now());
405
406        // Update tunnel state
407        {
408            let mut state = self.state.write().await;
409            *state = TunnelState::Connected;
410        }
411
412        // Update metrics
413        {
414            let mut metrics = self.metrics.write().await;
415            if let Some(established) = self.established_at {
416                metrics.establishment_time = established.elapsed();
417            }
418        }
419
420        if let Some(teredo_addr) = self.teredo_ipv6 {
421            info!("Teredo tunnel established: {}", teredo_addr);
422        }
423        
424        Ok(())
425    }
426
427    async fn disconnect(&mut self) -> Result<()> {
428        info!("Disconnecting Teredo tunnel");
429        
430        {
431            let mut state = self.state.write().await;
432            *state = TunnelState::Disconnecting;
433        }
434
435        // Close UDP socket
436        self.udp_socket = None;
437        
438        // Reset state
439        self.teredo_ipv6 = None;
440        self.external_ipv4 = None;
441        self.external_port = None;
442        self.established_at = None;
443        self.last_server_contact = None;
444
445        {
446            let mut state = self.state.write().await;
447            *state = TunnelState::Disconnected;
448        }
449
450        debug!("Teredo tunnel disconnected");
451        Ok(())
452    }
453
454    async fn is_active(&self) -> bool {
455        let state = self.state.read().await;
456        matches!(*state, TunnelState::Connected) && self.is_server_active()
457    }
458
459    async fn encapsulate(&self, ipv6_packet: &[u8]) -> Result<Vec<u8>> {
460        if !self.is_active().await {
461            return Err(P2PError::Network("Teredo tunnel not active".to_string()).into());
462        }
463
464        // Create Teredo header
465        let teredo_header = self.create_teredo_header(ipv6_packet);
466        
467        // Combine header and IPv6 packet
468        let mut encapsulated = Vec::with_capacity(teredo_header.len() + ipv6_packet.len());
469        encapsulated.extend_from_slice(&teredo_header);
470        encapsulated.extend_from_slice(ipv6_packet);
471
472        debug!("Encapsulated {} bytes for Teredo transmission", encapsulated.len());
473        Ok(encapsulated)
474    }
475
476    async fn decapsulate(&self, udp_packet: &[u8]) -> Result<Vec<u8>> {
477        if !self.is_active().await {
478            return Err(P2PError::Network("Teredo tunnel not active".to_string()).into());
479        }
480
481        if udp_packet.len() < 10 {
482            return Err(P2PError::Network("Teredo packet too short".to_string()).into());
483        }
484
485        // Extract IPv6 packet from Teredo encapsulation
486        let ipv6_payload = self.extract_ipv6_from_teredo(udp_packet)?;
487
488        debug!("Decapsulated {} bytes from Teredo packet", ipv6_payload.len());
489        Ok(ipv6_payload)
490    }
491
492    async fn send(&mut self, packet: &[u8]) -> Result<()> {
493        let encapsulated = self.encapsulate(packet).await?;
494        
495        // In a real implementation, this would send via UDP to the destination
496        // For now, we simulate the send operation
497        debug!("Sending {} bytes via Teredo tunnel", encapsulated.len());
498        
499        // Simulate network transmission delay
500        tokio::time::sleep(Duration::from_millis(5)).await;
501        
502        self.update_send_metrics(encapsulated.len()).await;
503        Ok(())
504    }
505
506    async fn receive(&mut self) -> Result<Vec<u8>> {
507        // In a real implementation, this would receive UDP packets
508        // For now, we simulate receiving a packet
509        debug!("Receiving packet via Teredo tunnel");
510        
511        // Simulate network reception delay
512        tokio::time::sleep(Duration::from_millis(8)).await;
513        
514        // Simulate a received Teredo packet
515        let simulated_packet = vec![0u8; 64]; // Placeholder
516        
517        let decapsulated = self.decapsulate(&simulated_packet).await?;
518        self.update_receive_metrics(decapsulated.len()).await;
519        
520        Ok(decapsulated)
521    }
522
523    async fn maintain(&mut self) -> Result<()> {
524        if !self.is_active().await {
525            return Ok(());
526        }
527
528        debug!("Performing Teredo tunnel maintenance");
529        
530        // Check if we need to refresh server qualification
531        if let Some(last_contact) = self.last_server_contact {
532            if last_contact.elapsed() > Duration::from_secs(240) { // 4 minutes
533                debug!("Refreshing Teredo server qualification");
534                self.qualify_with_server().await?;
535            }
536        }
537        
538        // Update metrics
539        {
540            let mut metrics = self.metrics.write().await;
541            if let Some(established) = self.established_at {
542                metrics.establishment_time = established.elapsed();
543            }
544        }
545
546        // In a real implementation, this might also:
547        // - Send periodic bubble packets to maintain NAT bindings
548        // - Check for server reachability
549        // - Update route table entries
550        // - Monitor for IPv4 address changes
551
552        Ok(())
553    }
554
555    async fn local_ipv6_addr(&self) -> Result<Ipv6Addr> {
556        self.teredo_ipv6.ok_or_else(|| {
557            P2PError::Network("Teredo tunnel not established".to_string()).into()
558        })
559    }
560
561    async fn local_ipv4_addr(&self) -> Result<Ipv4Addr> {
562        self.external_ipv4.ok_or_else(|| {
563            P2PError::Network("Teredo external address not discovered".to_string()).into()
564        })
565    }
566
567    async fn ping(&mut self, timeout: Duration) -> Result<Duration> {
568        if !self.is_active().await {
569            return Err(P2PError::Network("Teredo tunnel not active".to_string()).into());
570        }
571
572        let start = Instant::now();
573        
574        // Simulate a ping operation via Teredo server
575        debug!("Pinging via Teredo tunnel with timeout {:?}", timeout);
576        
577        // Send bubble packet as ping
578        let bubble = self.create_bubble_packet(&Ipv6Addr::LOCALHOST);
579        
580        if let Some(ref socket) = self.udp_socket {
581            socket.send_to(&bubble, self.server_addr)
582                .map_err(|e| P2PError::Network(format!("Ping failed: {}", e)))?;
583        }
584        
585        // Simulate network round trip time (Teredo typically has higher latency)
586        let simulated_rtt = Duration::from_millis(50 + (rand::random::<u64>() % 100));
587        tokio::time::sleep(simulated_rtt).await;
588        
589        let actual_rtt = start.elapsed();
590        
591        // Update last server contact time
592        self.last_server_contact = Some(Instant::now());
593        
594        // Update metrics with RTT
595        {
596            let mut metrics = self.metrics.write().await;
597            metrics.rtt = Some(actual_rtt);
598        }
599
600        debug!("Teredo tunnel ping successful: RTT = {:?}", actual_rtt);
601        Ok(actual_rtt)
602    }
603}
604
605#[cfg(test)]
606mod tests {
607    use super::*;
608
609    #[test]
610    fn test_teredo_address_generation() {
611        let server_ipv4 = Ipv4Addr::new(192, 88, 99, 1);
612        let external_ipv4 = Ipv4Addr::new(203, 0, 113, 1);
613        let external_port = 12345;
614        
615        let teredo_addr = TeredoTunnel::generate_teredo_address(
616            server_ipv4, external_ipv4, external_port
617        );
618        
619        // Should be 2001::/32 prefix
620        assert_eq!(teredo_addr.segments()[0], 0x2001);
621        
622        // Should contain server address
623        assert_eq!(teredo_addr.segments()[1], 0xc058); // 192.88
624        assert_eq!(teredo_addr.segments()[2], 0x6301); // 99.1
625    }
626
627    #[test]
628    fn test_teredo_address_parsing() {
629        let teredo_addr = Ipv6Addr::new(
630            0x2001, 0xc058, 0x6301, 0x0000,
631            0xcfc6, 0x34fe, 0x70fe, 0x8afe
632        );
633        
634        let parsed = TeredoTunnel::parse_teredo_address(&teredo_addr).unwrap();
635        assert_eq!(parsed.server_ipv4, Ipv4Addr::new(192, 88, 99, 1));
636        assert_eq!(parsed.flags, 0x0000);
637    }
638
639    #[test]
640    fn test_non_teredo_address() {
641        let ipv6 = Ipv6Addr::new(0x2002, 0xc000, 0x0201, 0, 0, 0, 0, 1); // 6to4 address
642        let result = TeredoTunnel::parse_teredo_address(&ipv6);
643        assert!(result.is_none());
644    }
645
646    #[tokio::test]
647    async fn test_tunnel_creation() {
648        let config = TunnelConfig {
649            protocol: TunnelProtocol::Teredo,
650            ..Default::default()
651        };
652
653        let tunnel = TeredoTunnel::new(config).unwrap();
654        assert_eq!(tunnel.protocol(), TunnelProtocol::Teredo);
655        assert_eq!(tunnel.state().await, TunnelState::Disconnected);
656    }
657
658    #[tokio::test]
659    async fn test_invalid_protocol() {
660        let config = TunnelConfig {
661            protocol: TunnelProtocol::SixToFour, // Wrong protocol
662            ..Default::default()
663        };
664
665        let result = TeredoTunnel::new(config);
666        assert!(result.is_err());
667    }
668}