From 4fc9ccb8601479987abcda54fa8ccae4cfc632cd Mon Sep 17 00:00:00 2001 From: alterdekim Date: Mon, 12 Aug 2024 03:54:49 +0300 Subject: [PATCH] Changes to be committed: modified: Cargo.lock modified: Cargo.toml modified: src/main.rs new file: src/tcp_client.rs new file: src/tcp_server.rs --- Cargo.lock | 16 +++++++ Cargo.toml | 3 +- src/main.rs | 10 +++-- src/tcp_client.rs | 111 ++++++++++++++++++++++++++++++++++++++++++++++ src/tcp_server.rs | 109 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 src/tcp_client.rs create mode 100644 src/tcp_server.rs diff --git a/Cargo.lock b/Cargo.lock index 9b0c452..b471680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,6 +275,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crypto-common" version = "0.1.6" @@ -793,6 +808,7 @@ dependencies = [ "block-modes", "block-padding", "clap", + "crossbeam-channel", "ctrlc", "ctrlc2", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index 4e0f6ca..a5f364b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,4 +27,5 @@ log = "0.4.20" futures = "0.3.30" tun2 = "2.0.5" packet = "0.1.4" -ctrlc2 = "3.5" \ No newline at end of file +ctrlc2 = "3.5" +crossbeam-channel = "0.5.13" diff --git a/src/main.rs b/src/main.rs index 81478a6..9eee371 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,8 +8,10 @@ use tun::platform::Device; use serde_derive::Serialize; use serde_derive::Deserialize; -mod client; -mod server; +//mod client; +//mod server; +mod tcp_client; +mod tcp_server; #[derive(Serialize, Deserialize)] struct VpnPacket { @@ -43,11 +45,11 @@ async fn main() { let is_server_mode = matches.value_of("mode").unwrap() == "server"; // "192.168.0.4:8879" if is_server_mode { - server::server_mode().await; + tcp_server::server_mode().await; } else { if let Some(vpn_server_ip) = matches.value_of("vpn-server") { let server_address = format!("{}:8879", vpn_server_ip); - client::client_mode(server_address).await; + tcp_client::client_mode(server_address).await; } else { eprintln!("Error: For client mode, you shall provide the '--vpn-server' argument."); } diff --git a/src/tcp_client.rs b/src/tcp_client.rs new file mode 100644 index 0000000..b53948b --- /dev/null +++ b/src/tcp_client.rs @@ -0,0 +1,111 @@ +use crossbeam_channel::{unbounded, Receiver}; +use tokio::{io::AsyncWriteExt, net::{TcpListener, TcpSocket, TcpStream}, sync::{mpsc, Mutex}}; +use tokio::task::JoinSet; +use packet::{builder::Builder, icmp, ip, Packet}; +use std::io::{Read, Write}; +use tun2::BoxError; +use log::{error, info, LevelFilter}; +use std::sync::Arc; +use std::net::SocketAddr; +use std::collections::HashMap; +use std::process::Command; + +fn configure_routes() { + let ip_output = Command::new("ip") + .arg("addr") + .arg("add") + .arg("10.8.0.2/24") + .arg("dev") + .arg("tun0") + .output() + .expect("Failed to execute IP command"); + + if !ip_output.status.success() { + eprintln!("Failed to set IP: {}", String::from_utf8_lossy(&ip_output.stderr)); + return; + } + + let link_output = Command::new("ip") + .arg("link") + .arg("set") + .arg("up") + .arg("dev") + .arg("tun0") + .output() + .expect("Failed to execute IP LINK command"); + + if !link_output.status.success() { + eprintln!("Failed to set link up: {}", String::from_utf8_lossy(&link_output.stderr)); + return; + } + + let route_output = Command::new("ip") + .arg("route") + .arg("add") + .arg("0.0.0.0/0") + .arg("via") + .arg("10.8.0.1") + .arg("dev") + .arg("tun0") + .output() + .expect("Failed to execute IP ROUTE command"); + + if !route_output.status.success() { + eprintln!("Failed to set route: {}", String::from_utf8_lossy(&route_output.stderr)); + } +} + +pub async fn client_mode(remote_addr: String) { + info!("Starting client..."); + + let mut config = tun2::Configuration::default(); + config.address("10.8.0.2"); + config.netmask("128.0.0.0"); + config.destination("0.0.0.0"); + config.name("tun0"); + config.up(); + + #[cfg(target_os = "linux")] + config.platform_config(|config| { + config.packet_information(true); + }); + + let dev = tun2::create(&config).unwrap(); + let (mut dev_reader, mut dev_writer) = dev.split(); + + #[cfg(target_os = "linux")] + configure_routes(); + + let socket = TcpStream::connect(&remote_addr).await.unwrap(); + let (mut sock_reader, mut sock_writer) = socket.into_split(); + + let (tx, rx) = unbounded::>(); + let (dx, mx) = unbounded::>(); + + tokio::spawn(async move { + while let Ok(bytes) = rx.recv() { + dev_writer.write(&bytes).unwrap(); + } + }); + + tokio::spawn(async move { + let mut buf = vec![0; 2048]; + while let Ok(n) = dev_reader.read(&mut buf) { + dx.send(buf[..n].to_vec()).unwrap(); + } + }); + + tokio::spawn(async move { + let mut buf = vec![0; 2048]; + loop { + let n = sock_reader.try_read(&mut buf).unwrap(); + tx.send(buf[..n].to_vec()).unwrap(); + } + }); + + loop { + if let Ok(bytes) = mx.recv() { + sock_writer.write(&bytes).await.unwrap(); + } + } +} \ No newline at end of file diff --git a/src/tcp_server.rs b/src/tcp_server.rs new file mode 100644 index 0000000..246cbb1 --- /dev/null +++ b/src/tcp_server.rs @@ -0,0 +1,109 @@ +use crossbeam_channel::{unbounded, Receiver}; +use tokio::{io::AsyncWriteExt, net::{TcpListener, TcpSocket, TcpStream}, sync::{mpsc, Mutex}}; +use tokio::task::JoinSet; +use packet::{builder::Builder, icmp, ip, Packet}; +use std::io::{Read, Write}; +use tun2::BoxError; +use log::{error, info, LevelFilter}; +use std::sync::Arc; +use std::net::SocketAddr; +use std::collections::HashMap; + +pub async fn server_mode() { + info!("Starting server..."); + + let mut config = tun2::Configuration::default(); + config.address("10.8.0.1"); + config.tun_name("tun0"); + config.up(); + + #[cfg(target_os = "linux")] + config.platform_config(|config| { + config.packet_information(true); + }); + + let dev = tun2::create(&config).unwrap(); + let (mut dev_reader, mut dev_writer) = dev.split(); + + let (tx, rx) = unbounded::>(); + let (dx, mx) = unbounded::>(); + + tokio::spawn(async move { + while let Ok(bytes) = rx.recv() { + dev_writer.write(&bytes).unwrap(); + } + }); + + tokio::spawn(async move { + let mut buf = vec![0; 2048]; + while let Ok(n) = dev_reader.read(&mut buf) { + dx.send(buf[..n].to_vec()).unwrap(); + } + }); + + let listener = TcpListener::bind("192.168.0.5:8879".parse::().unwrap()).await.unwrap(); + + loop { + let (mut socket, _) = listener.accept().await.unwrap(); + let (mut sock_reader, mut sock_writer) = socket.into_split(); + let thread_tx = tx.clone(); + let thread_mx = mx.clone(); + + tokio::spawn(async move { + loop { + if let Ok(bytes) = thread_mx.recv() { + sock_writer.write(&bytes).await.unwrap(); + } + } + }); + + tokio::spawn(async move { + let mut buf = vec![0; 2048]; + loop { + let n = sock_reader.try_read(&mut buf).unwrap(); + thread_tx.send(buf[..n].to_vec()).unwrap(); + } + }); + } + + /* let mut set = JoinSet::new(); + + set.spawn(async move { + let mut buf = [0; 4096]; + loop { + let size = reader.read(&mut buf)?; + let pkt = &buf[..size]; + use std::io::{Error, ErrorKind::Other}; + let m = clients_getter.lock().await; + match m.get(&"10.0.8.2") { + Some(&ref sock) => { sock.send(&pkt).await.unwrap(); info!("Wrote to sock") }, + None => { error!("There's no client!") } + }; + drop(m); + () + } + #[allow(unreachable_code)] + Ok::<(), std::io::Error>(()) + }); + + set.spawn(async move { + let mut buf = [0; 4096]; + loop { + if let Ok((len, addr)) = receiver_sock.recv_from(&mut buf).await { + let mut m = clients_inserter.lock().await; + if !m.contains_key(&"10.0.8.2") { + let cl = UdpSocket::bind("0.0.0.0:59611").await?; + cl.connect(addr).await?; + m.insert("10.0.8.2", cl); + } + drop(m); + writer.write_all(&buf[..len])?; + info!("Wrote to tun"); + } + } + }); + + while let Some(res) = set.join_next().await {} + + Ok(())*/ +} \ No newline at end of file