feat: added the ability to test a connection

This commit is contained in:
Andrew Rioux 2023-09-19 15:46:17 -04:00
parent fb98d062ef
commit 022340ec95
Signed by: andrew.rioux
GPG Key ID: 9B8BAC47C17ABB94
5 changed files with 132 additions and 5 deletions

View File

@ -18,11 +18,11 @@ mod commands;
mod shell;
pub struct Connection {
config: ClientConfig,
foreign_sign_pubkey: ed25519_dalek::PublicKey,
foreign_enc_pubkey: ecies_ed25519::PublicKey,
socket: Arc<UdpSocket>,
ip: SocketAddr,
pub(crate) config: ClientConfig,
pub(crate) foreign_sign_pubkey: ed25519_dalek::PublicKey,
pub(crate) foreign_enc_pubkey: ecies_ed25519::PublicKey,
pub(crate) socket: Arc<UdpSocket>,
pub(crate) ip: SocketAddr,
}
impl Connection {

View File

@ -0,0 +1,118 @@
use std::{
io::{self, Write},
net::SocketAddr,
path::PathBuf,
sync::Arc,
};
use anyhow::bail;
use ed25519_dalek::{Signature, Signer, Verifier};
use sparse_05_common::messages::{
Capabilities, Command, Response, CONNECTED_MESSAGE, CONNECT_MESSAGE,
};
use tokio::{fs, net::UdpSocket};
use crate::configs::ClientConfig;
pub async fn connecttest(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();
let mut counter = 0;
let (foreign_sign_pubkey, foreign_enc_pubkey, capabilities) = loop {
if counter > 25 {
bail!("could not connect to server");
}
print!(
"\rConnecting{}",
match counter % 3 {
2 => ".. ",
1 => ". ",
_ => "...",
}
);
io::stdout().flush().unwrap();
remote.send_to(connect_msg, ip).await?;
let mut buf = [0u8; 2000];
match tokio::time::timeout(
std::time::Duration::from_millis(250),
remote.recv_from(&mut buf),
)
.await
{
Ok(packet) => {
let (count, addr) = packet?;
if addr != ip {
bail!("received response from wrong source");
}
let data = &buf[..count];
if data.len() < 65 {
bail!("could not get signature from server");
}
let signature: [u8; 64] = data[..64].try_into().unwrap();
let data = &data[64..];
let Ok(foreign_keys) = ecies_ed25519::decrypt(&config.enc_privkey, data) else {
counter += 1;
continue;
};
if foreign_keys.len()
< ed25519_dalek::PUBLIC_KEY_LENGTH + ecies_ed25519::PUBLIC_KEY_LENGTH
{
bail!("could not get public keys from the server");
}
let foreign_sign_pubkey = ed25519_dalek::PublicKey::from_bytes(
&foreign_keys[..ed25519_dalek::PUBLIC_KEY_LENGTH],
)?;
let foreign_enc_pubkey = ecies_ed25519::PublicKey::from_bytes(
&foreign_keys[ed25519_dalek::PUBLIC_KEY_LENGTH
..(ed25519_dalek::PUBLIC_KEY_LENGTH + ecies_ed25519::PUBLIC_KEY_LENGTH)],
)?;
let capabilities: Capabilities = rmp_serde::from_slice(
&foreign_keys
[(ed25519_dalek::PUBLIC_KEY_LENGTH + ecies_ed25519::PUBLIC_KEY_LENGTH)..],
)?;
foreign_sign_pubkey.verify(data, &Signature::from(signature))?;
break (foreign_sign_pubkey, foreign_enc_pubkey, capabilities);
}
Err(_) => {
counter += 1;
}
}
};
let connection = Arc::new(crate::commands::connect::Connection {
config,
foreign_enc_pubkey,
foreign_sign_pubkey,
socket: Arc::clone(&remote),
ip,
});
remote
.send_to(&connection.encrypt_and_sign(CONNECTED_MESSAGE)?, ip)
.await?;
println!("\rConnected! ");
Ok(())
}

View File

@ -1,2 +1,3 @@
pub mod connect;
pub mod connecttest;
pub mod generate;

View File

@ -15,5 +15,6 @@ async fn main() -> anyhow::Result<()> {
commands::generate::generate(name, port, target).await
}
Command::Connect { config, ip } => commands::connect::connect(config, ip).await,
Command::ConnectTest { config, ip } => commands::connecttest::connecttest(config, ip).await,
}
}

View File

@ -46,6 +46,13 @@ pub enum Command {
#[structopt(parse(from_os_str))]
config: PathBuf,
#[structopt(parse(try_from_str = to_socket_addr))]
ip: SocketAddr,
},
ConnectTest {
#[structopt(parse(from_os_str))]
config: PathBuf,
#[structopt(parse(try_from_str = to_socket_addr))]
ip: SocketAddr,
},