init commit
This commit is contained in:
parent
2759076c93
commit
362ea225d5
445
Cargo.lock
generated
Normal file
445
Cargo.lock
generated
Normal file
@ -0,0 +1,445 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "bytebuffer"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7bfaf7cd08cacd74cdc6b521c37ac39cbc92692e5ab5c21ed5657a749b577c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "libyml"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e281a65eeba3d4503a2839252f86374528f9ceafe6fed97c1d3b52e1fb625c1"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "meexprox"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rust_mc_proto",
|
||||
"serde_yml",
|
||||
"simplelog",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_mc_proto"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5392814ae7129d56b0afcbdd5d6d4764ca51273fab7ff604ebe73018dbb562"
|
||||
dependencies = [
|
||||
"bytebuffer",
|
||||
"flate2",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.120"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yml"
|
||||
version = "0.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ce6afeda22f0b55dde2c34897bce76a629587348480384231205c14b59a01f"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"libyml",
|
||||
"log",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simplelog"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"termcolor",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"libc",
|
||||
"num-conv",
|
||||
"num_threads",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "meexprox"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serde_yml = "0.0.10"
|
||||
rust_mc_proto = "0.1.15"
|
||||
uuid = "1.10.0"
|
||||
log = "0.4.22"
|
||||
simplelog = "0.12.2"
|
15
config.yml
Normal file
15
config.yml
Normal file
@ -0,0 +1,15 @@
|
||||
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)
|
||||
|
||||
servers: # verified servers (name -> ip)
|
||||
play: 127.0.0.1:12345
|
||||
|
||||
forced_hosts: # connect to server from connected hostname (name -> hostname) (optional)
|
||||
play: play.localhost
|
||||
|
||||
default_server: play # default server to connect (optional)
|
||||
|
||||
player_forwarding: disabled # how to transfer player ip to connected server (handshake / plugin response / disabled)
|
||||
no_pf_for_ip_connect: true # disable player forwarding for connecting with server ip
|
5
latest.log
Normal file
5
latest.log
Normal file
@ -0,0 +1,5 @@
|
||||
23:50:29 [INFO] meexprox started on 127.0.0.1:25565
|
||||
23:50:49 [ERROR] clientbound error
|
||||
23:50:49 [ERROR] serverbound error
|
||||
23:51:05 [ERROR] clientbound error
|
||||
23:51:05 [ERROR] serverbound error
|
439
src/lib.rs
Normal file
439
src/lib.rs
Normal file
@ -0,0 +1,439 @@
|
||||
use log::{debug, error, info};
|
||||
use rust_mc_proto::{
|
||||
DataBufferReader, DataBufferWriter, MinecraftConnection, Packet, ProtocolError, Zigzag,
|
||||
};
|
||||
use serde_yml::Value;
|
||||
use std::{
|
||||
error::Error,
|
||||
fs,
|
||||
net::{SocketAddr, TcpListener, TcpStream},
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ProxyServer {
|
||||
pub name: String,
|
||||
pub host: String,
|
||||
pub forced_host: Option<String>,
|
||||
}
|
||||
|
||||
impl ProxyServer {
|
||||
pub fn new(name: String, host: String, forced_host: Option<String>) -> ProxyServer {
|
||||
ProxyServer {
|
||||
name,
|
||||
host,
|
||||
forced_host,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProxyError {
|
||||
ConfigParse,
|
||||
ServerConnect,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ProxyError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "({:?})", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ProxyError {}
|
||||
|
||||
macro_rules! extract_string {
|
||||
($data:expr, $key:expr) => {
|
||||
match $data.get(&Value::String($key.to_string())) {
|
||||
Some(Value::String(val)) => Some(val.clone()),
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum PlayerForwarding {
|
||||
Handshake,
|
||||
PluginResponse,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ProxyConfig {
|
||||
pub host: String,
|
||||
pub servers: Vec<ProxyServer>,
|
||||
pub default_server: Option<ProxyServer>,
|
||||
pub talk_host: Option<String>,
|
||||
pub talk_secret: Option<String>,
|
||||
pub player_forwarding: PlayerForwarding,
|
||||
}
|
||||
|
||||
impl ProxyConfig {
|
||||
pub fn new(
|
||||
host: String,
|
||||
servers: Vec<ProxyServer>,
|
||||
default_server: Option<ProxyServer>,
|
||||
talk_host: Option<String>,
|
||||
talk_secret: Option<String>,
|
||||
player_forwarding: PlayerForwarding,
|
||||
) -> ProxyConfig {
|
||||
ProxyConfig {
|
||||
host,
|
||||
servers,
|
||||
default_server,
|
||||
talk_host,
|
||||
talk_secret,
|
||||
player_forwarding,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(path: &str) -> Result<ProxyConfig, Box<dyn std::error::Error>> {
|
||||
let data = serde_yml::from_str::<Value>(&fs::read_to_string(path)?)?;
|
||||
let data = data.as_mapping().ok_or(ProxyError::ConfigParse)?;
|
||||
|
||||
let host = extract_string!(data, "host").ok_or(ProxyError::ConfigParse)?;
|
||||
let talk_host = extract_string!(data, "talk_host");
|
||||
let talk_secret = extract_string!(data, "talk_secret");
|
||||
let player_forwarding = match extract_string!(data, "player_forwarding") {
|
||||
Some(pf) => match pf.as_str() {
|
||||
"plugin response" => PlayerForwarding::PluginResponse,
|
||||
"disabled" => PlayerForwarding::Disabled,
|
||||
_ => PlayerForwarding::Handshake,
|
||||
},
|
||||
_ => PlayerForwarding::Handshake,
|
||||
};
|
||||
|
||||
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(ProxyServer::new(name.clone(), addr.clone(), 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 default_server = extract_string!(data, "default_server")
|
||||
.and_then(|ds| servers.iter().find(|s| s.name == ds).cloned());
|
||||
|
||||
Ok(ProxyConfig::new(
|
||||
host,
|
||||
servers,
|
||||
default_server,
|
||||
talk_host,
|
||||
talk_secret,
|
||||
player_forwarding,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn get_server_by_name(&self, name: &str) -> Option<ProxyServer> {
|
||||
for server in &self.servers {
|
||||
if &server.name == name {
|
||||
return Some(server.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_server_by_forced_host(&self, forced_host: &str) -> Option<ProxyServer> {
|
||||
for server in &self.servers {
|
||||
if let Some(server_forced_host) = &server.forced_host {
|
||||
if server_forced_host == forced_host {
|
||||
return Some(server.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_host(&self) -> &str {
|
||||
&self.host
|
||||
}
|
||||
|
||||
pub fn get_talk_enabled(&self) -> bool {
|
||||
self.talk_host.is_some() && self.talk_secret.is_some()
|
||||
}
|
||||
|
||||
pub fn get_talk_host(&self) -> Option<&String> {
|
||||
self.talk_host.as_ref()
|
||||
}
|
||||
|
||||
pub fn get_default_server(&self) -> Option<ProxyServer> {
|
||||
self.default_server.clone()
|
||||
}
|
||||
|
||||
pub fn get_talk_secret(&self) -> Option<&String> {
|
||||
self.talk_secret.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProxyPlayer {
|
||||
pub connection: TcpStream,
|
||||
pub connection_server: TcpStream,
|
||||
pub name: Option<String>,
|
||||
pub uuid: Option<Uuid>,
|
||||
pub server: Option<ProxyServer>,
|
||||
}
|
||||
|
||||
impl ProxyPlayer {
|
||||
pub fn new(
|
||||
connection: TcpStream,
|
||||
connection_server: TcpStream,
|
||||
name: Option<String>,
|
||||
uuid: Option<Uuid>,
|
||||
server: Option<ProxyServer>,
|
||||
) -> ProxyPlayer {
|
||||
ProxyPlayer {
|
||||
connection,
|
||||
connection_server,
|
||||
name,
|
||||
uuid,
|
||||
server,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MeexProx {
|
||||
pub config: ProxyConfig,
|
||||
pub players: Vec<ProxyPlayer>,
|
||||
pub listener: Option<TcpListener>,
|
||||
}
|
||||
|
||||
impl MeexProx {
|
||||
pub fn new(config: ProxyConfig) -> MeexProx {
|
||||
MeexProx {
|
||||
config,
|
||||
players: Vec::new(),
|
||||
listener: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_player(&self, uuid: Uuid) -> Option<&ProxyPlayer> {
|
||||
for player in &self.players {
|
||||
if let Some(player_uuid) = player.uuid {
|
||||
if player_uuid == uuid {
|
||||
return Some(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn accept(this: Arc<Mutex<Self>>, stream: TcpStream) -> Result<(), Box<dyn Error>> {
|
||||
let Ok(addr) = stream.peer_addr() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let server_config = this.lock().unwrap().config.clone();
|
||||
|
||||
let mut client_conn = MinecraftConnection::new(stream);
|
||||
|
||||
// TODO: remove this anti-ipv6 mrakobesie!!
|
||||
let SocketAddr::V4(addrv4) = addr else {
|
||||
return Ok(());
|
||||
};
|
||||
debug!(
|
||||
"accepted stream {}.{}.{}.{}:{}",
|
||||
addrv4.ip().octets()[0],
|
||||
addrv4.ip().octets()[1],
|
||||
addrv4.ip().octets()[2],
|
||||
addrv4.ip().octets()[3],
|
||||
addrv4.port()
|
||||
);
|
||||
// TODO: remove this anti-ipv6 mrakobesie!!
|
||||
|
||||
let mut handshake = client_conn.read_packet()?;
|
||||
|
||||
if handshake.id() != 0x00 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let protocol_version = handshake.read_u16_varint()?;
|
||||
let server_address = handshake.read_string()?;
|
||||
let server_port = handshake.read_unsigned_short()?;
|
||||
let next_state = handshake.read_u8_varint()?;
|
||||
|
||||
let server = server_config
|
||||
.get_server_by_forced_host(&server_address)
|
||||
.or(server_config.get_default_server())
|
||||
.ok_or(ProxyError::ConfigParse)?;
|
||||
|
||||
let mut server_conn = MinecraftConnection::connect(&server.host)?;
|
||||
|
||||
let handshake = Packet::build(0x00, |handshake| {
|
||||
handshake.write_u16_varint(protocol_version)?;
|
||||
handshake.write_string(&server_address)?;
|
||||
handshake.write_unsigned_short(server_port)?;
|
||||
handshake.write_u8_varint(next_state)?;
|
||||
|
||||
if let PlayerForwarding::Handshake = server_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(())
|
||||
})?;
|
||||
|
||||
server_conn.write_packet(&handshake)?;
|
||||
|
||||
if next_state == 1 {
|
||||
debug!("state: motd");
|
||||
|
||||
loop {
|
||||
server_conn.write_packet(&client_conn.read_packet()?)?;
|
||||
client_conn.write_packet(&server_conn.read_packet()?)?;
|
||||
}
|
||||
} else if next_state == 2 {
|
||||
debug!("state: login");
|
||||
|
||||
let plugin_response_packet = Packet::build(0x02, |packet| {
|
||||
packet.write_i8_varint(-99)?;
|
||||
packet.write_boolean(true)?;
|
||||
|
||||
if let SocketAddr::V4(addr) = addr {
|
||||
packet.write_boolean(false)?; // is ipv6
|
||||
packet.write_unsigned_short(addr.port())?; // port
|
||||
packet.write_bytes(&addr.ip().octets())?; // octets
|
||||
} else if let SocketAddr::V6(addr) = addr {
|
||||
packet.write_boolean(true)?;
|
||||
packet.write_unsigned_short(addr.port())?;
|
||||
packet.write_bytes(&addr.ip().octets())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
thread::spawn({
|
||||
let mut client_conn = client_conn.try_clone().unwrap();
|
||||
let mut server_conn = server_conn.try_clone().unwrap();
|
||||
|
||||
move || {
|
||||
move || -> Result<(), ProtocolError> {
|
||||
let mut joined = false;
|
||||
|
||||
loop {
|
||||
let mut packet = match client_conn.read_packet() {
|
||||
Ok(packet) => packet,
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
if packet.id() == 0x00 && !joined {
|
||||
let name = packet.read_string()?;
|
||||
let uuid = packet.read_uuid()?;
|
||||
|
||||
this.lock().unwrap().players.push(ProxyPlayer::new(
|
||||
client_conn.get_ref().try_clone().unwrap(),
|
||||
server_conn.get_ref().try_clone().unwrap(),
|
||||
Some(name),
|
||||
Some(uuid),
|
||||
Some(server.clone()),
|
||||
));
|
||||
|
||||
joined = true;
|
||||
}
|
||||
|
||||
// debug!("[C->S] sending packet {:#04X?} (size: {})", packet.id(), packet.len());
|
||||
server_conn.write_packet(&packet)?;
|
||||
}
|
||||
error!("serverbound error");
|
||||
|
||||
Ok(())
|
||||
}()
|
||||
.or_else(|e| {
|
||||
error!("serverbound error: {:?}", e);
|
||||
Ok::<(), ()>(())
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
move || -> Result<(), ProtocolError> {
|
||||
loop {
|
||||
let mut packet = match server_conn.read_packet() {
|
||||
Ok(packet) => packet,
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
if packet.id() == 0x02 {
|
||||
if let PlayerForwarding::PluginResponse = server_config.player_forwarding {
|
||||
debug!(
|
||||
"[C->S] sending packet {:#04X?} (size: {})",
|
||||
plugin_response_packet.id(),
|
||||
plugin_response_packet.len()
|
||||
);
|
||||
server_conn.write_packet(&plugin_response_packet)?;
|
||||
}
|
||||
}
|
||||
|
||||
// debug!("[C<-S] sending packet {:#04X?} (size: {})", packet.id(), packet.len());
|
||||
|
||||
client_conn.write_packet(&packet)?;
|
||||
|
||||
if packet.id() == 0x03 {
|
||||
let threshold = packet.read_isize_varint()?;
|
||||
|
||||
if threshold >= 0 {
|
||||
let threshold = threshold.zigzag();
|
||||
|
||||
server_conn.set_compression(Some(threshold));
|
||||
client_conn.set_compression(Some(threshold));
|
||||
} else {
|
||||
server_conn.set_compression(None);
|
||||
client_conn.set_compression(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
error!("clientbound error");
|
||||
|
||||
Ok(())
|
||||
}()
|
||||
.or_else(|e| {
|
||||
error!("clientbound error: {:?}", e);
|
||||
Ok::<(), ()>(())
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start(self) {
|
||||
let listener = TcpListener::bind(self.config.get_host()).expect("invalid host");
|
||||
|
||||
info!("meexprox started on {}", self.config.get_host());
|
||||
|
||||
let mutex_self = Arc::new(Mutex::new(self));
|
||||
|
||||
for client in listener.incoming() {
|
||||
if let Ok(client) = client {
|
||||
let mutex_self_clone = mutex_self.clone();
|
||||
thread::spawn(move || {
|
||||
Self::accept(mutex_self_clone, client).expect("accept error");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
src/main.rs
Normal file
16
src/main.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use meexprox::{MeexProx, ProxyConfig};
|
||||
use simplelog::{CombinedLogger, TermLogger, Config, LevelFilter, TerminalMode, ColorChoice, WriteLogger};
|
||||
use std::fs::File;
|
||||
|
||||
fn main() {
|
||||
CombinedLogger::init(
|
||||
vec![
|
||||
TermLogger::new(LevelFilter::Debug, Config::default(), TerminalMode::Mixed, ColorChoice::Auto),
|
||||
WriteLogger::new(LevelFilter::Info, Config::default(), File::create("latest.log").unwrap()),
|
||||
]
|
||||
).unwrap();
|
||||
|
||||
let config = ProxyConfig::load("config.yml").expect("config parse error");
|
||||
let meexprox = MeexProx::new(config);
|
||||
meexprox.start();
|
||||
}
|
Loading…
Reference in New Issue
Block a user