Add join forward method to proxy to other address while server starts
This commit is contained in:
parent
32cd9ffc73
commit
db99289ea7
@ -39,6 +39,7 @@ https://user-images.githubusercontent.com/856222/141378688-882082be-9efa-4cfe-81
|
|||||||
- Configure joining client occupation methods:
|
- Configure joining client occupation methods:
|
||||||
- Hold: hold clients when server starts, relay when ready, without them noticing
|
- Hold: hold clients when server starts, relay when ready, without them noticing
|
||||||
- Kick: kick clients when server starts, with a starting message
|
- Kick: kick clients when server starts, with a starting message
|
||||||
|
- Forward: forward client to another IP when server starts
|
||||||
- Customizable MOTD and login messages
|
- Customizable MOTD and login messages
|
||||||
- Automatically manages `server.properties` (host, port and RCON settings)
|
- Automatically manages `server.properties` (host, port and RCON settings)
|
||||||
- Graceful server sleep/shutdown through RCON (with `SIGTERM` fallback on Linux/Unix)
|
- Graceful server sleep/shutdown through RCON (with `SIGTERM` fallback on Linux/Unix)
|
||||||
|
@ -87,6 +87,16 @@ command = "java -Xmx1G -Xms1G -jar server.jar --nogui"
|
|||||||
# Keep below Minecraft timeout of 30 seconds.
|
# Keep below Minecraft timeout of 30 seconds.
|
||||||
#timeout = 25
|
#timeout = 25
|
||||||
|
|
||||||
|
[join.forward]
|
||||||
|
# Forward occupation method.
|
||||||
|
# Instantly forwards (proxies) the client to a different address.
|
||||||
|
# You may need to configure target server for it, such as allowing proxies.
|
||||||
|
# Consumes client, not allowing other join methods afterwards.
|
||||||
|
|
||||||
|
# IP and port to forward to.
|
||||||
|
# Forwarded-to server will receive original client handshake and login request as received by lazymc.
|
||||||
|
#address = "127.0.0.1:25565"
|
||||||
|
|
||||||
[lockout]
|
[lockout]
|
||||||
# Enable to prevent everybody from connecting through lazymc. Instantly kicks player.
|
# Enable to prevent everybody from connecting through lazymc. Instantly kicks player.
|
||||||
#enabled = false
|
#enabled = false
|
||||||
|
@ -230,8 +230,14 @@ impl Default for Motd {
|
|||||||
#[derive(Debug, Deserialize, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Deserialize, Copy, Clone, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum Method {
|
pub enum Method {
|
||||||
Hold,
|
/// Kick client with message.
|
||||||
Kick,
|
Kick,
|
||||||
|
|
||||||
|
/// Hold client connection until server is ready.
|
||||||
|
Hold,
|
||||||
|
|
||||||
|
/// Forward connection to another host.
|
||||||
|
Forward,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Join configuration.
|
/// Join configuration.
|
||||||
@ -248,6 +254,10 @@ pub struct Join {
|
|||||||
/// Join hold configuration.
|
/// Join hold configuration.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub hold: JoinHold,
|
pub hold: JoinHold,
|
||||||
|
|
||||||
|
/// Join forward configuration.
|
||||||
|
#[serde(default)]
|
||||||
|
pub forward: JoinForward,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Join {
|
impl Default for Join {
|
||||||
@ -256,6 +266,7 @@ impl Default for Join {
|
|||||||
methods: vec![Method::Hold, Method::Kick],
|
methods: vec![Method::Hold, Method::Kick],
|
||||||
kick: Default::default(),
|
kick: Default::default(),
|
||||||
hold: Default::default(),
|
hold: Default::default(),
|
||||||
|
forward: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,6 +305,22 @@ impl Default for JoinHold {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Join forward configuration.
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct JoinForward {
|
||||||
|
/// IP and port to forward to.
|
||||||
|
pub address: SocketAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for JoinForward {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
address: "127.0.0.1:25565".parse().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Lockout configuration.
|
/// Lockout configuration.
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::net::SocketAddr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
@ -103,9 +104,15 @@ fn route_proxy(inbound: TcpStream, config: Arc<Config>) {
|
|||||||
/// Route inbound TCP stream to proxy with queued data, spawning a new task.
|
/// Route inbound TCP stream to proxy with queued data, spawning a new task.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn route_proxy_queue(inbound: TcpStream, config: Arc<Config>, queue: BytesMut) {
|
pub fn route_proxy_queue(inbound: TcpStream, config: Arc<Config>, queue: BytesMut) {
|
||||||
|
route_proxy_address_queue(inbound, config.server.address, queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Route inbound TCP stream to proxy with given address and queued data, spawning a new task.
|
||||||
|
#[inline]
|
||||||
|
pub fn route_proxy_address_queue(inbound: TcpStream, addr: SocketAddr, queue: BytesMut) {
|
||||||
// When server is online, proxy all
|
// When server is online, proxy all
|
||||||
let service = async move {
|
let service = async move {
|
||||||
proxy::proxy_with_queue(inbound, config.server.address, &queue)
|
proxy::proxy_with_queue(inbound, addr, &queue)
|
||||||
.map(|r| {
|
.map(|r| {
|
||||||
if let Err(err) = r {
|
if let Err(err) = r {
|
||||||
warn!(target: "lazymc", "Failed to proxy: {}", err);
|
warn!(target: "lazymc", "Failed to proxy: {}", err);
|
||||||
|
@ -31,10 +31,13 @@ pub async fn serve(
|
|||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let (mut reader, mut writer) = inbound.split();
|
let (mut reader, mut writer) = inbound.split();
|
||||||
|
|
||||||
// Incoming buffer and packet holding queue
|
// Incoming buffer
|
||||||
let mut buf = BytesMut::new();
|
let mut buf = BytesMut::new();
|
||||||
let may_hold = config.join.methods.contains(&Method::Hold);
|
|
||||||
let mut hold_queue = BytesMut::new();
|
// Remember inbound packets, used for client holding and forwarding
|
||||||
|
let remember_inbound = config.join.methods.contains(&Method::Hold)
|
||||||
|
|| config.join.methods.contains(&Method::Forward);
|
||||||
|
let mut inbound_history = BytesMut::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Read packet from stream
|
// Read packet from stream
|
||||||
@ -71,8 +74,8 @@ pub async fn serve(
|
|||||||
client.set_state(new_state);
|
client.set_state(new_state);
|
||||||
|
|
||||||
// If login handshake and holding is enabled, hold packets
|
// If login handshake and holding is enabled, hold packets
|
||||||
if new_state == ClientState::Login && may_hold {
|
if new_state == ClientState::Login && remember_inbound {
|
||||||
hold_queue.extend(raw);
|
inbound_history.extend(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -123,26 +126,6 @@ pub async fn serve(
|
|||||||
// Use join occupy methods
|
// Use join occupy methods
|
||||||
for method in &config.join.methods {
|
for method in &config.join.methods {
|
||||||
match method {
|
match method {
|
||||||
// Hold method, hold client connection while server starts
|
|
||||||
Method::Hold => {
|
|
||||||
trace!(target: "lazymc", "Using hold method to occupy joining client");
|
|
||||||
|
|
||||||
// Server must be starting
|
|
||||||
if server.state() != State::Starting {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hold login packet and remaining read bytes
|
|
||||||
hold_queue.extend(&raw);
|
|
||||||
hold_queue.extend(buf.split_off(0));
|
|
||||||
|
|
||||||
// Start holding
|
|
||||||
if hold(&config, &server).await? {
|
|
||||||
service::server::route_proxy_queue(inbound, config, hold_queue);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kick method, immediately kick client
|
// Kick method, immediately kick client
|
||||||
Method::Kick => {
|
Method::Kick => {
|
||||||
trace!(target: "lazymc", "Using kick method to occupy joining client");
|
trace!(target: "lazymc", "Using kick method to occupy joining client");
|
||||||
@ -157,6 +140,47 @@ pub async fn serve(
|
|||||||
kick(msg, &mut writer).await?;
|
kick(msg, &mut writer).await?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hold method, hold client connection while server starts
|
||||||
|
Method::Hold => {
|
||||||
|
trace!(target: "lazymc", "Using hold method to occupy joining client");
|
||||||
|
|
||||||
|
// Server must be starting
|
||||||
|
if server.state() != State::Starting {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hold login packet and remaining read bytes
|
||||||
|
inbound_history.extend(&raw);
|
||||||
|
inbound_history.extend(buf.split_off(0));
|
||||||
|
|
||||||
|
// Start holding
|
||||||
|
if hold(&config, &server).await? {
|
||||||
|
service::server::route_proxy_queue(inbound, config, inbound_history);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward method, forward client connection while server starts
|
||||||
|
Method::Forward => {
|
||||||
|
trace!(target: "lazymc", "Using forward method to occupy joining client");
|
||||||
|
|
||||||
|
// Hold login packet and remaining read bytes
|
||||||
|
inbound_history.extend(&raw);
|
||||||
|
inbound_history.extend(buf.split_off(0));
|
||||||
|
|
||||||
|
// Forward client
|
||||||
|
debug!(target: "lazymc", "Forwarding client to {:?}!", config.join.forward.address);
|
||||||
|
|
||||||
|
service::server::route_proxy_address_queue(
|
||||||
|
inbound,
|
||||||
|
config.join.forward.address,
|
||||||
|
inbound_history,
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
|
||||||
|
// TODO: do not consume client here, allow other join method on fail
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user