#stack #tun #devices #userspace #async #stream #udp

ipstack

Asynchronous lightweight userspace implementation of TCP/IP stack for Tun device

13 releases

new 0.1.1 Dec 1, 2024
0.1.0 Jul 24, 2024
0.0.10 May 12, 2024
0.0.7 Mar 30, 2024
0.0.1 Nov 4, 2023

#1086 in Network programming

Download history 76/week @ 2024-08-17 159/week @ 2024-08-24 72/week @ 2024-08-31 40/week @ 2024-09-07 169/week @ 2024-09-14 279/week @ 2024-09-21 177/week @ 2024-09-28 140/week @ 2024-10-05 135/week @ 2024-10-12 436/week @ 2024-10-19 261/week @ 2024-10-26 175/week @ 2024-11-02 83/week @ 2024-11-09 99/week @ 2024-11-16 135/week @ 2024-11-23 185/week @ 2024-11-30

517 downloads per month
Used in 2 crates

Apache-2.0

70KB
1.5K SLoC

IpStack

An asynchronous lightweight userspace implementation of TCP/IP stack for Tun device. Unstable, under development.

Crates.io ipstack Documentation Download License

Usage

use etherparse::{IcmpEchoHeader, Icmpv4Header, IpNumber};
use ipstack::stream::IpStackStream;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use tokio::net::TcpStream;
use udp_stream::UdpStream;

#[tokio::main]
async fn main() {
    const MTU: u16 = 1500;
    let ipv4 = Ipv4Addr::new(10, 0, 0, 1);
    let netmask = Ipv4Addr::new(255, 255, 255, 0);
    let mut config = tun2::Configuration::default();
    config.address(ipv4).netmask(netmask).mtu(MTU).up();

    #[cfg(target_os = "linux")]
    config.platform_config(|config| {
        config.ensure_root_privileges(true);
    });

    #[cfg(target_os = "windows")]
    config.platform_config(|config| {
        config.device_guid(Some(12324323423423434234_u128));
    });

    let mut ipstack_config = ipstack::IpStackConfig::default();
    ipstack_config.mtu(MTU);
    let mut ip_stack =
        ipstack::IpStack::new(ipstack_config, tun2::create_as_async(&config).unwrap());

    while let Ok(stream) = ip_stack.accept().await {
        match stream {
            IpStackStream::Tcp(mut tcp) => {
                let mut rhs = TcpStream::connect("1.1.1.1:80").await.unwrap();
                tokio::spawn(async move {
                    let _ = tokio::io::copy_bidirectional(&mut tcp, &mut rhs).await;
                });
            }
            IpStackStream::Udp(mut udp) => {
                let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)), 53);
                let mut rhs = UdpStream::connect(addr).await.unwrap();
                tokio::spawn(async move {
                    let _ = tokio::io::copy_bidirectional(&mut udp, &mut rhs).await;
                });
            }
            IpStackStream::UnknownTransport(u) => {
                if u.src_addr().is_ipv4() && IpNumber::from(u.ip_protocol()) == IpNumber::ICMP {
                    let (icmp_header, req_payload) = Icmpv4Header::from_slice(u.payload()).unwrap();
                    if let etherparse::Icmpv4Type::EchoRequest(req) = icmp_header.icmp_type {
                        println!("ICMPv4 echo");
                        let echo = IcmpEchoHeader {
                            id: req.id,
                            seq: req.seq,
                        };
                        let mut resp = Icmpv4Header::new(etherparse::Icmpv4Type::EchoReply(echo));
                        resp.update_checksum(req_payload);
                        let mut payload = resp.to_bytes().to_vec();
                        payload.extend_from_slice(req_payload);
                        u.send(payload).unwrap();
                    } else {
                        println!("ICMPv4");
                    }
                    continue;
                }
                println!("unknown transport - Ip Protocol {}", u.ip_protocol().0);
            }
            IpStackStream::UnknownNetwork(pkt) => {
                println!("unknown transport - {} bytes", pkt.len());
            }
        }
    }
}

We also suggest that you take a look at the complete examples.

Dependencies

~6–12MB
~145K SLoC