velocity player forwarding

This commit is contained in:
MeexReay 2024-11-14 17:34:00 +03:00
parent 7a12dfb51d
commit 700bf95a5d
5 changed files with 148 additions and 15 deletions

72
Cargo.lock generated
View File

@ -29,6 +29,15 @@ 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.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
dependencies = [
"shlex",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -78,6 +87,17 @@ dependencies = [
"miniz_oxide", "miniz_oxide",
] ]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.1" version = "0.15.1"
@ -141,9 +161,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
name = "meexprox" name = "meexprox"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bytebuffer",
"ignore-result", "ignore-result",
"log", "log",
"random-string", "random-string",
"ring",
"rust_mc_proto", "rust_mc_proto",
"serde_yml", "serde_yml",
"simplelog", "simplelog",
@ -213,6 +235,21 @@ dependencies = [
"fastrand", "fastrand",
] ]
[[package]]
name = "ring"
version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [
"cc",
"cfg-if",
"getrandom",
"libc",
"spin",
"untrusted",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "rust_mc_proto" name = "rust_mc_proto"
version = "0.1.16" version = "0.1.16"
@ -264,6 +301,12 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "simplelog" name = "simplelog"
version = "0.12.2" version = "0.12.2"
@ -275,6 +318,12 @@ dependencies = [
"time", "time",
] ]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.87" version = "2.0.87"
@ -334,6 +383,12 @@ version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.11.0" version = "1.11.0"
@ -346,13 +401,28 @@ 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 = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
version = "0.1.9" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.59.0",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
] ]
[[package]] [[package]]

View File

@ -11,3 +11,5 @@ log = "0.4.22"
simplelog = "0.12.2" simplelog = "0.12.2"
ignore-result = "0.2.0" ignore-result = "0.2.0"
random-string = "1.1.0" random-string = "1.1.0"
ring = "0.17.8"
bytebuffer = "2.3.0"

View File

@ -30,5 +30,5 @@ incoming_forwarding: # player forwarding for incoming connections
# player forwarding types: # player forwarding types:
# - velocity (or "modern" in Velocity config) (secret is required) # - velocity (or "modern" in Velocity config) (secret is required)
# - bungeecord (or "legacy" in Velocity config) (secret is optional) # - bungeecord (or "legacy" in Velocity config) (secret is optional)
# - meexprox (best) (secret is required) # - meexprox (open-source protocol) (secret is required)
# - none (enabled: false) # - none (enabled: false)

View File

@ -1,11 +1,13 @@
use std::{net::{SocketAddr, TcpStream}, sync::{Arc, Mutex}, thread}; use std::{net::{SocketAddr, TcpStream}, sync::{Arc, Mutex}, thread};
use bytebuffer::ByteBuffer;
use ignore_result::Ignore; use ignore_result::Ignore;
use log::debug; use log::info;
use ring::hmac;
use rust_mc_proto::{DataBufferReader, DataBufferWriter, MCConnTcp, Packet, ProtocolError}; use rust_mc_proto::{DataBufferReader, DataBufferWriter, MCConnTcp, Packet, ProtocolError};
use uuid::Uuid; use uuid::Uuid;
use super::{config::{ProxyConfig, ServerInfo}, error::{AsProxyResult, ProxyError}}; use super::{config::{PlayerForwarding, ProxyConfig, ServerInfo}, error::{AsProxyResult, ProxyError}};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct LoginInfo { pub struct LoginInfo {
@ -74,6 +76,7 @@ pub struct Player {
impl Player { impl Player {
pub fn read( pub fn read(
_config: &ProxyConfig,
protocol_version: u16, protocol_version: u16,
server_address: String, server_address: String,
server_port: u16, server_port: u16,
@ -98,7 +101,7 @@ impl Player {
login_info: None, login_info: None,
name: name.clone(), name: name.clone(),
uuid, uuid,
server: Some(server), server: Some(server.clone()),
protocol_version protocol_version
}; };
@ -128,6 +131,47 @@ impl Player {
player.set_server_compression(compression); player.set_server_compression(compression);
player.set_client_compression(compression); player.set_client_compression(compression);
} }
0x04 => { // login plugin request
let message_id = packet.read_isize_varint().as_proxy()?;
let channel = packet.read_string().as_proxy()?;
if channel == "velocity:player_info" {
if let PlayerForwarding::Velocity(secret) = &server.player_forwarding {
let version: u8 = if packet.buffer().len() - packet.buffer().get_rpos() == 1 {
packet.read_byte().as_proxy()?
} else {
1
};
let response = Packet::build(0x02, |p| {
p.write_isize_varint(message_id)?;
p.write_boolean(true)?;
let mut buf = ByteBuffer::new();
DataBufferWriter::write_u8_varint(&mut buf, version)?;
DataBufferWriter::write_string(&mut buf, &addr.to_string())?;
DataBufferWriter::write_uuid(&mut buf, &uuid)?;
DataBufferWriter::write_string(&mut buf, &name)?;
DataBufferWriter::write_u8_varint(&mut buf, 0)?; // properties // maybe fix later
let buf = buf.as_bytes();
let key = hmac::Key::new(hmac::HMAC_SHA256, secret.as_bytes());
let sig = hmac::sign(&key, &buf);
p.write_bytes(sig.as_ref())?;
p.write_bytes(buf.as_ref())?;
Ok(())
}).as_proxy()?;
player.write_server_packet(&response)?;
continue;
}
}
player.write_client_packet(&packet)?;
player.write_server_packet(&player.read_client_packet()?)?;
}
_ => { _ => {
return Err(ProxyError::LoginPacket); return Err(ProxyError::LoginPacket);
}, },
@ -144,8 +188,6 @@ impl Player {
verify_token verify_token
}); });
debug!("player connected");
player.client_recv_loop(); player.client_recv_loop();
player.server_recv_loop(); player.server_recv_loop();
@ -155,40 +197,58 @@ impl Player {
pub fn client_recv_loop(&self) { pub fn client_recv_loop(&self) {
let mut client: rust_mc_proto::MinecraftConnection<TcpStream> = self.client_conn.clone().lock().unwrap().try_clone().unwrap(); let mut client: rust_mc_proto::MinecraftConnection<TcpStream> = self.client_conn.clone().lock().unwrap().try_clone().unwrap();
let server = self.server_conn.clone(); let server = self.server_conn.clone();
let name = self.name.clone();
thread::spawn(move || { thread::spawn(move || {
info!("Player {} connected", name);
while let Ok(packet) = client.read_packet() { while let Ok(packet) = client.read_packet() {
while !server.lock().unwrap().is_alive() {} while !server.lock().unwrap().is_alive() {}
server.lock().unwrap().write_packet(&packet).ignore(); server.lock().unwrap().write_packet(&packet).ignore();
} }
info!("Player {} disconnected", name);
server.lock().unwrap().close();
}); });
} }
pub fn disconnect(&self) {
self.client_conn.lock().unwrap().close();
self.server_conn.lock().unwrap().close();
}
pub fn kick(&self, text: String) -> Result<(), ProxyError> {
self.write_client_packet(&Packet::build(
0x1D, |p| p.write_string(&text)
).as_proxy()?)?;
self.disconnect();
Ok(())
}
pub fn server_recv_loop(&self) { pub fn server_recv_loop(&self) {
let mut server = self.server_conn.clone().lock().unwrap().try_clone().unwrap(); let mut server = self.server_conn.clone().lock().unwrap().try_clone().unwrap();
let client = self.client_conn.clone(); let client = self.client_conn.clone();
let server_name = self.server.as_ref().unwrap().name.clone();
let name = self.name.clone();
thread::spawn(move || { thread::spawn(move || {
info!("Server {} connected player {}", server_name, name);
while let Ok(packet) = server.read_packet() { while let Ok(packet) = server.read_packet() {
client.lock().unwrap().write_packet(&packet).ignore(); client.lock().unwrap().write_packet(&packet).ignore();
} }
info!("Server {} disconnected player {}", server_name, name);
}); });
} }
pub fn connect(&self, config: &ProxyConfig, server_conn: TcpStream) -> Result<(), ProxyError> { pub fn connect_server(&self, config: &ProxyConfig, server: ServerInfo) -> Result<(), ProxyError> {
self.server_conn.lock().unwrap().close(); self.server_conn.lock().unwrap().close();
let mut server_conn = MCConnTcp::new(server_conn); let mut server_conn = MCConnTcp::connect(&server.host).as_proxy()?;
if let Some(login_info) = &self.login_info { if let Some(login_info) = &self.login_info {
login_info.write(config, &mut server_conn).as_proxy()?; login_info.write(config, &mut server_conn).as_proxy()?;
} }
*self.server_conn.lock().unwrap() = server_conn;
self.server_recv_loop(); self.server_recv_loop();
Ok(()) 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> { pub fn write_client_packet(&self, packet: &Packet) -> Result<(), ProxyError> {
self.client_conn.lock().unwrap().write_packet(packet).as_proxy() self.client_conn.lock().unwrap().write_packet(packet).as_proxy()
} }

View File

@ -1,4 +1,4 @@
use log::{debug, error, info}; use log::{error, info};
use rust_mc_proto::{ use rust_mc_proto::{
read_packet, write_packet, DataBufferReader, DataBufferWriter, MCConnTcp, Packet read_packet, write_packet, DataBufferReader, DataBufferWriter, MCConnTcp, Packet
}; };
@ -89,6 +89,7 @@ impl MeexProx {
} }
} else if next_state == 2 { } else if next_state == 2 {
self.players.write().unwrap().push(Player::read( self.players.write().unwrap().push(Player::read(
&self.config,
protocol_version, protocol_version,
server_address, server_address,
server_port, server_port,