From e41c0060603d5a3b7b0d266e18bbcb07ef518f42 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Wed, 31 Jul 2024 19:38:07 +0300 Subject: [PATCH] some changes refactor and wowowow shkebede lavadovski --- src/lib.rs | 1053 +------------------------------------- src/main.rs | 25 +- src/meexprox/config.rs | 187 +++++++ src/meexprox/error.rs | 14 + src/meexprox/event.rs | 230 +++++++++ src/meexprox/meexprox.rs | 665 ++++++++++++++++++++++++ src/meexprox/mod.rs | 9 + 7 files changed, 1127 insertions(+), 1056 deletions(-) create mode 100644 src/meexprox/config.rs create mode 100644 src/meexprox/error.rs create mode 100644 src/meexprox/event.rs create mode 100644 src/meexprox/meexprox.rs create mode 100644 src/meexprox/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 25bc791..ed9eaa5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,1052 +1,3 @@ -use derivative::Derivative; -use log::{error, info}; -use rust_mc_proto::{ - DataBufferReader, DataBufferWriter, MinecraftConnection, Packet, ProtocolError, Zigzag, -}; -use serde_yml::Value; -use std::{ - error::Error, - fs, - net::{SocketAddr, TcpListener, TcpStream}, - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, Mutex, - }, - thread, -}; -use uuid::Uuid; +pub mod meexprox; -#[derive(Clone, Debug)] -pub struct ProxyServer { - name: String, - host: String, - forced_host: Option, -} - -impl ProxyServer { - pub fn new(name: String, host: String, forced_host: Option) -> ProxyServer { - ProxyServer { - name, - host, - forced_host, - } - } - - pub fn name(&self) -> &str { - &self.name - } - - pub fn host(&self) -> &str { - &self.host - } - - pub fn forced_host(&self) -> Option<&String> { - self.forced_host.as_ref() - } -} - -#[derive(Debug)] -pub enum ProxyError { - ConfigParse, - ServerConnect, - EventChanged, -} - -impl std::fmt::Display for ProxyError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "({:?})", self) - } -} - -impl std::error::Error for ProxyError {} - -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)] -pub enum PlayerForwarding { - Handshake, - Disabled, -} - -#[derive(Clone)] -pub struct ProxyConfig { - host: String, - servers: Vec, - default_server: Option, - talk_host: Option, - talk_secret: Option, - player_forwarding: PlayerForwarding, - no_pf_for_ip_connect: bool, -} - -impl ProxyConfig { - pub fn new( - host: String, - servers: Vec, - default_server: Option, - talk_host: Option, - talk_secret: Option, - player_forwarding: PlayerForwarding, - no_pf_for_ip_connect: bool, - ) -> ProxyConfig { - ProxyConfig { - host, - servers, - default_server, - talk_host, - talk_secret, - player_forwarding, - no_pf_for_ip_connect, - } - } - - pub fn host(&self) -> &str { - &self.host - } - - pub fn servers(&self) -> &Vec { - &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 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(path: &str) -> Result> { - let data = serde_yml::from_str::(&fs::read_to_string(path)?)?; - let data = data.as_mapping().ok_or(ProxyError::ConfigParse)?; - - let host = extract_string!(data, "host").ok_or(ProxyError::ConfigParse)?; - let talk_host = extract_string!(data, "talk_host"); - let talk_secret = extract_string!(data, "talk_secret"); - let player_forwarding = match extract_string!(data, "player_forwarding") { - Some(pf) => match pf.as_str() { - "disabled" => PlayerForwarding::Disabled, - _ => PlayerForwarding::Handshake, - }, - _ => PlayerForwarding::Handshake, - }; - let no_pf_for_ip_connect = data - .get(Value::String("no_pf_for_ip_connect".to_string())) - .or(Some(&Value::Bool(true))) - .ok_or(ProxyError::ConfigParse)? - .as_bool() - .ok_or(ProxyError::ConfigParse)?; - - let mut servers = Vec::new(); - if let Some(servers_map) = data - .get(&Value::String("servers".to_string())) - .and_then(Value::as_mapping) - { - for (name, addr) in servers_map { - if let (Value::String(name), Value::String(addr)) = (name, addr) { - servers.push(ProxyServer::new(name.clone(), addr.clone(), None)); - } - } - } - - if let Some(forced_hosts_map) = data - .get(&Value::String("forced_hosts".to_string())) - .and_then(Value::as_mapping) - { - for (name, host) in forced_hosts_map { - if let (Value::String(name), Value::String(host)) = (name, host) { - if let Some(server) = servers.iter_mut().find(|s| s.name == *name) { - server.forced_host = Some(host.clone()); - } - } - } - } - - let default_server = extract_string!(data, "default_server") - .and_then(|ds| servers.iter().find(|s| s.name == ds).cloned()); - - Ok(ProxyConfig::new( - host, - servers, - default_server, - talk_host, - talk_secret, - player_forwarding, - no_pf_for_ip_connect, - )) - } - - pub fn get_server_by_name(&self, name: &str) -> Option { - for server in &self.servers { - if &server.name == name { - return Some(server.clone()); - } - } - None - } - - pub fn get_server_by_forced_host(&self, forced_host: &str) -> Option { - for server in &self.servers { - if let Some(server_forced_host) = &server.forced_host { - if server_forced_host == forced_host { - return Some(server.clone()); - } - } - } - None - } -} - -#[derive(Derivative)] -#[derivative(Debug)] -pub struct ProxyPlayer { - #[derivative(Debug = "ignore")] - client_conn: MinecraftConnection, - #[derivative(Debug = "ignore")] - server_conn: MinecraftConnection, - name: Option, - uuid: Option, - protocol_version: u16, - server: Option, - shared_secret: Option>, - verify_token: Option>, - connection_id: Arc, -} - -impl ProxyPlayer { - pub fn new( - client_conn: MinecraftConnection, - server_conn: MinecraftConnection, - name: Option, - uuid: Option, - protocol_version: u16, - server: Option, - shared_secret: Option>, - verify_token: Option>, - connection_id: Arc, - ) -> ProxyPlayer { - ProxyPlayer { - client_conn, - server_conn, - name, - uuid, - protocol_version, - server, - shared_secret, - verify_token, - connection_id, - } - } - - pub fn client_conn(&self) -> &MinecraftConnection { - &self.client_conn - } - - pub fn server_conn(&self) -> &MinecraftConnection { - &self.client_conn - } - - pub fn client_conn_mut(&mut self) -> &mut MinecraftConnection { - &mut self.client_conn - } - - pub fn server_conn_mut(&mut self) -> &mut MinecraftConnection { - &mut self.client_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> { - self.shared_secret.as_ref() - } - - pub fn verify_token(&self) -> Option<&Vec> { - self.verify_token.as_ref() - } - - pub fn connection_id(&self) -> Arc { - self.connection_id.clone() - } - - pub fn connect_to_ip( - this: PlayerMutex, - meexprox: MeexProxMutex, - ip: &str, - server_address: &str, - server_port: u16, - ) -> Result<(), Box> { - this.lock() - .unwrap() - .connection_id - .fetch_add(1, Ordering::Relaxed); - - 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> { - this.lock() - .unwrap() - .connection_id - .fetch_add(1, Ordering::Relaxed); - - this.lock().unwrap().server = Some(server.clone()); - - this.lock().unwrap().server_conn.close(); - 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> { - this.lock() - .unwrap() - .connection_id - .fetch_add(1, Ordering::Relaxed); - - this.lock().unwrap().server_conn.close(); - this.lock().unwrap().server_conn = - MinecraftConnection::connect(&this.lock().unwrap().server.as_ref().unwrap().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 = ProxyEvent::send_server_packet(meexprox, packet, this.clone()); - - 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 = ProxyEvent::send_server_packet(meexprox, packet, this.clone()); - - 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> { - 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 server = this.lock().unwrap().server.clone(); - - let addr = client_conn.get_ref().peer_addr().unwrap(); - let Some(name) = this.lock().unwrap().name.clone() else { - return Ok(()); - }; - let server_config = meexprox.lock().unwrap().config.clone(); - - let atomic_connection_id = this.lock().unwrap().connection_id.clone(); - let connection_id = this.lock().unwrap().connection_id.load(Ordering::Relaxed); - - 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 = ProxyEvent::send_server_packet( - meexprox.clone(), - enc_response, - this.clone(), - ); - - 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 = - ProxyEvent::send_server_packet(meexprox.clone(), login_ack, this.clone()); - - server_conn.write_packet(&login_ack)?; - } - - thread::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 atomic_connection_id = atomic_connection_id.clone(); - - move || { - let _ = || -> Result<(), ProtocolError> { - while atomic_connection_id.load(Ordering::Relaxed) == connection_id { - let packet = match client_conn.read_packet() { - Ok(packet) => packet, - Err(_) => break, - }; - - let packet = - ProxyEvent::recv_client_packet(meexprox.clone(), packet, this.clone()); - - let packet = - ProxyEvent::send_server_packet(meexprox.clone(), packet, this.clone()); - - server_conn.write_packet(&packet)?; - } - - Ok(()) - }(); - - if atomic_connection_id.load(Ordering::Relaxed) == connection_id { - if meexprox.lock().unwrap().remove_player(this.clone()) { - info!("{} disconnected player {}", addr.to_string(), name); - ProxyEvent::player_disconnected(meexprox.clone(), this.clone()); - } - } - } - }); - - let _ = || -> Result<(), ProtocolError> { - while atomic_connection_id.load(Ordering::Relaxed) == connection_id { - let packet = match server_conn.read_packet() { - Ok(packet) => packet, - Err(_) => break, - }; - - let packet = ProxyEvent::recv_server_packet(meexprox.clone(), packet, this.clone()); - - let packet = ProxyEvent::send_client_packet(meexprox.clone(), packet, this.clone()); - - client_conn.write_packet(&packet)?; - } - - Ok(()) - }(); - - if atomic_connection_id.load(Ordering::Relaxed) == connection_id { - if meexprox.lock().unwrap().remove_player(this.clone()) { - info!("{} disconnected player {}", addr.to_string(), name); - ProxyEvent::player_disconnected(meexprox.clone(), this.clone()); - } - } - - Ok(()) - } -} - -#[derive(Debug)] -pub enum ProxyEvent { - /// client <- proxy <- server \ - ///   | \ - ///   RecvServerPacketEvent - RecvServerPacketEvent { - packet: Packet, - player: PlayerMutex, - }, - - /// client -> proxy -> server \ - ///   | \ - ///   SendServerPacketEvent - SendServerPacketEvent { - packet: Packet, - player: PlayerMutex, - }, - - /// client <- proxy <- server \ - ///   | \ - ///   SendClientPacketEvent - SendClientPacketEvent { - packet: Packet, - player: PlayerMutex, - }, - - /// client -> proxy -> server \ - ///   | \ - ///   RecvClientPacketEvent - RecvClientPacketEvent { - packet: Packet, - player: PlayerMutex, - }, - - PlayerConnectedEvent { - player: PlayerMutex, - }, - - PlayerConnectingServerEvent { - player: PlayerMutex, - server: ProxyServer, - }, - - PlayerConnectingIPEvent { - player: PlayerMutex, - ip: String, - }, - - PlayerDisconnectedEvent { - player: PlayerMutex, - }, - - StatusRequestEvent { - status: String, - client_address: SocketAddr, - server_address: String, - server_port: u16, - }, -} - -impl ProxyEvent { - pub fn status_request( - meexprox: MeexProxMutex, - status: String, - client_address: SocketAddr, - server_address: String, - server_port: u16, - ) -> String { - let ProxyEvent::StatusRequestEvent { - status, - client_address: _, - server_address: _, - server_port: _, - } = MeexProx::trigger_event( - meexprox, - ProxyEvent::StatusRequestEvent { - status: status.clone(), - client_address, - server_address, - server_port, - }, - ) - else { - return status; - }; - status - } - - pub fn player_connecting_server( - meexprox: MeexProxMutex, - player: PlayerMutex, - server: ProxyServer, - ) -> ProxyServer { - let ProxyEvent::PlayerConnectingServerEvent { server, player: _ } = MeexProx::trigger_event( - meexprox, - ProxyEvent::PlayerConnectingServerEvent { - server: server.clone(), - player, - }, - ) else { - return server; - }; - server - } - - 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 { - let ProxyEvent::SendClientPacketEvent { packet, player: _ } = MeexProx::trigger_event( - meexprox, - ProxyEvent::SendClientPacketEvent { - packet: packet.clone(), - player, - }, - ) else { - return packet; - }; - packet - } - - pub fn send_server_packet( - meexprox: MeexProxMutex, - packet: Packet, - player: PlayerMutex, - ) -> Packet { - let ProxyEvent::SendServerPacketEvent { packet, player: _ } = MeexProx::trigger_event( - meexprox, - ProxyEvent::SendServerPacketEvent { - packet: packet.clone(), - player, - }, - ) else { - return packet; - }; - packet - } - - 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 { - fn on_event( - &mut self, - meexprox: MeexProxMutex, - event: &mut ProxyEvent, - ) -> Result<(), Box>; -} - -pub struct MeexProx { - config: ProxyConfig, - players: Vec, - event_listeners: Vec>, -} - -impl MeexProx { - pub fn new(config: ProxyConfig) -> MeexProx { - MeexProx { - config, - players: Vec::new(), - event_listeners: Vec::new(), - } - } - - pub fn add_event_listener(&mut self, event_listener: Box) { - self.event_listeners.push(event_listener); - } - - pub fn trigger_event(this: MeexProxMutex, mut event: ProxyEvent) -> ProxyEvent { - for event_listener in &mut this.lock().unwrap().event_listeners { - let _ = event_listener.on_event(this.clone(), &mut event); - } - event - } - - pub fn get_player(&self, uuid: Uuid) -> Option { - for player in &self.players { - 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 { - match self.players.iter().position(|x| Arc::ptr_eq(x, &player)) { - Some(i) => { - self.players.remove(i); - true - } - None => false, - } - } - - pub fn accept_client(this: MeexProxMutex, stream: TcpStream) -> Result<(), Box> { - 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 { - return Ok(()); - } - - let protocol_version = handshake.read_u16_varint()?; - let server_address = handshake.read_string()?; - let server_port = handshake.read_unsigned_short()?; - let next_state = handshake.read_u8_varint()?; - - let server = server_config - .get_server_by_forced_host(&server_address) - .or(server_config.default_server) - .ok_or(ProxyError::ConfigParse)?; - - let mut server_conn = MinecraftConnection::connect(&server.host)?; - - let handshake = Packet::build(0x00, |handshake| { - handshake.write_u16_varint(protocol_version)?; - handshake.write_string(&server_address)?; - handshake.write_unsigned_short(server_port)?; - handshake.write_u8_varint(next_state)?; - - if let PlayerForwarding::Handshake = server_config.player_forwarding { - if let SocketAddr::V4(addr) = addr { - handshake.write_boolean(false)?; // is ipv6 - handshake.write_unsigned_short(addr.port())?; // port - handshake.write_bytes(&addr.ip().octets())?; // octets - } else if let SocketAddr::V6(addr) = addr { - handshake.write_boolean(true)?; - handshake.write_unsigned_short(addr.port())?; - handshake.write_bytes(&addr.ip().octets())?; - } - } - - Ok(()) - })?; - - server_conn.write_packet(&handshake)?; - - if next_state == 1 { - loop { - let client_packet = client_conn.read_packet()?; - - 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 ProxyEvent::StatusRequestEvent { - status: server_status, - client_address: _, - server_address: _, - server_port: _, - } = MeexProx::trigger_event( - this.clone(), - ProxyEvent::StatusRequestEvent { - status: server_status.clone(), - client_address: addr.clone(), - server_address: server_address.clone(), - server_port, - }, - ) - else { - return Ok(()); - }; - - server_packet = Packet::build(0x00, |p| p.write_string(&server_status))?; - } - - client_conn.write_packet(&server_packet)?; - } - } else if next_state == 2 { - let player = Arc::new(Mutex::new(ProxyPlayer::new( - client_conn.try_clone().unwrap(), - server_conn.try_clone().unwrap(), - None, - None, - protocol_version, - Some(server.clone()), - None, - None, - Arc::new(AtomicUsize::new(0)), - ))); - - 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(()); - // } - - thread::spawn({ - let this = this.clone(); - - move || { - 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, - &server_address, - server_port, - true, - ); - } - }); - } - - Ok(()) - } - - pub fn start(self) { - let listener = TcpListener::bind(&self.config.host).expect("invalid host"); - - info!("meexprox started on {}", &self.config.host); - - let mutex_self = Arc::new(Mutex::new(self)); - - for client in listener.incoming() { - if let Ok(client) = client { - let mutex_self_clone = mutex_self.clone(); - thread::spawn(move || { - match Self::accept_client(mutex_self_clone, client) { - Ok(_) => {} - Err(_) => { - // error!("connection error: {:?}", e); - } - }; - }); - } - } - } -} - -pub type PlayerMutex = Arc>; -pub type MeexProxMutex = Arc>; +pub use meexprox::*; diff --git a/src/main.rs b/src/main.rs index 9d10672..7ccb43a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ use rust_mc_proto::DataBufferReader; use simplelog::{ ColorChoice, CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode, WriteLogger, }; -use std::{error::Error, fs::File}; +use std::{error::Error, fs::File, sync::atomic::Ordering}; pub struct MyEventListener {} @@ -22,10 +22,18 @@ impl EventListener for MyEventListener { RecvServerPacketEvent { packet, player } => { // debug!("recv server packet event"); } - SendServerPacketEvent { packet, player } => { + SendServerPacketEvent { + packet, + player, + cancel, + } => { // debug!("send server packet event"); } - SendClientPacketEvent { packet, player } => { + SendClientPacketEvent { + packet, + player, + cancel, + } => { // debug!("send client packet event"); } RecvClientPacketEvent { packet, player } => { @@ -35,6 +43,7 @@ impl EventListener for MyEventListener { let command = packet.read_string()?; if command == "reconnect" { + println!("reconnect wow"); ProxyPlayer::reconnect(player.clone(), this.clone(), "localhost", 25565) .unwrap(); } @@ -43,10 +52,14 @@ impl EventListener for MyEventListener { PlayerConnectedEvent { player } => { debug!("player connected"); } - PlayerConnectingServerEvent { player, server } => { + PlayerConnectingServerEvent { + player, + server, + cancel, + } => { debug!("player connecting server"); } - PlayerConnectingIPEvent { player, ip } => { + PlayerConnectingIPEvent { player, ip, cancel } => { debug!("player connecting ip"); } PlayerDisconnectedEvent { player } => { @@ -57,8 +70,10 @@ impl EventListener for MyEventListener { client_address, server_address, server_port, + cancel, } => { debug!("status request"); + *status = String::from("123123"); } } diff --git a/src/meexprox/config.rs b/src/meexprox/config.rs new file mode 100644 index 0000000..1532c7c --- /dev/null +++ b/src/meexprox/config.rs @@ -0,0 +1,187 @@ +use super::ProxyError; +use serde_yml::Value; +use std::fs; + +#[derive(Clone, Debug)] +pub struct ProxyServer { + name: String, + host: String, + forced_host: Option, +} + +impl ProxyServer { + pub fn new(name: String, host: String, forced_host: Option) -> ProxyServer { + ProxyServer { + name, + host, + forced_host, + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn host(&self) -> &str { + &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)] +pub enum PlayerForwarding { + Handshake, + Disabled, +} + +#[derive(Clone)] +pub struct ProxyConfig { + host: String, + servers: Vec, + default_server: Option, + talk_host: Option, + talk_secret: Option, + player_forwarding: PlayerForwarding, + no_pf_for_ip_connect: bool, +} + +impl ProxyConfig { + pub fn new( + host: String, + servers: Vec, + default_server: Option, + talk_host: Option, + talk_secret: Option, + player_forwarding: PlayerForwarding, + no_pf_for_ip_connect: bool, + ) -> ProxyConfig { + ProxyConfig { + host, + servers, + default_server, + talk_host, + talk_secret, + player_forwarding, + no_pf_for_ip_connect, + } + } + + pub fn host(&self) -> &str { + &self.host + } + + pub fn servers(&self) -> &Vec { + &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(path: &str) -> Result> { + let data = serde_yml::from_str::(&fs::read_to_string(path)?)?; + let data = data.as_mapping().ok_or(ProxyError::ConfigParse)?; + + let host = extract_string!(data, "host").ok_or(ProxyError::ConfigParse)?; + let talk_host = extract_string!(data, "talk_host"); + let talk_secret = extract_string!(data, "talk_secret"); + let player_forwarding = match extract_string!(data, "player_forwarding") { + Some(pf) => match pf.as_str() { + "disabled" => PlayerForwarding::Disabled, + _ => PlayerForwarding::Handshake, + }, + _ => PlayerForwarding::Handshake, + }; + let no_pf_for_ip_connect = data + .get(Value::String("no_pf_for_ip_connect".to_string())) + .or(Some(&Value::Bool(true))) + .ok_or(ProxyError::ConfigParse)? + .as_bool() + .ok_or(ProxyError::ConfigParse)?; + + let mut servers = Vec::new(); + if let Some(servers_map) = data + .get(&Value::String("servers".to_string())) + .and_then(Value::as_mapping) + { + for (name, addr) in servers_map { + if let (Value::String(name), Value::String(addr)) = (name, addr) { + servers.push(ProxyServer::new(name.clone(), addr.clone(), None)); + } + } + } + + if let Some(forced_hosts_map) = data + .get(&Value::String("forced_hosts".to_string())) + .and_then(Value::as_mapping) + { + for (name, host) in forced_hosts_map { + if let (Value::String(name), Value::String(host)) = (name, host) { + if let Some(server) = servers.iter_mut().find(|s| s.name == *name) { + server.forced_host = Some(host.clone()); + } + } + } + } + + let default_server = extract_string!(data, "default_server") + .and_then(|ds| servers.iter().find(|s| s.name == ds).cloned()); + + Ok(ProxyConfig::new( + host, + servers, + default_server, + talk_host, + talk_secret, + player_forwarding, + no_pf_for_ip_connect, + )) + } + + pub fn get_server_by_name(&self, name: &str) -> Option { + for server in &self.servers { + if &server.name == name { + return Some(server.clone()); + } + } + None + } + + pub fn get_server_by_forced_host(&self, forced_host: &str) -> Option { + for server in &self.servers { + if let Some(server_forced_host) = &server.forced_host { + if server_forced_host == forced_host { + return Some(server.clone()); + } + } + } + None + } +} diff --git a/src/meexprox/error.rs b/src/meexprox/error.rs new file mode 100644 index 0000000..6693b5f --- /dev/null +++ b/src/meexprox/error.rs @@ -0,0 +1,14 @@ +#[derive(Debug)] +pub enum ProxyError { + ConfigParse, + ServerConnect, + EventChanged, +} + +impl std::fmt::Display for ProxyError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "({:?})", self) + } +} + +impl std::error::Error for ProxyError {} diff --git a/src/meexprox/event.rs b/src/meexprox/event.rs new file mode 100644 index 0000000..f497fdc --- /dev/null +++ b/src/meexprox/event.rs @@ -0,0 +1,230 @@ +use super::{MeexProx, MeexProxMutex, PlayerMutex, ProxyServer}; +use rust_mc_proto::Packet; +use std::{ + error::Error, + net::SocketAddr, + sync::atomic::{AtomicBool, Ordering}, +}; + +#[derive(Debug)] +pub enum ProxyEvent { + /// client <- proxy <- server \ + ///   | \ + ///   RecvServerPacketEvent + RecvServerPacketEvent { + packet: Packet, + player: PlayerMutex, + }, + + /// client -> proxy -> server \ + ///   | \ + ///   SendServerPacketEvent + SendServerPacketEvent { + packet: Packet, + player: PlayerMutex, + cancel: AtomicBool, + }, + + /// client <- proxy <- server \ + ///   | \ + ///   SendClientPacketEvent + SendClientPacketEvent { + packet: Packet, + player: PlayerMutex, + cancel: AtomicBool, + }, + + /// client -> proxy -> server \ + ///   | \ + ///   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_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 { + fn on_event( + &mut self, + meexprox: MeexProxMutex, + event: &mut ProxyEvent, + ) -> Result<(), Box>; +} diff --git a/src/meexprox/meexprox.rs b/src/meexprox/meexprox.rs new file mode 100644 index 0000000..3259f6f --- /dev/null +++ b/src/meexprox/meexprox.rs @@ -0,0 +1,665 @@ +use super::{EventListener, PlayerForwarding, ProxyConfig, ProxyError, ProxyEvent, ProxyServer}; +use derivative::Derivative; +use log::info; +use rust_mc_proto::{ + DataBufferReader, DataBufferWriter, MinecraftConnection, Packet, ProtocolError, Zigzag, +}; +use std::{ + error::Error, + net::{SocketAddr, TcpListener, TcpStream}, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, Mutex, + }, + thread, +}; +use uuid::Uuid; + +#[derive(Derivative)] +#[derivative(Debug)] +pub struct ProxyPlayer { + #[derivative(Debug = "ignore")] + client_conn: MinecraftConnection, + #[derivative(Debug = "ignore")] + server_conn: MinecraftConnection, + name: Option, + uuid: Option, + protocol_version: u16, + server: Option, + shared_secret: Option>, + verify_token: Option>, + connection_id: Arc, +} + +impl ProxyPlayer { + pub fn new( + client_conn: MinecraftConnection, + server_conn: MinecraftConnection, + name: Option, + uuid: Option, + protocol_version: u16, + server: Option, + shared_secret: Option>, + verify_token: Option>, + connection_id: Arc, + ) -> ProxyPlayer { + ProxyPlayer { + client_conn, + server_conn, + name, + uuid, + protocol_version, + server, + shared_secret, + verify_token, + connection_id, + } + } + + pub fn client_conn(&self) -> &MinecraftConnection { + &self.client_conn + } + + pub fn server_conn(&self) -> &MinecraftConnection { + &self.client_conn + } + + pub fn client_conn_mut(&mut self) -> &mut MinecraftConnection { + &mut self.client_conn + } + + pub fn server_conn_mut(&mut self) -> &mut MinecraftConnection { + &mut self.client_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> { + self.shared_secret.as_ref() + } + + pub fn verify_token(&self) -> Option<&Vec> { + self.verify_token.as_ref() + } + + pub fn connection_id(&self) -> Arc { + self.connection_id.clone() + } + + pub fn connect_to_ip( + this: PlayerMutex, + meexprox: MeexProxMutex, + ip: &str, + server_address: &str, + server_port: u16, + ) -> Result<(), Box> { + this.lock() + .unwrap() + .connection_id + .fetch_add(1, Ordering::Relaxed); + + 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> { + this.lock() + .unwrap() + .connection_id + .fetch_add(1, Ordering::Relaxed); + + this.lock().unwrap().server = Some(server.clone()); + + this.lock().unwrap().server_conn.close(); + 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> { + this.lock() + .unwrap() + .connection_id + .fetch_add(1, Ordering::Relaxed); + + this.lock().unwrap().server_conn.close(); + this.lock().unwrap().server_conn = + MinecraftConnection::connect(this.lock().unwrap().server().unwrap().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> { + 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 server = this.lock().unwrap().server.clone(); + + let addr = client_conn.get_ref().peer_addr().unwrap(); + let Some(name) = this.lock().unwrap().name.clone() else { + return Ok(()); + }; + let server_config = meexprox.lock().unwrap().config.clone(); + + let atomic_connection_id = this.lock().unwrap().connection_id.clone(); + let connection_id = this.lock().unwrap().connection_id.load(Ordering::Relaxed); + + 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)?; + } + } + + thread::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 atomic_connection_id = atomic_connection_id.clone(); + + move || { + let _ = || -> Result<(), ProtocolError> { + while atomic_connection_id.load(Ordering::Relaxed) == connection_id { + let packet = match client_conn.read_packet() { + Ok(packet) => packet, + Err(_) => break, + }; + + 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 { + server_conn.write_packet(&packet)?; + } + } + + Ok(()) + }(); + + if atomic_connection_id.load(Ordering::Relaxed) == connection_id { + if meexprox.lock().unwrap().remove_player(this.clone()) { + info!("{} disconnected player {}", addr.to_string(), name); + ProxyEvent::player_disconnected(meexprox.clone(), this.clone()); + } + } + } + }); + + let _ = || -> Result<(), ProtocolError> { + while atomic_connection_id.load(Ordering::Relaxed) == connection_id { + let packet = match server_conn.read_packet() { + Ok(packet) => packet, + Err(_) => break, + }; + + 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 { + client_conn.write_packet(&packet)?; + } + } + + Ok(()) + }(); + + if atomic_connection_id.load(Ordering::Relaxed) == connection_id { + if meexprox.lock().unwrap().remove_player(this.clone()) { + info!("{} disconnected player {}", addr.to_string(), name); + ProxyEvent::player_disconnected(meexprox.clone(), this.clone()); + } + } + + Ok(()) + } +} + +pub struct MeexProx { + config: ProxyConfig, + players: Vec, + event_listeners: Vec>, +} + +impl MeexProx { + pub fn new(config: ProxyConfig) -> MeexProx { + MeexProx { + config, + players: Vec::new(), + event_listeners: Vec::new(), + } + } + + pub fn add_event_listener(&mut self, event_listener: Box) { + self.event_listeners.push(event_listener); + } + + pub fn trigger_event(this: MeexProxMutex, mut event: ProxyEvent) -> ProxyEvent { + for event_listener in &mut this.lock().unwrap().event_listeners { + let _ = event_listener.on_event(this.clone(), &mut event); + } + event + } + + pub fn get_player(&self, uuid: Uuid) -> Option { + for player in &self.players { + 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 { + match self.players.iter().position(|x| Arc::ptr_eq(x, &player)) { + Some(i) => { + self.players.remove(i); + true + } + None => false, + } + } + + pub fn accept_client(this: MeexProxMutex, stream: TcpStream) -> Result<(), Box> { + 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 { + return Ok(()); + } + + let protocol_version = handshake.read_u16_varint()?; + let server_address = handshake.read_string()?; + let server_port = handshake.read_unsigned_short()?; + let next_state = handshake.read_u8_varint()?; + + let server = server_config + .get_server_by_forced_host(&server_address) + .or(server_config.default_server().cloned()) + .ok_or(ProxyError::ConfigParse)?; + + let mut server_conn = MinecraftConnection::connect(&server.host())?; + + let handshake = Packet::build(0x00, |handshake| { + handshake.write_u16_varint(protocol_version)?; + handshake.write_string(&server_address)?; + handshake.write_unsigned_short(server_port)?; + handshake.write_u8_varint(next_state)?; + + if let PlayerForwarding::Handshake = server_config.player_forwarding() { + if let SocketAddr::V4(addr) = addr { + handshake.write_boolean(false)?; // is ipv6 + handshake.write_unsigned_short(addr.port())?; // port + handshake.write_bytes(&addr.ip().octets())?; // octets + } else if let SocketAddr::V6(addr) = addr { + handshake.write_boolean(true)?; + handshake.write_unsigned_short(addr.port())?; + handshake.write_bytes(&addr.ip().octets())?; + } + } + + Ok(()) + })?; + + server_conn.write_packet(&handshake)?; + + if next_state == 1 { + loop { + let client_packet = client_conn.read_packet()?; + + 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 { + let player = Arc::new(Mutex::new(ProxyPlayer::new( + client_conn.try_clone().unwrap(), + server_conn.try_clone().unwrap(), + None, + None, + protocol_version, + Some(server.clone()), + None, + None, + Arc::new(AtomicUsize::new(0)), + ))); + + 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(()); + // } + + thread::spawn({ + let this = this.clone(); + + move || { + 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(()) + } + + pub fn start(self) { + let listener = TcpListener::bind(self.config.host()).expect("invalid host"); + + info!("meexprox started on {}", self.config.host()); + + let mutex_self = Arc::new(Mutex::new(self)); + + for client in listener.incoming() { + if let Ok(client) = client { + let mutex_self_clone = mutex_self.clone(); + thread::spawn(move || { + match Self::accept_client(mutex_self_clone, client) { + Ok(_) => {} + Err(_) => { + // error!("connection error: {:?}", e); + } + }; + }); + } + } + } +} + +pub type PlayerMutex = Arc>; +pub type MeexProxMutex = Arc>; diff --git a/src/meexprox/mod.rs b/src/meexprox/mod.rs new file mode 100644 index 0000000..9bf03bf --- /dev/null +++ b/src/meexprox/mod.rs @@ -0,0 +1,9 @@ +pub mod config; +pub mod error; +pub mod event; +pub mod meexprox; + +pub use config::*; +pub use error::*; +pub use event::*; +pub use meexprox::*;