From 08c6f75afff83496ad2651e504e37b089eaeabdb Mon Sep 17 00:00:00 2001 From: alterdekim Date: Tue, 15 Oct 2024 03:07:58 +0300 Subject: [PATCH] modified: Cargo.lock modified: Cargo.toml new file: src/android.rs modified: src/client.rs modified: src/main.rs --- Cargo.lock | 335 +++++++++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 14 ++- src/android.rs | 101 +++++++++++++++ src/client.rs | 245 +++++++++++++++++++++++++++++++++--- src/main.rs | 5 +- 5 files changed, 655 insertions(+), 45 deletions(-) create mode 100644 src/android.rs diff --git a/Cargo.lock b/Cargo.lock index 3cc7115..d1e4d18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "addr2line" version = "0.22.0" @@ -97,6 +107,12 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "async-stream" version = "0.3.5" @@ -299,6 +315,12 @@ version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -353,12 +375,22 @@ dependencies = [ "ansi_term", "atty", "bitflags 1.3.2", - "strsim", + "strsim 0.8.0", "textwrap", "unicode-width", "vec_map", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "console-api" version = "0.8.0" @@ -483,6 +515,58 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "destructure_traitobject" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" + [[package]] name = "either" version = "1.13.0" @@ -532,7 +616,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "frida_vpn" -version = "0.1.2" +version = "0.1.5" dependencies = [ "aes-gcm", "base64 0.22.1", @@ -546,16 +630,20 @@ dependencies = [ "futures", "generic-array", "hex", + "jni 0.20.0", "log", + "log4rs", "network-interface", + "nonblock", "packet", "rand", + "robusta_jni", "serde", "serde_derive", "serde_yaml", "socket2 0.4.10", - "socks5-server", "tokio", + "tokio-util", "tun2", "x25519-dalek", ] @@ -889,6 +977,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "indexmap" version = "1.9.3" @@ -939,6 +1033,40 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "js-sys" version = "0.3.70" @@ -985,6 +1113,43 @@ name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "serde", +] + +[[package]] +name = "log-mdc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" + +[[package]] +name = "log4rs" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6" +dependencies = [ + "anyhow", + "arc-swap", + "chrono", + "derivative", + "fnv", + "humantime", + "libc", + "log", + "log-mdc", + "once_cell", + "parking_lot", + "rand", + "serde", + "serde-value", + "serde_json", + "serde_yaml", + "thiserror", + "thread-id", + "typemap-ors", + "winapi", +] [[package]] name = "matchers" @@ -1083,6 +1248,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonblock" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51c7a4f22e5f2e2bd805d6ab56f1ae87eb1815673e1b452048896fb687a8a3d4" +dependencies = [ + "libc", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1113,6 +1287,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "packet" version = "0.1.4" @@ -1148,6 +1331,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1225,6 +1414,29 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -1358,6 +1570,33 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "robusta-codegen" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb512b451472948a204452dfad582bdc48d69caacdd3b1b4571d5e3f11707f3" +dependencies = [ + "Inflector", + "darling", + "proc-macro-error", + "proc-macro2", + "quote", + "rand", + "syn 1.0.109", +] + +[[package]] +name = "robusta_jni" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c080146e0cc733697fe500413871142af91bd879641205c2febbe5f982f304e3" +dependencies = [ + "jni 0.19.0", + "paste", + "robusta-codegen", + "static_assertions", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1385,6 +1624,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1406,6 +1654,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.205" @@ -1502,27 +1760,10 @@ dependencies = [ ] [[package]] -name = "socks5-proto" -version = "0.4.1" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d91431c4672e25e372ef46bc554be8f315068c03608f99267a71ad32a12e8c4" -dependencies = [ - "bytes", - "thiserror", - "tokio", -] - -[[package]] -name = "socks5-server" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5223c26981806584cc38c74fddf58808dbdcf4724890471ced69e7a2e8d86345" -dependencies = [ - "async-trait", - "bytes", - "socks5-proto", - "tokio", -] +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" @@ -1530,6 +1771,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.6.1" @@ -1608,6 +1855,16 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "thread-id" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe8f25bbdd100db7e1d34acf7fd2dc59c4bf8f7483f505eaa7d4f12f76cc0ea" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -1661,9 +1918,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -1808,6 +2065,15 @@ dependencies = [ "wintun", ] +[[package]] +name = "typemap-ors" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867" +dependencies = [ + "unsafe-any-ors", +] + [[package]] name = "typenum" version = "1.17.0" @@ -1836,6 +2102,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-any-ors" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad" +dependencies = [ + "destructure_traitobject", +] + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -1860,6 +2135,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index 922c132..244bf08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "frida_vpn" -version = "0.1.2" +version = "0.1.5" edition = "2021" license = "Apache-2.0" authors = ["alterdekim"] @@ -10,10 +10,15 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +crate-type = ["cdylib"] +path = "src/android.rs" + [dependencies] clap = "2.33" aes-gcm = "0.10.3" tokio = { version = "1", features = ["full", "signal", "tracing"] } +tokio-util = "0.7.12" serde = "1.0" serde_derive = "1.0.190" rand = { version = "0.8.5", features = ["small_rng", "getrandom", "std_rng"] } @@ -34,4 +39,9 @@ base64 = "0.22.1" chrono = "0.4.38" console-subscriber = "0.4.0" network-interface = "2.0.0" -socks5-server = "0.10.1" + +[target.'cfg(target_os="android")'.dependencies] +jni = "^0.20" +robusta_jni = "0.2.2" +nonblock = "0.2.0" +log4rs = "1.3.0" \ No newline at end of file diff --git a/src/android.rs b/src/android.rs new file mode 100644 index 0000000..7888ed5 --- /dev/null +++ b/src/android.rs @@ -0,0 +1,101 @@ +#![cfg(target_os = "android")] + +use ::jni::objects::GlobalRef; +use ::jni::JavaVM; +use robusta_jni::bridge; +use std::sync::OnceLock; +use robusta_jni::jni::JNIEnv; +use std::fs::File; +use std::io::Write; + +mod config; +mod client; +mod udp; +mod mobile; + +static TUN_QUIT: std::sync::Mutex> = std::sync::Mutex::new(None); + +#[bridge] +mod jni { + use jni::objects::{GlobalRef, JObject, JValue, JString}; + use jni::sys::{jboolean, jchar, jint, jstring}; + use log::{info, trace}; + use log::LevelFilter; + use log4rs::append::file::FileAppender; + use log4rs::encode::pattern::PatternEncoder; + use log4rs::config::{Appender, Config, Root}; + use robusta_jni::convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}; + use robusta_jni::jni::errors::Result as JniResult; + use robusta_jni::jni::objects::AutoLocal; + use robusta_jni::jni::JNIEnv; + use crate::mobile; + use crate::TUN_QUIT; + use std::fs::File; + + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(com.alterdekim.frida)] + pub struct FridaLib<'env: 'borrow, 'borrow> { + #[instance] + raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> FridaLib<'env, 'borrow> { + pub extern "jni" fn start(self, env: &JNIEnv, config_b32: String, + tun_fd: i32, + close_fd_on_drop: bool, + temp_file: String) -> JniResult { + + let logfile = FileAppender::builder() + .encoder(Box::new(PatternEncoder::new("{l} - {m}\n"))) + .build(&temp_file).unwrap(); + + let config = Config::builder() + .appender(Appender::builder().build("logfile", Box::new(logfile))) + .build(Root::builder() + .appender("logfile") + .build(LevelFilter::Info)).unwrap(); + + log4rs::init_config(config); + + let close_token = tokio_util::sync::CancellationToken::new(); + if let Ok(mut l) = TUN_QUIT.lock() { + if l.is_some() { + return Ok(-1); + } + *l = Some(close_token.clone()); + } else { + return Ok(-2); + } + + let main_loop = async move { + let config: ClientConfiguration = serde_yaml::from_slice(hex::decode(config_b32).unwrap().as_slice()).expect("Bad client config file structure"); + let client = AndroidClient{client_config: config, fd: tun_fd, close_token}; + client.start().await; + }; + + let exit_code = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { + Err(_e) => -3, + Ok(rt) => { rt.block_on(main_loop); -4 } + }; + + Ok(exit_code) + } + + pub extern "jni" fn stop(self, env: &JNIEnv) -> JniResult { + if let Ok(mut l) = TUN_QUIT.lock() { + if let Some(close_token) = l.take() { + close_token.cancel(); + return Ok(0); + } + } + Ok(-1) + } + + pub extern "java" fn traceFromNative( + env: &JNIEnv, + text: String, + ) -> JniResult<()> { + + } + } +} \ No newline at end of file diff --git a/src/client.rs b/src/client.rs index 3545039..0d8ddf7 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,13 +1,14 @@ use crossbeam_channel::unbounded; use socket2::SockAddr; -use tokio::{net::UdpSocket, sync::Mutex}; +use tokio::{net::UdpSocket, sync::{Mutex, mpsc}, io::{BufReader, BufWriter, AsyncWriteExt, AsyncReadExt}, fs::File}; +use tokio_util::sync::CancellationToken; use std::{io::{Read, Write}, net::SocketAddr}; use base64::prelude::*; use log::{error, info, warn}; use std::sync::Arc; use std::net::Ipv4Addr; use x25519_dalek::{PublicKey, StaticSecret}; -use std::process::Command; +use std::{ process::Command, os::unix::io::FromRawFd}; use aes_gcm::{ aead::{Aead, AeadCore, KeyInit, OsRng}, Aes256Gcm, Nonce}; @@ -17,7 +18,7 @@ use crate::udp::{UDPVpnPacket, UDPVpnHandshake, UDPSerializable}; use network_interface::NetworkInterface; use network_interface::NetworkInterfaceConfig; -fn configure_routes(endpoint_ip: &str, s_interface: Option<&str>) { +fn configure_routes(endpoint_ip: &str, s_interface: Option) { let interfaces = NetworkInterface::show().unwrap(); let net_inter = interfaces.iter() @@ -25,7 +26,7 @@ fn configure_routes(endpoint_ip: &str, s_interface: Option<&str>) { .min_by(|x, y| x.index.cmp(&y.index)) .unwrap(); - let inter_name = if s_interface.is_some() { s_interface.unwrap() } else { &net_inter.name }; + let inter_name = if s_interface.is_some() { s_interface.unwrap() } else { net_inter.name }; info!("Main network interface: {:?}", inter_name); @@ -73,22 +74,234 @@ fn configure_routes(endpoint_ip: &str, s_interface: Option<&str>) { } } -pub async fn client_mode(client_config: ClientConfiguration, s_interface: Option<&str>) { +/* +s_interface: Option<&str> +let s_a: SocketAddr = client_config.server.endpoint.parse().unwrap(); +#[cfg(target_os = "linux")] +configure_routes(&s_a.ip().to_string(), s_interface); +*/ + +/* +What the fuck I want to implement? +I need to make abstract class VPNClient which should be extended by several others: +AndroidClient +DesktopClient + +Both of child classes should trigger the same "core vpn client" module + +*/ + +pub struct AndroidClient { + client_config: ClientConfiguration, + fd: i32, + close_token: CancellationToken +} + +pub struct DesktopClient { + client_config: ClientConfiguration, + s_interface: Option +} + +impl VpnClient for AndroidClient { + async fn start(&self) { + info!("FD: {:?}", &self.fd); + let mut dev = unsafe { File::from_raw_fd(self.fd) }; + let mut dev1 = unsafe { File::from_raw_fd(self.fd) }; + let mut dev_reader = BufReader::new(dev); + let mut dev_writer = BufWriter::new(dev1); + let client = CoreVpnClient{client_config: self.client_config, dev_reader, dev_writer, close_token: self.close_token}; + client.start().await; + } +} + +impl VpnClient for DesktopClient { + async fn start(&self) { + info!("s_interface: {:?}", &self.s_interface); + let mut config = tun2::Configuration::default(); + config.address(&self.client_config.client.address) + .netmask("255.255.255.255") + .destination("10.66.66.1") + .tun_name("tun0") + .up(); + + let dev = tun2::create(&config).unwrap(); + let (mut dev_reader, mut dev_writer) = dev.split(); + let client = CoreVpnClient{ client_config: self.client_config, dev_reader, dev_writer, close_token: tokio_util::sync::CancellationToken::new()}; + client.start().await; + } +} + +pub trait VpnClient { + async fn start(&self); +} + +struct CoreVpnClient { + client_config: ClientConfiguration, + dev_reader: Reader, + dev_writer: Writer, + close_token: CancellationToken +} + +impl CoreVpnClient { + pub async fn start(&self) { + info!("Starting client..."); + + let dr_cancel: CancellationToken = CancellationToken::new(); + let sr_cancel: CancellationToken = CancellationToken::new(); + + let sock = UdpSocket::bind("0.0.0.0:25565").await.unwrap(); + sock.connect(&self.client_config.server.endpoint).await.unwrap(); + + let sock_rec = Arc::new(sock); + let sock_snd = sock_rec.clone(); + + let (tx, mut rx) = mpsc::unbounded_channel::>(); + let (dx, mut mx) = mpsc::unbounded_channel::>(); + + let cipher_shared: Arc>> = Arc::new(Mutex::new(None)); + + let dr_cc = dr_cancel.clone(); + let dev_read_task = tokio::spawn(async move { + let mut buf = vec![0; 1400]; // mtu + loop { + tokio::select! { + _ = dr_cc.cancelled() => { + info!("Cancellation token has been thrown dev_read_task"); + return; + } + rr = self.dev_reader.read(&mut buf) => { + if let Ok(n) = rr { + info!("Read from tun."); // hex::encode(&buf[..n]) + dx.send(buf[..n].to_vec()).unwrap(); + } + } + }; + } + }); + + let priv_key = BASE64_STANDARD.decode(self.client_config.client.private_key).unwrap(); + + let cipher_shared_clone = cipher_shared.clone(); + let sr_cc = sr_cancel.clone(); + let sock_read_task = tokio::spawn(async move { + let mut buf = vec![0; 4096]; + + loop { + tokio::select! { + _ = sr_cc.cancelled() => { + info!("Cancellation token has been thrown sock_read_task"); + return; + } + rr = sock_rec.recv(&mut buf) => { + if let Ok(l) = rr { + info!("Read from socket"); + let mut s_cipher = cipher_shared_clone.lock().await; + match buf.first() { + Some(h) => { + match h { + 0 => { + let handshake = UDPVpnHandshake::deserialize(&(buf[..l].to_vec())); + let mut k = [0u8; 32]; + for (&x, p) in handshake.public_key.iter().zip(k.iter_mut()) { + *p = x; + } + let mut k1 = [0u8; 32]; + for (&x, p) in priv_key.iter().zip(k1.iter_mut()) { + *p = x; + } + *s_cipher = Some(StaticSecret::from(k1) + .diffie_hellman(&PublicKey::from(k))); + }, // handshake + 1 => { + let wrapped_packet = UDPVpnPacket::deserialize(&(buf[..l].to_vec())); + if s_cipher.is_some() { + let aes = Aes256Gcm::new(s_cipher.as_ref().unwrap().as_bytes().into()); + let nonce = Nonce::clone_from_slice(&wrapped_packet.nonce); + match aes.decrypt(&nonce, &wrapped_packet.data[..]) { + Ok(decrypted) => { let _ = tx.send(decrypted); }, + Err(error) => { error!("Decryption error! {:?}", error); } + } + } else { + warn!("There is no static_secret"); + } + }, // payload + 2 => { info!("Got keepalive packet"); }, + _ => { error!("Unexpected header value."); } + } + }, + None => { error!("There is no header."); } + } + drop(s_cipher); + } + } + }; + } + }); + + let pkey = BASE64_STANDARD.decode(self.client_config.client.public_key).unwrap(); + let handshake = UDPVpnHandshake{ public_key: pkey, request_ip: self.client_config.client.address.parse::().unwrap() }; + let mut nz = 0; + while nz < 25 { + sock_snd.send(&handshake.serialize()).await.unwrap(); + nz += 1 + } + //sock_snd.send(&handshake.serialize()).await.unwrap(); + + let s_cipher = cipher_shared.clone(); + loop { + tokio::select! { + _ = self.close_token.cancelled() => { + info!("Cancellation token has been thrown"); + sr_cancel.cancel(); + dr_cancel.cancel(); + return; + } + rr = rx.recv() => { + if let Some(bytes) = rr { + info!("Write to tun."); + if let Err(e) = self.dev_writer.write_all(&bytes).await { + error!("Writing error: {:?}", e); + } + if let Err(e) = self.dev_writer.flush().await { + error!("Flushing error: {:?}", e); + } + } + } + rr2 = mx.recv() => { + if let Some(bytes) = rr2 { + let s_c = s_cipher.lock().await; + + if s_c.is_some() { + let aes = Aes256Gcm::new(s_c.as_ref().unwrap().as_bytes().into()); + let nonce = Aes256Gcm::generate_nonce(&mut OsRng); + let ciphered_data = aes.encrypt(&nonce, &bytes[..]); + + if let Ok(ciphered_d) = ciphered_data { + let vpn_packet = UDPVpnPacket{ data: ciphered_d, nonce: nonce.to_vec()}; + let serialized_data = vpn_packet.serialize(); + info!("Write to socket"); + sock_snd.send(&serialized_data).await.unwrap(); + } else { + error!("Socket encryption failed."); + } + } else { + error!("There is no shared_secret in main loop"); + } + } + } + }; + } + } +} + +/*pub async fn client_mode(client_config: ClientConfiguration, s_interface: Option<&str>) { info!("Starting client..."); info!("s_interface: {:?}", s_interface); let sock = UdpSocket::bind("0.0.0.0:25565").await.unwrap(); sock.connect(&client_config.server.endpoint).await.unwrap(); - let mut config = tun2::Configuration::default(); - config.address(&client_config.client.address) - .netmask("255.255.255.255") - .destination("10.66.66.1") - .tun_name("tun0") - .up(); - let dev = tun2::create(&config).unwrap(); - let (mut dev_reader, mut dev_writer) = dev.split(); let sock_rec = Arc::new(sock); let sock_snd = sock_rec.clone(); @@ -112,9 +325,7 @@ pub async fn client_mode(client_config: ClientConfiguration, s_interface: Option } }); - let s_a: SocketAddr = client_config.server.endpoint.parse().unwrap(); - #[cfg(target_os = "linux")] - configure_routes(&s_a.ip().to_string(), s_interface); + let priv_key = BASE64_STANDARD.decode(client_config.client.private_key).unwrap(); @@ -196,4 +407,4 @@ pub async fn client_mode(client_config: ClientConfiguration, s_interface: Option } } } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index ff044d2..f3980ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use clap::{App, Arg, ArgMatches}; use env_logger::Builder; use log::{error, LevelFilter}; use crate::config::{ ServerConfiguration, ClientConfiguration, ObfsProtocol, ServerPeer }; +use crate::client::{DesktopClient, VpnClient}; mod obfs; mod server; @@ -67,7 +68,9 @@ async fn init_server(cfg_raw: &str, s_interface: Option<&str>) { async fn init_client(cfg_raw: &str, s_interface: Option<&str>) { let config: ClientConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad client config file structure"); - client::client_mode(config, s_interface).await; + //client::client_mode(config, s_interface).await; + let client = DesktopClient{client_config: config, s_interface}; + client.start().await; } #[tokio::main]