Compare commits
7 commits
Author | SHA1 | Date | |
---|---|---|---|
|
838f9188b3 | ||
|
6ff29972c7 | ||
|
57c048ab83 | ||
|
2b1e16e1cb | ||
|
145181e364 | ||
|
ff9b2d3f96 | ||
|
9865c10f40 |
6 changed files with 398 additions and 85 deletions
95
Cargo.lock
generated
95
Cargo.lock
generated
|
@ -206,18 +206,95 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-channel"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-macro",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"memchr",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -401,10 +478,11 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mumble-rs"
|
name = "mumble-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"futures",
|
||||||
"prost",
|
"prost",
|
||||||
"prost-build",
|
"prost-build",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
|
@ -495,6 +573,12 @@ version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
|
@ -708,6 +792,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.2"
|
version = "1.13.2"
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
[package]
|
[package]
|
||||||
name = "mumble-rs"
|
name = "mumble-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "MIT"
|
||||||
|
description = "A small simple crate to communicate with a mumble server"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
|
@ -13,6 +15,7 @@ tokio-util = { version = "0.7", features = ["codec"] }
|
||||||
tokio-rustls = { version = "0.26" }
|
tokio-rustls = { version = "0.26" }
|
||||||
webpki-roots = "0.26"
|
webpki-roots = "0.26"
|
||||||
rustls-pki-types = { version = "1.7.0" , features = ["alloc", "std"]}
|
rustls-pki-types = { version = "1.7.0" , features = ["alloc", "std"]}
|
||||||
|
futures = "0.3.30"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
prost-build = "0.13"
|
prost-build = "0.13"
|
||||||
|
|
7
build.rs
7
build.rs
|
@ -1,4 +1,7 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
prost_build::compile_protos(&["src/protos/Mumble.proto", "src/protos/MumbleUDP.proto"], &["src/protos"])
|
prost_build::compile_protos(
|
||||||
.expect("Could not build protobuf files")
|
&["src/protos/Mumble.proto", "src/protos/MumbleUDP.proto"],
|
||||||
|
&["src/protos"],
|
||||||
|
)
|
||||||
|
.expect("Could not build protobuf files")
|
||||||
}
|
}
|
||||||
|
|
199
src/codec.rs
199
src/codec.rs
|
@ -1,25 +1,20 @@
|
||||||
|
use crate::proto::*;
|
||||||
|
use crate::MumbleMessage;
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use bytes::{Buf, BytesMut};
|
use bytes::{Buf, BufMut, BytesMut};
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use tokio_util::codec::Decoder;
|
use tokio_util::codec::{Decoder, Encoder};
|
||||||
use crate::proto::Version;
|
|
||||||
|
|
||||||
pub enum MumbleMessages {
|
pub struct MumbleTcpCodec {}
|
||||||
|
|
||||||
}
|
impl MumbleTcpCodec {
|
||||||
|
|
||||||
pub struct MumbleCodec {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MumbleCodec {
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decoder for MumbleCodec {
|
impl Decoder for MumbleTcpCodec {
|
||||||
type Item = ();
|
type Item = MumbleMessage;
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||||
|
@ -27,21 +22,183 @@ impl Decoder for MumbleCodec {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let message_type = u16::from_be_bytes(src[0..2].try_into()?) as usize;
|
let (message_type, rest) = src.split_at(2);
|
||||||
let message_length = u32::from_be_bytes(src[2..6].try_into()?) as usize;
|
let (message_length, rest) = rest.split_at(4);
|
||||||
let message_data = &src[6..message_length];
|
let message_type = u16::from_be_bytes(message_type.try_into()?) as usize;
|
||||||
|
let message_length = u32::from_be_bytes(message_length.try_into()?) as usize;
|
||||||
|
|
||||||
|
if message_length + 6 > src.len() {
|
||||||
|
src.reserve(message_length + 6 - src.len());
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (message_data, _) = rest.split_at(message_length);
|
||||||
|
let mut mumble_message: Option<MumbleMessage> = None;
|
||||||
|
|
||||||
match message_type {
|
match message_type {
|
||||||
0 => {
|
0 => {
|
||||||
//TODO: Version
|
mumble_message = Some(MumbleMessage::Version {
|
||||||
let version = Version::decode(message_data);
|
data: Version::decode(message_data)?,
|
||||||
println!("{version:?}");
|
});
|
||||||
Ok(Some(()))
|
}
|
||||||
|
1 => {
|
||||||
|
mumble_message = Some(MumbleMessage::UdpTunnel {
|
||||||
|
data: UdpTunnel::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
bail!("The server should never send Authenticate")
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
mumble_message = Some(MumbleMessage::Ping {
|
||||||
|
data: Ping::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
mumble_message = Some(MumbleMessage::Reject {
|
||||||
|
data: Reject::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
mumble_message = Some(MumbleMessage::ServerSync {
|
||||||
|
data: ServerSync::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
6 => {
|
||||||
|
mumble_message = Some(MumbleMessage::ChannelRemove {
|
||||||
|
data: ChannelRemove::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
7 => {
|
||||||
|
mumble_message = Some(MumbleMessage::ChannelState {
|
||||||
|
data: ChannelState::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
8 => {
|
||||||
|
mumble_message = Some(MumbleMessage::UserRemove {
|
||||||
|
data: UserRemove::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
9 => {
|
||||||
|
mumble_message = Some(MumbleMessage::UserState {
|
||||||
|
data: UserState::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
10 => {
|
||||||
|
mumble_message = Some(MumbleMessage::BanList {
|
||||||
|
data: BanList::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
11 => {
|
||||||
|
mumble_message = Some(MumbleMessage::TextMessage {
|
||||||
|
data: TextMessage::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
12 => {
|
||||||
|
mumble_message = Some(MumbleMessage::PermissionDenied {
|
||||||
|
data: PermissionDenied::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
13 => {
|
||||||
|
mumble_message = Some(MumbleMessage::Acl {
|
||||||
|
data: Acl::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
14 => {
|
||||||
|
mumble_message = Some(MumbleMessage::QueryUsers {
|
||||||
|
data: QueryUsers::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
15 => {
|
||||||
|
mumble_message = Some(MumbleMessage::CryptSetup {
|
||||||
|
data: CryptSetup::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
16 => {
|
||||||
|
mumble_message = Some(MumbleMessage::ContextActionModify {
|
||||||
|
data: ContextActionModify::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
17 => {
|
||||||
|
mumble_message = Some(MumbleMessage::ContextAction {
|
||||||
|
data: ContextAction::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
18 => {
|
||||||
|
mumble_message = Some(MumbleMessage::UserList {
|
||||||
|
data: UserList::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
19 => {
|
||||||
|
mumble_message = Some(MumbleMessage::VoiceTarget {
|
||||||
|
data: VoiceTarget::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
20 => {
|
||||||
|
mumble_message = Some(MumbleMessage::PermissionQuery {
|
||||||
|
data: PermissionQuery::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
21 => {
|
||||||
|
mumble_message = Some(MumbleMessage::CodecVersion {
|
||||||
|
data: CodecVersion::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
22 => {
|
||||||
|
mumble_message = Some(MumbleMessage::UserStats {
|
||||||
|
data: UserStats::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
23 => {
|
||||||
|
mumble_message = Some(MumbleMessage::RequestBlob {
|
||||||
|
data: RequestBlob::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
24 => {
|
||||||
|
mumble_message = Some(MumbleMessage::ServerConfig {
|
||||||
|
data: ServerConfig::decode(message_data)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
25 => {
|
||||||
|
mumble_message = Some(MumbleMessage::SuggestConfig {
|
||||||
|
data: SuggestConfig::decode(message_data)?,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
eprintln!("Unknown message type {:?}", message_type);
|
eprintln!("Unknown message type {:?}", message_type);
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
src.advance(message_length + 6);
|
||||||
|
Ok(mumble_message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encoder<MumbleMessage> for MumbleTcpCodec {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn encode(&mut self, item: MumbleMessage, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||||
|
let mut message = BytesMut::new();
|
||||||
|
match item {
|
||||||
|
MumbleMessage::Version { data } => {
|
||||||
|
Version::encode(&data, &mut message)?;
|
||||||
|
dst.put_u16(0);
|
||||||
|
}
|
||||||
|
MumbleMessage::Authenticate { data } => {
|
||||||
|
Authenticate::encode(&data, &mut message)?;
|
||||||
|
dst.put_u16(2);
|
||||||
|
}
|
||||||
|
MumbleMessage::Ping { data } => {
|
||||||
|
Ping::encode(&data, &mut message)?;
|
||||||
|
dst.put_u16(3);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
bail!("Could not encode unknown message")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.put_u32(message.len() as u32);
|
||||||
|
dst.extend_from_slice(&message);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
161
src/lib.rs
161
src/lib.rs
|
@ -1,4 +1,5 @@
|
||||||
pub mod codec;
|
pub mod codec;
|
||||||
|
use futures::sink::SinkExt;
|
||||||
|
|
||||||
pub mod proto {
|
pub mod proto {
|
||||||
include!(concat!(env!("OUT_DIR"), "/mumble_proto.rs"));
|
include!(concat!(env!("OUT_DIR"), "/mumble_proto.rs"));
|
||||||
|
@ -8,45 +9,95 @@ pub mod udp {
|
||||||
include!(concat!(env!("OUT_DIR"), "/mumble_udp.rs"));
|
include!(concat!(env!("OUT_DIR"), "/mumble_udp.rs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use crate::codec::MumbleTcpCodec;
|
||||||
use std::net::SocketAddr;
|
use crate::proto::*;
|
||||||
use tokio::net::TcpStream;
|
|
||||||
use tokio::io::AsyncWriteExt;
|
|
||||||
use tokio_stream::StreamExt;
|
|
||||||
use prost::Message;
|
|
||||||
use tokio_rustls::rustls::{ClientConfig, DigitallySignedStruct, Error, RootCertStore, SignatureScheme};
|
|
||||||
use tokio_rustls::client::TlsStream;
|
|
||||||
use tokio_rustls::{TlsConnector};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use rustls_pki_types::{CertificateDer, ServerName, UnixTime};
|
use rustls_pki_types::{CertificateDer, ServerName, UnixTime};
|
||||||
use tokio_util::codec::FramedRead;
|
use std::fmt::{Debug, Formatter};
|
||||||
use crate::codec::MumbleCodec;
|
use std::net::Ipv4Addr;
|
||||||
use bytes::BytesMut;
|
use std::sync::Arc;
|
||||||
use tokio_rustls::rustls::client::danger::{DangerousClientConfig, HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
|
use tokio::net::{TcpStream, UdpSocket};
|
||||||
|
use tokio_rustls::client::TlsStream;
|
||||||
|
use tokio_rustls::rustls::client::danger::{
|
||||||
|
HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier,
|
||||||
|
};
|
||||||
|
use tokio_rustls::rustls::{
|
||||||
|
ClientConfig, DigitallySignedStruct, Error, RootCertStore, SignatureScheme,
|
||||||
|
};
|
||||||
|
use tokio_rustls::TlsConnector;
|
||||||
|
use tokio_util::codec::Framed;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum MumbleMessage {
|
||||||
|
Version { data: Version },
|
||||||
|
UdpTunnel { data: UdpTunnel },
|
||||||
|
Ping { data: Ping },
|
||||||
|
Reject { data: Reject },
|
||||||
|
Authenticate { data: Authenticate },
|
||||||
|
ServerSync { data: ServerSync },
|
||||||
|
ChannelRemove { data: ChannelRemove },
|
||||||
|
ChannelState { data: ChannelState },
|
||||||
|
UserRemove { data: UserRemove },
|
||||||
|
UserState { data: UserState },
|
||||||
|
BanList { data: BanList },
|
||||||
|
TextMessage { data: TextMessage },
|
||||||
|
PermissionDenied { data: PermissionDenied },
|
||||||
|
Acl { data: Acl },
|
||||||
|
QueryUsers { data: QueryUsers },
|
||||||
|
CryptSetup { data: CryptSetup },
|
||||||
|
ContextActionModify { data: ContextActionModify },
|
||||||
|
ContextAction { data: ContextAction },
|
||||||
|
UserList { data: UserList },
|
||||||
|
VoiceTarget { data: VoiceTarget },
|
||||||
|
PermissionQuery { data: PermissionQuery },
|
||||||
|
CodecVersion { data: CodecVersion },
|
||||||
|
UserStats { data: UserStats },
|
||||||
|
RequestBlob { data: RequestBlob },
|
||||||
|
ServerConfig { data: ServerConfig },
|
||||||
|
SuggestConfig { data: SuggestConfig },
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MumbleClient {
|
pub struct MumbleClient {
|
||||||
host: SocketAddr,
|
host: String,
|
||||||
|
name: String,
|
||||||
|
port: u16,
|
||||||
|
password: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct NoVerifier;
|
pub(crate) struct NoVerifier;
|
||||||
|
|
||||||
impl Debug for NoVerifier {
|
impl Debug for NoVerifier {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
todo!()
|
write!(f, "NoVerifier")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerCertVerifier for NoVerifier {
|
impl ServerCertVerifier for NoVerifier {
|
||||||
fn verify_server_cert(&self, end_entity: &CertificateDer<'_>, intermediates: &[CertificateDer<'_>], server_name: &ServerName<'_>, ocsp_response: &[u8], now: UnixTime) -> Result<ServerCertVerified, Error> {
|
fn verify_server_cert(
|
||||||
|
&self,
|
||||||
|
_end_entity: &CertificateDer<'_>,
|
||||||
|
_intermediates: &[CertificateDer<'_>],
|
||||||
|
_server_name: &ServerName<'_>,
|
||||||
|
_ocsp_response: &[u8],
|
||||||
|
_now: UnixTime,
|
||||||
|
) -> Result<ServerCertVerified, Error> {
|
||||||
Ok(ServerCertVerified::assertion())
|
Ok(ServerCertVerified::assertion())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_tls12_signature(&self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct) -> Result<HandshakeSignatureValid, Error> {
|
fn verify_tls12_signature(
|
||||||
|
&self,
|
||||||
|
_message: &[u8],
|
||||||
|
_cert: &CertificateDer<'_>,
|
||||||
|
_dss: &DigitallySignedStruct,
|
||||||
|
) -> Result<HandshakeSignatureValid, Error> {
|
||||||
Ok(HandshakeSignatureValid::assertion())
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_tls13_signature(&self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct) -> Result<HandshakeSignatureValid, Error> {
|
fn verify_tls13_signature(
|
||||||
|
&self,
|
||||||
|
_message: &[u8],
|
||||||
|
_cert: &CertificateDer<'_>,
|
||||||
|
_dss: &DigitallySignedStruct,
|
||||||
|
) -> Result<HandshakeSignatureValid, Error> {
|
||||||
Ok(HandshakeSignatureValid::assertion())
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,9 +121,12 @@ impl ServerCertVerifier for NoVerifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MumbleClient {
|
impl MumbleClient {
|
||||||
pub fn new(host: SocketAddr) -> Self {
|
pub fn new(host: String, port: Option<u16>, name: String, password: Option<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
host
|
host,
|
||||||
|
port: port.unwrap_or(64738),
|
||||||
|
name,
|
||||||
|
password,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,37 +143,48 @@ impl MumbleClient {
|
||||||
.set_certificate_verifier(Arc::new(NoVerifier));
|
.set_certificate_verifier(Arc::new(NoVerifier));
|
||||||
|
|
||||||
let connector = TlsConnector::from(Arc::new(config));
|
let connector = TlsConnector::from(Arc::new(config));
|
||||||
let dnsname = ServerName::try_from("127.0.0.1")?;
|
let dnsname = ServerName::try_from(self.host.clone())?;
|
||||||
let stream = TcpStream::connect(&self.host).await?;
|
let stream = TcpStream::connect((self.host.clone(), self.port)).await?;
|
||||||
Ok(connector.connect(dnsname, stream).await?)
|
Ok(connector.connect(dnsname, stream).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn connect(&mut self) -> anyhow::Result<()> {
|
pub async fn create_udp_connection(&mut self) -> anyhow::Result<UdpSocket> {
|
||||||
let tcp_stream = self.create_tcp_connection().await?;
|
let sock = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).await?;
|
||||||
let mut framed_reader = FramedRead::new(tcp_stream, MumbleCodec::new());
|
sock.connect((self.host.clone(), self.port)).await?;
|
||||||
let mut message_buffer: BytesMut = BytesMut::new();
|
Ok(sock)
|
||||||
let version = (proto::Version {
|
}
|
||||||
os: Some(String::from("Linux")),
|
|
||||||
os_version: None,
|
|
||||||
release: None,
|
|
||||||
version_v1: None,
|
|
||||||
version_v2: None
|
|
||||||
}).encode(&mut message_buffer)?;
|
|
||||||
|
|
||||||
// let mut complete_buffer = BytesMut::new();
|
pub async fn connect(
|
||||||
// complete_buffer.extend((0u16).to_be_bytes());
|
&mut self,
|
||||||
// complete_buffer.extend(((2+4+message_buffer.len()) as u32).to_be_bytes());
|
) -> anyhow::Result<Framed<TlsStream<TcpStream>, MumbleTcpCodec>> {
|
||||||
// complete_buffer.extend(&message_buffer);
|
let mut framed = Framed::new(self.create_tcp_connection().await?, MumbleTcpCodec::new());
|
||||||
|
let version_v1 = (1u16 as u32) << 16 | (5u8 as u32) << 8 | (1u8 as u32);
|
||||||
|
let version_v2 = 1u64 << 48 | 5u64 << 32 | 0u64 << 16 | 1u64;
|
||||||
|
framed
|
||||||
|
.send(MumbleMessage::Version {
|
||||||
|
data: Version {
|
||||||
|
os: Some(String::from("Linux")),
|
||||||
|
os_version: Some(String::from("os version")),
|
||||||
|
release: Some(String::from("release")),
|
||||||
|
version_v1: Some(version_v1),
|
||||||
|
version_v2: Some(version_v2),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
// println!("{complete_buffer:?}");
|
framed
|
||||||
// tcp_stream.write_all(&complete_buffer).await?;
|
.send(MumbleMessage::Authenticate {
|
||||||
|
data: Authenticate {
|
||||||
|
username: Some(self.name.clone()),
|
||||||
|
password: self.password.clone(),
|
||||||
|
tokens: vec![],
|
||||||
|
celt_versions: vec![],
|
||||||
|
opus: Some(true),
|
||||||
|
client_type: Some(1),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
while let Some(frame_result) = framed_reader.next().await {
|
Ok(framed)
|
||||||
if let Ok(data) = frame_result {
|
|
||||||
println!("{data:?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
use mumble_rs::MumbleClient;
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() -> anyhow::Result<()> {
|
|
||||||
let mut client = MumbleClient::new("127.0.0.1:64738".parse()?);
|
|
||||||
client.connect().await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
Loading…
Reference in a new issue