diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config.rs | 16 | ||||
-rw-r--r-- | src/main.rs | 180 |
2 files changed, 196 insertions, 0 deletions
diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..45ed6f2 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,16 @@ +use std::net::SocketAddr; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub backend: SocketAddr, + pub bind: SocketAddr, + pub whitelist: Vec<PlayerConfig>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PlayerConfig { + pub token: Option<String>, + pub username: String, +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d79e98f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,180 @@ +pub mod config; + +use anyhow::bail; +use azalea_protocol::packets::handshake::ServerboundHandshakePacket; +use azalea_protocol::packets::login::ServerboundLoginPacket; +use azalea_protocol::packets::ConnectionProtocol; +use azalea_protocol::read::read_packet; +use azalea_protocol::write::write_packet; +use bytes::BytesMut; +use config::Config; +use log::{error, info, warn}; +use std::fs::read_to_string; +use std::net::SocketAddr; +use std::sync::Arc; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; +use tokio::net::{TcpListener, TcpStream}; + +#[tokio::main] +async fn main() { + env_logger::init_from_env("LOG"); + + let config = + Arc::new(serde_yaml::from_str::<Config>(&read_to_string("proxy.yaml").unwrap()).unwrap()); + + let listener = TcpListener::bind("127.0.0.1:25565").await.unwrap(); + info!("listening"); + loop { + match listener.accept().await { + Ok((sock, addr)) => { + let config = config.clone(); + tokio::spawn(async move { + match handle_client(config, sock, addr).await { + Ok(()) => (), + Err(e) => warn!("{e}"), + } + }); + } + Err(e) => error!("{}", e), + } + } +} + +async fn handle_client( + config: Arc<Config>, + sock: TcpStream, + addr: SocketAddr, +) -> anyhow::Result<()> { + info!("connection {addr}"); + let mut buf = BytesMut::new(); + let (mut downstream_reader, downstream_writer) = sock.into_split(); + + let handshake = read_packet::<ServerboundHandshakePacket, _>( + &mut downstream_reader, + &mut buf, + None, + &mut None, + ) + .await?; + let upstream_handshake = match handshake { + ServerboundHandshakePacket::ClientIntention(p) => { + info!( + "new client (version={}, intent={:?})", + p.protocol_version, p.intention + ); + match p.intention { + ConnectionProtocol::Status => { + bail!("we dont support ping yet") + } + ConnectionProtocol::Login => {} + _ => bail!("invalid intent"), + } + p + } + }; + + let login = + read_packet::<ServerboundLoginPacket, _>(&mut downstream_reader, &mut buf, None, &mut None) + .await?; + let upstream_login = match login { + ServerboundLoginPacket::Hello(mut p) => { + info!("client hello (username={:?})", p.username); + + let profile = config + .whitelist + .iter() + .find(|e| e.token.as_ref().map_or(false, |e| e == &p.username)); + + match profile { + Some(profile) => { + warn!("auth as {}", profile.username); + p.username = profile.username.clone(); + } + None => { + warn!("no profile found, disconnecting client"); + return Ok(()); + } + } + p + } + ServerboundLoginPacket::Key(_) => bail!("key not supported"), + ServerboundLoginPacket::CustomQuery(_) => bail!("custom query not supported"), + }; + + let upstream = TcpStream::connect("127.0.0.1:25567").await?; + let (upstream_reader, mut upstream_writer) = upstream.into_split(); + + write_packet( + &ServerboundHandshakePacket::ClientIntention(upstream_handshake), + &mut upstream_writer, + None, + &mut None, + ) + .await?; + + write_packet::<ServerboundLoginPacket, _>( + &ServerboundLoginPacket::Hello(upstream_login), + &mut upstream_writer, + None, + &mut None, + ) + .await?; + + tokio::spawn(async move { + connect(downstream_writer, upstream_reader).await.unwrap(); + }); + + connect(upstream_writer, downstream_reader).await?; + + Ok(()) + // for _ in 0..3 { + // let a = read_packet::<ClientboundLoginPacket, _>( + // &mut upstream_reader, + // &mut buf, + // None, + // &mut None, + // ) + // .await?; + // debug!("login {a:?}"); + // write_packet(&a, &mut downstream_writer, None, &mut None).await?; + // } + + // tokio::spawn(async move { + // let mut buf = BytesMut::new(); + // loop { + // let a = read_packet::<ClientboundGamePacket, _>( + // &mut upstream_reader, + // &mut buf, + // None, + // &mut None, + // ) + // .await + // .unwrap(); + // debug!("downstream {a:?}"); + // write_packet(&a, &mut downstream_writer, None, &mut None) + // .await + // .unwrap(); + // } + // }); + + // loop { + // let a = read_packet::<ClientboundGamePacket, _>( + // &mut downstream_reader, + // &mut buf, + // None, + // &mut None, + // ) + // .await?; + // debug!("upstream {a:?}"); + // write_packet(&a, &mut upstream_writer, None, &mut None).await?; + // } +} + +async fn connect(mut writer: OwnedWriteHalf, mut reader: OwnedReadHalf) -> anyhow::Result<()> { + let mut buf = [0; 1024]; + loop { + let size = reader.read(&mut buf).await?; + writer.write_all(&buf[..size]).await?; + } +} |