⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/net/vpn/
tunnel.rs

1//! Virtual Tunnel Interface (TUN/TAP)
2//!
3//! Provides L3 (TUN) and L2 (TAP) virtual network interfaces for VPN tunneling.
4//! Supports packet queuing, MTU management, route injection, and encapsulation
5//! headers for outer tunnel transport.
6
7#![allow(dead_code)]
8
9use alloc::{collections::BTreeMap, string::String, vec::Vec};
10
11use crate::net::Ipv4Address;
12
13// ── Constants ────────────────────────────────────────────────────────────────
14
15/// Default MTU for tunnel interfaces
16const DEFAULT_MTU: u16 = 1500;
17
18/// Maximum tunnel name length
19const MAX_NAME_LEN: usize = 16;
20
21/// Maximum number of packets in a queue
22const MAX_QUEUE_DEPTH: usize = 256;
23
24/// Maximum number of tunnel interfaces
25const MAX_TUNNELS: usize = 64;
26
27/// Maximum number of routes per tunnel
28const MAX_ROUTES: usize = 128;
29
30// ── Tunnel Types ─────────────────────────────────────────────────────────────
31
32/// Tunnel device type
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
34pub enum TunnelType {
35    /// Layer 3 tunnel (IP packets only)
36    #[default]
37    Tun,
38    /// Layer 2 tunnel (full Ethernet frames)
39    Tap,
40}
41
42/// Tunnel interface state
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
44pub enum TunnelState {
45    /// Interface is down / not active
46    #[default]
47    Down,
48    /// Interface is up and operational
49    Up,
50}
51
52/// Encapsulation protocol for the outer tunnel transport
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
54pub enum EncapProtocol {
55    /// UDP encapsulation (most common for VPN)
56    #[default]
57    Udp,
58    /// TCP encapsulation (for restricted networks)
59    Tcp,
60}
61
62/// Tunnel error types
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum TunnelError {
65    /// Tunnel interface already exists
66    AlreadyExists,
67    /// Tunnel interface not found
68    NotFound,
69    /// Tunnel interface is not up
70    NotUp,
71    /// Tunnel interface is already up
72    AlreadyUp,
73    /// Packet exceeds MTU
74    PacketTooLarge,
75    /// Queue is full
76    QueueFull,
77    /// Queue is empty (no packets available)
78    QueueEmpty,
79    /// Maximum number of tunnels reached
80    TooManyTunnels,
81    /// Maximum number of routes reached
82    TooManyRoutes,
83    /// Route already exists
84    RouteExists,
85    /// Route not found
86    RouteNotFound,
87    /// Invalid tunnel name (empty or too long)
88    InvalidName,
89    /// Invalid MTU value
90    InvalidMtu,
91}
92
93// ── Tunnel Statistics ────────────────────────────────────────────────────────
94
95/// Statistics for a tunnel interface
96#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
97pub struct TunnelStats {
98    /// Total packets transmitted
99    pub tx_packets: u64,
100    /// Total packets received
101    pub rx_packets: u64,
102    /// Total bytes transmitted
103    pub tx_bytes: u64,
104    /// Total bytes received
105    pub rx_bytes: u64,
106    /// Transmit errors (e.g., MTU exceeded, queue full)
107    pub tx_errors: u64,
108    /// Receive errors
109    pub rx_errors: u64,
110}
111
112// ── Tunnel Configuration ─────────────────────────────────────────────────────
113
114/// Configuration for a tunnel interface
115#[derive(Debug, Clone, PartialEq)]
116pub struct TunnelConfig {
117    /// Interface name (e.g., "tun0", "tap0")
118    pub name: String,
119    /// Tunnel type (L3 TUN or L2 TAP)
120    pub tunnel_type: TunnelType,
121    /// Maximum transmission unit
122    pub mtu: u16,
123    /// Local IP address assigned to this tunnel
124    pub local_address: Ipv4Address,
125    /// Remote peer IP address
126    pub peer_address: Ipv4Address,
127    /// Subnet mask for the tunnel network
128    pub subnet_mask: Ipv4Address,
129}
130
131impl TunnelConfig {
132    /// Create a new tunnel configuration with default MTU
133    pub fn new(
134        name: &str,
135        tunnel_type: TunnelType,
136        local_address: Ipv4Address,
137        peer_address: Ipv4Address,
138        subnet_mask: Ipv4Address,
139    ) -> Self {
140        Self {
141            name: String::from(name),
142            tunnel_type,
143            mtu: DEFAULT_MTU,
144            local_address,
145            peer_address,
146            subnet_mask,
147        }
148    }
149}
150
151// ── Encapsulation Header ─────────────────────────────────────────────────────
152
153/// Outer encapsulation header for tunnel packets
154#[derive(Debug, Clone, Copy, PartialEq, Eq)]
155pub struct EncapsulationHeader {
156    /// Outer source IP address
157    pub src_ip: Ipv4Address,
158    /// Outer destination IP address
159    pub dst_ip: Ipv4Address,
160    /// Transport protocol (UDP or TCP)
161    pub protocol: EncapProtocol,
162    /// Outer source port
163    pub src_port: u16,
164    /// Outer destination port
165    pub dst_port: u16,
166}
167
168impl EncapsulationHeader {
169    /// Create a new encapsulation header
170    pub fn new(
171        src_ip: Ipv4Address,
172        dst_ip: Ipv4Address,
173        protocol: EncapProtocol,
174        src_port: u16,
175        dst_port: u16,
176    ) -> Self {
177        Self {
178            src_ip,
179            dst_ip,
180            protocol,
181            src_port,
182            dst_port,
183        }
184    }
185
186    /// Serialise the encapsulation header to bytes (20-byte pseudo-header)
187    pub fn to_bytes(&self) -> [u8; 20] {
188        let mut buf = [0u8; 20];
189        buf[0..4].copy_from_slice(&self.src_ip.0);
190        buf[4..8].copy_from_slice(&self.dst_ip.0);
191        buf[8] = match self.protocol {
192            EncapProtocol::Udp => 17,
193            EncapProtocol::Tcp => 6,
194        };
195        buf[9] = 0; // reserved
196        buf[10..12].copy_from_slice(&self.src_port.to_be_bytes());
197        buf[12..14].copy_from_slice(&self.dst_port.to_be_bytes());
198        // bytes 14..20 reserved / padding
199        buf
200    }
201
202    /// Overhead in bytes added by the encapsulation
203    pub fn overhead(&self) -> u16 {
204        // IP header (20) + UDP/TCP header (8 for UDP, 20 for TCP)
205        match self.protocol {
206            EncapProtocol::Udp => 28,
207            EncapProtocol::Tcp => 40,
208        }
209    }
210}
211
212// ── Tunnel Interface ─────────────────────────────────────────────────────────
213
214/// Virtual tunnel network interface
215#[derive(Debug, PartialEq)]
216pub struct TunnelInterface {
217    /// Configuration for this tunnel
218    config: TunnelConfig,
219    /// Current interface state
220    state: TunnelState,
221    /// Transmit packet queue
222    tx_queue: Vec<Vec<u8>>,
223    /// Receive packet queue
224    rx_queue: Vec<Vec<u8>>,
225    /// Interface statistics
226    stats: TunnelStats,
227    /// Optional encapsulation header for outer transport
228    encap: Option<EncapsulationHeader>,
229}
230
231impl TunnelInterface {
232    /// Create a new tunnel interface from configuration
233    pub fn create(config: TunnelConfig) -> Result<Self, TunnelError> {
234        if config.name.is_empty() || config.name.len() > MAX_NAME_LEN {
235            return Err(TunnelError::InvalidName);
236        }
237        if config.mtu == 0 {
238            return Err(TunnelError::InvalidMtu);
239        }
240
241        Ok(Self {
242            config,
243            state: TunnelState::Down,
244            tx_queue: Vec::new(),
245            rx_queue: Vec::new(),
246            stats: TunnelStats::default(),
247            encap: None,
248        })
249    }
250
251    /// Bring the interface up
252    pub fn bring_up(&mut self) -> Result<(), TunnelError> {
253        if self.state == TunnelState::Up {
254            return Err(TunnelError::AlreadyUp);
255        }
256        self.state = TunnelState::Up;
257        Ok(())
258    }
259
260    /// Bring the interface down and flush queues
261    pub fn bring_down(&mut self) {
262        self.state = TunnelState::Down;
263        self.tx_queue.clear();
264        self.rx_queue.clear();
265    }
266
267    /// Enqueue a packet for transmission
268    pub fn send_packet(&mut self, data: &[u8]) -> Result<(), TunnelError> {
269        if self.state != TunnelState::Up {
270            return Err(TunnelError::NotUp);
271        }
272        if data.len() > self.config.mtu as usize {
273            self.stats.tx_errors += 1;
274            return Err(TunnelError::PacketTooLarge);
275        }
276        if self.tx_queue.len() >= MAX_QUEUE_DEPTH {
277            self.stats.tx_errors += 1;
278            return Err(TunnelError::QueueFull);
279        }
280
281        self.stats.tx_packets += 1;
282        self.stats.tx_bytes += data.len() as u64;
283        self.tx_queue.push(data.to_vec());
284        Ok(())
285    }
286
287    /// Dequeue a received packet
288    pub fn receive_packet(&mut self) -> Result<Vec<u8>, TunnelError> {
289        if self.state != TunnelState::Up {
290            return Err(TunnelError::NotUp);
291        }
292        if self.rx_queue.is_empty() {
293            return Err(TunnelError::QueueEmpty);
294        }
295
296        let pkt = self.rx_queue.remove(0);
297        self.stats.rx_packets += 1;
298        self.stats.rx_bytes += pkt.len() as u64;
299        Ok(pkt)
300    }
301
302    /// Enqueue a packet into the receive queue (called by the VPN transport
303    /// layer)
304    pub fn inject_rx(&mut self, data: Vec<u8>) -> Result<(), TunnelError> {
305        if self.rx_queue.len() >= MAX_QUEUE_DEPTH {
306            self.stats.rx_errors += 1;
307            return Err(TunnelError::QueueFull);
308        }
309        self.rx_queue.push(data);
310        Ok(())
311    }
312
313    /// Dequeue a packet from the transmit queue (called by the VPN transport
314    /// layer)
315    pub fn drain_tx(&mut self) -> Option<Vec<u8>> {
316        if self.tx_queue.is_empty() {
317            None
318        } else {
319            Some(self.tx_queue.remove(0))
320        }
321    }
322
323    /// Set the MTU for this interface
324    pub fn set_mtu(&mut self, mtu: u16) -> Result<(), TunnelError> {
325        if mtu == 0 {
326            return Err(TunnelError::InvalidMtu);
327        }
328        self.config.mtu = mtu;
329        Ok(())
330    }
331
332    /// Get the current MTU
333    pub fn get_mtu(&self) -> u16 {
334        self.config.mtu
335    }
336
337    /// Get interface statistics
338    pub fn get_stats(&self) -> TunnelStats {
339        self.stats
340    }
341
342    /// Get the interface name
343    pub fn name(&self) -> &str {
344        &self.config.name
345    }
346
347    /// Get the tunnel type
348    pub fn tunnel_type(&self) -> TunnelType {
349        self.config.tunnel_type
350    }
351
352    /// Get the current state
353    pub fn state(&self) -> TunnelState {
354        self.state
355    }
356
357    /// Get the configuration
358    pub fn config(&self) -> &TunnelConfig {
359        &self.config
360    }
361
362    /// Set the encapsulation header
363    pub fn set_encap(&mut self, encap: EncapsulationHeader) {
364        self.encap = Some(encap);
365    }
366
367    /// Get the encapsulation header
368    pub fn encap(&self) -> Option<&EncapsulationHeader> {
369        self.encap.as_ref()
370    }
371}
372
373// ── Route Injection ──────────────────────────────────────────────────────────
374
375/// A route entry that directs traffic through a tunnel
376#[derive(Debug, Clone, PartialEq, Eq)]
377pub struct TunnelRoute {
378    /// Destination network address
379    pub destination: Ipv4Address,
380    /// Subnet mask / prefix length (CIDR notation)
381    pub prefix_len: u8,
382    /// Name of the tunnel interface this route uses
383    pub tunnel_name: String,
384    /// Metric / priority (lower = preferred)
385    pub metric: u32,
386}
387
388/// Route injection manager for tunnel interfaces
389pub struct RouteInjection {
390    /// Active tunnel routes
391    routes: Vec<TunnelRoute>,
392}
393
394impl Default for RouteInjection {
395    fn default() -> Self {
396        Self::new()
397    }
398}
399
400impl RouteInjection {
401    /// Create a new route injection manager
402    pub fn new() -> Self {
403        Self { routes: Vec::new() }
404    }
405
406    /// Add a route through a tunnel interface
407    pub fn add_route(
408        &mut self,
409        destination: Ipv4Address,
410        prefix_len: u8,
411        tunnel_name: &str,
412        metric: u32,
413    ) -> Result<(), TunnelError> {
414        // Check for duplicate
415        for r in &self.routes {
416            if r.destination == destination
417                && r.prefix_len == prefix_len
418                && r.tunnel_name == tunnel_name
419            {
420                return Err(TunnelError::RouteExists);
421            }
422        }
423
424        if self.routes.len() >= MAX_ROUTES {
425            return Err(TunnelError::TooManyRoutes);
426        }
427
428        self.routes.push(TunnelRoute {
429            destination,
430            prefix_len,
431            tunnel_name: String::from(tunnel_name),
432            metric,
433        });
434        Ok(())
435    }
436
437    /// Remove a route
438    pub fn remove_route(
439        &mut self,
440        destination: Ipv4Address,
441        prefix_len: u8,
442        tunnel_name: &str,
443    ) -> Result<(), TunnelError> {
444        let idx = self
445            .routes
446            .iter()
447            .position(|r| {
448                r.destination == destination
449                    && r.prefix_len == prefix_len
450                    && r.tunnel_name == tunnel_name
451            })
452            .ok_or(TunnelError::RouteNotFound)?;
453
454        self.routes.remove(idx);
455        Ok(())
456    }
457
458    /// Get all routes
459    pub fn get_routes(&self) -> &[TunnelRoute] {
460        &self.routes
461    }
462
463    /// Find the best route for a given destination IP
464    pub fn lookup(&self, dst: &Ipv4Address) -> Option<&TunnelRoute> {
465        let mut best: Option<&TunnelRoute> = None;
466        let dst_u32 = dst.to_u32();
467
468        for route in &self.routes {
469            let mask = if route.prefix_len == 0 {
470                0u32
471            } else {
472                u32::MAX << (32 - route.prefix_len)
473            };
474            let net = route.destination.to_u32() & mask;
475            if (dst_u32 & mask) == net {
476                match best {
477                    None => best = Some(route),
478                    Some(b) => {
479                        // Prefer longer prefix, then lower metric
480                        if route.prefix_len > b.prefix_len
481                            || (route.prefix_len == b.prefix_len && route.metric < b.metric)
482                        {
483                            best = Some(route);
484                        }
485                    }
486                }
487            }
488        }
489
490        best
491    }
492}
493
494// ── Tunnel Manager ───────────────────────────────────────────────────────────
495
496/// Manager for all tunnel interfaces on the system
497pub struct TunnelManager {
498    /// Map of tunnel name -> tunnel interface
499    tunnels: BTreeMap<String, TunnelInterface>,
500    /// Route injection table
501    routes: RouteInjection,
502}
503
504impl Default for TunnelManager {
505    fn default() -> Self {
506        Self::new()
507    }
508}
509
510impl TunnelManager {
511    /// Create a new tunnel manager
512    pub fn new() -> Self {
513        Self {
514            tunnels: BTreeMap::new(),
515            routes: RouteInjection::new(),
516        }
517    }
518
519    /// Create and register a new tunnel interface
520    pub fn create_tunnel(&mut self, config: TunnelConfig) -> Result<(), TunnelError> {
521        if self.tunnels.len() >= MAX_TUNNELS {
522            return Err(TunnelError::TooManyTunnels);
523        }
524        if self.tunnels.contains_key(&config.name) {
525            return Err(TunnelError::AlreadyExists);
526        }
527
528        let name = config.name.clone();
529        let iface = TunnelInterface::create(config)?;
530        self.tunnels.insert(name, iface);
531        Ok(())
532    }
533
534    /// Destroy (remove) a tunnel interface
535    pub fn destroy_tunnel(&mut self, name: &str) -> Result<(), TunnelError> {
536        self.tunnels
537            .remove(name)
538            .map(|_| ())
539            .ok_or(TunnelError::NotFound)
540    }
541
542    /// Get a reference to a tunnel interface
543    pub fn get_tunnel(&self, name: &str) -> Option<&TunnelInterface> {
544        self.tunnels.get(name)
545    }
546
547    /// Get a mutable reference to a tunnel interface
548    pub fn get_tunnel_mut(&mut self, name: &str) -> Option<&mut TunnelInterface> {
549        self.tunnels.get_mut(name)
550    }
551
552    /// List all tunnel interface names
553    pub fn list_tunnels(&self) -> Vec<&str> {
554        self.tunnels.keys().map(|k| k.as_str()).collect()
555    }
556
557    /// Get the number of tunnels
558    pub fn tunnel_count(&self) -> usize {
559        self.tunnels.len()
560    }
561
562    /// Access the route injection table
563    pub fn routes(&self) -> &RouteInjection {
564        &self.routes
565    }
566
567    /// Access the route injection table mutably
568    pub fn routes_mut(&mut self) -> &mut RouteInjection {
569        &mut self.routes
570    }
571}
572
573// ── Tests ────────────────────────────────────────────────────────────────────
574
575#[cfg(test)]
576mod tests {
577    use super::*;
578
579    fn test_config(name: &str) -> TunnelConfig {
580        TunnelConfig::new(
581            name,
582            TunnelType::Tun,
583            Ipv4Address::new(10, 0, 0, 1),
584            Ipv4Address::new(10, 0, 0, 2),
585            Ipv4Address::new(255, 255, 255, 0),
586        )
587    }
588
589    #[test]
590    fn test_tunnel_create() {
591        let config = test_config("tun0");
592        let iface = TunnelInterface::create(config).unwrap();
593        assert_eq!(iface.name(), "tun0");
594        assert_eq!(iface.tunnel_type(), TunnelType::Tun);
595        assert_eq!(iface.state(), TunnelState::Down);
596        assert_eq!(iface.get_mtu(), DEFAULT_MTU);
597    }
598
599    #[test]
600    fn test_tunnel_create_invalid_name() {
601        let mut config = test_config("tun0");
602        config.name = String::new();
603        assert_eq!(
604            TunnelInterface::create(config),
605            Err(TunnelError::InvalidName)
606        );
607    }
608
609    #[test]
610    fn test_tunnel_bring_up_down() {
611        let config = test_config("tun0");
612        let mut iface = TunnelInterface::create(config).unwrap();
613
614        assert!(iface.bring_up().is_ok());
615        assert_eq!(iface.state(), TunnelState::Up);
616
617        // Double bring_up is an error
618        assert_eq!(iface.bring_up(), Err(TunnelError::AlreadyUp));
619
620        iface.bring_down();
621        assert_eq!(iface.state(), TunnelState::Down);
622    }
623
624    #[test]
625    fn test_tunnel_send_requires_up() {
626        let config = test_config("tun0");
627        let mut iface = TunnelInterface::create(config).unwrap();
628
629        assert_eq!(iface.send_packet(&[1, 2, 3]), Err(TunnelError::NotUp));
630    }
631
632    #[test]
633    fn test_tunnel_send_receive() {
634        let config = test_config("tun0");
635        let mut iface = TunnelInterface::create(config).unwrap();
636        iface.bring_up().unwrap();
637
638        let data = [0xAA; 100];
639        assert!(iface.send_packet(&data).is_ok());
640
641        // TX queue has one packet, RX queue is empty
642        let pkt = iface.drain_tx().unwrap();
643        assert_eq!(pkt.len(), 100);
644        assert!(iface.drain_tx().is_none());
645
646        // Inject into RX queue
647        iface.inject_rx(pkt).unwrap();
648        let received = iface.receive_packet().unwrap();
649        assert_eq!(received.len(), 100);
650        assert_eq!(received[0], 0xAA);
651    }
652
653    #[test]
654    fn test_tunnel_mtu_enforcement() {
655        let mut config = test_config("tun0");
656        config.mtu = 64;
657        let mut iface = TunnelInterface::create(config).unwrap();
658        iface.bring_up().unwrap();
659
660        // Packet within MTU
661        assert!(iface.send_packet(&[0u8; 64]).is_ok());
662
663        // Packet exceeding MTU
664        assert_eq!(
665            iface.send_packet(&[0u8; 65]),
666            Err(TunnelError::PacketTooLarge)
667        );
668
669        let stats = iface.get_stats();
670        assert_eq!(stats.tx_packets, 1);
671        assert_eq!(stats.tx_errors, 1);
672    }
673
674    #[test]
675    fn test_tunnel_set_mtu() {
676        let config = test_config("tun0");
677        let mut iface = TunnelInterface::create(config).unwrap();
678
679        assert!(iface.set_mtu(9000).is_ok());
680        assert_eq!(iface.get_mtu(), 9000);
681
682        assert_eq!(iface.set_mtu(0), Err(TunnelError::InvalidMtu));
683    }
684
685    #[test]
686    fn test_tunnel_stats() {
687        let config = test_config("tun0");
688        let mut iface = TunnelInterface::create(config).unwrap();
689        iface.bring_up().unwrap();
690
691        iface.send_packet(&[1u8; 50]).unwrap();
692        iface.send_packet(&[2u8; 100]).unwrap();
693        iface.inject_rx(alloc::vec![3u8; 75]).unwrap();
694        iface.receive_packet().unwrap();
695
696        let stats = iface.get_stats();
697        assert_eq!(stats.tx_packets, 2);
698        assert_eq!(stats.tx_bytes, 150);
699        assert_eq!(stats.rx_packets, 1);
700        assert_eq!(stats.rx_bytes, 75);
701        assert_eq!(stats.tx_errors, 0);
702        assert_eq!(stats.rx_errors, 0);
703    }
704
705    #[test]
706    fn test_tunnel_manager_create_destroy() {
707        let mut mgr = TunnelManager::new();
708
709        mgr.create_tunnel(test_config("tun0")).unwrap();
710        mgr.create_tunnel(test_config("tun1")).unwrap();
711        assert_eq!(mgr.tunnel_count(), 2);
712
713        // Duplicate name
714        assert_eq!(
715            mgr.create_tunnel(test_config("tun0")),
716            Err(TunnelError::AlreadyExists)
717        );
718
719        mgr.destroy_tunnel("tun0").unwrap();
720        assert_eq!(mgr.tunnel_count(), 1);
721
722        // Not found
723        assert_eq!(mgr.destroy_tunnel("tun0"), Err(TunnelError::NotFound));
724    }
725
726    #[test]
727    fn test_tunnel_manager_list() {
728        let mut mgr = TunnelManager::new();
729        mgr.create_tunnel(test_config("tun0")).unwrap();
730        mgr.create_tunnel(test_config("tun1")).unwrap();
731
732        let names = mgr.list_tunnels();
733        assert_eq!(names.len(), 2);
734        assert!(names.contains(&"tun0"));
735        assert!(names.contains(&"tun1"));
736    }
737
738    #[test]
739    fn test_route_injection_add_remove() {
740        let mut routes = RouteInjection::new();
741
742        routes
743            .add_route(Ipv4Address::new(10, 0, 0, 0), 24, "tun0", 100)
744            .unwrap();
745        assert_eq!(routes.get_routes().len(), 1);
746
747        // Duplicate route
748        assert_eq!(
749            routes.add_route(Ipv4Address::new(10, 0, 0, 0), 24, "tun0", 100),
750            Err(TunnelError::RouteExists)
751        );
752
753        routes
754            .remove_route(Ipv4Address::new(10, 0, 0, 0), 24, "tun0")
755            .unwrap();
756        assert_eq!(routes.get_routes().len(), 0);
757
758        assert_eq!(
759            routes.remove_route(Ipv4Address::new(10, 0, 0, 0), 24, "tun0"),
760            Err(TunnelError::RouteNotFound)
761        );
762    }
763
764    #[test]
765    fn test_route_lookup_longest_prefix() {
766        let mut routes = RouteInjection::new();
767
768        // Default route via tun0
769        routes
770            .add_route(Ipv4Address::new(0, 0, 0, 0), 0, "tun0", 100)
771            .unwrap();
772        // More specific route via tun1
773        routes
774            .add_route(Ipv4Address::new(10, 0, 0, 0), 24, "tun1", 100)
775            .unwrap();
776
777        // 10.0.0.5 matches both, but /24 is longer prefix
778        let route = routes.lookup(&Ipv4Address::new(10, 0, 0, 5)).unwrap();
779        assert_eq!(route.tunnel_name, "tun1");
780
781        // 192.168.1.1 only matches default
782        let route = routes.lookup(&Ipv4Address::new(192, 168, 1, 1)).unwrap();
783        assert_eq!(route.tunnel_name, "tun0");
784    }
785
786    #[test]
787    fn test_encap_header() {
788        let hdr = EncapsulationHeader::new(
789            Ipv4Address::new(192, 168, 1, 1),
790            Ipv4Address::new(203, 0, 113, 1),
791            EncapProtocol::Udp,
792            12345,
793            1194,
794        );
795
796        assert_eq!(hdr.overhead(), 28);
797
798        let bytes = hdr.to_bytes();
799        assert_eq!(&bytes[0..4], &[192, 168, 1, 1]);
800        assert_eq!(&bytes[4..8], &[203, 0, 113, 1]);
801        assert_eq!(bytes[8], 17); // UDP protocol number
802
803        let tcp_hdr = EncapsulationHeader::new(
804            Ipv4Address::new(10, 0, 0, 1),
805            Ipv4Address::new(10, 0, 0, 2),
806            EncapProtocol::Tcp,
807            443,
808            443,
809        );
810        assert_eq!(tcp_hdr.overhead(), 40);
811        assert_eq!(tcp_hdr.to_bytes()[8], 6); // TCP protocol number
812    }
813}