Changes to be committed:
modified: Cargo.lock modified: Cargo.toml modified: README.md modified: src/client.rs modified: src/main.rs modified: src/server.rs
This commit is contained in:
parent
f24dab6188
commit
8bf6d57ba8
56
Cargo.lock
generated
56
Cargo.lock
generated
@ -414,6 +414,12 @@ dependencies = [
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.9"
|
||||
@ -556,6 +562,12 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
@ -601,6 +613,16 @@ dependencies = [
|
||||
"phf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
@ -640,6 +662,12 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
@ -1201,7 +1229,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustvpn"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"aes 0.7.5",
|
||||
"aes-gcm",
|
||||
@ -1225,12 +1253,19 @@ dependencies = [
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_yaml",
|
||||
"socket2 0.4.10",
|
||||
"tokio",
|
||||
"tun",
|
||||
"tun2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@ -1257,6 +1292,19 @@ dependencies = [
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
@ -1473,6 +1521,12 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustvpn"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@ -31,4 +31,5 @@ ctrlc2 = "3.5"
|
||||
crossbeam-channel = "0.5.13"
|
||||
pnet = "0.35.0"
|
||||
net-route = "0.4.4"
|
||||
hex = "0.4"
|
||||
hex = "0.4"
|
||||
serde_yaml = "0.9.34"
|
||||
|
32
README.md
32
README.md
@ -1,4 +1,34 @@
|
||||
# Frida
|
||||
|
||||
A basic VPN tunnel with data obfuscation.
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
A lightweight VPN software, focused on scalability, traffic obfuscation and simplicity.
|
||||
|
||||
## Documentation
|
||||
|
||||
Check the [repository wiki]() to access the documentation, tutorials.
|
||||
|
||||
## Installation
|
||||
|
||||
On Linux, you can run this in a terminal (sudo required):
|
||||
|
||||
```
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://get-frida.awain.net | sh
|
||||
```
|
||||
|
||||
Also you can download latest version from the releases page.
|
||||
|
||||
## Android / IOS
|
||||
|
||||
There is an app for both Android and IOS devices.
|
||||
|
||||
### Android links
|
||||
- Google play: ...
|
||||
- Github: ...
|
||||
|
||||
### IOS links
|
||||
- Github: ...
|
||||
|
@ -11,7 +11,7 @@ use std::collections::HashMap;
|
||||
use std::process::Command;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
use crate::{UDPVpnHandshake, UDPVpnPacket, VpnPacket};
|
||||
use crate::{UDPVpnHandshake, UDPVpnPacket, VpnPacket, ClientConfiguration};
|
||||
|
||||
fn configure_routes() {
|
||||
let ip_output = Command::new("ip")
|
||||
@ -58,15 +58,15 @@ fn configure_routes() {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn client_mode(remote_addr: String) {
|
||||
pub async fn client_mode(client_config: ClientConfiguration) {
|
||||
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();
|
||||
config.address(&client_config.client.address)
|
||||
.netmask("128.0.0.0")
|
||||
.destination("0.0.0.0")
|
||||
.name("tun0")
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform_config(|config| {
|
||||
@ -80,7 +80,7 @@ pub async fn client_mode(remote_addr: String) {
|
||||
configure_routes();
|
||||
|
||||
let sock = UdpSocket::bind("0.0.0.0:59611").await.unwrap();
|
||||
sock.connect(&remote_addr).await.unwrap();
|
||||
sock.connect(&client_config.server.endpoint).await.unwrap();
|
||||
|
||||
let sock_rec = Arc::new(sock);
|
||||
let sock_snd = sock_rec.clone();
|
||||
|
161
src/main.rs
161
src/main.rs
@ -1,22 +1,21 @@
|
||||
use tokio::{net::UdpSocket, sync::mpsc};
|
||||
use std::{io::{self, Error, Read}, net::SocketAddr, sync::Arc, thread, time};
|
||||
use std::{fs, io::{self, Error, Read}, net::{IpAddr, SocketAddr}, sync::Arc, thread, time, str};
|
||||
use std::process::Command;
|
||||
use clap::{App, Arg};
|
||||
use env_logger::Builder;
|
||||
use log::{error, info, LevelFilter};
|
||||
use log::{error, info, warn, LevelFilter};
|
||||
use tun::platform::Device;
|
||||
use serde_derive::Serialize;
|
||||
use serde_derive::Deserialize;
|
||||
use std::str::FromStr;
|
||||
|
||||
mod tcp_client;
|
||||
mod tcp_server;
|
||||
//mod tcp_client;
|
||||
//mod tcp_server;
|
||||
mod server;
|
||||
mod client;
|
||||
|
||||
struct VpnPacket {
|
||||
//start: Vec<u8>
|
||||
data: Vec<u8>
|
||||
//end: Vec<u8>
|
||||
}
|
||||
|
||||
impl VpnPacket {
|
||||
@ -34,11 +33,8 @@ impl VpnPacket {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct UDPVpnPacket {
|
||||
//start: Vec<u8>
|
||||
data: Vec<u8>
|
||||
//end: Vec<u8>
|
||||
}
|
||||
|
||||
impl UDPVpnPacket {
|
||||
@ -56,6 +52,103 @@ impl UDPVpnHandshake {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
enum ServerMode {
|
||||
VPN,
|
||||
Hotspot
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct ServerInterface {
|
||||
bind_address: String,
|
||||
internal_address: String,
|
||||
private_key: String,
|
||||
mode: ServerMode,
|
||||
broadcast_mode: bool,
|
||||
keepalive: u8
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct ServerPeer {
|
||||
public_key: String,
|
||||
ip: IpAddr
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
enum ObfsProtocol {
|
||||
DNSMask,
|
||||
ICMPMask,
|
||||
VEIL
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct ObfsConfig {
|
||||
protocol: ObfsProtocol
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
pub struct ServerConfiguration {
|
||||
interface: ServerInterface,
|
||||
peers: Vec<ServerPeer>,
|
||||
obfs: ObfsConfig,
|
||||
dns: DNSConfig
|
||||
}
|
||||
|
||||
impl ServerConfiguration {
|
||||
fn default() -> Self {
|
||||
ServerConfiguration { interface: ServerInterface {
|
||||
bind_address: String::from_str("0.0.0.0:8879").unwrap(),
|
||||
internal_address: String::from_str("10.8.0.1").unwrap(),
|
||||
private_key: String::new(),
|
||||
mode: ServerMode::VPN,
|
||||
broadcast_mode: true,
|
||||
keepalive: 10
|
||||
},
|
||||
peers: Vec::new(),
|
||||
obfs: ObfsConfig { protocol: ObfsProtocol::DNSMask },
|
||||
dns: DNSConfig { enabled: false, net_name: String::from_str("fridah.vpn").unwrap(), entries: Vec::new() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct DNSConfig {
|
||||
enabled: bool,
|
||||
net_name: String,
|
||||
entries: Vec<DNSEntry>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct DNSEntry {
|
||||
ip: IpAddr,
|
||||
subdomain: String
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct ClientInterface {
|
||||
private_key: String,
|
||||
address: String
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct EndpointInterface {
|
||||
public_key: String,
|
||||
endpoint: String
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
pub struct ClientConfiguration {
|
||||
client: ClientInterface,
|
||||
server: EndpointInterface
|
||||
}
|
||||
|
||||
impl ClientConfiguration {
|
||||
fn default() -> Self {
|
||||
ClientConfiguration { client: ClientInterface { private_key: String::new(), address: String::from_str("10.8.0.2").unwrap() },
|
||||
server: EndpointInterface { public_key: String::new(), endpoint: String::from_str("192.168.0.2:8879").unwrap() } }
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
||||
@ -65,7 +158,7 @@ async fn main() {
|
||||
.init();
|
||||
|
||||
let matches = App::new("Frida VPN")
|
||||
.version("1.0")
|
||||
.version("0.1.2")
|
||||
.author("alterwain")
|
||||
.about("VPN software")
|
||||
.arg(Arg::with_name("mode")
|
||||
@ -73,34 +166,36 @@ async fn main() {
|
||||
.index(1)
|
||||
.possible_values(&["server", "client"])
|
||||
.help("Runs the program in either server or client mode"))
|
||||
.arg(Arg::with_name("vpn-server")
|
||||
.long("vpn-server")
|
||||
.value_name("IP")
|
||||
.help("The IP address of the VPN server to connect to (client mode only)")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("bind-to")
|
||||
.long("bind-to")
|
||||
.value_name("IP")
|
||||
.help("The IP address of the VPN server to bind to (server mode only)")
|
||||
.arg(Arg::with_name("config")
|
||||
.long("config")
|
||||
.required(true)
|
||||
.value_name("FILE")
|
||||
.help("The path to VPN configuration file")
|
||||
.takes_value(true))
|
||||
.get_matches();
|
||||
|
||||
let is_server_mode = matches.value_of("mode").unwrap() == "server";
|
||||
// "192.168.0.4:8879"
|
||||
if is_server_mode {
|
||||
if let Some(vpn_server_ip) = matches.value_of("bind-to") {
|
||||
let server_address = format!("{}:8879", vpn_server_ip);
|
||||
server::server_mode(server_address).await;
|
||||
} else {
|
||||
eprintln!("Error: For server mode, you shall provide the '--bind-to' argument.");
|
||||
|
||||
if let Some(config_path) = matches.value_of("config") {
|
||||
|
||||
let data = fs::read(config_path);
|
||||
|
||||
if data.is_err() {
|
||||
warn!("There is no config file. Generating it.");
|
||||
if is_server_mode {
|
||||
fs::write(config_path, serde_yaml::to_string(&ServerConfiguration::default()).unwrap());
|
||||
return;
|
||||
}
|
||||
fs::write(config_path, serde_yaml::to_string(&ClientConfiguration::default()).unwrap());
|
||||
return;
|
||||
}
|
||||
|
||||
} 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;
|
||||
} else {
|
||||
eprintln!("Error: For client mode, you shall provide the '--vpn-server' argument.");
|
||||
|
||||
if is_server_mode {
|
||||
let config: ServerConfiguration = serde_yaml::from_str(&String::from_utf8(data.unwrap()).unwrap()).unwrap();
|
||||
server::server_mode(config).await;
|
||||
return;
|
||||
}
|
||||
let config: ClientConfiguration = serde_yaml::from_str(&String::from_utf8(data.unwrap()).unwrap()).unwrap();
|
||||
client::client_mode(config).await;
|
||||
}
|
||||
}
|
@ -11,16 +11,16 @@ use std::collections::HashMap;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::VpnPacket;
|
||||
use crate::{ VpnPacket, ServerConfiguration };
|
||||
|
||||
pub async fn server_mode(bind_addr: String) {
|
||||
pub async fn server_mode(server_config: ServerConfiguration) {
|
||||
info!("Starting server...");
|
||||
|
||||
let mut config = tun2::Configuration::default();
|
||||
config.address("10.8.0.1");
|
||||
config.netmask("255.255.255.0");
|
||||
config.tun_name("tun0");
|
||||
config.up();
|
||||
config.address(&server_config.interface.internal_address)
|
||||
.netmask("255.255.255.0")
|
||||
.tun_name("tun0")
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform_config(|config| {
|
||||
@ -30,7 +30,7 @@ pub async fn server_mode(bind_addr: String) {
|
||||
let dev = tun2::create(&config).unwrap();
|
||||
let (mut dev_reader, mut dev_writer) = dev.split();
|
||||
|
||||
let sock = UdpSocket::bind(bind_addr).await.unwrap();
|
||||
let sock = UdpSocket::bind(&server_config.interface.bind_address).await.unwrap();
|
||||
let sock_rec = Arc::new(sock);
|
||||
let sock_snd = sock_rec.clone();
|
||||
let addresses = Arc::new(Mutex::new(HashMap::<IpAddr, UDPeer>::new()));
|
||||
@ -49,19 +49,17 @@ pub async fn server_mode(bind_addr: String) {
|
||||
tokio::spawn(async move {
|
||||
let mut buf = vec![0; 4096];
|
||||
while let Ok(n) = dev_reader.read(&mut buf) {
|
||||
// 16..=19
|
||||
if n > 19 {
|
||||
let ip = IpAddr::V4(Ipv4Addr::new(buf[16], buf[17], buf[18], buf[19]));
|
||||
let mp = addrs_cl.lock().await;
|
||||
if let Some(peer) = mp.get(&ip) {
|
||||
//info!("Sent to client");
|
||||
sock_snd.send_to(&buf[..n], peer.addr).await;
|
||||
} else {
|
||||
mp.values().for_each(| peer | { sock_snd.send_to(&buf[..n], peer.addr); });
|
||||
error!("UDPeer not found {:?}; what we have {:?}", ip, mp.keys().collect::<Vec<&IpAddr>>());
|
||||
}
|
||||
drop(mp);
|
||||
if n <= 19 { continue; }
|
||||
|
||||
let ip = IpAddr::V4(Ipv4Addr::new(buf[16], buf[17], buf[18], buf[19]));
|
||||
let mp = addrs_cl.lock().await;
|
||||
if let Some(peer) = mp.get(&ip) {
|
||||
sock_snd.send_to(&buf[..n], peer.addr).await;
|
||||
} else {
|
||||
// TODO: check in config is broadcast mode enabled (if not, do not send this to everyone)
|
||||
mp.values().for_each(| peer | { sock_snd.send_to(&buf[..n], peer.addr); });
|
||||
}
|
||||
drop(mp);
|
||||
}
|
||||
});
|
||||
|
||||
@ -85,9 +83,7 @@ pub async fn server_mode(bind_addr: String) {
|
||||
send2tun.send((&buf[1..len]).to_vec());
|
||||
}
|
||||
}, // payload
|
||||
_ => {
|
||||
error!("Unexpected header value.");
|
||||
}
|
||||
_ => error!("Unexpected header value.")
|
||||
}
|
||||
},
|
||||
None => error!("There is no header")
|
||||
|
Loading…
x
Reference in New Issue
Block a user