aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.rs16
-rw-r--r--src/main.rs180
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?;
+ }
+}