From b48c2143182af1a80973484b90c62a9cc03e71e7 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 1 Mar 2022 20:45:10 +0100 Subject: [PATCH] Initial commit --- .gitignore | 3 + Cargo.lock | 326 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 ++ lixcraft-derive/Cargo.lock | 46 ++++++ lixcraft-derive/Cargo.toml | 12 ++ lixcraft-derive/src/lib.rs | 55 +++++++ src/datatypes.rs | 134 +++++++++++++++ src/deserializer.rs | 204 +++++++++++++++++++++++ src/main.rs | 103 ++++++++++++ src/packets.rs | 31 ++++ src/passthroughmain.rs | 135 +++++++++++++++ src/serializer.rs | 282 ++++++++++++++++++++++++++++++++ 12 files changed, 1343 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 lixcraft-derive/Cargo.lock create mode 100644 lixcraft-derive/Cargo.toml create mode 100644 lixcraft-derive/src/lib.rs create mode 100644 src/datatypes.rs create mode 100644 src/deserializer.rs create mode 100644 src/main.rs create mode 100644 src/packets.rs create mode 100644 src/passthroughmain.rs create mode 100644 src/serializer.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..795e8e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +*.iml +/.idea diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..5290d4a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,326 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Lixcraft-Proxy" +version = "0.1.0" +dependencies = [ + "bytes", + "lixcraft-derive", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "libc" +version = "0.2.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" + +[[package]] +name = "lixcraft-derive" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "syn" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tokio" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..84cbfa6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "Lixcraft-Proxy" +version = "0.1.0" +authors = ["Lixfel "] +edition = "2018" + +[dependencies] +tokio = { version = "1.15", features = ["full"] } +serde = { version = "1.0", features = ["derive", "std"] } +bytes = "1.1" +serde_json = "1.0" +lixcraft-derive = { path = "lixcraft-derive" } diff --git a/lixcraft-derive/Cargo.lock b/lixcraft-derive/Cargo.lock new file mode 100644 index 0000000..a4d8f04 --- /dev/null +++ b/lixcraft-derive/Cargo.lock @@ -0,0 +1,46 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "lixcraft-derive" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/lixcraft-derive/Cargo.toml b/lixcraft-derive/Cargo.toml new file mode 100644 index 0000000..f48d69f --- /dev/null +++ b/lixcraft-derive/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "lixcraft-derive" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1.0", features = ["full"] } +quote = "1.0" diff --git a/lixcraft-derive/src/lib.rs b/lixcraft-derive/src/lib.rs new file mode 100644 index 0000000..08ddecd --- /dev/null +++ b/lixcraft-derive/src/lib.rs @@ -0,0 +1,55 @@ +use proc_macro::TokenStream; +use syn::{Data, DeriveInput, parse_macro_input}; +use quote::quote; + +#[proc_macro_derive(Wrapper)] +pub fn derive_wrapper(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + let ident = &input.ident; + + match &input.data { + Data::Struct(s) => { + if s.fields.len() != 1 { + panic!("#[derive(Wrapper)] only usable with one value") + } + for field in s.fields.iter() { + if field.ident.is_some() { + panic!("#[derive(Wrapper)] only usable on newtype structs") + } + + let field_type = &field.ty; + let output = quote!{ + impl From<#ident> for #field_type { + fn from(v: #ident) -> Self { + v.0 + } + } + + impl Deref for #ident { + type Target = #field_type; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl DerefMut for #ident { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + impl From<#field_type> for #ident { + fn from(v: #field_type) -> Self { + #ident(v) + } + } + }; + + return output.into(); + } + panic!("Unreachable") + }, + _ => panic!("#[derive(Wrapper)] only usable on structs") + } +} \ No newline at end of file diff --git a/src/datatypes.rs b/src/datatypes.rs new file mode 100644 index 0000000..7333778 --- /dev/null +++ b/src/datatypes.rs @@ -0,0 +1,134 @@ +use std::ops::{Deref, DerefMut}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::de::Error; +use lixcraft_derive::Wrapper; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Wrapper)] +pub struct VarInt(pub i32); + +impl From for usize { + fn from(v: VarInt) -> Self { + v.0 as usize + } +} + +impl From for VarInt { + fn from(v: usize) -> Self { + VarInt(v as i32) + } +} + +impl Serialize for VarInt { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + let mut v = self.0 as u32; + loop { + if v & 0x80 == 0 { + return serializer.serialize_u8(v as u8); + } + + serializer.serialize_u8((v as u8 & 0x7f) | 0x80)?; + v >>= 7; + } + } +} + +impl<'de> Deserialize<'de> for VarInt { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + let mut num_read = 0; + let mut result = 0; + loop { + let read = u8::deserialize(deserializer)?; + let value = i32::from(read & 0b0111_1111); + result |= value.overflowing_shl(7 * num_read).0; + + num_read += 1; + + if num_read > 5 { + return Err(D::Error::custom("VarInt too large")); + } + if read & 0b1000_0000 == 0 { + break; + } + } + Ok(VarInt(result)) + } +} + +#[derive(Debug)] +pub enum NextState { + Status, + Login +} + +impl Serialize for NextState { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + VarInt::from(match self { + NextState::Status => 1, + NextState::Login => 2 + }).serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for NextState { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + match VarInt::deserialize(deserializer)? { + VarInt(1) => Ok(NextState::Status), + VarInt(2) => Ok(NextState::Login), + _ => Err(D::Error::custom("Invalid NextState")) + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct StatusResponseVersion { + name: String, + protocol: i32 +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct StatusResponseSample { + name: String, + id: String +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct StatusResponsePlayers { + max: i32, + online: i32, + sample: Vec +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct StatusResponseDescription { + text: String +} + +#[derive(Debug)] +pub struct StatusResponse { + version: StatusResponseVersion, + players: StatusResponsePlayers, + description: StatusResponseDescription, + //#[serde(skip_serializing_if = "Option::is_none")] + favicon: Option +} + +impl Serialize for StatusResponse { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_str(&match serde_json::to_string(self) { + Ok(v) => v, + Err(_) => return Err(serde::ser::Error::custom("Could not serialize status response")) + }) + } +} + +impl<'de> Deserialize<'de> for StatusResponse { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + match String::deserialize(deserializer) { + Ok(json) => match serde_json::from_str(&json) { + Ok(v) => Ok(v), + Err(_) => Err(D::Error::custom("Could not parse json status response")) + }, + Err(err) => Err(err) + } + } +} \ No newline at end of file diff --git a/src/deserializer.rs b/src/deserializer.rs new file mode 100644 index 0000000..26d1fa2 --- /dev/null +++ b/src/deserializer.rs @@ -0,0 +1,204 @@ +use std::fmt::{Debug, Display, Formatter}; +use bytes::{Buf, Bytes}; +use serde::de::{DeserializeSeed, Error, SeqAccess, StdError, Visitor}; +use serde::{Deserialize, Deserializer}; +use crate::datatypes::VarInt; + +#[derive(Copy, Clone, Debug)] +pub enum JavaDeserError { + UnexpectedEnd, + UnexpectedCustom, + InvalidValue +} + +impl Display for JavaDeserError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + Debug::fmt(&self, f) + } +} + +impl StdError for JavaDeserError{} + +impl Error for JavaDeserError{ + fn custom(msg: T) -> Self where T: Display { + JavaDeserError::UnexpectedCustom + } +} + +pub struct JavaDeserializer { + input: Bytes +} + +impl JavaDeserializer { + + fn assert_remaining(&self, size: usize) -> Result<(), JavaDeserError> { + match self.input.remaining() >= size { + true => Ok(()), + false => Err(JavaDeserError::UnexpectedEnd) + } + } +} + +impl<'a, 'de> Deserializer<'de> for &'a mut JavaDeserializer { + type Error = JavaDeserError; + + fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de> { + panic!("Any not deserializable in Java protocol") + } + + fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(1)?; + match self.input.get_u8() { + 0x00 => visitor.visit_bool(false), + 0x01 => visitor.visit_bool(true), + _ => Err(JavaDeserError::InvalidValue) + } + } + + fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(1)?; + visitor.visit_i8(self.input.get_i8()) + } + + fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(2)?; + visitor.visit_i16(self.input.get_i16()) + } + + fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(4)?; + visitor.visit_i32(self.input.get_i32()) + } + + fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(8)?; + visitor.visit_i64(self.input.get_i64()) + } + + fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(1)?; + visitor.visit_u8(self.input.get_u8()) + } + + fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(2)?; + visitor.visit_u16(self.input.get_u16()) + } + + fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(4)?; + visitor.visit_u32(self.input.get_u32()) + } + + fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(8)?; + visitor.visit_u64(self.input.get_u64()) + } + + fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(4)?; + visitor.visit_f32(self.input.get_f32()) + } + + fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de> { + self.assert_remaining(8)?; + visitor.visit_f64(self.input.get_f64()) + } + + fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de> { + panic!("Char not deserializable in Java protocol") + } + + fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de> { + self.deserialize_string(visitor) + } + + fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de> { + let size = VarInt::deserialize(self)?; + if *size > 32767 { + return Err(JavaDeserError::InvalidValue) + } + + self.assert_remaining(usize::from(size))?; + visitor.visit_string(match String::from_utf8(self.input.copy_to_bytes(usize::from(size)).to_vec()) { + Ok(v) => v, + Err(_) => return Err(JavaDeserError::InvalidValue) + }) + } + + fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de> { + panic!("Bytes not deserializable in Java protocol") + } + + fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de> { + panic!("Byte buf not deserializable in Java protocol") + } + + fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de> { + panic!("Option not deserializable in Java protocol") + } + + fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de> { + panic!("Unit not deserializable in Java protocol") + } + + fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result where V: Visitor<'de> { + panic!("Unit struct not deserializable in Java protocol") + } + + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result where V: Visitor<'de> { + visitor.visit_newtype_struct(self) + } + + fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de> { + let size = VarInt::deserialize(self)?; + visitor.visit_seq(LengthPrefixedSeq { de: self, remaining: usize::from(size) }) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result where V: Visitor<'de> { + panic!("Tuple not deserializable in Java protocol") + } + + fn deserialize_tuple_struct(self, name: &'static str, len: usize, visitor: V) -> Result where V: Visitor<'de> { + panic!("Tuple struct not deserializable in Java protocol") + } + + fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de> { + panic!("Map not deserializable in Java protocol") + } + + fn deserialize_struct(self, name: &'static str, fields: &'static [&'static str], visitor: V) -> Result where V: Visitor<'de> { + panic!("Struct (missing #[serde(flatten)]?) not deserializable in Java protocol") + } + + fn deserialize_enum(self, name: &'static str, variants: &'static [&'static str], visitor: V) -> Result where V: Visitor<'de> { + panic!("Enum not deserializable in Java protocol") + } + + fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de> { + panic!("Identifier not deserializable in Java protocol") + } + + fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de> { + panic!("Ignored any not deserializable in Java protocol") + } +} + +struct LengthPrefixedSeq<'a> { + de: &'a mut JavaDeserializer, + remaining: usize +} + +impl<'de, 'a> SeqAccess<'de> for LengthPrefixedSeq<'a> { + type Error = <&'a mut JavaDeserializer as Deserializer<'de>>::Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> where T: DeserializeSeed<'de> { + match self.remaining { + 0 => Ok(None), + _ => { + self.remaining -= 1; + seed.deserialize(self.de).map(Some) + } + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..472b001 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,103 @@ +extern crate core; + +mod serializer; +mod datatypes; +mod deserializer; +mod packets; + +use tokio::io::{AsyncRead}; +use tokio::net::{TcpListener, TcpStream}; + +use std::error::Error; +use std::sync::Arc; +use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; +use async_trait::async_trait; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let listen_addr = String::from("127.0.0.1:25565"); + + println!("Listening on: {}", listen_addr); + + let listener = TcpListener::bind(listen_addr).await?; + + while let Ok((inbound, addr)) = listener.accept().await { + //TODO + } + + Ok(()) +} +pub struct Stoppable { + interruptor: tokio::sync::oneshot::Receiver, + interrupted: tokio::sync::oneshot::Sender +} + +pub struct Stopper { + interruptable: tokio::sync::oneshot::Sender, + interrupted: tokio::sync::oneshot::Receiver +} + +impl Stopper { + pub fn new() -> (Stopper, Stoppable) { + let (interruptable, interruptor) = tokio::sync::oneshot::channel(); + let (interrupted_s, interrupted_r) = tokio::sync::oneshot::channel(); + + (Stopper {interruptable, interrupted: interrupted_r}, Stoppable {interruptor, interrupted: interrupted_s}) + } + + pub async fn stop(&mut self) { + if self.interruptable.is_closed() { + return; + } + self.interruptable.send(true).unwrap_or_default(); + self.interrupted.await.expect_err("Send on Stopper.interrupted occured"); + } +} + +pub trait InputStream {} +pub trait OutputStream {} + +pub struct StoppableAsyncRead { + inner: T, + stoppable: Stoppable +} + +impl StoppableAsyncRead { + pub fn new(inner: T, stoppable: Stoppable) -> StoppableAsyncRead { + StoppableAsyncRead { inner, stoppable } + } + + pub fn unwrap(self) -> T { + self.inner + } +} + +impl InputStream for StoppableAsyncRead {} + +impl OutputStream for OwnedWriteHalf {} + +#[async_trait] +pub trait Reader { + async fn run(self, stream: T, connection: Arc); +} + +pub struct Connection { + writer: Box>, + stopper: Stopper +} + +impl Connection { + pub fn new>>(stream: TcpStream, reader: T) -> Arc { + let (read, write) = stream.into_split(); + let (stopper, stoppable) = Stopper::new(); + + let connection = Arc::new(Connection { + writer: Box::new(parking_lot::Mutex::new(write)), + stopper + }); + + tokio::spawn(reader.run(StoppableAsyncRead::new(read, stoppable), connection.clone())); + + connection + } +} \ No newline at end of file diff --git a/src/packets.rs b/src/packets.rs new file mode 100644 index 0000000..7dc2e5b --- /dev/null +++ b/src/packets.rs @@ -0,0 +1,31 @@ +mod handshake { + use serde::{Serialize, Deserialize}; + use crate::datatypes::{NextState, VarInt}; + + #[derive(Serialize, Deserialize, Debug)] + pub struct HandshakePacket { + protocol_version: VarInt, + server_address: String, + server_port: u16, + next_state: NextState + } +} + +mod status { + use serde::{Serialize, Deserialize}; + use crate::datatypes::StatusResponse; + + #[derive(Serialize, Deserialize, Debug)] + pub struct RequestPacket {} + + #[derive(Serialize, Deserialize, Debug)] + pub struct ResponsePacket { + response: StatusResponse + } + + #[derive(Serialize, Deserialize, Debug)] + pub struct PingPacket { + payload: u64 + } +} + diff --git a/src/passthroughmain.rs b/src/passthroughmain.rs new file mode 100644 index 0000000..87b7ac9 --- /dev/null +++ b/src/passthroughmain.rs @@ -0,0 +1,135 @@ +extern crate core; + +mod serializer; +mod datatypes; +mod deserializer; +mod packets; + +use tokio::io; +use tokio::io::{AsyncRead, AsyncWriteExt}; +use tokio::net::{TcpListener, TcpStream}; + +use futures::FutureExt; +use std::error::Error; +use std::sync::Arc; +use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; +use async_trait::async_trait; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let listen_addr = String::from("127.0.0.1:25565"); + let server_addr = String::from("steamwar.de:25565"); + + println!("Listening on: {}", listen_addr); + println!("Proxying to: {}", server_addr); + + let listener = TcpListener::bind(listen_addr).await?; + + while let Ok((inbound, _)) = listener.accept().await { + let transfer = transfer(inbound, server_addr.clone()).map(|r| { + if let Err(e) = r { + println!("Failed to transfer; error={}", e); + } + }); + + tokio::spawn(transfer); + } + + Ok(()) +} + +pub struct Stoppable { + interruptor: tokio::sync::oneshot::Receiver, + interrupted: tokio::sync::oneshot::Sender +} + +pub struct Stopper { + interruptable: tokio::sync::oneshot::Sender, + interrupted: tokio::sync::oneshot::Receiver +} + +impl Stopper { + pub fn new() -> (Stopper, Stoppable) { + let (interruptable, interruptor) = tokio::sync::oneshot::channel(); + let (interrupted_s, interrupted_r) = tokio::sync::oneshot::channel(); + + (Stopper {interruptable, interrupted: interrupted_r}, Stoppable {interruptor, interrupted: interrupted_s}) + } + + pub async fn stop(&mut self) { + if self.interruptable.is_closed() { + return; + } + self.interruptable.send(true).unwrap_or_default(); + self.interrupted.await.expect_err("Send on Stopper.interrupted occured"); + } +} + +pub trait InputStream {} +pub trait OutputStream {} + +pub struct StoppableAsyncRead { + inner: T, + stoppable: Stoppable +} + +impl StoppableAsyncRead { + pub fn new(inner: T, stoppable: Stoppable) -> StoppableAsyncRead { + StoppableAsyncRead { inner, stoppable } + } + + pub fn unwrap(self) -> T { + self.inner + } +} + +impl InputStream for StoppableAsyncRead {} + +impl OutputStream for OwnedWriteHalf {} + +#[async_trait] +pub trait Reader { + async fn run(self, stream: T, connection: Arc); +} + +pub struct Connection { + writer: Box>, + stopper: Stopper +} + +impl Connection { + pub fn new>>(stream: TcpStream, reader: T) -> Arc { + let (read, write) = stream.into_split(); + let (stopper, stoppable) = Stopper::new(); + + let connection = Arc::new(Connection { + writer: Box::new(parking_lot::Mutex::new(write)), + stopper + }); + + tokio::spawn(reader.run(StoppableAsyncRead::new(read, stoppable), connection.clone())); + + connection + } +} + +async fn transfer(mut inbound: TcpStream, proxy_addr: String) -> Result<(), Box> { + let mut outbound = TcpStream::connect(proxy_addr).await?; + + let (mut ri, mut wi) = inbound.split(); + let (mut ro, mut wo) = outbound.split(); + + let client_to_server = async { + io::copy(&mut ri, &mut wo).await?; + wo.shutdown().await + }; + + let server_to_client = async { + io::copy(&mut ro, &mut wi).await?; + wi.shutdown().await + }; + + tokio::try_join!(client_to_server, server_to_client)?; + + Ok(()) +} \ No newline at end of file diff --git a/src/serializer.rs b/src/serializer.rs new file mode 100644 index 0000000..dc55b9c --- /dev/null +++ b/src/serializer.rs @@ -0,0 +1,282 @@ +use std::fmt::{Debug, Display, Formatter}; +use bytes::{BufMut, BytesMut}; +use serde::{Serialize, Serializer}; +use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, StdError}; +use crate::datatypes::VarInt; + +#[derive(Copy, Clone, Debug)] +struct JavaSerError(); + +impl StdError for JavaSerError {} + +impl Display for JavaSerError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + Debug::fmt(&self, f) + } +} + +impl serde::ser::Error for JavaSerError { + fn custom(msg: T) -> Self where T: Display { + JavaSerError() + } +} + +pub struct JavaSerializer { + output: BytesMut +} + +impl JavaSerializer { + pub fn serialize(value: &T) -> BytesMut { + let mut serializer = JavaSerializer { + output: BytesMut::with_capacity(256) + }; + + match value.serialize(&mut serializer) { + Ok(()) => serializer.output, + Err(_) => panic!("Serialization error") + } + } +} + +impl<'a> Serializer for &'a mut JavaSerializer { + type Ok = (); + type Error = JavaSerError; + type SerializeSeq = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeStructVariant = Self; + + fn serialize_bool(self, v: bool) -> Result { + match v { + true => self.output.put_u8(0x00), + false => self.output.put_u8(0x01), + }; + Ok(()) + } + + fn serialize_i8(self, v: i8) -> Result { + self.output.put_i8(v); + Ok(()) + } + + fn serialize_i16(self, v: i16) -> Result { + self.output.put_i16(v); + Ok(()) + } + + fn serialize_i32(self, v: i32) -> Result { + self.output.put_i32(v); + Ok(()) + } + + fn serialize_i64(self, v: i64) -> Result { + self.output.put_i64(v); + Ok(()) + } + + fn serialize_u8(self, v: u8) -> Result { + self.output.put_u8(v); + Ok(()) + } + + fn serialize_u16(self, v: u16) -> Result { + self.output.put_u16(v); + Ok(()) + } + + fn serialize_u32(self, v: u32) -> Result { + self.output.put_u32(v); + Ok(()) + } + + fn serialize_u64(self, v: u64) -> Result { + self.output.put_u64(v); + Ok(()) + } + + fn serialize_f32(self, v: f32) -> Result { + self.output.put_f32(v); + Ok(()) + } + + fn serialize_f64(self, v: f64) -> Result { + self.output.put_f64(v); + Ok(()) + } + + fn serialize_char(self, v: char) -> Result { + panic!("Char not serializable in Java protocol") + } + + fn serialize_str(self, v: &str) -> Result { + let v = v.as_bytes(); + VarInt::serialize(&VarInt::from(v.len()), self)?; + self.serialize_bytes(v) + } + + fn serialize_bytes(self, v: &[u8]) -> Result { + self.output.put_slice(v); + Ok(()) + } + + fn serialize_none(self) -> Result { + Ok(()) + } + + fn serialize_some(self, value: &T) -> Result where T: Serialize { + value.serialize(self) + } + + fn serialize_unit(self) -> Result { + panic!("Unit not serializable in Java protocol") + } + + fn serialize_unit_struct(self, name: &'static str) -> Result { + panic!("Unit struct not serializable in Java protocol") + } + + fn serialize_unit_variant(self, name: &'static str, variant_index: u32, variant: &'static str) -> Result { + panic!("Variant not serializable in Java protocol") + //VarInt::from(variant_index as i32).serialize(self) + } + + fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result where T: Serialize { + value.serialize(self) + } + + fn serialize_newtype_variant(self, name: &'static str, variant_index: u32, variant: &'static str, value: &T) -> Result where T: Serialize { + panic!("Newtype variant not serializable in Java protocol") + //VarInt::from(variant_index as i32).serialize(self)?; + //value.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + match len { + Some(v) => VarInt::from(v).serialize(self)?, + None => () + } + Ok(self) + } + + fn serialize_tuple(self, len: usize) -> Result { + panic!("Tuple not serializable in Java protocol") + } + + fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result { + panic!("Tuple struct not serializable in Java protocol") + } + + fn serialize_tuple_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result { + panic!("Tuple struct variant not serializable in Java protocol") + } + + fn serialize_map(self, len: Option) -> Result { + panic!("Maps not serializable in Java protocol") + } + + fn serialize_struct(self, name: &'static str, len: usize) -> Result { + Ok(self) + } + + fn serialize_struct_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result { + panic!("Struct variant not serializable in Java protocol") + } +} + +impl<'a> SerializeSeq for &'a mut JavaSerializer { + type Ok = <&'a mut JavaSerializer as Serializer>::Ok; + type Error = <&'a mut JavaSerializer as Serializer>::Error; + + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where T: Serialize { + value.serialize(*self) + } + + fn end(self) -> Result { + Ok(()) + } +} + +impl<'a> SerializeStruct for &'a mut JavaSerializer { + type Ok = <&'a mut JavaSerializer as Serializer>::Ok; + type Error = <&'a mut JavaSerializer as Serializer>::Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: Serialize { + value.serialize(*self) + } + + fn end(self) -> Result { + Ok(()) + } +} + +impl<'a> SerializeTuple for &'a mut JavaSerializer { + type Ok = <&'a mut JavaSerializer as Serializer>::Ok; + type Error = <&'a mut JavaSerializer as Serializer>::Error; + + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where T: Serialize { + panic!("Tuple not serializable in Java protocol") + } + + fn end(self) -> Result { + panic!("Tuple not serializable in Java protocol") + } +} + +impl<'a> SerializeTupleStruct for &'a mut JavaSerializer { + type Ok = <&'a mut JavaSerializer as Serializer>::Ok; + type Error = <&'a mut JavaSerializer as Serializer>::Error; + + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> where T: Serialize { + panic!("Tuple struct not serializable in Java protocol") + } + + fn end(self) -> Result { + panic!("Tuple struct not serializable in Java protocol") + } +} + +impl<'a> SerializeTupleVariant for &'a mut JavaSerializer { + type Ok = <&'a mut JavaSerializer as Serializer>::Ok; + type Error = <&'a mut JavaSerializer as Serializer>::Error; + + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> where T: Serialize { + panic!("Tuple variant not serializable in Java protocol") + } + + fn end(self) -> Result { + panic!("Tuple variant not serializable in Java protocol") + } +} + +impl<'a> SerializeMap for &'a mut JavaSerializer { + type Ok = <&'a mut JavaSerializer as Serializer>::Ok; + type Error = <&'a mut JavaSerializer as Serializer>::Error; + + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> where T: Serialize { + panic!("Map not serializable in Java protocol") + } + + fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> where T: Serialize { + panic!("Map not serializable in Java protocol") + } + + fn end(self) -> Result { + panic!("Map not serializable in Java protocol") + } +} + +impl<'a> SerializeStructVariant for &'a mut JavaSerializer { + type Ok = <&'a mut JavaSerializer as Serializer>::Ok; + type Error = <&'a mut JavaSerializer as Serializer>::Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: Serialize { + panic!("Struct variant not serializable in Java protocol") + } + + fn end(self) -> Result { + panic!("Struct variant not serializable in Java protocol") + } +} \ No newline at end of file