Initial commit...it works?
This commit is contained in:
+251
@@ -0,0 +1,251 @@
|
||||
use anyhow::anyhow;
|
||||
use anyhow::Result;
|
||||
use futures::SinkExt;
|
||||
use futures::StreamExt;
|
||||
use mumble_protocol_2x::control::msgs;
|
||||
use mumble_protocol_2x::control::ClientControlCodec;
|
||||
use mumble_protocol_2x::control::ControlPacket;
|
||||
use mumble_protocol_2x::crypt::ClientCryptState;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::time::Duration;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_native_tls::TlsConnector;
|
||||
use tokio_util::codec::Decoder;
|
||||
use tracing::error;
|
||||
use tracing::info;
|
||||
use tracing::info_span;
|
||||
use tracing::Instrument;
|
||||
use tracing_subscriber::filter::LevelFilter;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use wtransport::endpoint::IncomingSession;
|
||||
use wtransport::Certificate;
|
||||
use wtransport::Endpoint;
|
||||
use wtransport::ServerConfig;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
init_logging();
|
||||
|
||||
let certificate = Certificate::load("./certificate.pem", "./certificate.key").await?;
|
||||
let hashes = certificate.hashes();
|
||||
info!("{}", hashes[0].fmt_as_byte_array());
|
||||
|
||||
let config = ServerConfig::builder()
|
||||
.with_bind_default(4433)
|
||||
//.with_certificate(Certificate::self_signed(["localhost"]))
|
||||
.with_certificate(certificate)
|
||||
.keep_alive_interval(Some(Duration::from_secs(3)))
|
||||
.build();
|
||||
|
||||
let server = Endpoint::server(config)?;
|
||||
info!("Server ready!");
|
||||
|
||||
for id in 0.. {
|
||||
let incoming_session = server.accept().await;
|
||||
tokio::spawn(handle_connection(incoming_session).instrument(info_span!("Connection", id)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_connection(incoming_session: IncomingSession) {
|
||||
let result = handle_connection_impl(incoming_session).await;
|
||||
error!("{:?}", result);
|
||||
}
|
||||
|
||||
async fn handle_connection_impl(incoming_session: IncomingSession) -> Result<()> {
|
||||
let mut buffer = vec![0; 65536].into_boxed_slice();
|
||||
|
||||
info!("Waiting for session request...");
|
||||
|
||||
let session_request = incoming_session.await?;
|
||||
|
||||
info!(
|
||||
"New session: Authority: '{}', Path: '{}'",
|
||||
session_request.authority(),
|
||||
session_request.path()
|
||||
);
|
||||
|
||||
let connection_params =
|
||||
connection_parameters_from_url(&session_request.authority(), &session_request.path())?;
|
||||
|
||||
let server_addr = (
|
||||
connection_params.hostname.clone(),
|
||||
connection_params.port.clone(),
|
||||
)
|
||||
.to_socket_addrs()
|
||||
.expect("Failed to parse server address")
|
||||
.next()
|
||||
.expect("Failed to resolve server address");
|
||||
|
||||
let stream = TcpStream::connect(&server_addr)
|
||||
.await
|
||||
.expect("Failed to connect to server:");
|
||||
|
||||
let mut builder = native_tls::TlsConnector::builder();
|
||||
builder.danger_accept_invalid_certs(true);
|
||||
let connector: TlsConnector = builder
|
||||
.build()
|
||||
.expect("Failed to create TLS connector")
|
||||
.into();
|
||||
let tls_stream = connector
|
||||
.connect(&connection_params.hostname, stream)
|
||||
.await
|
||||
.expect("Failed to connect TLS: {}");
|
||||
|
||||
let (mut sink, mut stream) = ClientControlCodec::new().framed(tls_stream).split();
|
||||
|
||||
let mut msg = msgs::Authenticate::new();
|
||||
msg.set_username(connection_params.username);
|
||||
msg.set_opus(true);
|
||||
sink.send(msg.into()).await.unwrap();
|
||||
|
||||
let connection = session_request.accept().await?;
|
||||
|
||||
info!("Waiting for data from client...");
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
stream = connection.accept_bi() => {
|
||||
let mut stream = stream?;
|
||||
info!("Accepted BI stream");
|
||||
|
||||
let bytes_read = match stream.1.read(&mut buffer).await? {
|
||||
Some(bytes_read) => bytes_read,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let str_data = std::str::from_utf8(&buffer[..bytes_read])?;
|
||||
|
||||
info!("Received (bi) '{str_data}' from client");
|
||||
|
||||
stream.0.write_all(b"ACK").await?;
|
||||
}
|
||||
stream = connection.accept_uni() => {
|
||||
let mut stream = stream?;
|
||||
info!("Accepted UNI stream");
|
||||
|
||||
let bytes_read = match stream.read(&mut buffer).await? {
|
||||
Some(bytes_read) => bytes_read,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let str_data = std::str::from_utf8(&buffer[..bytes_read])?;
|
||||
|
||||
info!("Received (uni) '{str_data}' from client");
|
||||
|
||||
let mut stream = connection.open_uni().await?.await?;
|
||||
stream.write_all(b"ACK").await?;
|
||||
}
|
||||
dgram = connection.receive_datagram() => {
|
||||
let dgram = dgram?;
|
||||
let str_data = std::str::from_utf8(&dgram)?;
|
||||
|
||||
info!("Received (dgram) '{str_data}' from client");
|
||||
|
||||
connection.send_datagram(b"ACK")?;
|
||||
}
|
||||
Some(mumble_server_pkt) = stream.next() => {
|
||||
match mumble_server_pkt.unwrap() {
|
||||
ControlPacket::TextMessage(mut msg) => {
|
||||
info!(
|
||||
"Got message from user with session ID {}: {}",
|
||||
msg.get_actor(),
|
||||
msg.get_message()
|
||||
);
|
||||
// Send reply back to server
|
||||
let mut response = msgs::TextMessage::new();
|
||||
response.mut_session().push(msg.get_actor());
|
||||
response.set_message(msg.take_message());
|
||||
sink.send(response.into()).await.unwrap();
|
||||
}
|
||||
ControlPacket::CryptSetup(msg) => {
|
||||
info!("Got crypt state");
|
||||
//// Wait until we're fully connected before initiating UDP voice
|
||||
//crypt_state = Some(ClientCryptState::new_from(
|
||||
// msg.get_key()
|
||||
// .try_into()
|
||||
// .expect("Server sent private key with incorrect size"),
|
||||
// msg.get_client_nonce()
|
||||
// .try_into()
|
||||
// .expect("Server sent client_nonce with incorrect size"),
|
||||
// msg.get_server_nonce()
|
||||
// .try_into()
|
||||
// .expect("Server sent server_nonce with incorrect size"),
|
||||
//));
|
||||
}
|
||||
ControlPacket::ServerSync(_) => {
|
||||
println!("Logged in!");
|
||||
//if let Some(sender) = crypt_state_sender.take() {
|
||||
// let _ = sender.send(
|
||||
// crypt_state
|
||||
// .take()
|
||||
// .expect("Server didn't send us any CryptSetup packet!"),
|
||||
// );
|
||||
//}
|
||||
}
|
||||
ControlPacket::Reject(msg) => {
|
||||
println!("Login rejected: {:?}", msg);
|
||||
}
|
||||
_ => {},
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_logging() {
|
||||
let env_filter = EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
.from_env_lossy();
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.with_target(true)
|
||||
.with_level(true)
|
||||
.with_env_filter(env_filter)
|
||||
.init();
|
||||
}
|
||||
|
||||
struct ConnectionParameters {
|
||||
pub hostname: String,
|
||||
pub port: u16,
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
fn connection_parameters_from_url(authority: &str, path: &str) -> Result<ConnectionParameters> {
|
||||
let url_str = format!("https://{}{}", authority, path);
|
||||
|
||||
let connection_url = url::Url::parse(&url_str)?;
|
||||
|
||||
let mut hostname: Option<String> = None;
|
||||
let mut port: Option<u16> = None;
|
||||
let mut username: Option<String> = None;
|
||||
|
||||
use std::borrow::Borrow;
|
||||
|
||||
for (k, v) in connection_url.query_pairs() {
|
||||
match k.borrow() {
|
||||
"hostname" => {
|
||||
hostname = Some(v.to_string());
|
||||
}
|
||||
"port" => {
|
||||
port = Some(v.parse::<u16>()?);
|
||||
}
|
||||
"username" => {
|
||||
username = Some(v.to_string());
|
||||
}
|
||||
&_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if hostname.is_none() && port.is_none() && username.is_none() {
|
||||
return Err(anyhow!("URL is missing required parametetrs"));
|
||||
}
|
||||
|
||||
Ok(ConnectionParameters {
|
||||
hostname: hostname.unwrap(),
|
||||
port: port.unwrap(),
|
||||
username: username.unwrap(),
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user