config update

This commit is contained in:
MeexReay 2024-11-14 01:35:17 +03:00
parent 58fbcb46c6
commit 9dfc6da081
7 changed files with 225 additions and 122 deletions

28
Cargo.lock generated
View File

@ -59,6 +59,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fastrand"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.34" version = "1.0.34"
@ -91,6 +100,15 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "instant"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.11" version = "1.0.11"
@ -125,6 +143,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"ignore-result", "ignore-result",
"log", "log",
"random-string",
"rust_mc_proto", "rust_mc_proto",
"serde_yml", "serde_yml",
"simplelog", "simplelog",
@ -185,6 +204,15 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "random-string"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f70fd13c3024ae3f17381bb5c4d409c6dc9ea6895c08fa2147aba305bea3c4af"
dependencies = [
"fastrand",
]
[[package]] [[package]]
name = "rust_mc_proto" name = "rust_mc_proto"
version = "0.1.16" version = "0.1.16"

View File

@ -9,8 +9,5 @@ rust_mc_proto = { git = "https://github.com/MeexReay/rust_mc_proto", features =
uuid = "1.11.0" uuid = "1.11.0"
log = "0.4.22" log = "0.4.22"
simplelog = "0.12.2" simplelog = "0.12.2"
# derivative = "2.2.0" ignore-result = "0.2.0"
# no_deadlocks = "1.3.2" random-string = "1.1.0"
# tokio = {version = "1.39.3", features = ["full"] }
# async-trait = "0.1.81"
ignore-result = "0.2.0"

View File

@ -6,5 +6,5 @@ Proxy for minecraft servers on rust
todo list: (✅ / ❌) todo list: (✅ / ❌)
- ❌ add methods `connect_to_ip`, `connect_to_server`, `connect_to_stream`, `reconnect` - ❌ add methods `connect_to_ip`, `connect_to_server`, `connect_to_stream`, `reconnect`
- ❌ make setting `no_pf_for_ip_connect` working - ❌ make setting `no_pf_for_ip_connect` working
- ❌ make talk server - ❌ make messaging server
- ❌ create bukkit plugin for player formatting support and talking - ❌ create bukkit plugin for player formatting support and messaging

View File

@ -1,16 +1,34 @@
host: 127.0.0.1:25565 # host to bind meexprox host: 127.0.0.1:25565 # host to bind meexprox
talk_host: 127.0.0.1:12346 # secret host to talk with meexprox (optional) messaging: # messaging server (optional)
talk_secret: qwerty123456 # secret token for talk with meexprox (optional) enabled: true
host: 127.0.0.1:12346 # host
secret: qwerty123456 # secret key
servers: # verified servers (name -> ip) servers:
play: 127.0.0.1:12345 play: # server internal name
host: 127.0.0.1:12345 # server host
domains:
- _ # means that this server is default to connect players
- play.localhost
- mc.localhost
forwarding: # player forwarding
enabled: true
type: velocity
secret: "123456"
forced_hosts: # connect to server from connected hostname (name -> hostname) (optional) default_forwarding: # player forwarding to use when you connecting by ip
play: play.localhost enabled: false # disable player forwarding means that you dont need to transfer player's ip and other info to this server
# type: velocity
# secret: "123456"
default_server: play # default server to connect (optional) incoming_forwarding: # player forwarding for incoming connections
enabled: false
# type: velocity
# secret: "123456"
player_forwarding: # how to transfer player ip to connected server (velocity:PASSWORD / bungeecord / bungeeguard:PASSWORD / none) # player forwarding types:
_: none # default player forwarding # - velocity (or "modern" in Velocity config) (secret is required)
play: velocity:123456 # specific player forwarding # - bungeecord (or "legacy" in Velocity config) (secret is optional)
# - meexprox (best) (secret is required)
# - none (enabled: false)

View File

@ -1,33 +1,36 @@
use serde_yml::Value; use serde_yml::{Mapping, Value};
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use super::error::ProxyError;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ServerInfo { pub struct ServerInfo {
pub name: String, pub name: String,
pub host: String, pub host: String,
pub forced_host: Option<String>, pub domains: Vec<String>,
pub player_forwarding: PlayerForwarding, pub player_forwarding: PlayerForwarding,
} }
impl ServerInfo { impl ServerInfo {
pub fn new(name: String, host: String, forced_host: Option<String>, player_forwarding: PlayerForwarding) -> ServerInfo { pub fn new(
name: String,
host: String,
domains: Vec<String>,
player_forwarding: PlayerForwarding
) -> ServerInfo {
ServerInfo { ServerInfo {
name, name,
host, host,
forced_host, domains,
player_forwarding player_forwarding
} }
} }
pub fn from_host(host: String, config: ProxyConfig) -> ServerInfo { pub fn from_host(host: String, player_forwarding: PlayerForwarding) -> ServerInfo {
ServerInfo { ServerInfo {
name: host.clone(), name: String::new(),
host, host,
forced_host: None, domains: Vec::new(),
player_forwarding: config.default_player_forwarding.clone() player_forwarding
} }
} }
} }
@ -35,111 +38,136 @@ impl ServerInfo {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum PlayerForwarding { pub enum PlayerForwarding {
Velocity(String), Velocity(String),
Bungeecord, Bungeecord(Option<String>),
Bungeeguard(String), Meexprox(String),
None, None
} }
impl PlayerForwarding { impl PlayerForwarding {
pub fn parse(name: &str) -> Result<PlayerForwarding, ProxyError> { pub fn from_data(data: Mapping) -> Option<PlayerForwarding> {
match name { if data.len() == 0 { return None }
"bungeecord" => Ok(PlayerForwarding::Bungeecord), Some(if data.get("enabled")?.as_bool()? {
"none" => Ok(PlayerForwarding::None), match data.get("type")?.as_str()? {
pf => { "velocity" => {
if pf.starts_with("bungeeguard:") { PlayerForwarding::Velocity(
Ok(PlayerForwarding::Bungeeguard(pf[9..].to_string())) data.get("secret")?
} else if pf.starts_with("velocity:") { .as_str()?
Ok(PlayerForwarding::Velocity(pf[9..].to_string())) .to_string()
} else { )
Err(ProxyError::ConfigParse) }, "bungeecord" => {
PlayerForwarding::Bungeecord(
data.get("secret")
.map(|o| o.as_str())
.flatten()
.map(|o| o.to_string())
)
}, "meexprox" => {
PlayerForwarding::Meexprox(
data.get("secret")?
.as_str()?
.to_string()
)
}, _ => {
return None;
} }
}, }
} } else {
PlayerForwarding::None
})
} }
} }
#[derive(Clone)]
pub struct Messaging {
pub host: String,
pub secret: String
}
#[derive(Clone)] #[derive(Clone)]
pub struct ProxyConfig { pub struct ProxyConfig {
pub host: String, pub host: String,
pub servers: Vec<ServerInfo>, pub servers: Vec<ServerInfo>,
pub default_server: Option<ServerInfo>, pub messaging: Option<Messaging>,
pub talk_host: Option<String>, pub default_forwarding: PlayerForwarding,
pub talk_secret: Option<String>, pub incoming_forwarding: PlayerForwarding
pub default_player_forwarding: PlayerForwarding,
} }
impl ProxyConfig { impl ProxyConfig {
pub fn new( pub fn new(
host: String, host: String,
servers: Vec<ServerInfo>, servers: Vec<ServerInfo>,
default_server: Option<ServerInfo>, messaging: Option<Messaging>,
talk_host: Option<String>, default_forwarding: PlayerForwarding,
talk_secret: Option<String>, incoming_forwarding: PlayerForwarding
default_player_forwarding: PlayerForwarding
) -> ProxyConfig { ) -> ProxyConfig {
ProxyConfig { ProxyConfig {
host, host,
servers, servers,
default_server, messaging,
talk_host, default_forwarding,
talk_secret, incoming_forwarding
default_player_forwarding
} }
} }
pub fn load_yml(data: String) -> Result<ProxyConfig, Box<dyn std::error::Error>> { pub fn load_yml(data: String) -> Option<ProxyConfig> {
let data = serde_yml::from_str::<Value>(&data)?; let data = serde_yml::from_str::<Value>(&data).ok()?;
let data = data.as_mapping().ok_or(ProxyError::ConfigParse)?; let data = data.as_mapping()?;
let host = data.get("host").map(|o| o.as_str()).flatten().ok_or(ProxyError::ConfigParse)?.to_string(); let host = data.get("host")?.as_str()?.to_string();
let talk_host = data.get("talk_host").map(|o| o.as_str()).flatten().map(|o| o.to_string());
let talk_secret = data.get("talk_secret").map(|o| o.as_str()).flatten().map(|o| o.to_string()); let messaging = if let Some(map) = data.get("messaging") {
let player_forwarding = data.get("player_forwarding").ok_or(ProxyError::ConfigParse)?.as_mapping().ok_or(ProxyError::ConfigParse)?.clone(); let map = map.as_mapping()?;
let default_player_forwarding = PlayerForwarding::parse(player_forwarding["_"].as_str().ok_or(ProxyError::ConfigParse)?)?;
let mut servers = Vec::new(); if map.get("enabled")?.as_bool()? {
if let Some(servers_map) = data Some(Messaging {
.get(&Value::String("servers".to_string())) host: map.get("host")?.as_str()?.to_string(),
.and_then(Value::as_mapping) secret: map.get("secret")?.as_str()?.to_string(),
{ })
for (name, addr) in servers_map { } else {
if let (Value::String(name), Value::String(addr)) = (name, addr) { None
servers.push(ServerInfo::new(name.clone(), addr.clone(), None,
player_forwarding.get(name).map(|o| o.as_str()).flatten()
.map(PlayerForwarding::parse).ok_or(ProxyError::ConfigParse)??));
}
} }
} } else {
None
};
if let Some(forced_hosts_map) = data let servers: Vec<ServerInfo> = data.get("servers")?.as_mapping()?
.get(&Value::String("forced_hosts".to_string())) .iter()
.and_then(Value::as_mapping) .filter_map(|o| -> Option<ServerInfo> {
{ let map = o.1.as_mapping()?;
for (name, host) in forced_hosts_map { Some(ServerInfo::new(
if let (Value::String(name), Value::String(host)) = (name, host) { o.0.as_str()?.to_string(),
if let Some(server) = servers.iter_mut().find(|s| s.name == *name) { map.get("host")?.as_str()?.to_string(),
server.forced_host = Some(host.clone()); map.get("domains")?.as_sequence()?
} .iter()
} .filter_map(|o| o.as_str())
} .map(|o| o.to_string())
} .collect(),
PlayerForwarding::from_data(
map.get("forwarding")?.as_mapping()?.clone()
)?
))
})
.collect();
let default_server = data.get("default_server") let default_forwarding = PlayerForwarding::from_data(
.map(|o| o.as_str()).flatten() data.get("default_forwarding")?.as_mapping()?.clone()
.and_then(|ds| servers.iter().find(|s| s.name == ds).cloned()); )?;
Ok(ProxyConfig::new( let incoming_forwarding = PlayerForwarding::from_data(
data.get("incoming_forwarding")?.as_mapping()?.clone()
)?;
Some(ProxyConfig::new(
host, host,
servers, servers,
default_server, messaging,
talk_host, default_forwarding,
talk_secret, incoming_forwarding
default_player_forwarding,
)) ))
} }
pub fn load(path: impl AsRef<Path>) -> Result<ProxyConfig, Box<dyn std::error::Error>> { pub fn load(path: impl AsRef<Path>) -> Option<ProxyConfig> {
Self::load_yml(fs::read_to_string(path)?) Self::load_yml(fs::read_to_string(path).ok()?)
} }
pub fn get_server_by_name(&self, name: &str) -> Option<ServerInfo> { pub fn get_server_by_name(&self, name: &str) -> Option<ServerInfo> {
@ -151,14 +179,19 @@ impl ProxyConfig {
None None
} }
pub fn get_server_by_forced_host(&self, forced_host: &str) -> Option<ServerInfo> { pub fn get_server_by_domain(&self, domain: &str) -> Option<ServerInfo> {
for server in &self.servers { for server in &self.servers {
if let Some(server_forced_host) = &server.forced_host { if server.domains.contains(&domain.to_string()) {
if server_forced_host == forced_host { return Some(server.clone());
return Some(server.clone());
}
} }
} }
for server in &self.servers {
if server.domains.contains(&"_".to_string()) {
return Some(server.clone());
}
}
None None
} }
} }

View File

@ -1,7 +1,7 @@
use std::{net::TcpStream, sync::{Arc, Mutex}, thread}; use std::{net::{SocketAddr, TcpStream}, sync::{Arc, Mutex}, thread};
use ignore_result::Ignore; use ignore_result::Ignore;
use rust_mc_proto::{DataBufferReader, MCConnTcp, Packet}; use rust_mc_proto::{DataBufferReader, DataBufferWriter, MCConnTcp, Packet, ProtocolError};
use uuid::Uuid; use uuid::Uuid;
use super::{config::{ProxyConfig, ServerInfo}, error::{AsProxyResult, ProxyError}}; use super::{config::{ProxyConfig, ServerInfo}, error::{AsProxyResult, ProxyError}};
@ -18,8 +18,45 @@ pub struct LoginInfo {
} }
impl LoginInfo { impl LoginInfo {
pub fn write(&self, config: &ProxyConfig, stream: &mut MCConnTcp) { pub fn write(&self, _config: &ProxyConfig, stream: &mut MCConnTcp) -> Result<(), ProtocolError> {
todo!() // TODO: write login packets sending stream.write_packet(&Packet::build(0x00, |p| {
p.write_u16_varint(self.protocol_version)?;
p.write_string(&self.server_address)?;
p.write_short(self.server_port as i16)?;
p.write_u8_varint(2)
})?)?;
stream.write_packet(&Packet::build(0x00, |p| {
p.write_string(&self.name)?;
p.write_uuid(&self.uuid)
})?)?;
loop {
let mut packet = stream.read_packet()?;
match packet.id() {
0x01 => {
stream.write_packet(&Packet::build(0x00, |p| {
p.write_usize_varint(self.shared_secret.as_ref().unwrap().len())?;
p.write_bytes(&self.shared_secret.as_ref().unwrap())?;
p.write_usize_varint(self.verify_token.as_ref().unwrap().len())?;
p.write_bytes(&self.verify_token.as_ref().unwrap())
})?)?;
}
0x02 => {
break;
}
0x03 => {
let compression = Some(packet.read_usize_varint()?);
stream.set_compression(compression);
}
_ => {}
}
}
stream.write_packet(&Packet::empty(0x03))?;
Ok(())
} }
} }
@ -30,7 +67,8 @@ pub struct Player {
pub name: String, pub name: String,
pub uuid: Uuid, pub uuid: Uuid,
pub server: Option<ServerInfo>, pub server: Option<ServerInfo>,
pub protocol_version: u16 pub protocol_version: u16,
pub addr: SocketAddr
} }
impl Player { impl Player {
@ -39,6 +77,7 @@ impl Player {
server_address: String, server_address: String,
server_port: u16, server_port: u16,
server: ServerInfo, server: ServerInfo,
addr: SocketAddr,
mut client_conn: MCConnTcp, mut client_conn: MCConnTcp,
mut server_conn: MCConnTcp mut server_conn: MCConnTcp
) -> Result<Player, ProxyError> { ) -> Result<Player, ProxyError> {
@ -52,6 +91,7 @@ impl Player {
server_conn.write_packet(&packet).as_proxy()?; server_conn.write_packet(&packet).as_proxy()?;
let mut player = Player { let mut player = Player {
addr,
client_conn: Arc::new(Mutex::new(client_conn)), client_conn: Arc::new(Mutex::new(client_conn)),
server_conn: Arc::new(Mutex::new(server_conn)), server_conn: Arc::new(Mutex::new(server_conn)),
login_info: None, login_info: None,

View File

@ -1,5 +1,4 @@
use log::{error, info}; use log::{error, info};
// use no_deadlocks::Mutex;
use rust_mc_proto::{ use rust_mc_proto::{
read_packet, write_packet, DataBufferReader, DataBufferWriter, MCConnTcp, Packet read_packet, write_packet, DataBufferReader, DataBufferWriter, MCConnTcp, Packet
}; };
@ -64,8 +63,7 @@ impl MeexProx {
let next_state = handshake.read_u8_varint().as_proxy()?; let next_state = handshake.read_u8_varint().as_proxy()?;
let server = self.config let server = self.config
.get_server_by_forced_host(&server_address) .get_server_by_domain(&server_address)
.or(self.config.default_server.clone())
.ok_or(ProxyError::ConfigParse)?; .ok_or(ProxyError::ConfigParse)?;
let mut server_conn = TcpStream::connect(&server.host).map_err(|_| ProxyError::ServerConnect)?; let mut server_conn = TcpStream::connect(&server.host).map_err(|_| ProxyError::ServerConnect)?;
@ -76,18 +74,6 @@ impl MeexProx {
handshake.write_unsigned_short(server_port)?; handshake.write_unsigned_short(server_port)?;
handshake.write_u8_varint(next_state)?; handshake.write_u8_varint(next_state)?;
if let PlayerForwarding::Handshake = self.config.player_forwarding {
if let SocketAddr::V4(addr) = addr {
handshake.write_boolean(false)?; // is ipv6
handshake.write_unsigned_short(addr.port())?; // port
handshake.write_bytes(&addr.ip().octets())?; // octets
} else if let SocketAddr::V6(addr) = addr {
handshake.write_boolean(true)?;
handshake.write_unsigned_short(addr.port())?;
handshake.write_bytes(&addr.ip().octets())?;
}
}
Ok(()) Ok(())
}).as_proxy()?; }).as_proxy()?;
@ -107,6 +93,7 @@ impl MeexProx {
server_address, server_address,
server_port, server_port,
server, server,
addr,
client_conn, client_conn,
server_conn server_conn
)?); )?);