Show MOTD for banned players, kick with reason on login
This commit is contained in:
parent
e816d4ff6c
commit
28dbcdbfd6
10
src/lobby.rs
10
src/lobby.rs
@ -588,11 +588,15 @@ async fn connect_to_server_no_timeout(
|
|||||||
.await
|
.await
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ())?;
|
||||||
|
|
||||||
let (mut reader, mut writer) = outbound.split();
|
// Construct temporary server client
|
||||||
|
let tmp_client = match outbound.local_addr() {
|
||||||
let tmp_client = Client::default();
|
Ok(addr) => Client::new(addr),
|
||||||
|
Err(_) => Client::dummy(),
|
||||||
|
};
|
||||||
tmp_client.set_state(ClientState::Login);
|
tmp_client.set_state(ClientState::Login);
|
||||||
|
|
||||||
|
let (mut reader, mut writer) = outbound.split();
|
||||||
|
|
||||||
// Handshake packet
|
// Handshake packet
|
||||||
packet::write_packet(
|
packet::write_packet(
|
||||||
Handshake {
|
Handshake {
|
||||||
|
@ -17,6 +17,14 @@ pub struct BannedIps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BannedIps {
|
impl BannedIps {
|
||||||
|
/// Get ban entry if IP if it exists.
|
||||||
|
///
|
||||||
|
/// This uses the latest known `banned-ips.json` contents if known.
|
||||||
|
/// If this feature is disabled, this will always return false.
|
||||||
|
pub fn get(&self, ip: &IpAddr) -> Option<BannedIp> {
|
||||||
|
self.ips.get(ip).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
/// Check whether the given IP is banned.
|
/// Check whether the given IP is banned.
|
||||||
///
|
///
|
||||||
/// This uses the latest known `banned-ips.json` contents if known.
|
/// This uses the latest known `banned-ips.json` contents if known.
|
||||||
@ -27,7 +35,7 @@ impl BannedIps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A banned IP entry.
|
/// A banned IP entry.
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
pub struct BannedIp {
|
pub struct BannedIp {
|
||||||
/// Banned IP.
|
/// Banned IP.
|
||||||
pub ip: IpAddr,
|
pub ip: IpAddr,
|
||||||
|
@ -98,7 +98,7 @@ async fn fetch_status(config: &Config, addr: SocketAddr) -> Result<ServerStatus,
|
|||||||
let mut stream = TcpStream::connect(addr).await.map_err(|_| ())?;
|
let mut stream = TcpStream::connect(addr).await.map_err(|_| ())?;
|
||||||
|
|
||||||
// Dummy client
|
// Dummy client
|
||||||
let client = Client::default();
|
let client = Client::dummy();
|
||||||
|
|
||||||
send_handshake(&client, &mut stream, config, addr).await?;
|
send_handshake(&client, &mut stream, config, addr).await?;
|
||||||
request_status(&client, &mut stream).await?;
|
request_status(&client, &mut stream).await?;
|
||||||
@ -110,7 +110,7 @@ async fn do_ping(config: &Config, addr: SocketAddr) -> Result<(), ()> {
|
|||||||
let mut stream = TcpStream::connect(addr).await.map_err(|_| ())?;
|
let mut stream = TcpStream::connect(addr).await.map_err(|_| ())?;
|
||||||
|
|
||||||
// Dummy client
|
// Dummy client
|
||||||
let client = Client::default();
|
let client = Client::dummy();
|
||||||
|
|
||||||
send_handshake(&client, &mut stream, config, addr).await?;
|
send_handshake(&client, &mut stream, config, addr).await?;
|
||||||
let token = send_ping(&client, &mut stream).await?;
|
let token = send_ping(&client, &mut stream).await?;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::net::SocketAddr;
|
||||||
use std::sync::atomic::{AtomicI32, Ordering};
|
use std::sync::atomic::{AtomicI32, Ordering};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
@ -6,6 +7,9 @@ use std::sync::Mutex;
|
|||||||
/// Note: this does not keep track of encryption states.
|
/// Note: this does not keep track of encryption states.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
|
/// Client peer address.
|
||||||
|
pub peer: SocketAddr,
|
||||||
|
|
||||||
/// Current client state.
|
/// Current client state.
|
||||||
pub state: Mutex<ClientState>,
|
pub state: Mutex<ClientState>,
|
||||||
|
|
||||||
@ -16,6 +20,20 @@ pub struct Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
|
/// Construct new client with given peer address.
|
||||||
|
pub fn new(peer: SocketAddr) -> Self {
|
||||||
|
Self {
|
||||||
|
peer,
|
||||||
|
state: Default::default(),
|
||||||
|
compression: AtomicI32::new(-1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct dummy client.
|
||||||
|
pub fn dummy() -> Self {
|
||||||
|
Self::new("0.0.0.0:0".parse().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
/// Get client state.
|
/// Get client state.
|
||||||
pub fn state(&self) -> ClientState {
|
pub fn state(&self) -> ClientState {
|
||||||
*self.state.lock().unwrap()
|
*self.state.lock().unwrap()
|
||||||
@ -44,15 +62,6 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Client {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
state: Default::default(),
|
|
||||||
compression: AtomicI32::new(-1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Protocol state a client may be in.
|
/// Protocol state a client may be in.
|
||||||
///
|
///
|
||||||
/// Note: this does not include the `play` state, because this is never used anymore when a client
|
/// Note: this does not include the `play` state, because this is never used anymore when a client
|
||||||
|
@ -13,7 +13,7 @@ use tokio::sync::{Mutex, RwLock, RwLockReadGuard};
|
|||||||
use tokio::time;
|
use tokio::time;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::mc::ban::BannedIps;
|
use crate::mc::ban::{BannedIp, BannedIps};
|
||||||
use crate::os;
|
use crate::os;
|
||||||
|
|
||||||
/// Server cooldown after the process quit.
|
/// Server cooldown after the process quit.
|
||||||
@ -320,6 +320,11 @@ impl Server {
|
|||||||
self.banned_ips.read().await.is_banned(ip)
|
self.banned_ips.read().await.is_banned(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get user ban entry.
|
||||||
|
pub async fn ban_entry(&self, ip: &IpAddr) -> Option<BannedIp> {
|
||||||
|
self.banned_ips.read().await.get(ip)
|
||||||
|
}
|
||||||
|
|
||||||
/// Check whether the given IP is banned.
|
/// Check whether the given IP is banned.
|
||||||
///
|
///
|
||||||
/// This uses the latest known `banned-ips.json` contents if known.
|
/// This uses the latest known `banned-ips.json` contents if known.
|
||||||
|
@ -70,48 +70,33 @@ pub async fn service(config: Arc<Config>) -> Result<(), ()> {
|
|||||||
/// Route inbound TCP stream to correct service, spawning a new task.
|
/// Route inbound TCP stream to correct service, spawning a new task.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn route(inbound: TcpStream, config: Arc<Config>, server: Arc<Server>) {
|
fn route(inbound: TcpStream, config: Arc<Config>, server: Arc<Server>) {
|
||||||
// Check ban
|
|
||||||
if !check_ban(&inbound, &server) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Route connection through proper channel
|
|
||||||
let should_proxy = server.state() == server::State::Started && !config.lockout.enabled;
|
|
||||||
if should_proxy {
|
|
||||||
route_proxy(inbound, config)
|
|
||||||
} else {
|
|
||||||
route_status(inbound, config, server)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check whether user IP is banned.
|
|
||||||
///
|
|
||||||
/// Returns `true` if user is still allowed to connect.
|
|
||||||
fn check_ban(inbound: &TcpStream, server: &Server) -> bool {
|
|
||||||
// Get user peer address
|
// Get user peer address
|
||||||
let peer = match inbound.peer_addr() {
|
let peer = match inbound.peer_addr() {
|
||||||
Ok(peer) => peer,
|
Ok(peer) => peer,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(target: "lazymc", "Connection from unknown peer, disconnecting: {}", err);
|
warn!(target: "lazymc", "Connection from unknown peer address, disconnecting: {}", err);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if user is banned
|
// Check ban state
|
||||||
let is_banned = server.is_banned_ip_blocking(&peer.ip());
|
let banned = server.is_banned_ip_blocking(&peer.ip());
|
||||||
if is_banned {
|
|
||||||
warn!(target: "lazymc", "Connection from banned IP {}, disconnecting", peer);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
// Route connection through proper channel
|
||||||
|
let should_proxy =
|
||||||
|
!banned && server.state() == server::State::Started && !config.lockout.enabled;
|
||||||
|
if should_proxy {
|
||||||
|
route_proxy(inbound, config)
|
||||||
|
} else {
|
||||||
|
route_status(inbound, config, server, peer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Route inbound TCP stream to status server, spawning a new task.
|
/// Route inbound TCP stream to status server, spawning a new task.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn route_status(inbound: TcpStream, config: Arc<Config>, server: Arc<Server>) {
|
fn route_status(inbound: TcpStream, config: Arc<Config>, server: Arc<Server>, peer: SocketAddr) {
|
||||||
// When server is not online, spawn a status server
|
// When server is not online, spawn a status server
|
||||||
let client = Client::default();
|
let client = Client::new(peer);
|
||||||
let service = status::serve(client, inbound, config, server).map(|r| {
|
let service = status::serve(client, inbound, config, server).map(|r| {
|
||||||
if let Err(err) = r {
|
if let Err(err) = r {
|
||||||
warn!(target: "lazymc", "Failed to serve status: {:?}", err);
|
warn!(target: "lazymc", "Failed to serve status: {:?}", err);
|
||||||
|
@ -127,6 +127,15 @@ pub async fn serve(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Kick if client is banned
|
||||||
|
if let Some(ban) = server.ban_entry(&client.peer.ip()).await {
|
||||||
|
if ban.is_banned() {
|
||||||
|
warn!(target: "lazymc", "Login from banned IP {} ({}), disconnecting", client.peer.ip(), &ban.reason);
|
||||||
|
action::kick(&client, &ban.reason, &mut writer).await?;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start server if not starting yet
|
// Start server if not starting yet
|
||||||
Server::start(config.clone(), server.clone(), username).await;
|
Server::start(config.clone(), server.clone(), username).await;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user