add to simple wisp client

This commit is contained in:
Toshit Chawda 2024-09-14 18:14:10 -07:00
parent 577ce71b89
commit 24ccd8d393
No known key found for this signature in database
GPG key ID: 91480ED99E2B3D9D
7 changed files with 82 additions and 9 deletions

2
Cargo.lock generated
View file

@ -1952,12 +1952,14 @@ dependencies = [
"bytes", "bytes",
"clap", "clap",
"console-subscriber", "console-subscriber",
"ed25519-dalek",
"fastwebsockets", "fastwebsockets",
"futures", "futures",
"http-body-util", "http-body-util",
"humantime", "humantime",
"hyper", "hyper",
"hyper-util", "hyper-util",
"sha2",
"simple_moving_average", "simple_moving_average",
"tokio", "tokio",
"wisp-mux", "wisp-mux",

View file

@ -7,7 +7,7 @@ use log::LevelFilter;
use regex::RegexSet; use regex::RegexSet;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use wisp_mux::extensions::{ use wisp_mux::extensions::{
cert::CertAuthProtocolExtensionBuilder, cert::{CertAuthProtocolExtension, CertAuthProtocolExtensionBuilder},
motd::MotdProtocolExtensionBuilder, motd::MotdProtocolExtensionBuilder,
password::{PasswordProtocolExtension, PasswordProtocolExtensionBuilder}, password::{PasswordProtocolExtension, PasswordProtocolExtensionBuilder},
udp::UdpProtocolExtensionBuilder, udp::UdpProtocolExtensionBuilder,
@ -304,6 +304,7 @@ impl WispConfig {
get_certificates_from_paths(self.certificate_extension_keys.clone()) get_certificates_from_paths(self.certificate_extension_keys.clone())
.await?, .await?,
))); )));
required_extensions.push(CertAuthProtocolExtension::ID);
} }
None => {} None => {}
} }

View file

@ -179,9 +179,7 @@ async fn handle_stream(
let id = muxstream.stream_id; let id = muxstream.stream_id;
let (mut rx, mut tx) = muxstream.into_io().into_asyncrw().into_split(); let (mut rx, mut tx) = muxstream.into_io().into_asyncrw().into_split();
match twisp::handle_twisp(id, &mut rx, &mut tx, twisp_map.clone(), pty, cmd) match twisp::handle_twisp(id, &mut rx, &mut tx, twisp_map.clone(), pty, cmd).await {
.await
{
Ok(()) => { Ok(()) => {
let _ = closer.close(CloseReason::Voluntary).await; let _ = closer.close(CloseReason::Voluntary).await;
} }

View file

@ -8,12 +8,14 @@ atomic-counter = "1.0.1"
bytes = "1.7.1" bytes = "1.7.1"
clap = { version = "4.5.16", features = ["cargo", "derive"] } clap = { version = "4.5.16", features = ["cargo", "derive"] }
console-subscriber = { version = "0.4.0", optional = true } console-subscriber = { version = "0.4.0", optional = true }
ed25519-dalek = { version = "2.1.1", features = ["pem"] }
fastwebsockets = { version = "0.8.0", features = ["unstable-split", "upgrade"] } fastwebsockets = { version = "0.8.0", features = ["unstable-split", "upgrade"] }
futures = "0.3.30" futures = "0.3.30"
http-body-util = "0.1.2" http-body-util = "0.1.2"
humantime = "2.1.0" humantime = "2.1.0"
hyper = { version = "1.4.1", features = ["http1", "client"] } hyper = { version = "1.4.1", features = ["http1", "client"] }
hyper-util = { version = "0.1.7", features = ["tokio"] } hyper-util = { version = "0.1.7", features = ["tokio"] }
sha2 = "0.10.8"
simple_moving_average = "1.0.2" simple_moving_average = "1.0.2"
tokio = { version = "1.39.3", features = ["full"] } tokio = { version = "1.39.3", features = ["full"] }
wisp-mux = { path = "../wisp", features = ["fastwebsockets"]} wisp-mux = { path = "../wisp", features = ["fastwebsockets"]}

View file

@ -1,6 +1,7 @@
use atomic_counter::{AtomicCounter, RelaxedCounter}; use atomic_counter::{AtomicCounter, RelaxedCounter};
use bytes::Bytes; use bytes::Bytes;
use clap::Parser; use clap::Parser;
use ed25519_dalek::pkcs8::DecodePrivateKey;
use fastwebsockets::handshake; use fastwebsockets::handshake;
use futures::future::select_all; use futures::future::select_all;
use http_body_util::Empty; use http_body_util::Empty;
@ -10,12 +11,14 @@ use hyper::{
Request, Uri, Request, Uri,
}; };
use hyper_util::rt::TokioIo; use hyper_util::rt::TokioIo;
use sha2::{Digest, Sha512};
use simple_moving_average::{SingleSumSMA, SMA}; use simple_moving_average::{SingleSumSMA, SMA};
use std::{ use std::{
error::Error, error::Error,
future::Future, future::Future,
io::{stdout, Cursor, IsTerminal, Write}, io::{stdout, Cursor, IsTerminal, Write},
net::SocketAddr, net::SocketAddr,
path::PathBuf,
process::{abort, exit}, process::{abort, exit},
sync::Arc, sync::Arc,
time::{Duration, Instant}, time::{Duration, Instant},
@ -29,6 +32,8 @@ use tokio::{
}; };
use wisp_mux::{ use wisp_mux::{
extensions::{ extensions::{
cert::{CertAuthProtocolExtension, CertAuthProtocolExtensionBuilder, SigningKey},
motd::{MotdProtocolExtension, MotdProtocolExtensionBuilder},
password::{PasswordProtocolExtension, PasswordProtocolExtensionBuilder}, password::{PasswordProtocolExtension, PasswordProtocolExtensionBuilder},
udp::{UdpProtocolExtension, UdpProtocolExtensionBuilder}, udp::{UdpProtocolExtension, UdpProtocolExtensionBuilder},
ProtocolExtensionBuilder, ProtocolExtensionBuilder,
@ -92,11 +97,28 @@ struct Cli {
/// Usernames and passwords are sent in plaintext!! /// Usernames and passwords are sent in plaintext!!
#[arg(long)] #[arg(long)]
auth: Option<String>, auth: Option<String>,
/// Enable certauth
#[arg(long)]
certauth: Option<PathBuf>,
/// Enable motd parsing
#[arg(long)]
motd: bool,
/// Make a Wisp V2 connection /// Make a Wisp V2 connection
#[arg(long)] #[arg(long)]
wisp_v2: bool, wisp_v2: bool,
} }
async fn get_cert(path: PathBuf) -> Result<SigningKey, Box<dyn Error + Sync + Send>> {
let data = tokio::fs::read_to_string(path).await?;
let signer = ed25519_dalek::SigningKey::from_pkcs8_pem(&data)?;
let binary_key = signer.verifying_key().to_bytes();
let mut hasher = Sha512::new();
hasher.update(binary_key);
let hash: [u8; 64] = hasher.finalize().into();
Ok(SigningKey::new_ed25519(Arc::new(signer), hash))
}
#[tokio::main(flavor = "multi_thread")] #[tokio::main(flavor = "multi_thread")]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> { async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
#[cfg(feature = "tokio-console")] #[cfg(feature = "tokio-console")]
@ -153,10 +175,19 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
extensions.push(Box::new(UdpProtocolExtensionBuilder)); extensions.push(Box::new(UdpProtocolExtensionBuilder));
extension_ids.push(UdpProtocolExtension::ID); extension_ids.push(UdpProtocolExtension::ID);
} }
if opts.motd {
extensions.push(Box::new(MotdProtocolExtensionBuilder::Client));
}
if let Some(auth) = auth { if let Some(auth) = auth {
extensions.push(Box::new(auth)); extensions.push(Box::new(auth));
extension_ids.push(PasswordProtocolExtension::ID); extension_ids.push(PasswordProtocolExtension::ID);
} }
if let Some(certauth) = opts.certauth {
let key = get_cert(certauth).await?;
let extension = CertAuthProtocolExtensionBuilder::new_client(key);
extensions.push(Box::new(extension));
extension_ids.push(CertAuthProtocolExtension::ID);
}
let (mux, fut) = if !opts.wisp_v2 { let (mux, fut) = if !opts.wisp_v2 {
ClientMux::create(rx, tx, None) ClientMux::create(rx, tx, None)
@ -169,9 +200,19 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
.await? .await?
}; };
let motd_extension = mux
.supported_extensions
.iter()
.find_map(|x| x.downcast_ref::<MotdProtocolExtension>());
println!( println!(
"connected and created ClientMux, was downgraded {}, extensions supported {:?}\n", "connected and created ClientMux, was downgraded {}, extensions supported {:?}, motd {:?}\n\n",
mux.downgraded, mux.supported_extension_ids mux.downgraded,
mux.supported_extensions
.iter()
.map(|x| x.get_id())
.collect::<Vec<_>>(),
motd_extension.map(|x| x.motd.clone())
); );
let mut threads = Vec::with_capacity((opts.streams * 2) + 3); let mut threads = Vec::with_capacity((opts.streams * 2) + 3);

View file

@ -74,7 +74,10 @@ pub struct VerifyKey {
impl VerifyKey { impl VerifyKey {
/// Create a new ED25519 verification key. /// Create a new ED25519 verification key.
pub fn new_ed25519(verifier: Arc<dyn Verifier<Signature> + Sync + Send>, hash: [u8; 64]) -> Self { pub fn new_ed25519(
verifier: Arc<dyn Verifier<Signature> + Sync + Send>,
hash: [u8; 64],
) -> Self {
Self { Self {
cert_type: SupportedCertificateTypes::Ed25519, cert_type: SupportedCertificateTypes::Ed25519,
hash, hash,
@ -314,9 +317,9 @@ impl ProtocolExtensionBuilder for CertAuthProtocolExtensionBuilder {
fn build_to_extension(&mut self, _: Role) -> Result<AnyProtocolExtension, WispError> { fn build_to_extension(&mut self, _: Role) -> Result<AnyProtocolExtension, WispError> {
match self { match self {
Self::ServerBeforeChallenge { verifiers } => { Self::ServerBeforeChallenge { verifiers } => {
let mut challenge = BytesMut::with_capacity(64); let mut challenge = [0u8; 64];
getrandom::getrandom(&mut challenge).map_err(CertAuthError::from)?; getrandom::getrandom(&mut challenge).map_err(CertAuthError::from)?;
let challenge = challenge.freeze(); let challenge = Bytes::from(challenge.to_vec());
*self = Self::ServerAfterChallenge { *self = Self::ServerAfterChallenge {
verifiers: verifiers.to_vec(), verifiers: verifiers.to_vec(),

View file

@ -32,6 +32,16 @@ impl AnyProtocolExtension {
pub fn downcast<T: ProtocolExtension>(self) -> Result<Box<T>, Self> { pub fn downcast<T: ProtocolExtension>(self) -> Result<Box<T>, Self> {
self.0.__downcast().map_err(Self) self.0.__downcast().map_err(Self)
} }
/// Downcast the protocol extension.
pub fn downcast_ref<T: ProtocolExtension>(&self) -> Option<&T> {
self.0.__downcast_ref()
}
/// Downcast the protocol extension.
pub fn downcast_mut<T: ProtocolExtension>(&mut self) -> Option<&mut T> {
self.0.__downcast_mut()
}
} }
impl Deref for AnyProtocolExtension { impl Deref for AnyProtocolExtension {
@ -126,6 +136,22 @@ impl dyn ProtocolExtension {
Err(self) Err(self)
} }
} }
fn __downcast_ref<T: ProtocolExtension>(&self) -> Option<&T> {
if self.__is::<T>() {
unsafe { Some(&*(self as *const dyn ProtocolExtension as *const T)) }
} else {
None
}
}
fn __downcast_mut<T: ProtocolExtension>(&mut self) -> Option<&mut T> {
if self.__is::<T>() {
unsafe { Some(&mut *(self as *mut dyn ProtocolExtension as *mut T)) }
} else {
None
}
}
} }
/// Trait to build a Wisp protocol extension from a payload. /// Trait to build a Wisp protocol extension from a payload.