pub mod backend;
pub mod client;
pub mod forwarding;
use std::io;
use aes::Aes128;
use bytes::{Buf, BytesMut};
use cfb8::cipher::generic_array::GenericArray;
use cfb8::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
use deepslate_protocol::codec;
use deepslate_protocol::packet::Packet;
use deepslate_protocol::packet::login::SetCompressionPacket;
use deepslate_protocol::varint;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
type Aes128Cfb8Enc = cfb8::Encryptor<Aes128>;
type Aes128Cfb8Dec = cfb8::Decryptor<Aes128>;
struct CipherPair {
encryptor: Aes128Cfb8Enc,
decryptor: Aes128Cfb8Dec,
}
impl CipherPair {
fn new(shared_secret: &[u8]) -> Self {
let key = shared_secret.into();
let iv = shared_secret.into();
Self {
encryptor: Aes128Cfb8Enc::new(key, iv),
decryptor: Aes128Cfb8Dec::new(key, iv),
}
}
fn encrypt(&mut self, data: &mut [u8]) {
let mut block = GenericArray::default();
for byte in data.iter_mut() {
block[0] = *byte;
self.encryptor.encrypt_block_mut(&mut block);
*byte = block[0];
}
}
fn decrypt(&mut self, data: &mut [u8]) {
let mut block = GenericArray::default();
for byte in data.iter_mut() {
block[0] = *byte;
self.decryptor.decrypt_block_mut(&mut block);
*byte = block[0];
}
}
}
pub struct MinecraftConnection {
stream: TcpStream,
read_buf: BytesMut,
cipher: Option<CipherPair>,
compression_threshold: i32,
decompressor: libdeflater::Decompressor,
compressor: libdeflater::Compressor,
decompress_buf: Vec<u8>,
compress_buf: Vec<u8>,
write_buf: Vec<u8>,
}
impl MinecraftConnection {
#[must_use]
pub fn new(stream: TcpStream, compression_level: libdeflater::CompressionLvl) -> Self {
Self {
stream,
read_buf: BytesMut::with_capacity(32768),
cipher: None,
compression_threshold: -1,
decompressor: libdeflater::Decompressor::new(),
compressor: libdeflater::Compressor::new(compression_level),
decompress_buf: Vec::new(),
compress_buf: Vec::new(),
write_buf: Vec::new(),
}
}
pub fn enable_encryption(&mut self, shared_secret: &[u8]) {
self.cipher = Some(CipherPair::new(shared_secret));
}
pub const fn enable_compression(&mut self, threshold: i32) {
self.compression_threshold = threshold;
}
pub fn into_split(self) -> (MinecraftReader, MinecraftWriter) {
let (read_half, write_half) = self.stream.into_split();
let (enc_cipher, dec_cipher) = if let Some(cipher) = self.cipher {
(
Some(EncryptCipher(cipher.encryptor)),
Some(DecryptCipher(cipher.decryptor)),
)
} else {
(None, None)
};
(
MinecraftReader {
stream: read_half,
read_buf: self.read_buf,
cipher: dec_cipher,
},
MinecraftWriter {
stream: write_half,
cipher: enc_cipher,
},
)
}
#[allow(clippy::large_stack_arrays)]
pub async fn read_frame(&mut self) -> io::Result<Option<BytesMut>> {
loop {
if let Some((varint_size, frame_len)) =
codec::try_read_frame(&self.read_buf).map_err(protocol_err)?
{
self.read_buf.advance(varint_size);
let frame = self.read_buf.split_to(frame_len);
if self.compression_threshold >= 0 {
let (uncompressed_size, payload) =
codec::read_compressed_frame(&frame).map_err(protocol_err)?;
if uncompressed_size == 0 {
return Ok(Some(BytesMut::from(payload)));
}
self.decompress_buf.resize(uncompressed_size, 0);
self.decompressor
.zlib_decompress(payload, &mut self.decompress_buf)
.map_err(|e| {
protocol_err(
deepslate_protocol::types::ProtocolError::CompressionError(
format!("zlib decompression failed: {e}"),
),
)
})?;
return Ok(Some(BytesMut::from(&self.decompress_buf[..])));
}
return Ok(Some(frame));
}
if let Some(cipher) = &mut self.cipher {
let mut tmp = [0u8; 32768];
let n = self.stream.read(&mut tmp).await?;
if n == 0 {
return Ok(None);
}
cipher.decrypt(&mut tmp[..n]);
self.read_buf.extend_from_slice(&tmp[..n]);
} else {
let n = self.stream.read_buf(&mut self.read_buf).await?;
if n == 0 {
return Ok(None);
}
}
}
}
#[allow(clippy::future_not_send)]
pub async fn write_packet<P: Packet>(&mut self, packet: &P) -> io::Result<()> {
let packet_data = codec::encode_packet_data(P::PACKET_ID, |buf| packet.encode(buf));
self.write_raw_packet(&packet_data).await
}
#[allow(
clippy::cast_sign_loss,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap
)]
pub async fn write_raw_packet(&mut self, packet_data: &[u8]) -> io::Result<()> {
self.write_buf.clear();
if self.compression_threshold >= 0 {
if packet_data.len() >= self.compression_threshold as usize {
let max_size = self.compressor.zlib_compress_bound(packet_data.len());
self.compress_buf.resize(max_size, 0);
let actual_size = self
.compressor
.zlib_compress(packet_data, &mut self.compress_buf)
.map_err(|e| {
protocol_err(deepslate_protocol::types::ProtocolError::CompressionError(
format!("zlib compression failed: {e}"),
))
})?;
codec::write_compressed_frame(
&mut self.write_buf,
packet_data.len() as i32,
&self.compress_buf[..actual_size],
);
} else {
codec::write_compressed_frame(&mut self.write_buf, 0, packet_data);
}
} else {
codec::write_frame(&mut self.write_buf, packet_data);
}
if let Some(cipher) = &mut self.cipher {
cipher.encrypt(&mut self.write_buf);
}
self.stream.write_all(&self.write_buf).await?;
Ok(())
}
pub async fn set_compression(&mut self, threshold: i32) -> io::Result<()> {
self.write_packet(&SetCompressionPacket { threshold })
.await?;
self.compression_threshold = threshold;
Ok(())
}
pub async fn shutdown(&mut self) -> io::Result<()> {
self.stream.flush().await?;
self.stream.shutdown().await?;
let drain = async {
let mut buf = [0u8; 1024];
loop {
match self.stream.read(&mut buf).await {
Ok(0) | Err(_) => break,
Ok(_) => {}
}
}
};
let _ = tokio::time::timeout(std::time::Duration::from_secs(5), drain).await;
Ok(())
}
}
struct EncryptCipher(Aes128Cfb8Enc);
impl EncryptCipher {
fn encrypt(&mut self, data: &mut [u8]) {
let mut block = GenericArray::default();
for byte in data.iter_mut() {
block[0] = *byte;
self.0.encrypt_block_mut(&mut block);
*byte = block[0];
}
}
}
struct DecryptCipher(Aes128Cfb8Dec);
impl DecryptCipher {
fn decrypt(&mut self, data: &mut [u8]) {
let mut block = GenericArray::default();
for byte in data.iter_mut() {
block[0] = *byte;
self.0.decrypt_block_mut(&mut block);
*byte = block[0];
}
}
}
pub struct MinecraftReader {
stream: tokio::net::tcp::OwnedReadHalf,
read_buf: BytesMut,
cipher: Option<DecryptCipher>,
}
impl MinecraftReader {
#[allow(
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::large_stack_arrays
)]
pub async fn read_raw_frame(&mut self) -> io::Result<Option<Vec<u8>>> {
loop {
if let Some((varint_size, frame_len)) =
codec::try_read_frame(&self.read_buf).map_err(protocol_err)?
{
let mut out = Vec::with_capacity(varint_size + frame_len);
varint::write_var_int(&mut out, frame_len as i32);
self.read_buf.advance(varint_size);
let frame = self.read_buf.split_to(frame_len);
out.extend_from_slice(&frame);
return Ok(Some(out));
}
if let Some(cipher) = &mut self.cipher {
let mut tmp = [0u8; 32768];
let n = self.stream.read(&mut tmp).await?;
if n == 0 {
return Ok(None);
}
cipher.decrypt(&mut tmp[..n]);
self.read_buf.extend_from_slice(&tmp[..n]);
} else {
let n = self.stream.read_buf(&mut self.read_buf).await?;
if n == 0 {
return Ok(None);
}
}
}
}
}
pub struct MinecraftWriter {
pub(crate) stream: tokio::net::tcp::OwnedWriteHalf,
cipher: Option<EncryptCipher>,
}
impl MinecraftWriter {
pub async fn write_raw_frame(&mut self, mut data: Vec<u8>) -> io::Result<()> {
if let Some(cipher) = &mut self.cipher {
cipher.encrypt(&mut data);
}
self.stream.write_all(&data).await
}
}
fn protocol_err(e: deepslate_protocol::types::ProtocolError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, e)
}