This commit is contained in:
MeexReay 2024-11-12 21:43:38 +03:00
parent 67e547a275
commit d21e25eda9
11 changed files with 414 additions and 1312 deletions

329
Cargo.lock generated
View File

@ -3,46 +3,22 @@
version = 3 version = 3
[[package]] [[package]]
name = "addr2line" name = "adler2"
version = "0.22.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
dependencies = [
"gimli",
]
[[package]] [[package]]
name = "adler" name = "anyhow"
version = "1.0.2" version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
[[package]]
name = "backtrace"
version = "0.3.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]] [[package]]
name = "bytebuffer" name = "bytebuffer"
version = "2.2.0" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7bfaf7cd08cacd74cdc6b521c37ac39cbc92692e5ab5c21ed5657a749b577c" checksum = "2618ff1f07e000264e355904bff5c0527091fcbad883ff7f71383c5428915f4b"
dependencies = [ dependencies = [
"byteorder", "byteorder",
] ]
@ -53,29 +29,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "contracts"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9424f2ca1e42776615720e5746eed6efa19866fdbaac2923ab51c294ac4d1f2"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.4.2" version = "1.4.2"
@ -94,72 +53,34 @@ dependencies = [
"powerfmt", "powerfmt",
] ]
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.30" version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide", "miniz_oxide",
] ]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gimli"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.5" version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "ignore-result"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "665ff4dce8edd10d490641ccb78949832f1ddbff02c584fb1f85ab888fe0e50c"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.2.6" version = "2.2.6"
@ -184,15 +105,13 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]] [[package]]
name = "libyml" name = "libyml"
version = "0.0.3" version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e281a65eeba3d4503a2839252f86374528f9ceafe6fed97c1d3b52e1fb625c1" checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980"
dependencies = [
[[package]] "anyhow",
name = "linux-raw-sys" "version_check",
version = "0.4.14" ]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]] [[package]]
name = "log" name = "log"
@ -204,13 +123,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
name = "meexprox" name = "meexprox"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"derivative", "ignore-result",
"log", "log",
"no_deadlocks",
"rust_mc_proto", "rust_mc_proto",
"serde_yml", "serde_yml",
"simplelog", "simplelog",
"tokio",
"uuid", "uuid",
] ]
@ -222,21 +139,11 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.4" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
dependencies = [ dependencies = [
"adler", "adler2",
]
[[package]]
name = "no_deadlocks"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0e0af0e4fcf0d695f224cafbf5e4fb750b85aa1cd1ad0b37d8d0d98c0d2ce5e"
dependencies = [
"backtrace",
"vector-map",
] ]
[[package]] [[package]]
@ -254,36 +161,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "object"
version = "0.36.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
dependencies = [
"memchr",
]
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]] [[package]]
name = "powerfmt" name = "powerfmt"
version = "0.2.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f"
dependencies = [
"zerocopy",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.86" version = "1.0.86"
@ -302,77 +185,16 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]] [[package]]
name = "rust_mc_proto" name = "rust_mc_proto"
version = "0.1.15" version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/MeexReay/rust_mc_proto#26a78af446bd7ceba54fa2fa34d2f6570e827904"
checksum = "fb5392814ae7129d56b0afcbdd5d6d4764ca51273fab7ff604ebe73018dbb562"
dependencies = [ dependencies = [
"bytebuffer", "bytebuffer",
"flate2", "flate2",
"uuid", "uuid",
] ]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustix"
version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.18" version = "1.0.18"
@ -396,35 +218,22 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn",
]
[[package]]
name = "serde_json"
version = "1.0.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
dependencies = [
"itoa",
"ryu",
"serde",
] ]
[[package]] [[package]]
name = "serde_yml" name = "serde_yml"
version = "0.0.10" version = "0.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ce6afeda22f0b55dde2c34897bce76a629587348480384231205c14b59a01f" checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"itoa", "itoa",
"libyml", "libyml",
"log",
"memchr", "memchr",
"ryu", "ryu",
"serde", "serde",
"serde_json", "version_check",
"tempfile",
] ]
[[package]] [[package]]
@ -438,17 +247,6 @@ dependencies = [
"time", "time",
] ]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.71" version = "2.0.71"
@ -460,18 +258,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "tempfile"
version = "3.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
dependencies = [
"cfg-if",
"fastrand",
"rustix",
"windows-sys",
]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.4.1" version = "1.4.1"
@ -514,16 +300,6 @@ dependencies = [
"time-core", "time-core",
] ]
[[package]]
name = "tokio"
version = "1.39.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
dependencies = [
"backtrace",
"pin-project-lite",
]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.12"
@ -532,25 +308,15 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.10.0" version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
[[package]] [[package]]
name = "vector-map" name = "version_check"
version = "1.0.1" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "550f72ae94a45c0e2139188709e6c4179f0b5ff9bdaa435239ad19048b0cd68c" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
dependencies = [
"contracts",
"rand",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
@ -633,24 +399,3 @@ name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "zerocopy"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
]

View File

@ -4,11 +4,13 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
serde_yml = "0.0.10" serde_yml = "0.0.12"
rust_mc_proto = "0.1.15" rust_mc_proto = { git = "https://github.com/MeexReay/rust_mc_proto", features = ["atomic_clone"] }
uuid = "1.10.0" uuid = "1.11.0"
log = "0.4.22" log = "0.4.22"
simplelog = "0.12.2" simplelog = "0.12.2"
derivative = "2.2.0" # derivative = "2.2.0"
no_deadlocks = "1.3.2" # no_deadlocks = "1.3.2"
tokio = {version = "1.39.2", features = ["rt"] } # tokio = {version = "1.39.3", features = ["full"] }
# async-trait = "0.1.81"
ignore-result = "0.2.0"

View File

@ -4,7 +4,7 @@ Proxy for minecraft servers on rust
`in developement` `in developement`
todo list: (✅ / ❌) todo list: (✅ / ❌)
- ❌ (deadlock) add methods `connect_to_ip`, `connect_to_server`, `connect_to_stream`, `reconnect` - ❌ add methods `connect_to_ip`, `connect_to_server`, `connect_to_stream`, `reconnect`
- ❌ make setting `no_pf_for_ip_connect` working - ❌ make setting `no_pf_for_ip_connect` working
- ❌ make talk server - ❌ make talk server
- ❌ create bukkit plugin for player formatting support and talking - ❌ create bukkit plugin for player formatting support and talking

View File

@ -4,7 +4,7 @@ talk_host: 127.0.0.1:12346 # secret host to talk with meexprox (optional)
talk_secret: qwerty123456 # secret token for talk with meexprox (optional) talk_secret: qwerty123456 # secret token for talk with meexprox (optional)
servers: # verified servers (name -> ip) servers: # verified servers (name -> ip)
play: 6.tcp.eu.ngrok.io:17753 play: 127.0.0.1:12345
forced_hosts: # connect to server from connected hostname (name -> hostname) (optional) forced_hosts: # connect to server from connected hostname (name -> hostname) (optional)
play: play.localhost play: play.localhost

View File

@ -1,91 +1,18 @@
use log::debug; use std::{fs::{self, File}, path::Path};
use meexprox::{
EventListener, MeexProx, MeexProxMutex, ProxyConfig,
ProxyEvent::{self, *},
ProxyPlayer,
};
use rust_mc_proto::DataBufferReader;
use simplelog::{
ColorChoice, CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode, WriteLogger,
};
use std::{
error::Error,
fs::{self, File},
path::Path,
sync::atomic::Ordering,
};
pub struct MyEventListener {} use log::LevelFilter;
use meexprox::{config::ProxyConfig, MeexProx};
use simplelog::{ColorChoice, CombinedLogger, Config, TermLogger, TerminalMode, WriteLogger};
impl EventListener for MyEventListener {
fn on_event(
&mut self,
this: MeexProxMutex,
event: &mut ProxyEvent,
) -> Result<(), Box<dyn Error>> {
match event {
RecvServerPacketEvent { packet, player } => {
// debug!("recv server packet event");
}
SendServerPacketEvent {
packet,
player,
cancel,
} => {
// debug!("send server packet event");
}
SendClientPacketEvent {
packet,
player,
cancel,
} => {
// debug!("send client packet event");
}
RecvClientPacketEvent { packet, player } => {
// debug!("recv client packet event");
if packet.id() == 0x03 || packet.id() == 0x04 {
let command = packet.read_string()?;
if command == "reconnect" { // pub struct MyEventListener {}
println!("reconnect wow");
ProxyPlayer::reconnect(player.clone(), this.clone(), "localhost", 25565)
.unwrap();
}
}
}
PlayerConnectedEvent { player } => {
debug!("player connected");
}
PlayerConnectingServerEvent {
player,
server,
cancel,
} => {
debug!("player connecting server");
}
PlayerConnectingIPEvent { player, ip, cancel } => {
debug!("player connecting ip");
}
PlayerDisconnectedEvent { player } => {
debug!("player disconnected");
}
StatusRequestEvent {
status,
client_address,
server_address,
server_port,
cancel,
} => {
debug!("status request");
}
}
Ok(()) // impl EventListener for MyEventListener {
}
}
fn main() { // }
pub fn main() {
CombinedLogger::init(vec![ CombinedLogger::init(vec![
TermLogger::new( TermLogger::new(
LevelFilter::Debug, LevelFilter::Debug,
@ -104,15 +31,13 @@ fn main() {
let config_path = Path::new("config.yml"); let config_path = Path::new("config.yml");
if !config_path.exists() { if !config_path.exists() {
fs::write(config_path, include_bytes!("../default_config.yml")) fs::write(config_path, include_bytes!("../config.yml"))
.expect("config write error"); .expect("config write error");
} }
let config = ProxyConfig::load(config_path).expect("config parse error"); let config = ProxyConfig::load(config_path).expect("config parse error");
let mut meexprox = MeexProx::new(config); let meexprox = MeexProx::new(config);
// meexprox.add_event_listener(Box::new(MyEventListener {}));
meexprox.add_event_listener(Box::new(MyEventListener {}));
meexprox.start(); meexprox.start();
} }

View File

@ -1,45 +1,32 @@
use super::ProxyError;
use serde_yml::Value; use serde_yml::Value;
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use super::error::ProxyError;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ProxyServer { pub struct ServerInfo {
name: String, pub name: String,
host: String, pub host: String,
forced_host: Option<String>, pub forced_host: Option<String>,
} }
impl ProxyServer { impl ServerInfo {
pub fn new(name: String, host: String, forced_host: Option<String>) -> ProxyServer { pub fn new(name: String, host: String, forced_host: Option<String>) -> ServerInfo {
ProxyServer { ServerInfo {
name, name,
host, host,
forced_host, forced_host,
} }
} }
pub fn name(&self) -> &str { pub fn from_host(host: String) -> ServerInfo {
&self.name ServerInfo {
} name: host.clone(),
host,
pub fn host(&self) -> &str { forced_host: None,
&self.host
}
pub fn forced_host(&self) -> Option<&String> {
self.forced_host.as_ref()
}
}
macro_rules! extract_string {
($data:expr, $key:expr) => {
match $data.get(&Value::String($key.to_string())) {
Some(Value::String(val)) => Some(val.clone()),
_ => None,
} }
}; }
} }
#[derive(Clone)] #[derive(Clone)]
@ -50,20 +37,20 @@ pub enum PlayerForwarding {
#[derive(Clone)] #[derive(Clone)]
pub struct ProxyConfig { pub struct ProxyConfig {
host: String, pub host: String,
servers: Vec<ProxyServer>, pub servers: Vec<ServerInfo>,
default_server: Option<ProxyServer>, pub default_server: Option<ServerInfo>,
talk_host: Option<String>, pub talk_host: Option<String>,
talk_secret: Option<String>, pub talk_secret: Option<String>,
player_forwarding: PlayerForwarding, pub player_forwarding: PlayerForwarding,
no_pf_for_ip_connect: bool, pub no_pf_for_ip_connect: bool,
} }
impl ProxyConfig { impl ProxyConfig {
pub fn new( pub fn new(
host: String, host: String,
servers: Vec<ProxyServer>, servers: Vec<ServerInfo>,
default_server: Option<ProxyServer>, default_server: Option<ServerInfo>,
talk_host: Option<String>, talk_host: Option<String>,
talk_secret: Option<String>, talk_secret: Option<String>,
player_forwarding: PlayerForwarding, player_forwarding: PlayerForwarding,
@ -80,42 +67,15 @@ impl ProxyConfig {
} }
} }
pub fn host(&self) -> &str { pub fn load_yml(data: String) -> Result<ProxyConfig, Box<dyn std::error::Error>> {
&self.host
}
pub fn servers(&self) -> &Vec<ProxyServer> {
&self.servers
}
pub fn talk_host(&self) -> Option<&String> {
self.talk_host.as_ref()
}
pub fn talk_secret(&self) -> Option<&String> {
self.talk_secret.as_ref()
}
pub fn default_server(&self) -> Option<&ProxyServer> {
self.default_server.as_ref()
}
pub fn player_forwarding(&self) -> &PlayerForwarding {
&self.player_forwarding
}
pub fn no_pf_for_ip_connect(&self) -> bool {
self.no_pf_for_ip_connect
}
pub fn load_data(data: String) -> Result<ProxyConfig, Box<dyn std::error::Error>> {
let data = serde_yml::from_str::<Value>(&data)?; let data = serde_yml::from_str::<Value>(&data)?;
let data = data.as_mapping().ok_or(ProxyError::ConfigParse)?; let data = data.as_mapping().ok_or(ProxyError::ConfigParse)?;
let host = extract_string!(data, "host").ok_or(ProxyError::ConfigParse)?; let host = data.get("host").map(|o| o.as_str()).flatten().ok_or(ProxyError::ConfigParse)?.to_string();
let talk_host = extract_string!(data, "talk_host"); let talk_host = data.get("talk_host").map(|o| o.as_str()).flatten().map(|o| o.to_string());
let talk_secret = extract_string!(data, "talk_secret"); let talk_secret = data.get("talk_secret").map(|o| o.as_str()).flatten().map(|o| o.to_string());
let player_forwarding = match extract_string!(data, "player_forwarding") { let player_forwarding = match data.get("player_forwarding").map(|o| o.as_str()).flatten() {
Some(pf) => match pf.as_str() { Some(pf) => match pf {
"disabled" => PlayerForwarding::Disabled, "disabled" => PlayerForwarding::Disabled,
_ => PlayerForwarding::Handshake, _ => PlayerForwarding::Handshake,
}, },
@ -135,7 +95,7 @@ impl ProxyConfig {
{ {
for (name, addr) in servers_map { for (name, addr) in servers_map {
if let (Value::String(name), Value::String(addr)) = (name, addr) { if let (Value::String(name), Value::String(addr)) = (name, addr) {
servers.push(ProxyServer::new(name.clone(), addr.clone(), None)); servers.push(ServerInfo::new(name.clone(), addr.clone(), None));
} }
} }
} }
@ -153,7 +113,8 @@ impl ProxyConfig {
} }
} }
let default_server = extract_string!(data, "default_server") let default_server = data.get("default_server")
.map(|o| o.as_str()).flatten()
.and_then(|ds| servers.iter().find(|s| s.name == ds).cloned()); .and_then(|ds| servers.iter().find(|s| s.name == ds).cloned());
Ok(ProxyConfig::new( Ok(ProxyConfig::new(
@ -168,10 +129,10 @@ impl ProxyConfig {
} }
pub fn load(path: impl AsRef<Path>) -> Result<ProxyConfig, Box<dyn std::error::Error>> { pub fn load(path: impl AsRef<Path>) -> Result<ProxyConfig, Box<dyn std::error::Error>> {
Self::load_data(fs::read_to_string(path)?) Self::load_yml(fs::read_to_string(path)?)
} }
pub fn get_server_by_name(&self, name: &str) -> Option<ProxyServer> { pub fn get_server_by_name(&self, name: &str) -> Option<ServerInfo> {
for server in &self.servers { for server in &self.servers {
if &server.name == name { if &server.name == name {
return Some(server.clone()); return Some(server.clone());
@ -180,7 +141,7 @@ impl ProxyConfig {
None None
} }
pub fn get_server_by_forced_host(&self, forced_host: &str) -> Option<ProxyServer> { pub fn get_server_by_forced_host(&self, forced_host: &str) -> Option<ServerInfo> {
for server in &self.servers { for server in &self.servers {
if let Some(server_forced_host) = &server.forced_host { if let Some(server_forced_host) = &server.forced_host {
if server_forced_host == forced_host { if server_forced_host == forced_host {

180
src/meexprox/connection.rs Normal file
View File

@ -0,0 +1,180 @@
use std::{net::TcpStream, sync::{Arc, Mutex}, thread};
use ignore_result::Ignore;
use rust_mc_proto::{DataBufferReader, MCConnTcp, Packet};
use uuid::Uuid;
use super::{config::{ProxyConfig, ServerInfo}, error::{AsProxyResult, ProxyError}};
#[derive(Clone, Debug)]
pub struct LoginInfo {
protocol_version: u16,
server_address: String,
server_port: u16,
name: String,
uuid: Uuid,
shared_secret: Option<Vec<u8>>,
verify_token: Option<Vec<u8>>
}
impl LoginInfo {
pub fn write(&self, config: &ProxyConfig, stream: &mut MCConnTcp) {
todo!() // TODO: write login packets sending
}
}
pub struct Player {
client_conn: Arc<Mutex<MCConnTcp>>,
server_conn: Arc<Mutex<MCConnTcp>>,
login_info: Option<LoginInfo>,
pub name: String,
pub uuid: Uuid,
pub server: Option<ServerInfo>,
pub protocol_version: u16
}
impl Player {
pub fn read(
protocol_version: u16,
server_address: String,
server_port: u16,
server: ServerInfo,
mut client_conn: MCConnTcp,
mut server_conn: MCConnTcp
) -> Result<Player, ProxyError> {
let mut packet = client_conn.read_packet().as_proxy()?;
if packet.id() != 0x00 { return Err(ProxyError::LoginPacket); }
let name = packet.read_string().as_proxy()?;
let uuid = packet.read_uuid().as_proxy()?;
server_conn.write_packet(&packet).as_proxy()?;
let mut player = Player {
client_conn: Arc::new(Mutex::new(client_conn)),
server_conn: Arc::new(Mutex::new(server_conn)),
login_info: None,
name: name.clone(),
uuid,
server: Some(server),
protocol_version
};
let mut shared_secret = None;
let mut verify_token = None;
loop {
let mut packet = player.read_server_packet()?;
match packet.id() {
0x01 => {
player.write_client_packet(&packet)?;
let mut packet = player.read_client_packet()?;
let i = packet.read_usize_varint().as_proxy()?;
shared_secret = Some(packet.read_bytes(i).as_proxy()?);
let i = packet.read_usize_varint().as_proxy()?;
verify_token = Some(packet.read_bytes(i).as_proxy()?);
player.write_server_packet(&packet)?;
}
0x02 => {
player.write_client_packet(&packet)?;
break;
}
0x03 => {
player.write_client_packet(&packet)?;
let compression = Some(packet.read_usize_varint().as_proxy()?);
player.set_server_compression(compression);
player.set_client_compression(compression);
}
_ => {
return Err(ProxyError::LoginPacket);
},
}
}
player.login_info = Some(LoginInfo {
protocol_version,
server_address,
server_port,
name,
uuid,
shared_secret,
verify_token
});
player.write_server_packet(&player.read_client_packet()?)?;
player.client_recv_loop();
Ok(player)
}
pub fn client_recv_loop(&self) {
let mut client: rust_mc_proto::MinecraftConnection<TcpStream> = self.client_conn.clone().lock().unwrap().try_clone().unwrap();
let server = self.server_conn.clone();
thread::spawn(move || {
while let Ok(packet) = client.read_packet() {
while !server.lock().unwrap().is_alive() {}
server.lock().unwrap().write_packet(&packet).ignore();
}
});
}
pub fn server_recv_loop(&self) {
let mut server = self.server_conn.clone().lock().unwrap().try_clone().unwrap();
let client = self.client_conn.clone();
thread::spawn(move || {
while let Ok(packet) = server.read_packet() {
client.lock().unwrap().write_packet(&packet).ignore();
}
});
}
pub fn connect(&self, config: &ProxyConfig, server_conn: TcpStream) -> Result<(), ProxyError> {
self.server_conn.lock().unwrap().close();
let mut server_conn = MCConnTcp::new(server_conn);
if let Some(login_info) = &self.login_info {
login_info.write(config, &mut server_conn);
}
self.server_recv_loop();
Ok(())
}
pub fn connect_server(&self, config: &ProxyConfig, server: ServerInfo) -> Result<(), ProxyError> {
self.connect(config, TcpStream::connect(&server.host).map_err(|_| ProxyError::ServerConnect)?)
}
pub fn write_client_packet(&self, packet: &Packet) -> Result<(), ProxyError> {
self.client_conn.lock().unwrap().write_packet(packet).as_proxy()
}
pub fn write_server_packet(&self, packet: &Packet) -> Result<(), ProxyError> {
self.server_conn.lock().unwrap().write_packet(packet).as_proxy()
}
fn read_client_packet(&self) -> Result<Packet, ProxyError> {
self.client_conn.lock().unwrap().read_packet().as_proxy()
}
fn read_server_packet(&self) -> Result<Packet, ProxyError> {
self.server_conn.lock().unwrap().read_packet().as_proxy()
}
fn set_server_compression(&self, threshold: Option<usize>) {
self.server_conn.lock().unwrap().set_compression(threshold);
}
fn set_client_compression(&self, threshold: Option<usize>) {
self.client_conn.lock().unwrap().set_compression(threshold);
}
pub fn server_compression(&self) -> Option<usize> {
self.server_conn.lock().unwrap().compression()
}
pub fn client_compression(&self) -> Option<usize> {
self.client_conn.lock().unwrap().compression()
}
}

View File

@ -1,8 +1,14 @@
use rust_mc_proto::ProtocolError;
#[derive(Debug)] #[derive(Debug)]
pub enum ProxyError { pub enum ProxyError {
ConfigParse, ConfigParse,
ServerConnect, ServerConnect,
EventChanged, EventChanged,
HandshakePacket,
LoginPacket,
PeerAddr,
ProtocolError(ProtocolError)
} }
impl std::fmt::Display for ProxyError { impl std::fmt::Display for ProxyError {
@ -12,3 +18,23 @@ impl std::fmt::Display for ProxyError {
} }
impl std::error::Error for ProxyError {} impl std::error::Error for ProxyError {}
pub trait AsProxyError {
fn as_proxy(self) -> ProxyError;
}
pub trait AsProxyResult<T> {
fn as_proxy(self) -> Result<T, ProxyError>;
}
impl AsProxyError for ProtocolError {
fn as_proxy(self) -> ProxyError {
ProxyError::ProtocolError(self)
}
}
impl <T> AsProxyResult<T> for Result<T, ProtocolError> {
fn as_proxy(self) -> Result<T, ProxyError> {
self.map_err(|o| o.as_proxy())
}
}

View File

@ -1,252 +1,59 @@
use super::{MeexProx, MeexProxMutex, PlayerMutex, ProxyServer}; use std::net::SocketAddr;
use rust_mc_proto::Packet; use rust_mc_proto::Packet;
use std::{
error::Error,
net::SocketAddr,
sync::atomic::{AtomicBool, Ordering},
};
pub enum ProxyEvent { use super::{config::ServerInfo, connection::Player, error::ProxyError};
/// client <- proxy <- server \
/// &nbsp; | \
/// &nbsp; RecvServerPacketEvent
RecvServerPacketEvent {
packet: Packet,
player: PlayerMutex,
},
/// client -> proxy -> server \
/// &nbsp; | \
/// &nbsp; SendServerPacketEvent
SendServerPacketEvent {
packet: Packet,
player: PlayerMutex,
cancel: AtomicBool,
},
/// client <- proxy <- server \
/// &nbsp; | \
/// &nbsp; SendClientPacketEvent
SendClientPacketEvent {
packet: Packet,
player: PlayerMutex,
cancel: AtomicBool,
},
/// client -> proxy -> server \
/// &nbsp; | \
/// &nbsp; RecvClientPacketEvent
RecvClientPacketEvent {
packet: Packet,
player: PlayerMutex,
},
PlayerConnectedEvent {
player: PlayerMutex,
},
PlayerDisconnectedEvent {
player: PlayerMutex,
},
PlayerConnectingServerEvent {
player: PlayerMutex,
server: ProxyServer,
cancel: AtomicBool,
},
PlayerConnectingIPEvent {
player: PlayerMutex,
ip: String,
cancel: AtomicBool,
},
StatusRequestEvent {
status: String,
client_address: SocketAddr,
server_address: String,
server_port: u16,
cancel: AtomicBool,
},
}
impl ProxyEvent {
pub fn status_request(
meexprox: MeexProxMutex,
status: String,
client_address: SocketAddr,
server_address: String,
server_port: u16,
) -> (String, bool) {
let ProxyEvent::StatusRequestEvent {
status,
client_address: _,
server_address: _,
server_port: _,
cancel,
} = MeexProx::trigger_event(
meexprox,
ProxyEvent::StatusRequestEvent {
status: status.clone(),
client_address,
server_address,
server_port,
cancel: AtomicBool::from(false),
},
)
else {
return (status, false);
};
(status, cancel.load(Ordering::Relaxed))
}
pub fn player_connecting_ip(
meexprox: MeexProxMutex,
player: PlayerMutex,
ip: String,
) -> (String, bool) {
let ProxyEvent::PlayerConnectingIPEvent {
ip,
player: _,
cancel,
} = MeexProx::trigger_event(
meexprox,
ProxyEvent::PlayerConnectingIPEvent {
ip: ip.clone(),
player,
cancel: AtomicBool::from(false),
},
)
else {
return (ip, false);
};
(ip, cancel.load(Ordering::Relaxed))
}
pub fn player_connecting_server(
meexprox: MeexProxMutex,
player: PlayerMutex,
server: ProxyServer,
) -> (ProxyServer, bool) {
let ProxyEvent::PlayerConnectingServerEvent {
server,
player: _,
cancel,
} = MeexProx::trigger_event(
meexprox,
ProxyEvent::PlayerConnectingServerEvent {
server: server.clone(),
player,
cancel: AtomicBool::from(false),
},
)
else {
return (server, false);
};
(server, cancel.load(Ordering::Relaxed))
}
pub fn player_disconnected(meexprox: MeexProxMutex, player: PlayerMutex) -> () {
let ProxyEvent::PlayerDisconnectedEvent { player: _ } =
MeexProx::trigger_event(meexprox, ProxyEvent::PlayerDisconnectedEvent { player })
else {
return;
};
}
pub fn player_connected(meexprox: MeexProxMutex, player: PlayerMutex) -> () {
let ProxyEvent::PlayerConnectedEvent { player: _ } =
MeexProx::trigger_event(meexprox, ProxyEvent::PlayerConnectedEvent { player })
else {
return;
};
}
pub fn send_client_packet(
meexprox: MeexProxMutex,
packet: Packet,
player: PlayerMutex,
) -> (Packet, bool) {
let ProxyEvent::SendClientPacketEvent {
packet,
player: _,
cancel,
} = MeexProx::trigger_event(
meexprox,
ProxyEvent::SendClientPacketEvent {
packet: packet.clone(),
player,
cancel: AtomicBool::from(false),
},
)
else {
return (packet, false);
};
(packet, cancel.load(Ordering::Relaxed))
}
pub fn send_server_packet(
meexprox: MeexProxMutex,
packet: Packet,
player: PlayerMutex,
) -> (Packet, bool) {
let ProxyEvent::SendServerPacketEvent {
packet,
player: _,
cancel,
} = MeexProx::trigger_event(
meexprox,
ProxyEvent::SendServerPacketEvent {
packet: packet.clone(),
player,
cancel: AtomicBool::from(false),
},
)
else {
return (packet, false);
};
(packet, cancel.load(Ordering::Relaxed))
}
pub fn recv_server_packet(
meexprox: MeexProxMutex,
packet: Packet,
player: PlayerMutex,
) -> Packet {
let ProxyEvent::RecvServerPacketEvent { packet, player: _ } = MeexProx::trigger_event(
meexprox,
ProxyEvent::RecvServerPacketEvent {
packet: packet.clone(),
player,
},
) else {
return packet;
};
packet
}
pub fn recv_client_packet(
meexprox: MeexProxMutex,
packet: Packet,
player: PlayerMutex,
) -> Packet {
let ProxyEvent::RecvClientPacketEvent { packet, player: _ } = MeexProx::trigger_event(
meexprox,
ProxyEvent::RecvClientPacketEvent {
packet: packet.clone(),
player,
},
) else {
return packet;
};
packet
}
}
pub trait EventListener { pub trait EventListener {
fn on_event( fn on_server_recv_packet(
&mut self, &self,
meexprox: MeexProxMutex, packet: &mut Packet,
event: &mut ProxyEvent, player: &Player,
) -> Result<(), Box<dyn Error>>; ) -> Result<(), ProxyError>;
}
fn on_server_send_packet(
&self,
packet: &mut Packet,
cancel: &mut bool,
player: &Player,
) -> Result<(), ProxyError>;
fn on_client_send_packet(
&self,
packet: &mut Packet,
cancel: &mut bool,
player: &Player,
) -> Result<(), ProxyError>;
fn on_client_recv_packet(
&self,
packet: &mut Packet,
player: &Player,
) -> Result<(), ProxyError>;
fn on_player_connected(
&self,
player: &Player,
) -> Result<(), ProxyError>;
fn on_player_disconnected(
&self,
player: &Player,
) -> Result<(), ProxyError>;
fn on_player_connecting_server(
&self,
player: &Player,
cancel: &mut bool,
server: &mut ServerInfo
) -> Result<(), ProxyError>;
fn on_status_request(
&self,
status: String,
client_address: SocketAddr,
server_address: String,
server_port: u16,
cancel: &mut bool,
) -> Result<(), ProxyError>;
}

View File

@ -1,512 +1,74 @@
use super::{EventListener, PlayerForwarding, ProxyConfig, ProxyError, ProxyEvent, ProxyServer}; use log::{error, info};
use derivative::Derivative; // use no_deadlocks::Mutex;
use log::{debug, info};
use no_deadlocks::Mutex;
use rust_mc_proto::{ use rust_mc_proto::{
DataBufferReader, DataBufferWriter, MinecraftConnection, Packet, ProtocolError, Zigzag, read_packet, write_packet, DataBufferReader, DataBufferWriter, MCConnTcp, Packet
}; };
use std::{ use std::{
error::Error,
net::{SocketAddr, TcpListener, TcpStream}, net::{SocketAddr, TcpListener, TcpStream},
sync::{ sync::{
atomic::{AtomicUsize, Ordering}, Arc, RwLock, RwLockReadGuard
Arc, }, thread,
},
thread,
}; };
use tokio::task::AbortHandle;
use uuid::Uuid;
#[derive(Derivative)] use super::{config::{PlayerForwarding, ProxyConfig}, connection::Player, error::{AsProxyResult, ProxyError}, event::EventListener};
#[derivative(Debug)]
pub struct ProxyPlayer {
#[derivative(Debug = "ignore")]
client_conn: MinecraftConnection<TcpStream>,
#[derivative(Debug = "ignore")]
server_conn: MinecraftConnection<TcpStream>,
connection_threads: Vec<AbortHandle>,
name: Option<String>,
uuid: Option<Uuid>,
protocol_version: u16,
server: Option<ProxyServer>,
shared_secret: Option<Vec<u8>>,
verify_token: Option<Vec<u8>>,
}
impl ProxyPlayer {
pub fn new(
client_conn: MinecraftConnection<TcpStream>,
server_conn: MinecraftConnection<TcpStream>,
connection_threads: Vec<AbortHandle>,
name: Option<String>,
uuid: Option<Uuid>,
protocol_version: u16,
server: Option<ProxyServer>,
shared_secret: Option<Vec<u8>>,
verify_token: Option<Vec<u8>>,
) -> ProxyPlayer {
ProxyPlayer {
client_conn,
server_conn,
name,
uuid,
protocol_version,
server,
shared_secret,
verify_token,
connection_threads,
}
}
pub fn client_conn(&self) -> &MinecraftConnection<TcpStream> {
&self.client_conn
}
pub fn server_conn(&self) -> &MinecraftConnection<TcpStream> {
&self.server_conn
}
pub fn client_conn_mut(&mut self) -> &mut MinecraftConnection<TcpStream> {
&mut self.client_conn
}
pub fn server_conn_mut(&mut self) -> &mut MinecraftConnection<TcpStream> {
&mut self.server_conn
}
pub fn name(&self) -> Option<&String> {
self.name.as_ref()
}
pub fn uuid(&self) -> Option<&Uuid> {
self.uuid.as_ref()
}
pub fn protocol_version(&self) -> u16 {
self.protocol_version
}
pub fn server(&self) -> Option<&ProxyServer> {
self.server.as_ref()
}
pub fn shared_secret(&self) -> Option<&Vec<u8>> {
self.shared_secret.as_ref()
}
pub fn verify_token(&self) -> Option<&Vec<u8>> {
self.verify_token.as_ref()
}
pub fn connection_threads(&mut self) -> &mut Vec<AbortHandle> {
&mut self.connection_threads
}
pub fn connect_to_ip(
this: PlayerMutex,
meexprox: MeexProxMutex,
ip: &str,
server_address: &str,
server_port: u16,
) -> Result<(), Box<dyn Error>> {
let (ip, cancel) =
ProxyEvent::player_connecting_ip(meexprox.clone(), this.clone(), ip.to_string());
let ip = &ip;
if cancel {
return Ok(());
}
for thread in &mut this.lock().unwrap().connection_threads {
thread.abort();
}
this.lock().unwrap().server_conn.close();
this.lock().unwrap().server_conn = MinecraftConnection::connect(ip)?;
thread::spawn({
let player_forwarding = meexprox.lock().unwrap().config.player_forwarding().clone();
let server_address = server_address.to_string();
move || {
let _ = ProxyPlayer::connect(
this,
meexprox,
player_forwarding,
&server_address,
server_port,
false,
);
}
});
Ok(())
}
pub fn connect_to_server(
this: PlayerMutex,
meexprox: MeexProxMutex,
server: ProxyServer,
server_address: &str,
server_port: u16,
) -> Result<(), Box<dyn Error>> {
let (server, cancel) =
ProxyEvent::player_connecting_server(meexprox.clone(), this.clone(), server);
if cancel {
return Ok(());
}
for thread in &mut this.lock().unwrap().connection_threads {
thread.abort();
}
this.lock().unwrap().server_conn.close();
this.lock().unwrap().server = Some(server.clone());
this.lock().unwrap().server_conn = MinecraftConnection::connect(server.host())?;
thread::spawn({
let player_forwarding = meexprox.lock().unwrap().config.player_forwarding().clone();
let server_address = server_address.to_string();
move || {
let _ = ProxyPlayer::connect(
this,
meexprox,
player_forwarding,
&server_address,
server_port,
false,
);
}
});
Ok(())
}
pub fn reconnect(
this: PlayerMutex,
meexprox: MeexProxMutex,
server_address: &str,
server_port: u16,
) -> Result<(), Box<dyn Error>> {
for thread in &mut this.lock().unwrap().connection_threads {
thread.abort();
}
this.lock().unwrap().server_conn.close();
let server_host = this.lock().unwrap().server().unwrap().host().to_string();
this.lock().unwrap().server_conn = MinecraftConnection::connect(&server_host)?;
thread::spawn({
let player_forwarding = meexprox.lock().unwrap().config.player_forwarding().clone();
let server_address = server_address.to_string();
move || {
let _ = ProxyPlayer::connect(
this,
meexprox,
player_forwarding,
&server_address,
server_port,
false,
);
}
});
Ok(())
}
fn send_handshake(
this: PlayerMutex,
meexprox: MeexProxMutex,
player_forwarding: PlayerForwarding,
addr: SocketAddr,
server_address: &str,
server_port: u16,
) -> Result<(), ProtocolError> {
let protocol_version = this.lock().unwrap().protocol_version;
let packet = Packet::build(0x00, move |packet| {
packet.write_u16_varint(protocol_version)?;
packet.write_string(&server_address)?;
packet.write_unsigned_short(server_port)?;
packet.write_u8_varint(2)?;
if let PlayerForwarding::Handshake = player_forwarding {
if let SocketAddr::V4(addr) = addr {
packet.write_boolean(false)?; // is ipv6
packet.write_unsigned_short(addr.port())?; // port
packet.write_bytes(&addr.ip().octets())?; // octets
} else if let SocketAddr::V6(addr) = addr {
packet.write_boolean(true)?;
packet.write_unsigned_short(addr.port())?;
packet.write_bytes(&addr.ip().octets())?;
}
}
Ok(())
})?;
let (packet, cancel) = ProxyEvent::send_server_packet(meexprox, packet, this.clone());
if !cancel {
this.lock().unwrap().server_conn.write_packet(&packet)?;
}
Ok(())
}
fn send_login(this: PlayerMutex, meexprox: MeexProxMutex) -> Result<(), ProtocolError> {
if let Some(player_name) = this.lock().unwrap().name.as_ref() {
if let Some(player_uuid) = this.lock().unwrap().uuid.as_ref() {
let packet = Packet::build(0x00, move |packet| {
packet.write_string(&player_name)?;
packet.write_uuid(&player_uuid)?;
Ok(())
})?;
let (packet, cancel) =
ProxyEvent::send_server_packet(meexprox, packet, this.clone());
if !cancel {
this.lock().unwrap().server_conn.write_packet(&packet)?;
}
}
}
Ok(())
}
fn connect(
this: PlayerMutex,
meexprox: MeexProxMutex,
player_forwarding: PlayerForwarding,
server_address: &str,
server_port: u16,
logged: bool,
) -> Result<(), Box<dyn Error>> {
let mut client_conn = this.lock().unwrap().client_conn.try_clone().unwrap();
let mut server_conn = this.lock().unwrap().server_conn.try_clone().unwrap();
let addr = client_conn.get_ref().peer_addr().unwrap();
let Some(name) = this.lock().unwrap().name.clone() else {
return Ok(());
};
if !logged {
ProxyPlayer::send_handshake(
this.clone(),
meexprox.clone(),
player_forwarding,
addr,
server_address,
server_port,
)?;
ProxyPlayer::send_login(this.clone(), meexprox.clone())?;
while let Ok(mut packet) = server_conn.read_packet() {
if packet.id() == 0x01 {
if let Some(shared_secret) = this.lock().unwrap().shared_secret.clone() {
if let Some(verify_token) = this.lock().unwrap().verify_token.clone() {
let mut enc_response = Packet::empty(0x01);
enc_response.write_usize_varint(shared_secret.len())?;
enc_response.write_bytes(&shared_secret)?;
enc_response.write_usize_varint(shared_secret.len())?;
enc_response.write_bytes(&verify_token)?;
let (enc_response, cancel) = ProxyEvent::send_server_packet(
meexprox.clone(),
enc_response,
this.clone(),
);
if !cancel {
server_conn.write_packet(&enc_response)?;
}
}
}
}
if packet.id() == 0x03 {
let threshold = packet.read_isize_varint()?;
if threshold >= 0 {
let threshold = threshold.zigzag();
server_conn.set_compression(Some(threshold));
client_conn.set_compression(Some(threshold));
} else {
server_conn.set_compression(None);
client_conn.set_compression(None);
}
}
if packet.id() == 0x02 {
break;
}
}
let login_ack = Packet::empty(0x03);
let (login_ack, cancel) =
ProxyEvent::send_server_packet(meexprox.clone(), login_ack, this.clone());
if !cancel {
server_conn.write_packet(&login_ack)?;
}
}
let mut handles = Vec::new();
handles.push(
tokio::spawn({
let mut client_conn = client_conn.try_clone().unwrap();
let mut server_conn = server_conn.try_clone().unwrap();
let this = this.clone();
let meexprox = meexprox.clone();
let name = name.clone();
let addr = addr.clone();
async move {
while let Ok(packet) = client_conn.read_packet() {
let packet =
ProxyEvent::recv_client_packet(meexprox.clone(), packet, this.clone());
let (packet, cancel) =
ProxyEvent::send_server_packet(meexprox.clone(), packet, this.clone());
if !cancel {
match server_conn.write_packet(&packet) {
Ok(_) => {}
Err(_) => {
break;
}
};
}
}
if meexprox.lock().unwrap().remove_player(this.clone()) {
info!("{} disconnected player {}", addr.to_string(), name);
ProxyEvent::player_disconnected(meexprox.clone(), this.clone());
}
}
})
.abort_handle(),
);
handles.push(
tokio::spawn({
let this = this.clone();
async move {
while let Ok(packet) = server_conn.read_packet() {
let packet =
ProxyEvent::recv_server_packet(meexprox.clone(), packet, this.clone());
let (packet, cancel) =
ProxyEvent::send_client_packet(meexprox.clone(), packet, this.clone());
if !cancel {
match client_conn.write_packet(&packet) {
Ok(_) => {}
Err(_) => {
break;
}
};
}
}
if meexprox.lock().unwrap().remove_player(this.clone()) {
info!("{} disconnected player {}", addr.to_string(), name);
ProxyEvent::player_disconnected(meexprox.clone(), this.clone());
}
}
})
.abort_handle(),
);
this.lock().unwrap().connection_threads = handles;
Ok(())
}
}
pub struct MeexProx { pub struct MeexProx {
config: ProxyConfig, config: ProxyConfig,
players: Vec<PlayerMutex>, players: RwLock<Vec<Player>>,
event_listeners: Vec<Box<dyn EventListener + Send + Sync>>, event_listeners: Vec<Box<dyn EventListener + Send + Sync>>
} }
impl MeexProx { impl MeexProx {
pub fn new(config: ProxyConfig) -> MeexProx { pub fn new(config: ProxyConfig) -> MeexProx {
MeexProx { MeexProx {
config, config,
players: Vec::new(), players: RwLock::new(Vec::new()),
event_listeners: Vec::new(), event_listeners: Vec::new(),
} }
} }
pub fn add_event_listener(&mut self, event_listener: Box<dyn EventListener + Send + Sync>) { pub fn add_event_listener(
&mut self,
event_listener: Box<dyn EventListener + Send + Sync>,
) {
self.event_listeners.push(event_listener); self.event_listeners.push(event_listener);
} }
pub fn trigger_event(this: MeexProxMutex, mut event: ProxyEvent) -> ProxyEvent { pub fn trigger_event(
for event_listener in &mut this.lock().unwrap().event_listeners { &self,
let _ = event_listener.on_event(this.clone(), &mut event); trigger: fn(&dyn EventListener) -> Result<(), ProxyError>
) -> Result<(), ProxyError> {
for event_listener in &self.event_listeners {
trigger(event_listener.as_ref())?
} }
event Ok(())
} }
pub fn get_player(&self, uuid: Uuid) -> Option<PlayerMutex> { pub async fn get_players(&self) -> RwLockReadGuard<'_, Vec<Player>> {
for player in &self.players { self.players.read().unwrap()
if let Some(player_uuid) = player.lock().unwrap().uuid {
if player_uuid == uuid {
return Some(player.clone());
}
}
}
None
} }
pub fn remove_player(&mut self, player: PlayerMutex) -> bool { pub fn accept_client(&self, mut client_conn: TcpStream) -> Result<(), ProxyError> {
match self.players.iter().position(|x| Arc::ptr_eq(x, &player)) { let addr = client_conn.peer_addr().map_err(|_| ProxyError::PeerAddr)?;
Some(i) => {
self.players.remove(i);
true
}
None => false,
}
}
pub fn accept_client(this: MeexProxMutex, stream: TcpStream) -> Result<(), Box<dyn Error>> { let mut handshake = read_packet(&mut client_conn, None).as_proxy()?;
let Ok(addr) = stream.peer_addr() else {
return Ok(());
};
let server_config = this.lock().unwrap().config.clone();
let mut client_conn = MinecraftConnection::new(stream);
let mut handshake = client_conn.read_packet()?;
if handshake.id() != 0x00 { if handshake.id() != 0x00 {
return Ok(()); return Err(ProxyError::HandshakePacket);
} }
let protocol_version = handshake.read_u16_varint()?; let protocol_version = handshake.read_u16_varint().as_proxy()?;
let server_address = handshake.read_string()?; let server_address = handshake.read_string().as_proxy()?;
let server_port = handshake.read_unsigned_short()?; let server_port = handshake.read_unsigned_short().as_proxy()?;
let next_state = handshake.read_u8_varint()?; let next_state = handshake.read_u8_varint().as_proxy()?;
let server = server_config let server = self.config
.get_server_by_forced_host(&server_address) .get_server_by_forced_host(&server_address)
.or(server_config.default_server().cloned()) .or(self.config.default_server.clone())
.ok_or(ProxyError::ConfigParse)?; .ok_or(ProxyError::ConfigParse)?;
let mut server_conn = MinecraftConnection::connect(&server.host())?; let mut server_conn = TcpStream::connect(&server.host).map_err(|_| ProxyError::ServerConnect)?;
let handshake = Packet::build(0x00, |handshake| { let handshake = Packet::build(0x00, |handshake| {
handshake.write_u16_varint(protocol_version)?; handshake.write_u16_varint(protocol_version)?;
@ -514,7 +76,7 @@ impl MeexProx {
handshake.write_unsigned_short(server_port)?; handshake.write_unsigned_short(server_port)?;
handshake.write_u8_varint(next_state)?; handshake.write_u8_varint(next_state)?;
if let PlayerForwarding::Handshake = server_config.player_forwarding() { if let PlayerForwarding::Handshake = self.config.player_forwarding {
if let SocketAddr::V4(addr) = addr { if let SocketAddr::V4(addr) = addr {
handshake.write_boolean(false)?; // is ipv6 handshake.write_boolean(false)?; // is ipv6
handshake.write_unsigned_short(addr.port())?; // port handshake.write_unsigned_short(addr.port())?; // port
@ -527,155 +89,51 @@ impl MeexProx {
} }
Ok(()) Ok(())
})?; }).as_proxy()?;
server_conn.write_packet(&handshake)?; write_packet(&mut server_conn, None, 0, &handshake).as_proxy()?;
let mut client_conn = MCConnTcp::new(client_conn);
let mut server_conn = MCConnTcp::new(server_conn);
if next_state == 1 { if next_state == 1 {
loop { loop {
let client_packet = client_conn.read_packet()?; server_conn.write_packet(&client_conn.read_packet().as_proxy()?).as_proxy()?;
client_conn.write_packet(&server_conn.read_packet().as_proxy()?).as_proxy()?;
server_conn.write_packet(&client_packet)?;
let mut server_packet = server_conn.read_packet()?;
if client_packet.id() == 0x00 {
let server_status = server_packet.read_string()?;
let (status, cancel) = ProxyEvent::status_request(
this.clone(),
server_status.clone(),
addr.clone(),
server_address.clone(),
server_port,
);
if cancel {
break;
}
server_packet = Packet::build(0x00, |p| p.write_string(&status))?;
}
client_conn.write_packet(&server_packet)?;
} }
} else if next_state == 2 { } else if next_state == 2 {
let player = Arc::new(Mutex::new(ProxyPlayer::new( self.players.write().unwrap().push(Player::read(
client_conn.try_clone().unwrap(), protocol_version,
server_conn.try_clone().unwrap(), server_address,
Vec::new(), server_port,
None, server,
None, client_conn,
protocol_version, server_conn
Some(server.clone()), )?);
None,
None,
)));
let (server, cancel) =
ProxyEvent::player_connecting_server(this.clone(), player.clone(), server.clone());
if cancel {
return Ok(());
}
player.lock().unwrap().server = Some(server);
this.lock().unwrap().players.push(player.clone());
let mut login_start = client_conn.read_packet()?;
player.lock().unwrap().name = Some(login_start.read_string()?);
player.lock().unwrap().uuid = Some(login_start.read_uuid()?);
server_conn.write_packet(&login_start)?;
while let Ok(mut packet) = server_conn.read_packet() {
client_conn.write_packet(&packet)?;
if packet.id() == 0x01 {
let mut enc_response = client_conn.read_packet()?;
let shared_secret_length = enc_response.read_usize_varint()?;
player.lock().unwrap().shared_secret =
Some(enc_response.read_bytes(shared_secret_length)?);
let verify_token_length = enc_response.read_usize_varint()?;
player.lock().unwrap().verify_token =
Some(enc_response.read_bytes(verify_token_length)?);
server_conn.write_packet(&enc_response)?;
}
if packet.id() == 0x03 {
let threshold = packet.read_isize_varint()?;
if threshold >= 0 {
let threshold = threshold.zigzag();
server_conn.set_compression(Some(threshold));
client_conn.set_compression(Some(threshold));
} else {
server_conn.set_compression(None);
client_conn.set_compression(None);
}
}
if packet.id() == 0x02 {
break;
}
}
// println!("lac re");
// let login_ack = client_conn.read_packet()?;
// println!("lac {}", login_ack.id());
// if login_ack.id() != 0x03 {
// return Ok(());
// }
let this = this.clone();
info!(
"{} connected player {}",
addr.to_string(),
player.lock().unwrap().name.clone().unwrap()
);
ProxyEvent::player_connected(this.clone(), player.clone());
let _ = ProxyPlayer::connect(
player,
this,
server_config.player_forwarding().clone(),
&server_address,
server_port,
true,
);
} }
Ok(()) Ok(())
} }
pub fn start(self) { pub fn start(self) {
let listener = TcpListener::bind(self.config.host()).expect("invalid host"); let listener = TcpListener::bind(&self.config.host).expect("invalid host");
info!("meexprox started on {}", self.config.host()); info!("meexprox started on {}", &self.config.host);
let mutex_self = Arc::new(Mutex::new(self)); let self_arc = Arc::new(self);
for client in listener.incoming() { for client in listener.incoming() {
if let Ok(client) = client { if let Ok(client) = client {
let mutex_self_clone = mutex_self.clone(); let self_arc = self_arc.clone();
thread::spawn(move || { thread::spawn(move || {
match Self::accept_client(mutex_self_clone, client) { match self_arc.accept_client(client) {
Ok(_) => {} Ok(_) => {}
Err(_) => { Err(e) => {
// error!("connection error: {:?}", e); error!("connection error: {:?}", e);
} }
}; };
}); });
} }
} }
} }
} }
pub type PlayerMutex = Arc<Mutex<ProxyPlayer>>;
pub type MeexProxMutex = Arc<Mutex<MeexProx>>;

View File

@ -2,8 +2,6 @@ pub mod config;
pub mod error; pub mod error;
pub mod event; pub mod event;
pub mod meexprox; pub mod meexprox;
pub mod connection;
pub use config::*;
pub use error::*;
pub use event::*;
pub use meexprox::*; pub use meexprox::*;