mirror of
https://github.com/Astatin3/unshell-nodes-rs.git
synced 2026-06-08 16:18:08 -06:00
Start rewrite, get layers working
This commit is contained in:
+3
-5
@@ -8,14 +8,12 @@ clap = { version = "4.5.39", features = ["derive"] }
|
||||
crossbeam-channel = "0.5.15"
|
||||
lazy_static = "1.5.0"
|
||||
log = "0.4.27"
|
||||
mio = { version = "1.0.4", features = ["os-poll"] }
|
||||
native-tls = "0.2.14"
|
||||
pretty_env_logger = "0.5.0"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
slint = "1.11.0"
|
||||
# slint = "1.11.0"
|
||||
unshell-rs-lib = { path = "./unshell-rs-lib" }
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
slint-build = "1.11.0"
|
||||
# [build-dependencies]
|
||||
# slint-build = "1.11.0"
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "payload"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0.140"
|
||||
# libc = "0.2.172"
|
||||
unshell-rs-lib = { path = "../unshell-rs-lib" }
|
||||
@@ -1,79 +0,0 @@
|
||||
use std::error::Error;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(unix)]
|
||||
unsafe fn execute_in_memory(binary_data: &[u8]) -> Result<(), Box<dyn Error>> {
|
||||
use std::mem;
|
||||
|
||||
// Allocate executable memory
|
||||
let size = binary_data.len();
|
||||
let page_size = 4096; // Typical page size
|
||||
let aligned_size = (size + page_size - 1) & !(page_size - 1);
|
||||
|
||||
let ptr = libc::mmap(
|
||||
std::ptr::null_mut(),
|
||||
aligned_size,
|
||||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
|
||||
-1,
|
||||
0,
|
||||
);
|
||||
|
||||
if ptr == libc::MAP_FAILED {
|
||||
return Err(Box::new(std::io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
// Copy binary data to allocated memory
|
||||
std::ptr::copy_nonoverlapping(binary_data.as_ptr(), ptr as *mut u8, size);
|
||||
|
||||
// Make memory executable
|
||||
if libc::mprotect(ptr, aligned_size, libc::PROT_READ | libc::PROT_EXEC) != 0 {
|
||||
libc::munmap(ptr, aligned_size);
|
||||
return Err(Box::new(std::io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
// Cast to function pointer and execute
|
||||
// This assumes the binary is a simple executable that can be called as a function
|
||||
// For ELF binaries, you'd need proper ELF parsing and loading
|
||||
let func: extern "C" fn() = mem::transmute(ptr);
|
||||
|
||||
println!("Executing binary...");
|
||||
func();
|
||||
|
||||
// Clean up
|
||||
libc::munmap(ptr, aligned_size);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe fn execute_in_memory(binary_data: &[u8]) -> Result<(), Box<dyn Error>> {
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
// Allocate executable memory
|
||||
let ptr = winapi::um::memoryapi::VirtualAlloc(
|
||||
ptr::null_mut(),
|
||||
binary_data.len(),
|
||||
winapi::um::winnt::MEM_COMMIT | winapi::um::winnt::MEM_RESERVE,
|
||||
winapi::um::winnt::PAGE_EXECUTE_READWRITE,
|
||||
);
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(Box::new(std::io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
// Copy binary data to allocated memory
|
||||
ptr::copy_nonoverlapping(binary_data.as_ptr(), ptr as *mut u8, binary_data.len());
|
||||
|
||||
// Cast to function pointer and execute
|
||||
let func: extern "C" fn() = mem::transmute(ptr);
|
||||
|
||||
println!("Executing binary...");
|
||||
func();
|
||||
|
||||
// Clean up
|
||||
winapi::um::memoryapi::VirtualFree(ptr, 0, winapi::um::winnt::MEM_RELEASE);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// #[allow(unsafe_op_in_unsafe_fn)]
|
||||
// mod execute;
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use unshell_rs_lib::{
|
||||
networkers::{ClientTrait, Connection, TCPClient, TCPConnection},
|
||||
packets::Packet,
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
run_client::<TCPConnection, TCPClient>("127.0.0.1:3000")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
use std::{error::Error, io::Write, net::SocketAddr};
|
||||
|
||||
use unshell_rs_lib::{
|
||||
layers::{LayerConfig, build_client},
|
||||
networkers::{ClientTrait, Connection, TCPClient},
|
||||
};
|
||||
|
||||
use crate::client;
|
||||
|
||||
pub struct Cli;
|
||||
|
||||
impl Cli {
|
||||
pub fn connect(addr: SocketAddr) -> Result<(), Box<dyn Error>> {
|
||||
let mut client = build_client(
|
||||
TCPClient::connect(&addr)?,
|
||||
vec![LayerConfig::Handshake, LayerConfig::Base64],
|
||||
)?;
|
||||
|
||||
let stdin = std::io::stdin();
|
||||
let mut stdout = std::io::stdout();
|
||||
|
||||
loop {
|
||||
print!("> ");
|
||||
stdout.flush()?;
|
||||
|
||||
let mut input = String::new();
|
||||
stdin.read_line(&mut input)?;
|
||||
let input = input.trim();
|
||||
|
||||
client.write(input)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
use std::{
|
||||
error::Error,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use unshell_rs_lib::{
|
||||
connection::{C2Packet, Parameter, Parameters},
|
||||
networkers::{AsyncConnection, ClientTrait, TCPClient, TCPConnection},
|
||||
};
|
||||
|
||||
pub struct UnshellClient {
|
||||
#[allow(dead_code)]
|
||||
addr: SocketAddr,
|
||||
tx: Sender<C2Packet>,
|
||||
pub rx: Receiver<C2Packet>,
|
||||
parameters: Arc<Mutex<Parameters>>,
|
||||
}
|
||||
|
||||
impl UnshellClient {
|
||||
pub fn new(addr: SocketAddr) -> Result<Self, Box<dyn Error>> {
|
||||
let client = TCPClient::connect(&addr)?;
|
||||
|
||||
let (tx, rx) = TCPConnection::as_async(client);
|
||||
|
||||
let parameters = Arc::new(Mutex::new(Parameters::new()));
|
||||
|
||||
Ok(Self {
|
||||
addr,
|
||||
tx,
|
||||
rx,
|
||||
parameters,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_parameter(&mut self, key: String, param: Parameter) {
|
||||
let mut params_lock = self.parameters.lock().unwrap();
|
||||
params_lock.insert(key.clone(), param.clone());
|
||||
self.tx.send(C2Packet::SetParameter(key, param)).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_parameter(&self, key: &str) -> Option<Parameter> {
|
||||
self.parameters.lock().unwrap().get(key).cloned()
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
use slint::{ComponentHandle, Weak};
|
||||
use std::{
|
||||
error::Error,
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
};
|
||||
use unshell_rs_lib::connection::{C2Packet, Parameter};
|
||||
|
||||
use crate::client::UnshellClient;
|
||||
|
||||
pub struct UnshellGui {}
|
||||
|
||||
slint::include_modules!();
|
||||
impl UnshellGui {
|
||||
pub fn start(client: UnshellClient) -> Result<(), Box<dyn Error>> {
|
||||
let ui = AppWindow::new()?;
|
||||
let rx = client.rx.clone();
|
||||
let client = Arc::new(Mutex::new(client));
|
||||
|
||||
let ui_handle = ui.as_weak();
|
||||
let client_clone = Arc::clone(&client);
|
||||
ui.on_tab_clicked(move |index| {
|
||||
let ui = ui_handle.unwrap();
|
||||
ui.set_current_tab(index);
|
||||
let mut client_lock = client_clone.lock().unwrap();
|
||||
client_lock.set_parameter("Current Tab".to_string(), Parameter::CurrentTab(index));
|
||||
trace!("Tab {} selected", index);
|
||||
});
|
||||
|
||||
ui.set_app_info({
|
||||
(String::new()
|
||||
+ "Unshell\n"
|
||||
+ "Version "
|
||||
+ env!("CARGO_PKG_VERSION")
|
||||
+ "\n\n View the source code at:\n https://github.com/astatin3/unshell-rs")
|
||||
.into()
|
||||
});
|
||||
|
||||
let ui_handle = ui.as_weak();
|
||||
thread::spawn(move || {
|
||||
fn on_param_update(ui_handle: Weak<AppWindow>, parameter: &Parameter) {
|
||||
// info!("{}", name);
|
||||
match parameter {
|
||||
Parameter::Test1 => todo!(),
|
||||
Parameter::CurrentTab(i) => {
|
||||
let i = i.clone();
|
||||
slint::invoke_from_event_loop(move || {
|
||||
ui_handle.unwrap().set_current_tab(i)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
if let Ok(data) = rx.recv() {
|
||||
match data {
|
||||
C2Packet::SetAllParameters(parameters) => {
|
||||
for key in parameters.keys() {
|
||||
on_param_update(ui_handle.clone(), parameters.get(key).unwrap());
|
||||
}
|
||||
}
|
||||
C2Packet::ParameterUpate(name, parameter) => {
|
||||
on_param_update(ui_handle.clone(), ¶meter);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
+2
-5
@@ -1,6 +1,3 @@
|
||||
mod gui;
|
||||
mod cli;
|
||||
|
||||
mod client;
|
||||
|
||||
pub use client::UnshellClient;
|
||||
pub use gui::UnshellGui;
|
||||
pub use cli::Cli;
|
||||
|
||||
+6
-4
@@ -2,8 +2,10 @@
|
||||
extern crate log;
|
||||
|
||||
mod client;
|
||||
mod server;
|
||||
// mod server;
|
||||
|
||||
pub use client::UnshellClient;
|
||||
pub use client::UnshellGui;
|
||||
pub use server::UnshellServer;
|
||||
pub use client::Cli;
|
||||
|
||||
// pub use client::UnshellClient;
|
||||
// pub use client::UnshellGui;
|
||||
// pub use server::UnshellServer;
|
||||
|
||||
+22
-36
@@ -7,7 +7,9 @@ use std::{
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use log::error;
|
||||
use unshell_rs::{UnshellClient, UnshellGui, UnshellServer};
|
||||
use unshell_rs::Cli;
|
||||
use unshell_rs_lib::connection::Node;
|
||||
// use unshell_rs::{UnshellClient, UnshellGui, UnshellServer};
|
||||
// use unshell_rs
|
||||
|
||||
pub static DEFAULT_CONFIG_FILEPATH: &'static str = "server_config.json";
|
||||
@@ -32,7 +34,7 @@ struct Args {
|
||||
enum Commands {
|
||||
/// Run as a service, and potentially hosting a website
|
||||
#[command(arg_required_else_help = true)]
|
||||
Server {
|
||||
Relay {
|
||||
/// IPv4 to listen for clients on.
|
||||
host: String,
|
||||
|
||||
@@ -47,8 +49,8 @@ enum Commands {
|
||||
// #[arg(short, long, default_value_t = DEFAULT_SERVICE_PORT)]
|
||||
// web_port: u16,
|
||||
},
|
||||
/// Run GUI and connect to remote server
|
||||
Remote {
|
||||
/// Connect to remote server
|
||||
Connect {
|
||||
/// Remote server to connect to
|
||||
host: String,
|
||||
|
||||
@@ -56,12 +58,6 @@ enum Commands {
|
||||
#[arg(short, long, default_value_t = DEFAULT_SERVICE_PORT)]
|
||||
port: u16,
|
||||
},
|
||||
/// Run both server and GUI on local machine.
|
||||
Local {
|
||||
/// Json file to store config
|
||||
#[arg(short, long, default_value_t = DEFAULT_CONFIG_FILEPATH.to_string())]
|
||||
config_filepath: String,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
@@ -73,41 +69,31 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args = Args::parse();
|
||||
|
||||
match args.command {
|
||||
Commands::Local { config_filepath } => {
|
||||
let mut server = UnshellServer::from_filepath(config_filepath.as_str());
|
||||
server.run(LOCAL_SOCKET)?;
|
||||
|
||||
let client = UnshellClient::new(LOCAL_SOCKET)?;
|
||||
|
||||
UnshellGui::start(client)?;
|
||||
}
|
||||
Commands::Remote { host, port } => {
|
||||
let addr = SocketAddr::from_str(format!("{}:{}", host, port).as_str());
|
||||
let client = UnshellClient::new(if let Ok(addr) = addr {
|
||||
addr
|
||||
} else {
|
||||
error!("Could not parse address!");
|
||||
return Ok(());
|
||||
})?;
|
||||
|
||||
UnshellGui::start(client)?;
|
||||
}
|
||||
Commands::Server {
|
||||
Commands::Relay {
|
||||
host,
|
||||
port,
|
||||
config_filepath,
|
||||
} => {
|
||||
let mut unshell_server = UnshellServer::from_filepath(config_filepath.as_str());
|
||||
|
||||
let addr = SocketAddr::from_str(format!("{}:{}", host, port).as_str());
|
||||
if let Ok(addr) = addr {
|
||||
unshell_server.run(addr)?;
|
||||
if let Err(e) = Node::run(if let Ok(addr) = addr {
|
||||
addr
|
||||
} else {
|
||||
error!("Could not parse address!");
|
||||
return Ok(());
|
||||
}) {
|
||||
error!("{}", e);
|
||||
}
|
||||
}
|
||||
Commands::Connect { host, port } => {
|
||||
let addr = SocketAddr::from_str(format!("{}:{}", host, port).as_str());
|
||||
if let Err(e) = Cli::connect(if let Ok(addr) = addr {
|
||||
addr
|
||||
} else {
|
||||
error!("Could not parse address!");
|
||||
return Ok(());
|
||||
}) {
|
||||
error!("{}", e);
|
||||
}
|
||||
|
||||
loop {}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
use lazy_static::lazy_static;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use unshell_rs_lib::config::campaign::CampaignConfig;
|
||||
|
||||
use unshell_rs_lib::connection::Parameters;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref DEFAULT_CAMPAIGN: CampaignConfig = CampaignConfig {
|
||||
name: "Default Campaign".to_string(),
|
||||
listeners: Vec::new(),
|
||||
};
|
||||
pub static ref DEFAULT_USERS: Vec<User> = vec![User {
|
||||
name: "User".into(),
|
||||
key: "CHANGEME".to_string(),
|
||||
}];
|
||||
pub static ref DEFAULT_PARAMETERS: Parameters = {
|
||||
let p = Parameters::new();
|
||||
|
||||
p
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct User {
|
||||
pub name: String,
|
||||
pub key: String,
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
mod config;
|
||||
mod server;
|
||||
|
||||
pub use crate::server::config::{DEFAULT_CAMPAIGN, DEFAULT_USERS, User};
|
||||
|
||||
pub use server::UnshellServer;
|
||||
@@ -1,155 +0,0 @@
|
||||
use std::{
|
||||
error::Error,
|
||||
fs::File,
|
||||
io::Read,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
};
|
||||
|
||||
use crossbeam_channel::Sender;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use unshell_rs_lib::{
|
||||
config::campaign::CampaignConfig,
|
||||
connection::{C2Packet, ErrorPacket, Parameters},
|
||||
networkers::{AsyncConnection, ServerTrait, TCPConnection, TCPServer, run_listener_state},
|
||||
};
|
||||
|
||||
use crate::server::{DEFAULT_CAMPAIGN, DEFAULT_USERS, User, config::DEFAULT_PARAMETERS};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct UnshellServerConfig {
|
||||
campaign: CampaignConfig,
|
||||
parameters: Parameters,
|
||||
users: Vec<User>,
|
||||
|
||||
#[serde(skip)]
|
||||
clients: Vec<Client>,
|
||||
}
|
||||
|
||||
impl UnshellServerConfig {
|
||||
pub fn broadcast_update_param(&self, name: String) {
|
||||
for i in 0..self.clients.len() {
|
||||
let _ = self.clients.get(i).unwrap().broadcast_tx.send(name.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UnshellServer {
|
||||
config: Arc<Mutex<UnshellServerConfig>>,
|
||||
}
|
||||
|
||||
impl UnshellServer {
|
||||
pub fn from_filepath(filepath: &str) -> Self {
|
||||
let s = (|| -> Result<Self, Box<dyn Error>> {
|
||||
let mut file = File::open(filepath.to_string())?;
|
||||
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
|
||||
let config = serde_json::from_str::<UnshellServerConfig>(contents.as_str())?;
|
||||
|
||||
info!("Loaded server config from {}", filepath);
|
||||
|
||||
Ok(Self {
|
||||
config: Arc::new(Mutex::new(config)),
|
||||
})
|
||||
})()
|
||||
.unwrap_or({
|
||||
warn!("Loaded default server config");
|
||||
Self {
|
||||
config: Arc::new(Mutex::new(UnshellServerConfig {
|
||||
campaign: DEFAULT_CAMPAIGN.clone(),
|
||||
users: DEFAULT_USERS.clone(),
|
||||
parameters: DEFAULT_PARAMETERS.clone(),
|
||||
|
||||
clients: Vec::new(),
|
||||
})),
|
||||
}
|
||||
});
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
pub fn run(&mut self, addr: SocketAddr) -> Result<(), Box<dyn Error>> {
|
||||
let config_clone = Arc::clone(&self.config);
|
||||
run_listener_state(TCPServer::bind(&addr)?, Client::run, config_clone);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Remote client type for unshell parameters
|
||||
struct Client {
|
||||
pub broadcast_tx: Sender<String>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn run(connection: TCPConnection, config: Arc<Mutex<UnshellServerConfig>>) {
|
||||
let (tx, rx) = TCPConnection::as_async::<C2Packet>(connection);
|
||||
|
||||
let (broadcast_tx, broadcast_rx) = crossbeam_channel::unbounded::<String>();
|
||||
|
||||
let s = Self { broadcast_tx };
|
||||
|
||||
let mut config_lock = config.lock().unwrap();
|
||||
config_lock.clients.push(s);
|
||||
let config_clone = Arc::clone(&config);
|
||||
let tx_clone = tx.clone();
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
if let Ok(key) = broadcast_rx.recv() {
|
||||
let config_lock = config_clone.lock().unwrap();
|
||||
if let Err(e) = tx_clone.send(C2Packet::ParameterUpate(
|
||||
key.clone(),
|
||||
config_lock.parameters.get(&key).unwrap().clone(),
|
||||
)) {
|
||||
error!("Failed to send packet: {}", e);
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let Err(e) = tx.send(C2Packet::SetAllParameters(config_lock.parameters.clone())) {
|
||||
error!("Failed to send packet: {}", e);
|
||||
};
|
||||
std::mem::drop(config_lock);
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
// if !connection.is_alive() {
|
||||
// warn!("Client {} disconnected!", connection.get_info());
|
||||
// break;
|
||||
// }
|
||||
if let Ok(packet) = rx.recv() {
|
||||
if let Err(e) = match packet {
|
||||
C2Packet::GetParameter(param) => {
|
||||
tx.send(C2Packet::AckGetParameter(param.clone(), {
|
||||
let config_lock = config.lock().unwrap();
|
||||
let result = config_lock.parameters.get(¶m);
|
||||
result.cloned()
|
||||
}))
|
||||
}
|
||||
C2Packet::SetParameter(name, param) => {
|
||||
tx.send(C2Packet::AckSetParameter({
|
||||
let mut config_lock = config.lock().unwrap();
|
||||
config_lock.parameters.insert(name.clone(), param);
|
||||
config_lock.broadcast_update_param(name);
|
||||
true
|
||||
}))
|
||||
}
|
||||
|
||||
C2Packet::Error(error) => {
|
||||
warn!("Got error: {:?}", error);
|
||||
Ok(())
|
||||
}
|
||||
_ => tx.send(C2Packet::Error(ErrorPacket::UnsupportedRequestError)),
|
||||
} {
|
||||
error!("Failed to send packet: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,5 @@ edition = "2024"
|
||||
base64 = "0.22.1"
|
||||
crossbeam-channel = "0.5.15"
|
||||
log = "0.4.27"
|
||||
mio = { version = "1.0.4", features = ["os-poll"] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::config::listeners::ListenerConfig;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct CampaignConfig {
|
||||
pub name: String,
|
||||
pub listeners: Vec<ListenerConfig>,
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum LayerConfig {}
|
||||
@@ -1,47 +0,0 @@
|
||||
use std::{
|
||||
error::Error,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
config::layers::LayerConfig,
|
||||
networkers::{ServerTrait, TCPConnection, TCPServer},
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub enum ListenerConfig {
|
||||
Tcp {
|
||||
enabled: bool,
|
||||
name: String,
|
||||
addr: SocketAddr,
|
||||
layers: Vec<LayerConfig>,
|
||||
|
||||
#[serde(skip)]
|
||||
connections: Option<Arc<Mutex<Vec<TCPConnection>>>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl ListenerConfig {
|
||||
pub fn start(self) -> Result<(), Box<dyn Error>> {
|
||||
match self {
|
||||
ListenerConfig::Tcp {
|
||||
mut enabled,
|
||||
addr,
|
||||
layers,
|
||||
mut connections,
|
||||
..
|
||||
} => {
|
||||
let server = TCPServer::bind(&addr)?;
|
||||
|
||||
enabled = true;
|
||||
|
||||
// connections = Some(run_listener(server));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
pub mod campaign;
|
||||
pub mod layers;
|
||||
pub mod listeners;
|
||||
@@ -1,6 +1,2 @@
|
||||
mod packets;
|
||||
|
||||
pub use packets::C2Packet;
|
||||
pub use packets::ErrorPacket;
|
||||
pub use packets::Parameter;
|
||||
pub use packets::Parameters;
|
||||
mod node;
|
||||
pub use node::Node;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
use std::{net::SocketAddr, thread};
|
||||
|
||||
use crate::{
|
||||
Error,
|
||||
layers::LayerConfig,
|
||||
networkers::{Connection, ServerTrait, TCPConnection, TCPServer, run_listener},
|
||||
};
|
||||
|
||||
pub struct Node;
|
||||
|
||||
impl Node {
|
||||
pub fn run(addr: SocketAddr) -> Result<(), Error> {
|
||||
let layers = vec![LayerConfig::Handshake, LayerConfig::Base64];
|
||||
|
||||
run_listener(
|
||||
TCPServer::bind(&addr)?,
|
||||
layers,
|
||||
|connection: Box<dyn Connection + Send + 'static>| {
|
||||
thread::spawn(move || {
|
||||
let mut connection = connection;
|
||||
|
||||
loop {
|
||||
if let Ok(data) = connection.read() {
|
||||
if !connection.is_alive() {
|
||||
warn!("{} Disconnected!", connection.get_info());
|
||||
break;
|
||||
}
|
||||
println!("Data: {}", data);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
use std::{collections::HashMap, fmt};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Result;
|
||||
|
||||
use crate::config::campaign::CampaignConfig;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum C2Packet {
|
||||
GetClients,
|
||||
AckGetClients,
|
||||
|
||||
RequestCampaign,
|
||||
AckRequestCampaign(CampaignConfig),
|
||||
|
||||
SetCampaign(CampaignConfig),
|
||||
AckSetCampaign,
|
||||
|
||||
GetParameter(String),
|
||||
AckGetParameter(String, Option<Parameter>),
|
||||
ParameterUpate(String, Parameter),
|
||||
|
||||
SetParameter(String, Parameter),
|
||||
AckSetParameter(bool),
|
||||
|
||||
SetAllParameters(Parameters),
|
||||
|
||||
Error(ErrorPacket),
|
||||
|
||||
Sysinfo { hostname: String },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum ErrorPacket {
|
||||
UnsupportedRequestError,
|
||||
}
|
||||
|
||||
impl fmt::Debug for CampaignConfig {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "CampaignConfig")
|
||||
}
|
||||
}
|
||||
|
||||
pub type Parameters = HashMap<String, Parameter>;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum Parameter {
|
||||
Test1,
|
||||
CurrentTab(i32),
|
||||
}
|
||||
|
||||
impl C2Packet {
|
||||
pub fn encode(&self) -> Result<String> {
|
||||
serde_json::to_string(self)
|
||||
}
|
||||
|
||||
pub fn decode(string: &str) -> Result<Self> {
|
||||
serde_json::from_str::<Self>(string)
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,44 @@
|
||||
use crate::layers::Layer;
|
||||
use base64;
|
||||
use crate::{
|
||||
Error,
|
||||
networkers::{Connection, ProtocolLayer},
|
||||
};
|
||||
use base64::{Engine as _, engine::general_purpose};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct Base64;
|
||||
|
||||
impl Layer for Base64 {
|
||||
fn encode(&mut self, data: &[u8]) -> Vec<u8> {
|
||||
#[allow(deprecated)]
|
||||
base64::encode(str::from_utf8(data).unwrap()).into_bytes()
|
||||
pub struct Base64Layer<C: Connection> {
|
||||
inner: C,
|
||||
}
|
||||
|
||||
fn decode(&mut self, data: &[u8]) -> Vec<u8> {
|
||||
#[allow(deprecated)]
|
||||
base64::decode(str::from_utf8(data).unwrap()).unwrap()
|
||||
impl<C: Connection> Connection for Base64Layer<C> {
|
||||
fn get_info(&self) -> String {
|
||||
format!("b64->{}", self.inner.get_info())
|
||||
}
|
||||
|
||||
fn is_alive(&self) -> bool {
|
||||
self.inner.is_alive()
|
||||
}
|
||||
|
||||
fn read(&mut self) -> Result<String, Error> {
|
||||
Ok(str::from_utf8(
|
||||
&general_purpose::STANDARD
|
||||
.decode(&self.inner.read()?)
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
.to_string())
|
||||
}
|
||||
|
||||
fn write(&mut self, data: &str) -> Result<(), Error> {
|
||||
info!("Bsae");
|
||||
|
||||
self.inner.write(&general_purpose::STANDARD.encode(data))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Connection> ProtocolLayer<C> for Base64Layer<C> {
|
||||
fn new(inner: C) -> Result<Self, Error> {
|
||||
Ok(Base64Layer { inner })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
use crate::{
|
||||
Error,
|
||||
layers::{Base64Layer, HandshakeLayer, LayerConfig},
|
||||
networkers::{Connection, ProtocolLayer},
|
||||
};
|
||||
|
||||
impl Connection for Box<dyn Connection + Send> {
|
||||
fn get_info(&self) -> String {
|
||||
(**self).get_info()
|
||||
}
|
||||
|
||||
fn is_alive(&self) -> bool {
|
||||
(**self).is_alive()
|
||||
}
|
||||
|
||||
fn read(&mut self) -> Result<String, Error> {
|
||||
(**self).read()
|
||||
}
|
||||
|
||||
fn write(&mut self, data: &str) -> Result<(), Error> {
|
||||
(**self).write(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_client<C>(base_conn: C, layers: Vec<LayerConfig>) -> Result<Box<dyn Connection>, Error>
|
||||
where
|
||||
C: Connection + 'static,
|
||||
{
|
||||
let mut current_conn: Box<dyn Connection + Send> = Box::new(base_conn);
|
||||
|
||||
for layer_config in &layers {
|
||||
current_conn = match layer_config {
|
||||
LayerConfig::Base64 => Box::new(Base64Layer::new(current_conn)?),
|
||||
LayerConfig::Handshake => {
|
||||
let mut handshake_layer = HandshakeLayer::new(current_conn)?;
|
||||
handshake_layer.initialize_client()?;
|
||||
Box::new(handshake_layer)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(current_conn)
|
||||
}
|
||||
|
||||
pub fn create_server_builder<C>(
|
||||
layers: Vec<LayerConfig>,
|
||||
) -> Result<Box<dyn Fn(C) -> Result<Box<dyn Connection + Send>, Error>>, Error>
|
||||
where
|
||||
C: Connection + 'static,
|
||||
{
|
||||
Ok(Box::new(
|
||||
move |base_conn: C| -> Result<Box<dyn Connection + Send>, Error> {
|
||||
let mut current_conn: Box<dyn Connection + Send> = Box::new(base_conn);
|
||||
|
||||
for layer_config in &layers {
|
||||
current_conn = match layer_config {
|
||||
LayerConfig::Base64 => Box::new(Base64Layer::new(current_conn)?),
|
||||
LayerConfig::Handshake => {
|
||||
let mut handshake_layer = HandshakeLayer::new(current_conn)?;
|
||||
handshake_layer.initialize_server()?;
|
||||
Box::new(handshake_layer)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(current_conn)
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
use crate::{
|
||||
layers::Base64Layer,
|
||||
networkers::{Connection, ProtocolLayer},
|
||||
};
|
||||
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
|
||||
// 4-Way Handshake Layer
|
||||
pub struct HandshakeLayer<C: Connection> {
|
||||
inner: C,
|
||||
finished_handshake: bool,
|
||||
}
|
||||
|
||||
impl<C: Connection> Connection for HandshakeLayer<C> {
|
||||
fn get_info(&self) -> String {
|
||||
format!("handshake->{}", self.inner.get_info())
|
||||
}
|
||||
|
||||
fn is_alive(&self) -> bool {
|
||||
self.inner.is_alive()
|
||||
}
|
||||
|
||||
fn read(&mut self) -> Result<String, Error> {
|
||||
if !self.finished_handshake {
|
||||
return Err("NotComplete".into());
|
||||
}
|
||||
self.inner.read()
|
||||
}
|
||||
|
||||
fn write(&mut self, data: &str) -> Result<(), Error> {
|
||||
if !self.finished_handshake {
|
||||
return Err("NotComplete".into());
|
||||
}
|
||||
self.inner.write(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Connection + 'static> ProtocolLayer<C> for HandshakeLayer<C> {
|
||||
fn new(inner: C) -> Result<Self, Error> {
|
||||
Ok(HandshakeLayer {
|
||||
inner,
|
||||
finished_handshake: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn initialize_client(&mut self) -> Result<(), Error> {
|
||||
println!("Starting client handshake...");
|
||||
|
||||
// Step 1: Client sends SYN
|
||||
self.inner.write("SYN")?;
|
||||
println!("Client: Sent SYN");
|
||||
|
||||
// Step 2: Client receives SYN-ACK
|
||||
let response = self.inner.read()?;
|
||||
if response != "SYN-ACK" {
|
||||
return Err(format!("Expected SYN-ACK, got: {}", response).into());
|
||||
}
|
||||
println!("Client: Received SYN-ACK");
|
||||
|
||||
// Step 3: Client sends ACK
|
||||
self.inner.write("ACK")?;
|
||||
println!("Client: Sent ACK");
|
||||
|
||||
// Step 4: Client receives FIN (final confirmation)
|
||||
let response = self.inner.read()?;
|
||||
if response != "FIN" {
|
||||
return Err(format!("Expected FIN, got: {}", response).into());
|
||||
}
|
||||
println!("Client: Received FIN - Handshake complete!");
|
||||
|
||||
self.finished_handshake = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_server(&mut self) -> Result<(), Error> {
|
||||
println!("Starting server handshake...");
|
||||
|
||||
// Step 1: Server receives SYN
|
||||
let request = self.inner.read()?;
|
||||
if request != "SYN" {
|
||||
return Err(format!("Expected SYN, got: {}", request).into());
|
||||
}
|
||||
println!("Server: Received SYN");
|
||||
|
||||
// Step 2: Server sends SYN-ACK
|
||||
self.inner.write("SYN-ACK")?;
|
||||
println!("Server: Sent SYN-ACK");
|
||||
|
||||
// Step 3: Server receives ACK
|
||||
let response = self.inner.read()?;
|
||||
if response != "ACK" {
|
||||
return Err(format!("Expected ACK, got: {}", response).into());
|
||||
}
|
||||
println!("Server: Received ACK");
|
||||
|
||||
// Step 4: Server sends FIN (final confirmation)
|
||||
self.inner.write("FIN")?;
|
||||
println!("Server: Sent FIN - Handshake complete!");
|
||||
|
||||
self.finished_handshake = true;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
pub trait Layer: Serialize + Deserialize<'static> + Sized {
|
||||
fn encode(&mut self, data: &[u8]) -> Vec<u8>;
|
||||
fn decode(&mut self, data: &[u8]) -> Vec<u8>;
|
||||
pub enum LayerConfig {
|
||||
Base64,
|
||||
Handshake,
|
||||
}
|
||||
|
||||
pub mod base64;
|
||||
mod builder;
|
||||
pub mod handshake;
|
||||
|
||||
pub use base64::Base64;
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use base64::Base64Layer;
|
||||
pub use handshake::HandshakeLayer;
|
||||
|
||||
pub use builder::build_client;
|
||||
pub use builder::create_server_builder;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod config;
|
||||
pub type Error = Box<dyn std::error::Error>;
|
||||
|
||||
// pub mod config;
|
||||
pub mod connection;
|
||||
pub mod layers;
|
||||
pub mod networkers;
|
||||
|
||||
@@ -1,115 +1,15 @@
|
||||
/// This is the lowset-level data transmission type
|
||||
|
||||
pub trait Connection: Send + Sync {
|
||||
type Error: std::fmt::Debug;
|
||||
|
||||
fn get_info(&self) -> String;
|
||||
fn is_alive(&self) -> bool;
|
||||
|
||||
fn read(&mut self) -> Result<String, Self::Error>;
|
||||
fn write(&mut self, data: &str) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
pub trait AsyncConnection<C>
|
||||
where
|
||||
C: Connection,
|
||||
{
|
||||
type Error: std::fmt::Debug;
|
||||
|
||||
fn as_async<T: Serialize + DeserializeOwned + Send + 'static>(
|
||||
connection: C,
|
||||
) -> (Sender<T>, Receiver<T>);
|
||||
}
|
||||
|
||||
pub trait ServerTrait<C: Connection> {
|
||||
type Error: std::fmt::Debug;
|
||||
|
||||
fn get_info(&self) -> String;
|
||||
fn accept(&self) -> Result<C, Self::Error>;
|
||||
fn bind(address: &SocketAddr) -> Result<Self, Self::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
pub trait ClientTrait<C: Connection + Sized> {
|
||||
type Error: std::fmt::Debug;
|
||||
|
||||
fn connect(address: &SocketAddr) -> Result<C, Self::Error>;
|
||||
}
|
||||
|
||||
pub fn run_listener_state<S, C, R, A>(server: S, on_connect_callback: R, state: Arc<A>)
|
||||
/*-> Arc<Mutex<Vec<C>>>*/
|
||||
where
|
||||
S: ServerTrait<C> + Sync + Send + 'static,
|
||||
C: Connection + 'static,
|
||||
R: Fn(C, Arc<A>) + Sync + Send + 'static,
|
||||
A: Sync + Send + 'static,
|
||||
{
|
||||
info!("Started listener {}", server.get_info());
|
||||
// let clients: Arc<Mutex<Vec<C>>> = Arc::new(Mutex::new(Vec::new()));
|
||||
// let clients_clone = Arc::clone(&clients);
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
match server.accept() {
|
||||
Ok(conn) => {
|
||||
info!("New connection ({})", conn.get_info());
|
||||
|
||||
on_connect_callback(conn, Arc::clone(&state));
|
||||
|
||||
// OnConnectCallback::on_connect(&mut on_connect_callback, conn);
|
||||
// let mut clients_lock = clients_clone.lock().unwrap();
|
||||
// clients_lock.push(conn);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to accept connection: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn run_listener<S, C, R>(server: S, on_connect_callback: R)
|
||||
/*-> Arc<Mutex<Vec<C>>>*/
|
||||
where
|
||||
S: ServerTrait<C> + Sync + Send + 'static,
|
||||
C: Connection + 'static,
|
||||
R: Fn(C) + Sync + Send + 'static,
|
||||
{
|
||||
info!("Started listener {}", server.get_info());
|
||||
// let clients: Arc<Mutex<Vec<C>>> = Arc::new(Mutex::new(Vec::new()));
|
||||
// let clients_clone = Arc::clone(&clients);
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
match server.accept() {
|
||||
Ok(conn) => {
|
||||
info!("New connection ({})", conn.get_info());
|
||||
|
||||
on_connect_callback(conn);
|
||||
|
||||
// OnConnectCallback::on_connect(&mut on_connect_callback, conn);
|
||||
// let mut clients_lock = clients_clone.lock().unwrap();
|
||||
// clients_lock.push(conn);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to accept connection: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mod server;
|
||||
mod tcp;
|
||||
mod traits;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
pub use tcp::TCPClient;
|
||||
pub use tcp::TCPConnection;
|
||||
pub use tcp::TCPServer;
|
||||
|
||||
// pub use traits::AsyncConnection;
|
||||
pub use traits::ClientTrait;
|
||||
pub use traits::Connection;
|
||||
pub use traits::ProtocolLayer;
|
||||
pub use traits::ServerTrait;
|
||||
|
||||
pub use server::run_listener;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use crate::{
|
||||
layers::{LayerConfig, create_server_builder},
|
||||
networkers::{Connection, ServerTrait},
|
||||
};
|
||||
|
||||
// Helper macros for building layered connections
|
||||
macro_rules! build_layered_connection {
|
||||
($base:expr) => {
|
||||
$base
|
||||
};
|
||||
($base:expr, $layer:ty) => {
|
||||
<$layer>::new($base)?
|
||||
};
|
||||
($base:expr, $layer:ty, $($layers:ty),+) => {
|
||||
build_layered_connection!(<$layer>::new($base)?, $($layers),+)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn run_listener_state<S, C, R, A>(server: S, on_connect_callback: R, state: Arc<A>)
|
||||
/*-> Arc<Mutex<Vec<C>>>*/
|
||||
where
|
||||
S: ServerTrait<C> + Sync + Send + 'static,
|
||||
C: Connection + 'static,
|
||||
R: Fn(C, Arc<A>) + Sync + Send + 'static,
|
||||
A: Sync + Send + 'static,
|
||||
{
|
||||
info!("Started listener {}", server.get_info());
|
||||
// let clients: Arc<Mutex<Vec<C>>> = Arc::new(Mutex::new(Vec::new()));
|
||||
// let clients_clone = Arc::clone(&clients);
|
||||
|
||||
loop {
|
||||
match server.accept() {
|
||||
Ok(conn) => {
|
||||
info!("New connection ({})", conn.get_info());
|
||||
|
||||
on_connect_callback(conn, Arc::clone(&state));
|
||||
|
||||
// OnConnectCallback::on_connect(&mut on_connect_callback, conn);
|
||||
// let mut clients_lock = clients_clone.lock().unwrap();
|
||||
// clients_lock.push(conn);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to accept connection: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_listener<S, C, R>(server: S, layers: Vec<LayerConfig>, on_connect_callback: R)
|
||||
/*-> Arc<Mutex<Vec<C>>>*/
|
||||
where
|
||||
S: ServerTrait<C> + Sync + Send + 'static,
|
||||
C: Connection + 'static,
|
||||
R: Fn(Box<dyn Connection + Send + 'static>) + Sync + Send + 'static,
|
||||
{
|
||||
let layer_builder = create_server_builder::<C>(layers).unwrap();
|
||||
|
||||
info!("Started listener {}", server.get_info());
|
||||
// let clients: Arc<Mutex<Vec<C>>> = Arc::new(Mutex::new(Vec::new()));
|
||||
// let clients_clone = Arc::clone(&clients);
|
||||
|
||||
loop {
|
||||
match server.accept() {
|
||||
Ok(conn) => match layer_builder(conn) {
|
||||
Ok(conn) => {
|
||||
info!("New connection ({})", conn.get_info());
|
||||
on_connect_callback(conn);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to create layers: {:?}", e);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to accept connection: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
use std::{
|
||||
io::{self, BufRead, BufReader, Write},
|
||||
net::{SocketAddr, TcpListener, TcpStream},
|
||||
thread,
|
||||
};
|
||||
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
|
||||
use crate::networkers::{AsyncConnection, ClientTrait, Connection, ServerTrait};
|
||||
use crate::{
|
||||
Error,
|
||||
networkers::{ClientTrait, Connection, ServerTrait},
|
||||
};
|
||||
|
||||
pub struct TCPConnection {
|
||||
stream: TcpStream,
|
||||
@@ -16,8 +15,6 @@ pub struct TCPConnection {
|
||||
}
|
||||
|
||||
impl Connection for TCPConnection {
|
||||
type Error = io::Error;
|
||||
|
||||
fn get_info(&self) -> String {
|
||||
format!(
|
||||
"tcp://{}",
|
||||
@@ -33,7 +30,7 @@ impl Connection for TCPConnection {
|
||||
self.is_alive
|
||||
}
|
||||
|
||||
fn read(&mut self) -> Result<String, Self::Error> {
|
||||
fn read(&mut self) -> Result<String, Error> {
|
||||
let mut line = String::new();
|
||||
let n = self.reader.read_line(&mut line)?;
|
||||
|
||||
@@ -45,79 +42,78 @@ impl Connection for TCPConnection {
|
||||
Ok(line.trim_end().to_string())
|
||||
}
|
||||
|
||||
fn write(&mut self, data: &str) -> Result<(), Self::Error> {
|
||||
fn write(&mut self, data: &str) -> Result<(), Error> {
|
||||
info!("Sent: {}", data);
|
||||
writeln!(self.stream, "{}", data)?;
|
||||
self.stream.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncConnection<TCPConnection> for TCPConnection {
|
||||
type Error = io::Error;
|
||||
// impl AsyncConnection<TCPConnection> for TCPConnection {
|
||||
// type Error = io::Error;
|
||||
|
||||
fn as_async<T: Serialize + DeserializeOwned + Send + 'static>(
|
||||
connection: TCPConnection,
|
||||
) -> (Sender<T>, Receiver<T>) {
|
||||
let (send_tx, send_rx) = crossbeam_channel::unbounded::<T>();
|
||||
let (recv_tx, recv_rx) = crossbeam_channel::unbounded::<T>();
|
||||
// fn as_async<T: Serialize + DeserializeOwned + Send + 'static>(
|
||||
// connection: TCPConnection,
|
||||
// ) -> (Sender<T>, Receiver<T>) {
|
||||
// let (send_tx, send_rx) = crossbeam_channel::unbounded::<T>();
|
||||
// let (recv_tx, recv_rx) = crossbeam_channel::unbounded::<T>();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut reader = connection.reader;
|
||||
// thread::spawn(move || {
|
||||
// let mut reader = connection.reader;
|
||||
|
||||
let mut read = || -> Result<String, Self::Error> {
|
||||
let mut line = String::new();
|
||||
let _ = reader.read_line(&mut line)?;
|
||||
// let mut read = || -> Result<String, Self::Error> {
|
||||
// let mut line = String::new();
|
||||
// let _ = reader.read_line(&mut line)?;
|
||||
|
||||
Ok(line.trim_end().to_string())
|
||||
};
|
||||
// Ok(line.trim_end().to_string())
|
||||
// };
|
||||
|
||||
loop {
|
||||
if let Ok(data) = read() {
|
||||
if data.is_empty() {
|
||||
break;
|
||||
}
|
||||
info!("Got {}", data);
|
||||
if let Ok(decoded) = serde_json::from_str::<T>(&data) {
|
||||
if let Err(e) = send_tx.send(decoded) {
|
||||
error!("Got error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// loop {
|
||||
// if let Ok(data) = read() {
|
||||
// if data.is_empty() {
|
||||
// break;
|
||||
// }
|
||||
// info!("Got {}", data);
|
||||
// if let Ok(decoded) = serde_json::from_str::<T>(&data) {
|
||||
// if let Err(e) = send_tx.send(decoded) {
|
||||
// error!("Got error: {}", e);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut stream = connection.stream;
|
||||
// thread::spawn(move || {
|
||||
// let mut stream = connection.stream;
|
||||
|
||||
let mut write = |data: String| -> Result<(), Self::Error> {
|
||||
writeln!(stream, "{}", data)?;
|
||||
stream.flush()?;
|
||||
Ok(())
|
||||
};
|
||||
// let mut write = |data: String| -> Result<(), Self::Error> {
|
||||
// writeln!(stream, "{}", data)?;
|
||||
// stream.flush()?;
|
||||
// Ok(())
|
||||
// };
|
||||
|
||||
loop {
|
||||
if let Ok(data) = recv_rx.recv() {
|
||||
if let Ok(encoded) = serde_json::to_string(&data) {
|
||||
info!("Write {}", encoded);
|
||||
if let Err(e) = write(encoded) {
|
||||
error!("Got error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// loop {
|
||||
// if let Ok(data) = recv_rx.recv() {
|
||||
// if let Ok(encoded) = serde_json::to_string(&data) {
|
||||
// info!("Write {}", encoded);
|
||||
// if let Err(e) = write(encoded) {
|
||||
// error!("Got error: {}", e);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
(recv_tx, send_rx)
|
||||
}
|
||||
}
|
||||
// (recv_tx, send_rx)
|
||||
// }
|
||||
// }
|
||||
|
||||
pub struct TCPServer {
|
||||
listener: TcpListener,
|
||||
}
|
||||
|
||||
impl ServerTrait<TCPConnection> for TCPServer {
|
||||
type Error = io::Error;
|
||||
|
||||
fn get_info(&self) -> String {
|
||||
format!(
|
||||
"tcp://{}",
|
||||
@@ -129,7 +125,7 @@ impl ServerTrait<TCPConnection> for TCPServer {
|
||||
)
|
||||
}
|
||||
|
||||
fn accept(&self) -> Result<TCPConnection, Self::Error> {
|
||||
fn accept(&self) -> Result<TCPConnection, Error> {
|
||||
let (stream, _) = self.listener.accept()?;
|
||||
let reader = BufReader::new(stream.try_clone()?);
|
||||
Ok(TCPConnection {
|
||||
@@ -139,7 +135,7 @@ impl ServerTrait<TCPConnection> for TCPServer {
|
||||
})
|
||||
}
|
||||
|
||||
fn bind(address: &SocketAddr) -> Result<Self, Self::Error> {
|
||||
fn bind(address: &SocketAddr) -> Result<Self, Error> {
|
||||
let listener = TcpListener::bind(address)?;
|
||||
Ok(Self { listener })
|
||||
}
|
||||
@@ -148,9 +144,7 @@ impl ServerTrait<TCPConnection> for TCPServer {
|
||||
pub struct TCPClient;
|
||||
|
||||
impl ClientTrait<TCPConnection> for TCPClient {
|
||||
type Error = io::Error;
|
||||
|
||||
fn connect(address: &SocketAddr) -> Result<TCPConnection, Self::Error> {
|
||||
fn connect(address: &SocketAddr) -> Result<TCPConnection, Error> {
|
||||
let stream = TcpStream::connect(address)?;
|
||||
let reader = BufReader::new(stream.try_clone()?);
|
||||
let conn = TCPConnection {
|
||||
@@ -158,7 +152,6 @@ impl ClientTrait<TCPConnection> for TCPClient {
|
||||
reader,
|
||||
is_alive: true,
|
||||
};
|
||||
info!("Connected to {}", conn.get_info());
|
||||
Ok(conn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
use std::net::SocketAddr;
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
// This is the lowset-level data transmission type
|
||||
pub trait Connection: Send {
|
||||
fn get_info(&self) -> String;
|
||||
fn is_alive(&self) -> bool;
|
||||
|
||||
fn read(&mut self) -> Result<String, Error>;
|
||||
fn write(&mut self, data: &str) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
// Trait for protocol layers that can be initialized
|
||||
pub trait ProtocolLayer<C: Connection>: Connection {
|
||||
fn new(inner: C) -> Result<Self, Error>
|
||||
where
|
||||
Self: Sized;
|
||||
fn initialize_client(&mut self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn initialize_server(&mut self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// impl Sized for dyn Connection {}
|
||||
|
||||
// pub trait AsyncConnection<C>
|
||||
// where
|
||||
// C: Connection,
|
||||
// {
|
||||
// fn as_async<T: Serialize + DeserializeOwned + Send + 'static>(
|
||||
// connection: C,
|
||||
// ) -> (Sender<T>, Receiver<T>);
|
||||
// }
|
||||
|
||||
pub trait ServerTrait<C: Connection> {
|
||||
fn get_info(&self) -> String;
|
||||
fn accept(&self) -> Result<C, Error>;
|
||||
fn bind(address: &SocketAddr) -> Result<Self, Error>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
pub trait ClientTrait<C: Connection + Sized> {
|
||||
fn connect(address: &SocketAddr) -> Result<C, Error>;
|
||||
}
|
||||
Reference in New Issue
Block a user