feat: use port value of handshake to determine where to route the data
This commit is contained in:
parent
6c56b9e0e3
commit
402e315a93
3 changed files with 90 additions and 58 deletions
|
|
@ -11,7 +11,11 @@ use tracing::Instrument;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mc_server::{MinecraftAPI, MinecraftServerHandle, ServerDeploymentStatus},
|
mc_server::{MinecraftAPI, MinecraftServerHandle, ServerDeploymentStatus},
|
||||||
packets::{clientbound::status::StatusTrait, SendPacket},
|
packets::{
|
||||||
|
clientbound::status::StatusTrait,
|
||||||
|
serverbound::handshake::{self},
|
||||||
|
SendPacket,
|
||||||
|
},
|
||||||
OpaqueError,
|
OpaqueError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -57,15 +61,15 @@ impl KubeCache {
|
||||||
self.services.list(&lp).await.unwrap()
|
self.services.list(&lp).await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn query_dep_addr(&self, addr: &str) -> Option<String> {
|
pub async fn query_dep_addr(&self, addr: &str, port: &str) -> Option<String> {
|
||||||
let deploys = self.get_deploys().await;
|
let deploys = self.get_deploys().await;
|
||||||
let result = deploys.iter().find(|x| filter_label_value(x, addr))?;
|
let result = deploys.iter().find(|x| filter_label_value(x, addr, port))?;
|
||||||
Some(result.name()?.to_string())
|
Some(result.name()?.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn query_srv_addr(&self, addr: &str) -> Option<String> {
|
pub async fn query_srv_addr(&self, addr: &str, port: &str) -> Option<String> {
|
||||||
let deploys = self.get_srvs().await;
|
let deploys = self.get_srvs().await;
|
||||||
let result = deploys.iter().find(|x| filter_label_value(x, addr))?;
|
let result = deploys.iter().find(|x| filter_label_value(x, addr, port))?;
|
||||||
Some(result.name()?.to_string())
|
Some(result.name()?.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,9 +87,15 @@ pub struct McApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MinecraftAPI<Server> for McApi {
|
impl MinecraftAPI<Server> for McApi {
|
||||||
#[tracing::instrument(name = "MinecraftAPI::query_server", level = "info", skip(self, addr))]
|
#[tracing::instrument(
|
||||||
async fn query_server(&self, addr: &str) -> Result<Server, OpaqueError> {
|
name = "MinecraftAPI::query_server",
|
||||||
let dep_name = match self.cache.query_dep_addr(&addr).await {
|
level = "info",
|
||||||
|
skip(self, addr, port)
|
||||||
|
)]
|
||||||
|
async fn query_server(&self, addr: &str, port: &str) -> Result<Server, OpaqueError> {
|
||||||
|
let addr = sanitize_addr(&addr);
|
||||||
|
|
||||||
|
let dep_name = match self.cache.query_dep_addr(&addr, &port).await {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => {
|
None => {
|
||||||
return Err(OpaqueError::create(&format!(
|
return Err(OpaqueError::create(&format!(
|
||||||
|
|
@ -93,7 +103,7 @@ impl MinecraftAPI<Server> for McApi {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let srv_name = match self.cache.query_srv_addr(&addr).await {
|
let srv_name = match self.cache.query_srv_addr(&addr, &port).await {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => {
|
None => {
|
||||||
return Err(OpaqueError::create(&format!(
|
return Err(OpaqueError::create(&format!(
|
||||||
|
|
@ -130,6 +140,7 @@ impl MinecraftAPI<Server> for McApi {
|
||||||
frequency: Duration,
|
frequency: Duration,
|
||||||
) -> Result<(), OpaqueError> {
|
) -> Result<(), OpaqueError> {
|
||||||
let addr = server.get_addr().ok_or("could not get addr of server")?;
|
let addr = server.get_addr().ok_or("could not get addr of server")?;
|
||||||
|
let port = server.get_port().ok_or("could not get port of server")?;
|
||||||
if self.map.lock().await.get(&addr).is_none() {
|
if self.map.lock().await.get(&addr).is_none() {
|
||||||
let span = tracing::span!(parent: None,tracing::Level::INFO, "server_watcher", addr);
|
let span = tracing::span!(parent: None,tracing::Level::INFO, "server_watcher", addr);
|
||||||
|
|
||||||
|
|
@ -137,7 +148,7 @@ impl MinecraftAPI<Server> for McApi {
|
||||||
async move {
|
async move {
|
||||||
tracing::info!("starting watch");
|
tracing::info!("starting watch");
|
||||||
tokio::time::sleep(frequency).await;
|
tokio::time::sleep(frequency).await;
|
||||||
let server = self.query_server(&addr).await.unwrap();
|
let server = self.query_server(&addr, &port).await.unwrap();
|
||||||
let status_json = match server.query_description().await {
|
let status_json = match server.query_description().await {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -274,9 +285,7 @@ impl MinecraftServerHandle for Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_internal_address(&self) -> Option<String> {
|
fn get_internal_address(&self) -> Option<String> {
|
||||||
let a = self.srv.clone().spec.unwrap().ports.unwrap();
|
Some(format!("localhost:{}", self.get_port()?))
|
||||||
let port = a.iter().find(|x| x.name.clone().unwrap() == "mc-router")?;
|
|
||||||
Some(format!("localhost:{}", port.node_port?))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_addr(&self) -> Option<String> {
|
fn get_addr(&self) -> Option<String> {
|
||||||
|
|
@ -324,6 +333,12 @@ impl MinecraftServerHandle for Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_port(&self) -> Option<String> {
|
||||||
|
let a = self.srv.clone().spec.unwrap().ports.unwrap();
|
||||||
|
let port = a.iter().find(|x| x.name.clone().unwrap() == "mc-router")?;
|
||||||
|
port.node_port.map(|x| x.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
|
|
@ -342,11 +357,23 @@ impl Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_label_value<R>(dep: &&R, str: &str) -> bool
|
fn filter_label_value<R>(res: &&R, addr: &str, port: &str) -> bool
|
||||||
where
|
where
|
||||||
R: ResourceExt,
|
R: ResourceExt,
|
||||||
{
|
{
|
||||||
dep.labels().values().filter(|x| x.as_str() == str).count() > 0
|
let mut found_port = false;
|
||||||
|
res.labels()
|
||||||
|
.iter()
|
||||||
|
.filter(|(key, value)| match key.as_str() {
|
||||||
|
"tami.moe/minecraft" => value.as_str() == addr,
|
||||||
|
"tami.moe/minecraft-port" => {
|
||||||
|
found_port = true;
|
||||||
|
value.as_str() == port
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
.count()
|
||||||
|
> 0
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ServerDeploymentStatus {
|
impl fmt::Debug for ServerDeploymentStatus {
|
||||||
|
|
@ -364,3 +391,34 @@ impl From<kube::Error> for OpaqueError {
|
||||||
OpaqueError::create(value.to_string().as_str())
|
OpaqueError::create(value.to_string().as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn terminate_at_null(str: &str) -> &str {
|
||||||
|
match str.split('\0').next() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => str,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sanitize_addr(addr: &str) -> &str {
|
||||||
|
// Thanks to a buggy minecraft, when the client sends a join
|
||||||
|
// from a SRV DNS record, it will not use the address typed
|
||||||
|
// in the game, but use the address redicted *to* by the
|
||||||
|
// DNS record as the address for joining, plus a trailing "."
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// server.example.com (_minecraft._tcp.server.example.com)
|
||||||
|
// (the typed address) I (the DNS SRV record which gets read)
|
||||||
|
// V
|
||||||
|
// 5 25565 server.example.com
|
||||||
|
// I (the response for the DNS SRV query)
|
||||||
|
// V
|
||||||
|
// server.example.com.
|
||||||
|
// (the address used in the protocol)
|
||||||
|
let addr = addr.trim_end_matches(".");
|
||||||
|
|
||||||
|
// Modded minecraft clients send null terminated strings,
|
||||||
|
// after which they have extra data. This just removes them
|
||||||
|
// from the addr lookup
|
||||||
|
let addr = terminate_at_null(addr);
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
|
|
||||||
52
src/main.rs
52
src/main.rs
|
|
@ -109,7 +109,7 @@ async fn process_connection<T: MinecraftServerHandle>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "info", fields(server_addr = handshake.get_server_address()),skip(client_stream, handshake, api))]
|
#[tracing::instrument(level = "info", fields(server_addr = handshake.get_server_address(),server_port = handshake.server_port.get_value()),skip(client_stream, handshake, api))]
|
||||||
async fn handle_status<T: MinecraftServerHandle>(
|
async fn handle_status<T: MinecraftServerHandle>(
|
||||||
client_stream: &mut TcpStream,
|
client_stream: &mut TcpStream,
|
||||||
handshake: &Handshake,
|
handshake: &Handshake,
|
||||||
|
|
@ -124,13 +124,18 @@ async fn handle_status<T: MinecraftServerHandle>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let server_addr = handshake.get_server_address();
|
let server_addr = handshake.get_server_address();
|
||||||
let server_addr = sanitize_addr(&server_addr);
|
|
||||||
let commit_hash: &'static str = env!("COMMIT_HASH");
|
let commit_hash: &'static str = env!("COMMIT_HASH");
|
||||||
let mut status_struct = StatusStructNew::create();
|
let mut status_struct = StatusStructNew::create();
|
||||||
status_struct.version.protocol = handshake.protocol_version.get_int();
|
status_struct.version.protocol = handshake.protocol_version.get_int();
|
||||||
let bye_message = format!(" - §dTami§r with §d<3§r §8(rev: {commit_hash})§r");
|
let bye_message = format!(" - §dTami§r with §d<3§r §8(rev: {commit_hash})§r");
|
||||||
|
|
||||||
let server = match api.query_server(server_addr).await {
|
let server = match api
|
||||||
|
.query_server(
|
||||||
|
&handshake.get_server_address(),
|
||||||
|
&handshake.server_port.get_value().to_string(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::warn!(err = e.context);
|
tracing::warn!(err = e.context);
|
||||||
|
|
@ -166,8 +171,7 @@ async fn handle_status<T: MinecraftServerHandle>(
|
||||||
ServerDeploymentStatus::Starting | ServerDeploymentStatus::PodOk => {
|
ServerDeploymentStatus::Starting | ServerDeploymentStatus::PodOk => {
|
||||||
status_struct.players.max = 1;
|
status_struct.players.max = 1;
|
||||||
status_struct.players.online = 1;
|
status_struct.players.online = 1;
|
||||||
status_struct.description.text =
|
status_struct.description.text = format!("\n§2Server is starting...§r{bye_message}");
|
||||||
format!("§aServer is starting...§r please wait\n{bye_message}");
|
|
||||||
}
|
}
|
||||||
ServerDeploymentStatus::Offline => {
|
ServerDeploymentStatus::Offline => {
|
||||||
status_struct.players.max = 1;
|
status_struct.players.max = 1;
|
||||||
|
|
@ -181,14 +185,17 @@ async fn handle_status<T: MinecraftServerHandle>(
|
||||||
return mc_server::handle_ping(client_stream).await;
|
return mc_server::handle_ping(client_stream).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "info", fields(server_addr = handshake.get_server_address()),skip(client_stream, handshake, api))]
|
#[tracing::instrument(level = "info", fields(server_addr = handshake.get_server_address(),server_port = handshake.server_port.get_value()),skip(client_stream, handshake, api))]
|
||||||
async fn handle_login<T: MinecraftServerHandle>(
|
async fn handle_login<T: MinecraftServerHandle>(
|
||||||
client_stream: &mut TcpStream,
|
client_stream: &mut TcpStream,
|
||||||
handshake: &Handshake,
|
handshake: &Handshake,
|
||||||
api: impl MinecraftAPI<T>,
|
api: impl MinecraftAPI<T>,
|
||||||
) -> Result<(), OpaqueError> {
|
) -> Result<(), OpaqueError> {
|
||||||
let server = api
|
let server = api
|
||||||
.query_server(sanitize_addr(&handshake.get_server_address()))
|
.query_server(
|
||||||
|
&handshake.get_server_address(),
|
||||||
|
&handshake.server_port.get_value().to_string(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let status = server.query_status().await?;
|
let status = server.query_status().await?;
|
||||||
|
|
@ -235,34 +242,3 @@ async fn handle_login<T: MinecraftServerHandle>(
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminate_at_null(str: &str) -> &str {
|
|
||||||
match str.split('\0').next() {
|
|
||||||
Some(x) => x,
|
|
||||||
None => str,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sanitize_addr(addr: &str) -> &str {
|
|
||||||
// Thanks to a buggy minecraft, when the client sends a join
|
|
||||||
// from a SRV DNS record, it will not use the address typed
|
|
||||||
// in the game, but use the address redicted *to* by the
|
|
||||||
// DNS record as the address for joining, plus a trailing "."
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
// server.example.com (_minecraft._tcp.server.example.com)
|
|
||||||
// (the typed address) I (the DNS SRV record which gets read)
|
|
||||||
// V
|
|
||||||
// 5 25565 server.example.com
|
|
||||||
// I (the response for the DNS SRV query)
|
|
||||||
// V
|
|
||||||
// server.example.com.
|
|
||||||
// (the address used in the protocol)
|
|
||||||
let addr = addr.trim_end_matches(".");
|
|
||||||
|
|
||||||
// Modded minecraft clients send null terminated strings,
|
|
||||||
// after which they have extra data. This just removes them
|
|
||||||
// from the addr lookup
|
|
||||||
let addr = terminate_at_null(addr);
|
|
||||||
addr
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use tokio::{io::AsyncWriteExt, net::TcpStream};
|
use tokio::{io::AsyncWriteExt, net::TcpStream};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mc_server,
|
|
||||||
packets::{
|
packets::{
|
||||||
clientbound::status::{StatusStructNew, StatusTrait},
|
clientbound::status::{StatusStructNew, StatusTrait},
|
||||||
serverbound::handshake::Handshake,
|
serverbound::handshake::{self, Handshake},
|
||||||
Packet, SendPacket,
|
Packet, SendPacket,
|
||||||
},
|
},
|
||||||
OpaqueError,
|
OpaqueError,
|
||||||
|
|
@ -71,6 +68,7 @@ pub trait MinecraftServerHandle: Clone {
|
||||||
async fn query_status(&self) -> Result<ServerDeploymentStatus, OpaqueError>;
|
async fn query_status(&self) -> Result<ServerDeploymentStatus, OpaqueError>;
|
||||||
fn get_internal_address(&self) -> Option<String>;
|
fn get_internal_address(&self) -> Option<String>;
|
||||||
fn get_addr(&self) -> Option<String>;
|
fn get_addr(&self) -> Option<String>;
|
||||||
|
fn get_port(&self) -> Option<String>;
|
||||||
|
|
||||||
async fn query_server_connectable(&self) -> Result<TcpStream, OpaqueError> {
|
async fn query_server_connectable(&self) -> Result<TcpStream, OpaqueError> {
|
||||||
let address = self
|
let address = self
|
||||||
|
|
@ -124,7 +122,7 @@ pub trait MinecraftServerHandle: Clone {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MinecraftAPI<T> {
|
pub trait MinecraftAPI<T> {
|
||||||
async fn query_server(&self, addr: &str) -> Result<T, OpaqueError>;
|
async fn query_server(&self, addr: &str, port: &str) -> Result<T, OpaqueError>;
|
||||||
async fn start_watch(
|
async fn start_watch(
|
||||||
self,
|
self,
|
||||||
server: impl MinecraftServerHandle,
|
server: impl MinecraftServerHandle,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue