config update
This commit is contained in:
parent
58fbcb46c6
commit
9dfc6da081
28
Cargo.lock
generated
28
Cargo.lock
generated
@ -59,6 +59,15 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.34"
|
||||
@ -91,6 +100,15 @@ dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
@ -125,6 +143,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"ignore-result",
|
||||
"log",
|
||||
"random-string",
|
||||
"rust_mc_proto",
|
||||
"serde_yml",
|
||||
"simplelog",
|
||||
@ -185,6 +204,15 @@ dependencies = [
|
||||
"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]]
|
||||
name = "rust_mc_proto"
|
||||
version = "0.1.16"
|
||||
|
@ -9,8 +9,5 @@ rust_mc_proto = { git = "https://github.com/MeexReay/rust_mc_proto", features =
|
||||
uuid = "1.11.0"
|
||||
log = "0.4.22"
|
||||
simplelog = "0.12.2"
|
||||
# derivative = "2.2.0"
|
||||
# no_deadlocks = "1.3.2"
|
||||
# tokio = {version = "1.39.3", features = ["full"] }
|
||||
# async-trait = "0.1.81"
|
||||
ignore-result = "0.2.0"
|
||||
ignore-result = "0.2.0"
|
||||
random-string = "1.1.0"
|
@ -6,5 +6,5 @@ Proxy for minecraft servers on rust
|
||||
todo list: (✅ / ❌)
|
||||
- ❌ add methods `connect_to_ip`, `connect_to_server`, `connect_to_stream`, `reconnect`
|
||||
- ❌ make setting `no_pf_for_ip_connect` working
|
||||
- ❌ make talk server
|
||||
- ❌ create bukkit plugin for player formatting support and talking
|
||||
- ❌ make messaging server
|
||||
- ❌ create bukkit plugin for player formatting support and messaging
|
||||
|
38
config.yml
38
config.yml
@ -1,16 +1,34 @@
|
||||
host: 127.0.0.1:25565 # host to bind meexprox
|
||||
|
||||
talk_host: 127.0.0.1:12346 # secret host to talk with meexprox (optional)
|
||||
talk_secret: qwerty123456 # secret token for talk with meexprox (optional)
|
||||
messaging: # messaging server (optional)
|
||||
enabled: true
|
||||
host: 127.0.0.1:12346 # host
|
||||
secret: qwerty123456 # secret key
|
||||
|
||||
servers: # verified servers (name -> ip)
|
||||
play: 127.0.0.1:12345
|
||||
servers:
|
||||
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)
|
||||
play: play.localhost
|
||||
default_forwarding: # player forwarding to use when you connecting by ip
|
||||
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)
|
||||
_: none # default player forwarding
|
||||
play: velocity:123456 # specific player forwarding
|
||||
# player forwarding types:
|
||||
# - velocity (or "modern" in Velocity config) (secret is required)
|
||||
# - bungeecord (or "legacy" in Velocity config) (secret is optional)
|
||||
# - meexprox (best) (secret is required)
|
||||
# - none (enabled: false)
|
@ -1,33 +1,36 @@
|
||||
use serde_yml::Value;
|
||||
use serde_yml::{Mapping, Value};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use super::error::ProxyError;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ServerInfo {
|
||||
pub name: String,
|
||||
pub host: String,
|
||||
pub forced_host: Option<String>,
|
||||
pub domains: Vec<String>,
|
||||
pub player_forwarding: PlayerForwarding,
|
||||
}
|
||||
|
||||
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 {
|
||||
name,
|
||||
host,
|
||||
forced_host,
|
||||
domains,
|
||||
player_forwarding
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_host(host: String, config: ProxyConfig) -> ServerInfo {
|
||||
pub fn from_host(host: String, player_forwarding: PlayerForwarding) -> ServerInfo {
|
||||
ServerInfo {
|
||||
name: host.clone(),
|
||||
name: String::new(),
|
||||
host,
|
||||
forced_host: None,
|
||||
player_forwarding: config.default_player_forwarding.clone()
|
||||
domains: Vec::new(),
|
||||
player_forwarding
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,111 +38,136 @@ impl ServerInfo {
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PlayerForwarding {
|
||||
Velocity(String),
|
||||
Bungeecord,
|
||||
Bungeeguard(String),
|
||||
None,
|
||||
Bungeecord(Option<String>),
|
||||
Meexprox(String),
|
||||
None
|
||||
}
|
||||
|
||||
impl PlayerForwarding {
|
||||
pub fn parse(name: &str) -> Result<PlayerForwarding, ProxyError> {
|
||||
match name {
|
||||
"bungeecord" => Ok(PlayerForwarding::Bungeecord),
|
||||
"none" => Ok(PlayerForwarding::None),
|
||||
pf => {
|
||||
if pf.starts_with("bungeeguard:") {
|
||||
Ok(PlayerForwarding::Bungeeguard(pf[9..].to_string()))
|
||||
} else if pf.starts_with("velocity:") {
|
||||
Ok(PlayerForwarding::Velocity(pf[9..].to_string()))
|
||||
} else {
|
||||
Err(ProxyError::ConfigParse)
|
||||
pub fn from_data(data: Mapping) -> Option<PlayerForwarding> {
|
||||
if data.len() == 0 { return None }
|
||||
Some(if data.get("enabled")?.as_bool()? {
|
||||
match data.get("type")?.as_str()? {
|
||||
"velocity" => {
|
||||
PlayerForwarding::Velocity(
|
||||
data.get("secret")?
|
||||
.as_str()?
|
||||
.to_string()
|
||||
)
|
||||
}, "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)]
|
||||
pub struct ProxyConfig {
|
||||
pub host: String,
|
||||
pub servers: Vec<ServerInfo>,
|
||||
pub default_server: Option<ServerInfo>,
|
||||
pub talk_host: Option<String>,
|
||||
pub talk_secret: Option<String>,
|
||||
pub default_player_forwarding: PlayerForwarding,
|
||||
pub messaging: Option<Messaging>,
|
||||
pub default_forwarding: PlayerForwarding,
|
||||
pub incoming_forwarding: PlayerForwarding
|
||||
}
|
||||
|
||||
impl ProxyConfig {
|
||||
pub fn new(
|
||||
host: String,
|
||||
servers: Vec<ServerInfo>,
|
||||
default_server: Option<ServerInfo>,
|
||||
talk_host: Option<String>,
|
||||
talk_secret: Option<String>,
|
||||
default_player_forwarding: PlayerForwarding
|
||||
messaging: Option<Messaging>,
|
||||
default_forwarding: PlayerForwarding,
|
||||
incoming_forwarding: PlayerForwarding
|
||||
) -> ProxyConfig {
|
||||
ProxyConfig {
|
||||
host,
|
||||
servers,
|
||||
default_server,
|
||||
talk_host,
|
||||
talk_secret,
|
||||
default_player_forwarding
|
||||
messaging,
|
||||
default_forwarding,
|
||||
incoming_forwarding
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_yml(data: String) -> Result<ProxyConfig, Box<dyn std::error::Error>> {
|
||||
let data = serde_yml::from_str::<Value>(&data)?;
|
||||
let data = data.as_mapping().ok_or(ProxyError::ConfigParse)?;
|
||||
pub fn load_yml(data: String) -> Option<ProxyConfig> {
|
||||
let data = serde_yml::from_str::<Value>(&data).ok()?;
|
||||
let data = data.as_mapping()?;
|
||||
|
||||
let host = data.get("host").map(|o| o.as_str()).flatten().ok_or(ProxyError::ConfigParse)?.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 player_forwarding = data.get("player_forwarding").ok_or(ProxyError::ConfigParse)?.as_mapping().ok_or(ProxyError::ConfigParse)?.clone();
|
||||
let default_player_forwarding = PlayerForwarding::parse(player_forwarding["_"].as_str().ok_or(ProxyError::ConfigParse)?)?;
|
||||
let host = data.get("host")?.as_str()?.to_string();
|
||||
|
||||
let messaging = if let Some(map) = data.get("messaging") {
|
||||
let map = map.as_mapping()?;
|
||||
|
||||
let mut servers = Vec::new();
|
||||
if let Some(servers_map) = data
|
||||
.get(&Value::String("servers".to_string()))
|
||||
.and_then(Value::as_mapping)
|
||||
{
|
||||
for (name, addr) in servers_map {
|
||||
if let (Value::String(name), Value::String(addr)) = (name, addr) {
|
||||
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)??));
|
||||
}
|
||||
if map.get("enabled")?.as_bool()? {
|
||||
Some(Messaging {
|
||||
host: map.get("host")?.as_str()?.to_string(),
|
||||
secret: map.get("secret")?.as_str()?.to_string(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(forced_hosts_map) = data
|
||||
.get(&Value::String("forced_hosts".to_string()))
|
||||
.and_then(Value::as_mapping)
|
||||
{
|
||||
for (name, host) in forced_hosts_map {
|
||||
if let (Value::String(name), Value::String(host)) = (name, host) {
|
||||
if let Some(server) = servers.iter_mut().find(|s| s.name == *name) {
|
||||
server.forced_host = Some(host.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let servers: Vec<ServerInfo> = data.get("servers")?.as_mapping()?
|
||||
.iter()
|
||||
.filter_map(|o| -> Option<ServerInfo> {
|
||||
let map = o.1.as_mapping()?;
|
||||
Some(ServerInfo::new(
|
||||
o.0.as_str()?.to_string(),
|
||||
map.get("host")?.as_str()?.to_string(),
|
||||
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")
|
||||
.map(|o| o.as_str()).flatten()
|
||||
.and_then(|ds| servers.iter().find(|s| s.name == ds).cloned());
|
||||
let default_forwarding = PlayerForwarding::from_data(
|
||||
data.get("default_forwarding")?.as_mapping()?.clone()
|
||||
)?;
|
||||
|
||||
Ok(ProxyConfig::new(
|
||||
let incoming_forwarding = PlayerForwarding::from_data(
|
||||
data.get("incoming_forwarding")?.as_mapping()?.clone()
|
||||
)?;
|
||||
|
||||
Some(ProxyConfig::new(
|
||||
host,
|
||||
servers,
|
||||
default_server,
|
||||
talk_host,
|
||||
talk_secret,
|
||||
default_player_forwarding,
|
||||
messaging,
|
||||
default_forwarding,
|
||||
incoming_forwarding
|
||||
))
|
||||
}
|
||||
|
||||
pub fn load(path: impl AsRef<Path>) -> Result<ProxyConfig, Box<dyn std::error::Error>> {
|
||||
Self::load_yml(fs::read_to_string(path)?)
|
||||
pub fn load(path: impl AsRef<Path>) -> Option<ProxyConfig> {
|
||||
Self::load_yml(fs::read_to_string(path).ok()?)
|
||||
}
|
||||
|
||||
pub fn get_server_by_name(&self, name: &str) -> Option<ServerInfo> {
|
||||
@ -151,14 +179,19 @@ impl ProxyConfig {
|
||||
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 {
|
||||
if let Some(server_forced_host) = &server.forced_host {
|
||||
if server_forced_host == forced_host {
|
||||
return Some(server.clone());
|
||||
}
|
||||
if server.domains.contains(&domain.to_string()) {
|
||||
return Some(server.clone());
|
||||
}
|
||||
}
|
||||
|
||||
for server in &self.servers {
|
||||
if server.domains.contains(&"_".to_string()) {
|
||||
return Some(server.clone());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -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 rust_mc_proto::{DataBufferReader, MCConnTcp, Packet};
|
||||
use rust_mc_proto::{DataBufferReader, DataBufferWriter, MCConnTcp, Packet, ProtocolError};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{config::{ProxyConfig, ServerInfo}, error::{AsProxyResult, ProxyError}};
|
||||
@ -18,8 +18,45 @@ pub struct LoginInfo {
|
||||
}
|
||||
|
||||
impl LoginInfo {
|
||||
pub fn write(&self, config: &ProxyConfig, stream: &mut MCConnTcp) {
|
||||
todo!() // TODO: write login packets sending
|
||||
pub fn write(&self, _config: &ProxyConfig, stream: &mut MCConnTcp) -> Result<(), ProtocolError> {
|
||||
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 uuid: Uuid,
|
||||
pub server: Option<ServerInfo>,
|
||||
pub protocol_version: u16
|
||||
pub protocol_version: u16,
|
||||
pub addr: SocketAddr
|
||||
}
|
||||
|
||||
impl Player {
|
||||
@ -39,6 +77,7 @@ impl Player {
|
||||
server_address: String,
|
||||
server_port: u16,
|
||||
server: ServerInfo,
|
||||
addr: SocketAddr,
|
||||
mut client_conn: MCConnTcp,
|
||||
mut server_conn: MCConnTcp
|
||||
) -> Result<Player, ProxyError> {
|
||||
@ -52,6 +91,7 @@ impl Player {
|
||||
server_conn.write_packet(&packet).as_proxy()?;
|
||||
|
||||
let mut player = Player {
|
||||
addr,
|
||||
client_conn: Arc::new(Mutex::new(client_conn)),
|
||||
server_conn: Arc::new(Mutex::new(server_conn)),
|
||||
login_info: None,
|
||||
|
@ -1,5 +1,4 @@
|
||||
use log::{error, info};
|
||||
// use no_deadlocks::Mutex;
|
||||
use rust_mc_proto::{
|
||||
read_packet, write_packet, DataBufferReader, DataBufferWriter, MCConnTcp, Packet
|
||||
};
|
||||
@ -64,8 +63,7 @@ impl MeexProx {
|
||||
let next_state = handshake.read_u8_varint().as_proxy()?;
|
||||
|
||||
let server = self.config
|
||||
.get_server_by_forced_host(&server_address)
|
||||
.or(self.config.default_server.clone())
|
||||
.get_server_by_domain(&server_address)
|
||||
.ok_or(ProxyError::ConfigParse)?;
|
||||
|
||||
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_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(())
|
||||
}).as_proxy()?;
|
||||
|
||||
@ -107,6 +93,7 @@ impl MeexProx {
|
||||
server_address,
|
||||
server_port,
|
||||
server,
|
||||
addr,
|
||||
client_conn,
|
||||
server_conn
|
||||
)?);
|
||||
|
Loading…
Reference in New Issue
Block a user