Skip to content

Commit

Permalink
Merge pull request #18 from xmh0511/main
Browse files Browse the repository at this point in the history
Update example
  • Loading branch information
SajjadPourali committed Jan 22, 2024
2 parents 9be0637 + 2d76591 commit dd932b6
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 128 deletions.
10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,19 @@ tracing = { version = "0.1", default-features = false, features = [
[dev-dependencies]
clap = { version = "4.4", features = ["derive"] }
udp-stream = { version = "0.0", default-features = false }
tun2 = { version = "0.6", features = ["async"] }
tokio = { version = "1.35", features = [
"rt-multi-thread",
], default-features = false }

#tun2.rs example
tun2 = { version = "0.7", features = ["async"] }

#tun_wintun.rs example
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dev-dependencies]
tun = { version = "0.6.1", features = ["async"], default-features = false }
[target.'cfg(target_os = "windows")'.dev-dependencies]
wintun = { version = "0.4", default-features = false }

[profile.release]
opt-level = 'z' # Optimize for size.
lto = true # Enable Link Time Optimization
Expand Down
70 changes: 51 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,82 @@ An asynchronous lightweight implementation of TCP/IP stack for Tun device.
Unstable, under development.

### Usage
````rust

```rust
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use udp_stream::UdpStream;
use tokio::io{AsyncRead, AsyncWrite};
async fn copy_from_lhs_to_rhs(lhs: impl AsyncRead + AsyncWrite, rhs: impl AsyncRead + AsyncWrite) {
let (mut lhs_reader, mut lhs_writer) = tokio::io::split(lhs);
let (mut rhs_reader, mut rhs_writer) = tokio::io::split(rhs);
let _r = tokio::join! {
tokio::io::copy(&mut lhs_reader, &mut rhs_writer) ,
tokio::io::copy(&mut rhs_reader, &mut lhs_writer),
};
}
use etherparse::{IcmpEchoHeader, Icmpv4Header};

#[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 = tun::Configuration::default();
let mut config = tun2::Configuration::default();
config.address(ipv4).netmask(netmask).mtu(MTU as i32).up();

#[cfg(target_os = "linux")]
config.platform_config(|config| {
config.packet_information(true);
config.apply_settings(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 packet_information = cfg!(all(target_family = "unix", not(target_os = "android")));
ipstack_config.packet_information(packet_information);
let mut ip_stack = ipstack::IpStack::new(ipstack_config, tun::create_as_async(&config).unwrap());
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(tcp) => {
let rhs = TcpStream::connect("1.1.1.1:80").await.unwrap();
IpStackStream::Tcp(mut tcp) => {
let mut rhs = TcpStream::connect("1.1.1.1:80").await.unwrap();
tokio::spawn(async move {
copy_from_lhs_to_rhs(tcp, rhs).await;
let _ = tokio::io::copy_bidirectional(& mut tcp, & mut rhs).await;
});
}
IpStackStream::Udp(udp) => {
IpStackStream::Udp(mut udp) => {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)), 53);
let rhs = UdpStream::connect(addr).await.unwrap();
let mut rhs = UdpStream::connect(addr).await.unwrap();
tokio::spawn(async move {
copy_from_lhs_to_rhs(udp, rhs).await;
let _ = tokio::io::copy_bidirectional(& mut udp, & mut rhs).await;
});
}
IpStackStream::UnknownTransport(u) => {
if u.src_addr().is_ipv4() && u.ip_protocol() == 1 {
let (icmp_header, req_payload) = Icmpv4Header::from_slice(u.payload())?;
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).await?;
} else {
println!("ICMPv4");
}
continue;
}
println!("unknown transport - Ip Protocol {}", u.ip_protocol());
continue;
}
IpStackStream::UnknownNetwork(pkt) => {
println!("unknown transport - {} bytes", pkt.len());
continue;
}
}
}
}
````
```

We also suggest that you take a look at the complete [examples](examples).
We also suggest that you take a look at the complete [examples](examples).
76 changes: 0 additions & 76 deletions examples/echo.rs

This file was deleted.

59 changes: 27 additions & 32 deletions examples/tun.rs → examples/tun2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
//! ```
//! To route traffic to the tun interface, run the following command with root or administrator privileges:
//! ```
//! sudo ip route add 1.2.3.4/32 dev utun3 # Linux
//! sudo ip route add 1.2.3.4/32 dev tun0 # Linux
//! route add 1.2.3.4 mask 255.255.255.255 10.0.0.1 metric 100 # Windows
//! sudo route add 1.2.3.4/32 10.0.0.1 # Apple macOS
//! sudo route add 1.2.3.4/32 10.0.0.1 # macOS
//! ```
//! Now you can test it with `nc 1.2.3.4 any_port` or `nc -u 1.2.3.4 any_port`.
//! You can watch the echo information in the `nc` console.
Expand All @@ -29,7 +29,7 @@ use clap::Parser;
use etherparse::{IcmpEchoHeader, Icmpv4Header};
use ipstack::stream::IpStackStream;
use std::net::{Ipv4Addr, SocketAddr};
use tokio::{join, net::TcpStream};
use tokio::net::TcpStream;
use udp_stream::UdpStream;

// const MTU: u16 = 1500;
Expand All @@ -56,13 +56,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
config.destination(gateway);

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

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

let mut ipstack_config = ipstack::IpStackConfig::default();
Expand All @@ -76,37 +77,31 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

loop {
match ip_stack.accept().await? {
IpStackStream::Tcp(tcp) => {
let s = TcpStream::connect(server_addr).await;
if let Err(ref err) = s {
println!("connect TCP server failed \"{}\"", err);
continue;
}
IpStackStream::Tcp(mut tcp) => {
let mut s = match TcpStream::connect(server_addr).await {
Ok(s) => s,
Err(e) => {
println!("connect TCP server failed \"{}\"", e);
continue;
}
};
println!("==== New TCP connection ====");
let (mut t_rx, mut t_tx) = tokio::io::split(tcp);
let (mut s_rx, mut s_tx) = tokio::io::split(s?);
tokio::spawn(async move {
let _r = join! {
tokio::io::copy(&mut t_rx, &mut s_tx) ,
tokio::io::copy(&mut s_rx, &mut t_tx),
};
let _ = tokio::io::copy_bidirectional(&mut tcp, &mut s).await;
println!("====== end tcp connection ======");
});
}
IpStackStream::Udp(udp) => {
let s = UdpStream::connect(server_addr).await;
if let Err(ref err) = s {
println!("connect UDP server failed \"{}\"", err);
continue;
}
IpStackStream::Udp(mut udp) => {
let mut s = match UdpStream::connect(server_addr).await {
Ok(s) => s,
Err(e) => {
println!("connect UDP server failed \"{}\"", e);
continue;
}
};
println!("==== New UDP connection ====");
let (mut t_rx, mut t_tx) = tokio::io::split(udp);
let (mut s_rx, mut s_tx) = tokio::io::split(s?);
tokio::spawn(async move {
let _r = join! {
tokio::io::copy(&mut t_rx, &mut s_tx) ,
tokio::io::copy(&mut s_rx, &mut t_tx),
};
let _ = tokio::io::copy_bidirectional(&mut udp, &mut s).await;
println!("==== end UDP connection ====");
});
}
Expand All @@ -132,8 +127,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("unknown transport - Ip Protocol {}", u.ip_protocol());
continue;
}
IpStackStream::UnknownNetwork(payload) => {
println!("unknown transport - {} bytes", payload.len());
IpStackStream::UnknownNetwork(pkt) => {
println!("unknown transport - {} bytes", pkt.len());
continue;
}
};
Expand Down
Loading

0 comments on commit dd932b6

Please sign in to comment.