modified: Cargo.lock

modified:   frida_cli/Cargo.toml
	modified:   frida_cli/src/main.rs
	modified:   frida_client/Cargo.toml
	modified:   frida_client/src/client.rs
	new file:   frida_client/src/lib.rs
	renamed:    frida_cli/src/config/mod.rs -> frida_core/src/config.rs
	modified:   frida_core/src/device.rs
	modified:   frida_core/src/lib.rs
	modified:   frida_core/src/linux_tun.rs
	renamed:    frida_cli/src/obfs.rs -> frida_core/src/obfs.rs
	renamed:    frida_cli/src/udp.rs -> frida_core/src/udp.rs
	modified:   frida_core/src/win_tun.rs
This commit is contained in:
Michael Wain 2024-12-09 19:02:35 +03:00
parent c3b886c21f
commit 3c23c38d25
13 changed files with 122 additions and 59 deletions

12
Cargo.lock generated
View File

@ -1646,6 +1646,18 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]] [[package]]
name = "frida_cli" name = "frida_cli"
version = "0.2.0" version = "0.2.0"
dependencies = [
"clap",
"env_logger",
"frida_client",
"frida_core",
"log",
"serde",
"serde_derive",
"serde_yaml",
"tokio 1.42.0",
"tokio-util",
]
[[package]] [[package]]
name = "frida_client" name = "frida_client"

View File

@ -10,3 +10,13 @@ readme = "../README.md"
workspace = "../" workspace = "../"
[dependencies] [dependencies]
clap = "2.33"
env_logger = "0.9"
log = "0.4.20"
serde = "1.0"
serde_derive = "1.0.190"
serde_yaml = "0.9.34"
tokio = { version = "1", features = ["full", "signal", "tracing"] }
tokio-util = "0.7.12"
frida_core = { path = "../frida_core" }
frida_client = { path = "../frida_client" }

View File

@ -1,16 +1,12 @@
use std::{fs, net::{Ipv4Addr}, str}; use std::{fs, net::{Ipv4Addr}, str};
use clap::{App, Arg, ArgMatches}; use clap::{crate_authors, crate_name, crate_version, App, Arg, ArgMatches};
use env_logger::Builder; use env_logger::Builder;
use log::{error, LevelFilter}; use log::{error, LevelFilter};
use crate::config::{ ServerConfiguration, ClientConfiguration, ObfsProtocol, ServerPeer }; use frida_core::config::{ ServerConfiguration, ClientConfiguration, ObfsProtocol, ServerPeer };
use crate::client::{desktop::DesktopClient, general::VpnClient}; use frida_client::client::{desktop::DesktopClient, general::VpnClient};
mod obfs; //mod server;
mod server;
mod client;
mod udp;
mod config;
fn generate_server_config(matches: &ArgMatches, config_path: &str) { fn generate_server_config(matches: &ArgMatches, config_path: &str) {
let bind_address = matches.value_of("bind-address").expect("No bind address specified"); let bind_address = matches.value_of("bind-address").expect("No bind address specified");
@ -62,7 +58,7 @@ fn generate_peer_config(matches: &ArgMatches, config_path: &str, cfg_raw: &Strin
async fn init_server(cfg_raw: &str, s_interface: Option<&str>) { async fn init_server(cfg_raw: &str, s_interface: Option<&str>) {
let config: ServerConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad server config file structure"); let config: ServerConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad server config file structure");
server::server_mode(config, s_interface).await; //server::server_mode(config, s_interface).await;
} }
async fn init_client(cfg_raw: &str, s_interface: Option<String>) { async fn init_client(cfg_raw: &str, s_interface: Option<String>) {
@ -74,16 +70,14 @@ async fn init_client(cfg_raw: &str, s_interface: Option<String>) {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
//console_subscriber::init();
// Initialize the logger with 'info' as the default level // Initialize the logger with 'info' as the default level
Builder::new() Builder::new()
.filter(None, LevelFilter::Info) .filter(None, LevelFilter::Info)
.init(); .init();
let matches = App::new("Frida") let matches = App::new(crate_name!())
.version("0.1.2") .version(crate_version!())
.author("alterwain") .author(crate_authors!())
.about("VPN software") .about("VPN software")
.arg(Arg::with_name("mode") .arg(Arg::with_name("mode")
.required(true) .required(true)

View File

@ -8,9 +8,8 @@ keywords = ["tun", "network", "tunnel", "vpn"]
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
readme = "../README.md" readme = "../README.md"
[[bin]] [lib]
name = "frida_client" crate-type = ["staticlib", "cdylib", "lib"]
path = "src/client.rs"
[dependencies] [dependencies]
frida_core = { path = "../frida_core", package = "frida_core" } frida_core = { path = "../frida_core", package = "frida_core" }

View File

@ -1,7 +1,5 @@
pub mod general { pub mod general {
use crate::config::ClientConfiguration; use frida_core::config::ClientConfiguration;
use async_channel::{Receiver, Sender};
use futures::{stream::{SplitSink, SplitStream}, SinkExt, StreamExt};
use tokio_util::{codec::Framed, sync::CancellationToken}; use tokio_util::{codec::Framed, sync::CancellationToken};
use tokio::{net::UdpSocket, sync::{Mutex, mpsc}, io::{AsyncWriteExt, AsyncReadExt}, fs::File}; use tokio::{net::UdpSocket, sync::{Mutex, mpsc}, io::{AsyncWriteExt, AsyncReadExt}, fs::File};
use log::{error, info, warn}; use log::{error, info, warn};
@ -13,9 +11,7 @@ pub mod general {
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use x25519_dalek::{PublicKey, StaticSecret}; use x25519_dalek::{PublicKey, StaticSecret};
use crate::udp::{UDPVpnPacket, UDPVpnHandshake, UDPSerializable}; use frida_core::udp::{UDPVpnPacket, UDPVpnHandshake, UDPSerializable};
use frida_core::tun::create_tun;
use frida_core::{DeviceReader, DeviceWriter}; use frida_core::{DeviceReader, DeviceWriter};
pub trait VpnClient { pub trait VpnClient {
@ -24,13 +20,11 @@ pub mod general {
pub struct CoreVpnClient { pub struct CoreVpnClient {
pub client_config: ClientConfiguration, pub client_config: ClientConfiguration,
pub dev_reader: DeviceReader,
pub dev_writer: DeviceWriter,
pub close_token: CancellationToken pub close_token: CancellationToken
} }
impl CoreVpnClient { impl CoreVpnClient {
pub async fn start(&mut self, sock: UdpSocket) { pub async fn start(&mut self, sock: UdpSocket, dev_reader: DeviceReader, dev_writer: DeviceWriter) {
info!("Starting client..."); info!("Starting client...");
let dr_cancel: CancellationToken = CancellationToken::new(); let dr_cancel: CancellationToken = CancellationToken::new();
@ -59,11 +53,23 @@ pub mod general {
let s_cipher = cipher_shared.clone(); let s_cipher = cipher_shared.clone();
let _ = self.dev_writer.write(handshake.serialize()).await; let _ = dev_writer.write(&handshake.serialize()).await;
let mut buf = vec![0; 1400]; // mtu
let mut buf1 = vec![0; 4096]; // should be changed to less bytes let mut buf1 = vec![0; 4096]; // should be changed to less bytes
tokio::spawn(async move {
let mut buf = vec![0; 1400]; // mtu
loop {
match dev_reader.read(&mut buf).await {
Ok(n) => {
info!("Read from tun."); // hex::encode(&buf[..n])
dx.send(buf[..n].to_vec()).unwrap();
},
Err(e) => { error!("{}", e); }
}
}
});
loop { loop {
tokio::select! { tokio::select! {
_ = self.close_token.cancelled() => { _ = self.close_token.cancelled() => {
@ -76,7 +82,7 @@ pub mod general {
if let Some(bytes) = rr { if let Some(bytes) = rr {
info!("Write to tun. len={:?}", bytes.len()); info!("Write to tun. len={:?}", bytes.len());
if let Err(e) = self.dev_writer.write(&bytes).await { if let Err(e) = dev_writer.write(&bytes).await {
error!("Writing error: {:?}", e); error!("Writing error: {:?}", e);
} }
/* if let Err(e) = self.dev_writer.flush().await { /* if let Err(e) = self.dev_writer.flush().await {
@ -86,6 +92,7 @@ pub mod general {
} }
rr2 = mx.recv() => { rr2 = mx.recv() => {
if let Some(bytes) = rr2 { if let Some(bytes) = rr2 {
info!("Got info for sending");
let s_c = s_cipher.lock().await; let s_c = s_cipher.lock().await;
if s_c.is_some() { if s_c.is_some() {
@ -106,12 +113,6 @@ pub mod general {
} }
} }
} }
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();
}
}
rr = sock_rec.recv(&mut buf1) => { rr = sock_rec.recv(&mut buf1) => {
if let Ok(l) = rr { if let Ok(l) = rr {
info!("Read from socket"); info!("Read from socket");
@ -190,11 +191,12 @@ pub mod android {
} }
pub mod desktop { pub mod desktop {
use crate::client::general::{CoreVpnClient, DevReader, DevWriter, VpnClient}; use std::net::Ipv4Addr;
use crate::config::ClientConfiguration;
use frida_core::create; use crate::client::general::{CoreVpnClient, VpnClient};
use frida_core::config::ClientConfiguration;
use frida_core::tun::create_tun;
use frida_core::device::AbstractDevice; use frida_core::device::AbstractDevice;
use futures::{SinkExt, StreamExt};
use log::info; use log::info;
use tokio::net::UdpSocket; use tokio::net::UdpSocket;
use tokio::sync::Mutex; use tokio::sync::Mutex;
@ -270,21 +272,19 @@ pub mod desktop {
info!("s_interface: {:?}", &self.s_interface); info!("s_interface: {:?}", &self.s_interface);
info!("client_address: {:?}", &self.client_config.client.address); info!("client_address: {:?}", &self.client_config.client.address);
let mut config = AbstractDevice::default(); let mut config = AbstractDevice::default();
config.address(&self.client_config.client.address) config.address(self.client_config.client.address.parse().unwrap())
.netmask("255.255.255.255") .netmask(std::net::IpAddr::V4(Ipv4Addr::new(255, 255, 255, 255)))
.destination("10.66.66.1") .destination(std::net::IpAddr::V4(Ipv4Addr::new(10, 66, 66, 1)))
.mtu(1400) .mtu(1400)
.tun_name("tun0") .tun_name("tun0");
.up();
info!("SSS: {:?}", &self.client_config.server.endpoint); info!("SSS: {:?}", &self.client_config.server.endpoint);
let sock = UdpSocket::bind(("0.0.0.0", 0)).await.unwrap(); let sock = UdpSocket::bind(("0.0.0.0", 0)).await.unwrap();
sock.connect(&self.client_config.server.endpoint).await.unwrap(); sock.connect(&self.client_config.server.endpoint).await.unwrap();
let dev = create(&config).unwrap(); let (dev_reader, dev_writer) = create_tun(config);
let (mut dev_writer , mut dev_reader) = dev.into_framed().split();
let mut client = CoreVpnClient{ client_config: self.client_config.clone(), dev_reader: DevReader{ dr: dev_reader }, dev_writer: DevWriter{dr: dev_writer }, close_token: tokio_util::sync::CancellationToken::new()}; let mut client = CoreVpnClient{ client_config: self.client_config.clone(), close_token: tokio_util::sync::CancellationToken::new()};
info!("Platform specific code"); info!("Platform specific code");
/* #[cfg(target_os = "linux")] /* #[cfg(target_os = "linux")]
@ -293,7 +293,7 @@ pub mod desktop {
configure_routes(&s_a.ip().to_string(), self.s_interface.clone()); configure_routes(&s_a.ip().to_string(), self.s_interface.clone());
}*/ }*/
client.start(sock).await; client.start(sock, dev_reader, dev_writer).await;
} }
} }
} }

1
frida_client/src/lib.rs Normal file
View File

@ -0,0 +1 @@
pub mod client;

View File

@ -3,11 +3,11 @@ use std::net::IpAddr;
#[derive(Default)] #[derive(Default)]
pub struct AbstractDevice { pub struct AbstractDevice {
address: Option<IpAddr>, pub(crate) address: Option<IpAddr>,
netmask: Option<IpAddr>, pub(crate) netmask: Option<IpAddr>,
destination: Option<IpAddr>, pub(crate) destination: Option<IpAddr>,
mtu: Option<u16>, pub(crate) mtu: Option<u16>,
tun_name: Option<String> pub(crate) tun_name: Option<String>
} }
impl AbstractDevice { impl AbstractDevice {

View File

@ -1,5 +1,8 @@
pub mod device; pub mod device;
pub mod tun; pub mod tun;
pub mod obfs;
pub mod udp;
pub mod config;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
mod win_tun; mod win_tun;

View File

@ -7,9 +7,11 @@ use std::os::unix::io::AsRawFd;
pub fn create(cfg: AbstractDevice) -> (DeviceReader, DeviceWriter) { pub fn create(cfg: AbstractDevice) -> (DeviceReader, DeviceWriter) {
let tun = Arc::new( let tun = Arc::new(
Tun::builder() Tun::builder()
.name("") // if name is empty, then it is set by kernel. .name(cfg.tun_name.unwrap()) // if name is empty, then it is set by kernel.
.tap() // uses TAP instead of TUN (default). .mtu(cfg.mtu.unwrap())
.packet_info() // avoids setting IFF_NO_PI. .address(cfg.address.unwrap())
.netmask(cfg.netmask.unwrap())
.destination(cfg.destination.unwrap())
.up() // or set it up manually using `sudo ip link set <tun-name> up`. .up() // or set it up manually using `sudo ip link set <tun-name> up`.
.try_build() // or `.try_build_mq(queues)` for multi-queue support. .try_build() // or `.try_build_mq(queues)` for multi-queue support.
.unwrap(), .unwrap(),

View File

@ -10,15 +10,57 @@ pub fn create(cfg: AbstractDevice) -> (DeviceReader, DeviceWriter) {
let wintun = unsafe { wintun::load_from_path("wintun.dll") } let wintun = unsafe { wintun::load_from_path("wintun.dll") }
.expect("Failed to load wintun dll"); .expect("Failed to load wintun dll");
//Try to open an adapter with the name "Demo" let tun_name = match cfg.tun_name {
let adapter = match wintun::Adapter::open(&wintun, "Demo") { Some(n) => n,
None => "Demo".into()
};
//Try to open an adapter with the certain name
let adapter = match wintun::Adapter::open(&wintun, &tun_name) {
Ok(a) => a, Ok(a) => a,
Err(_) => { Err(_) => {
wintun::Adapter::create(&wintun, "Demo", "Example", None) wintun::Adapter::create(&wintun, &tun_name, "FridaVPN", None)
.expect("Failed to create wintun adapter!") .expect("Failed to create wintun adapter!")
} }
}; };
let args = &["interface", "ipv4", "set", "interface", &tun_name, "metric=5"];
let _ = wintun::run_command("netsh", args).unwrap();
let mut gateway = "gateway=".to_owned();
gateway.push_str(&cfg.destination.unwrap().to_string());
let mut address = cfg.address.unwrap().to_string().to_owned();
address.push_str("/32");
let args = &[
"interface",
"ipv4",
"set",
"address",
&tun_name,
"static",
&address,
&gateway,
];
let _ = wintun::run_command("netsh", args).unwrap();
let mut mtu = "mtu=".to_owned();
mtu.push_str(&cfg.mtu.unwrap().to_string());
let args = &[
"interface",
"ipv4",
"set",
"subinterface",
&tun_name,
&mtu,
"store=persistent"
];
let _ = wintun::run_command("netsh", args).unwrap();
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap()); let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
let reader_session = session.clone(); let reader_session = session.clone();
let writer_session = session.clone(); let writer_session = session.clone();