feat: adding a bind shell example with more stuff

adding a bind shell that can allow for more practice with future
features such as multiple transports, encryption, transferring files,
and a more robust client interface
This commit is contained in:
Andrew Rioux
2023-09-02 14:32:34 -04:00
parent 180b29531a
commit aecf1c9b80
21 changed files with 878 additions and 37 deletions

View File

@@ -0,0 +1,27 @@
use std::{net::SocketAddr, path::PathBuf, sync::Arc};
use ed25519_dalek::{Keypair, Signer};
use sparse_05_common::messages::CONNECT_MESSAGE;
use tokio::{fs, net::UdpSocket};
use crate::configs::ClientConfig;
enum State {
Ready,
UploadingFile,
DownloadingFile,
}
pub async fn connect(config: PathBuf, ip: SocketAddr) -> anyhow::Result<()> {
let config = fs::read(&config).await?;
let config: ClientConfig = rmp_serde::from_slice(&config)?;
let remote = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
let connect_signature = config.keypair.sign(CONNECT_MESSAGE).to_bytes();
let connect_msg = &[&connect_signature, CONNECT_MESSAGE].concat();
remote.send_to(connect_msg, ip).await?;
Ok(())
}

View File

@@ -0,0 +1,48 @@
use std::{ffi::OsString, path::PathBuf};
use ed25519_dalek::Keypair;
use sparse_05_common::CONFIG_SEPARATOR;
use tokio::{fs, io::AsyncWriteExt};
use crate::configs::ClientConfig;
#[cfg(debug_assertions)]
pub const SPARSE_SERVER_BINARY: &'static [u8] =
include_bytes!("../../../../target/debug/sparse-05-server");
#[cfg(not(debug_assertions))]
pub const SPARSE_SERVER_BINARY: &'static [u8] =
include_bytes!("../../../../target/release/sparse-05-server");
pub async fn generate(mut name: PathBuf, port: u16) -> anyhow::Result<()> {
let mut csprng = rand::thread_rng();
let keypair = Keypair::generate(&mut csprng);
let mut file = fs::OpenOptions::new()
.write(true)
.create(true)
.mode(0o755)
.open(&name)
.await?;
file.write_all(SPARSE_SERVER_BINARY).await?;
file.write_all(CONFIG_SEPARATOR).await?;
file.write_all(&port.to_be_bytes()[..]).await?;
file.write_all(keypair.public.as_bytes()).await?;
let config = ClientConfig { keypair, port };
let mut file_part = name.file_name().unwrap().to_owned();
file_part.push(OsString::from(".conf"));
name.pop();
name.push(file_part);
let mut file = fs::OpenOptions::new()
.write(true)
.create(true)
.open(&name)
.await?;
let config = rmp_serde::to_vec(&config)?;
file.write_all(&config).await?;
Ok(())
}

View File

@@ -0,0 +1,2 @@
pub mod connect;
pub mod generate;

View File

@@ -0,0 +1,8 @@
use ed25519_dalek::Keypair;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct ClientConfig {
pub keypair: Keypair,
pub port: u16,
}

View File

@@ -0,0 +1,17 @@
use structopt::StructOpt;
mod commands;
mod configs;
mod options;
use options::{Command, Options};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let options = Options::from_args();
match options.command {
Command::Generate { name, port } => commands::generate::generate(name, port).await,
Command::Connect { config, ip } => commands::connect::connect(config, ip).await,
}
}

View File

@@ -0,0 +1,43 @@
use std::{
net::{Ipv4Addr, SocketAddr, ToSocketAddrs},
path::PathBuf,
};
use structopt::{self, StructOpt};
fn to_socket_addr(src: &str) -> Result<SocketAddr, std::io::Error> {
use std::io::{Error, ErrorKind};
src.to_socket_addrs()?.next().ok_or(Error::new(
ErrorKind::Other,
"could not get a valid socket address",
))
}
#[derive(StructOpt)]
pub enum Command {
Generate {
#[structopt(parse(from_os_str))]
name: PathBuf,
#[structopt(default_value = "54248")]
port: u16,
},
Connect {
#[structopt(parse(from_os_str))]
config: PathBuf,
#[structopt(parse(try_from_str = to_socket_addr))]
ip: SocketAddr,
},
}
#[derive(StructOpt)]
#[structopt(
name = "sparse-client",
about = "Client to and generator of sparse shells"
)]
pub struct Options {
#[structopt(subcommand)]
pub command: Command,
}