Implement prevent-proxy-connections

This adds the `prevent-proxy-connections` server property and implements it into valence.

Note that if the server is in offline mode, this changes nothing.

By default, proxy connections are allowed.

Fixes #95
This commit is contained in:
Terminator 2022-10-01 19:42:43 +02:00 committed by GitHub
parent 838a75d2f9
commit ef64296159
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 6 deletions

View file

@ -95,6 +95,20 @@ pub trait Config: Sized + Send + Sync + UnwindSafe + RefUnwindSafe + 'static {
true true
} }
/// Called once at startup to get the "prevent-proxy-connections" option,
/// which determines if client IP validation should take place.
///
/// When prevent_proxy_connections is enabled, clients can no longer log-in
/// if they connected to the yggdrasil server using a different IP.
///
/// # Default Implementation
/// Proxy connections are allowed.
///
/// Returns `false`.
fn prevent_proxy_connections(&self) -> bool {
false
}
/// Called once at startup to get the capacity of the buffer used to /// Called once at startup to get the capacity of the buffer used to
/// hold incoming packets. /// hold incoming packets.
/// ///
@ -225,7 +239,11 @@ pub trait Config: Sized + Send + Sync + UnwindSafe + RefUnwindSafe + 'static {
auth_digest: &str, auth_digest: &str,
player_ip: &IpAddr, player_ip: &IpAddr,
) -> String { ) -> String {
if self.prevent_proxy_connections() {
format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={auth_digest}&ip={player_ip}") format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={auth_digest}&ip={player_ip}")
} else {
format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={auth_digest}")
}
} }
/// Called after the server is created, but prior to accepting connections /// Called after the server is created, but prior to accepting connections

View file

@ -46,6 +46,7 @@ use crate::protocol::packets::s2c::play::S2cPlayPacket;
use crate::protocol::packets::s2c::status::{PingResponse, StatusResponse}; use crate::protocol::packets::s2c::status::{PingResponse, StatusResponse};
use crate::protocol::packets::Property; use crate::protocol::packets::Property;
use crate::protocol::{BoundedArray, BoundedString, VarInt}; use crate::protocol::{BoundedArray, BoundedString, VarInt};
use crate::text::Text;
use crate::util::valid_username; use crate::util::valid_username;
use crate::world::Worlds; use crate::world::Worlds;
use crate::{ident, Ticks, PROTOCOL_VERSION, VERSION_NAME}; use crate::{ident, Ticks, PROTOCOL_VERSION, VERSION_NAME};
@ -716,11 +717,17 @@ async fn handle_login<C: Config>(
); );
let resp = server.0.http_client.get(url).send().await?; let resp = server.0.http_client.get(url).send().await?;
let status = resp.status(); match resp.status().as_u16() {
ensure!( 200 => (),
status.is_success(), 204 => {
"session server GET request failed: {status}" let reason = Text::translate("multiplayer.disconnect.unverified_username");
); c.enc.write_packet(&DisconnectLogin { reason }).await?;
bail!("Could not verify username");
}
status => {
bail!("session server GET request failed: {status}");
}
}
let data: AuthResponse = resp.json().await?; let data: AuthResponse = resp.json().await?;