Compare commits
10 Commits
79727e2b78
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
c8e5efe395
|
|||
| 2753fbba13 | |||
| 5d3cb90d4a | |||
| 6861c820bd | |||
|
|
347ec4590d | ||
|
|
d794e1532f | ||
|
|
91624eec0f | ||
|
|
339d6fab82 | ||
|
|
492f62d6b3 | ||
|
|
f66e8412e5 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
|||||||
/.idea
|
/.idea
|
||||||
/我是崩服小能手
|
/我是崩服小能手
|
||||||
/config.json
|
/config.json
|
||||||
|
/release
|
||||||
137
Cargo.lock
generated
137
Cargo.lock
generated
@@ -6,6 +6,8 @@ version = 4
|
|||||||
name = "ServerCrasherRust"
|
name = "ServerCrasherRust"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"env_logger",
|
||||||
|
"log",
|
||||||
"rand",
|
"rand",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rust_mc_proto",
|
"rust_mc_proto",
|
||||||
@@ -31,6 +33,65 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"once_cell",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic-waker"
|
name = "atomic-waker"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
@@ -112,6 +173,12 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
@@ -157,6 +224,29 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_filter"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.11.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"env_filter",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -340,6 +430,12 @@ version = "1.9.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
|
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.5.2"
|
version = "1.5.2"
|
||||||
@@ -567,6 +663,12 @@ version = "2.11.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
@@ -838,6 +940,35 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.12"
|
version = "0.12.12"
|
||||||
@@ -1354,6 +1485,12 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.12.1"
|
version = "1.12.1"
|
||||||
|
|||||||
@@ -12,3 +12,5 @@ uuid = "1.12.1"
|
|||||||
rand = "0.8.5" # 添加rand库依赖
|
rand = "0.8.5" # 添加rand库依赖
|
||||||
reqwest = "0.12.12"
|
reqwest = "0.12.12"
|
||||||
tokio = { version = "1.43.0", features = ["full", "rt", "rt-multi-thread"] }
|
tokio = { version = "1.43.0", features = ["full", "rt", "rt-multi-thread"] }
|
||||||
|
log = "0.4.25"
|
||||||
|
env_logger = "0.11.6"
|
||||||
|
|||||||
@@ -11,6 +11,6 @@ cd ServerCrasherRust
|
|||||||
cargo run
|
cargo run
|
||||||
```
|
```
|
||||||
## TODO List
|
## TODO List
|
||||||
1. 实现配置文件&更加灵活的代理设置
|
1. 实现配置文件&更加灵活的代理设置 [已完成]
|
||||||
2. 实现spammer,tab completion crash等实用的~~熊服~~(划掉)功能
|
2. 实现spammer,tab completion crash等实用的~~熊服~~(划掉)功能 [部分完成]
|
||||||
3. 适配多版本(flag先立着,什么时候实现不一定)
|
3. 适配多版本(flag先立着,什么时候实现不一定)[Waiting...]
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
// bot的实现
|
// bot的实现
|
||||||
|
|
||||||
use std::{io::{Error, Read, Write}, net::TcpStream, sync::Arc, thread::{self, sleep}, time::{self, Duration}};
|
use std::{io::{Error, Read, Write}, net::TcpStream, str::FromStr, sync::Arc, thread::{self, sleep}, time::{self, Duration}};
|
||||||
|
|
||||||
|
use log::{info, warn};
|
||||||
use rust_mc_proto::{DataBufferReader, DataBufferWriter, MinecraftConnection, Packet, ProtocolError};
|
use rust_mc_proto::{DataBufferReader, DataBufferWriter, MinecraftConnection, Packet, ProtocolError};
|
||||||
use socks::Socks5Stream;
|
use socks::Socks5Stream;
|
||||||
use tokio::{io::{AsyncBufReadExt, AsyncSeekExt}, sync::Mutex};
|
use tokio::{io::{AsyncBufReadExt, AsyncSeekExt}, sync::Mutex};
|
||||||
@@ -10,34 +11,20 @@ use crate::{configuration::Configuration, utils};
|
|||||||
// 让所有bot能够共享变量
|
// 让所有bot能够共享变量
|
||||||
pub struct BotVariable {
|
pub struct BotVariable {
|
||||||
pub spam_file: Arc<Mutex<Option<tokio::fs::File>>>,
|
pub spam_file: Arc<Mutex<Option<tokio::fs::File>>>,
|
||||||
pub spam_cursor: Arc<Mutex<u64>>
|
pub spam_cursor: Arc<Mutex<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Clone for BotVariable {
|
// Bot主线程和worker线程间的通信
|
||||||
// fn clone(&self) -> Self {
|
pub struct BotMessage {
|
||||||
// Self { spam_file: self.spam_file.clone() }
|
pub state: i32,
|
||||||
// }
|
pub last_keepalive_sec: u64,
|
||||||
// }
|
}
|
||||||
|
|
||||||
// 定义一个StreamType的特性,要求实现Read和Write,且含有connect函数
|
// 定义一个StreamType的特性,要求实现Read和Write,且含有connect函数
|
||||||
pub trait StreamType: Read + Write {
|
pub trait StreamType: Read + Write {
|
||||||
fn connect(server_addr: &str,proxy_addr: &str) -> Result<Self, Error> where Self: Sized;
|
fn connect(server_addr: &str,proxy_addr: &str) -> Result<Self, Error> where Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
// *由于下面的Stream已经实现过connect了,所以这里没必要重复一遍
|
|
||||||
// // 然后让Socks5Stream实现StreamType
|
|
||||||
// impl StreamType for Socks5Stream{
|
|
||||||
// fn connect(server_addr: &str,proxy_addr: &str) -> Result<Self, Error> where Self: Sized {
|
|
||||||
// return Socks5Stream::connect(proxy_addr, server_addr);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // 再让TcpStream实现StreamType
|
|
||||||
// impl StreamType for TcpStream {
|
|
||||||
// fn connect(server_addr: &str,_: &str) -> Result<Self, Error> where Self: Sized {
|
|
||||||
// return TcpStream::connect(server_addr);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Bot泛型版
|
// Bot泛型版
|
||||||
pub struct Bot<T: StreamType> {
|
pub struct Bot<T: StreamType> {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
@@ -48,6 +35,7 @@ pub struct Bot<T: StreamType> {
|
|||||||
config: Arc<Configuration>,
|
config: Arc<Configuration>,
|
||||||
status: i32,
|
status: i32,
|
||||||
var: Arc<BotVariable>,
|
var: Arc<BotVariable>,
|
||||||
|
alive: Arc<Mutex<bool>>
|
||||||
}
|
}
|
||||||
|
|
||||||
// 然后用一个Stream枚举来包装TcpStream和Socks5Stream(trait不能拿来创建bot)
|
// 然后用一个Stream枚举来包装TcpStream和Socks5Stream(trait不能拿来创建bot)
|
||||||
@@ -103,13 +91,14 @@ impl Clone for Bot<Stream> {
|
|||||||
should_restart: self.should_restart.clone(),
|
should_restart: self.should_restart.clone(),
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
status: self.status.clone(),
|
status: self.status.clone(),
|
||||||
var: self.var.clone()}
|
var: self.var.clone(),
|
||||||
|
alive: self.alive.clone()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: StreamType> Bot<T> {
|
impl<T: StreamType> Bot<T> {
|
||||||
pub fn new(username: String, proxy_addr: String, server_addr: String, config: Arc<Configuration>, var: Arc<BotVariable>) -> Result<Bot<T>, Error> {
|
pub fn new(username: String, proxy_addr: String, server_addr: String, config: Arc<Configuration>, var: Arc<BotVariable>) -> Result<Bot<T>, Error> {
|
||||||
println!("[{}] Creating bot on {} with proxy {}", username, server_addr, proxy_addr);
|
info!("[{}] Creating bot on {} with proxy {}", username, server_addr, proxy_addr);
|
||||||
let stream = T::connect(server_addr.as_str(), proxy_addr.as_str());
|
let stream = T::connect(server_addr.as_str(), proxy_addr.as_str());
|
||||||
let should_restart = false;
|
let should_restart = false;
|
||||||
match stream {
|
match stream {
|
||||||
@@ -121,7 +110,8 @@ impl<T: StreamType> Bot<T> {
|
|||||||
should_restart,
|
should_restart,
|
||||||
config,
|
config,
|
||||||
status: 0,
|
status: 0,
|
||||||
var: var}),
|
var: var,
|
||||||
|
alive: Arc::new(Mutex::new(true))}),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,7 +187,7 @@ impl<T: StreamType> Bot<T> {
|
|||||||
// disconnect
|
// disconnect
|
||||||
let message = packet.read_string()?;
|
let message = packet.read_string()?;
|
||||||
let text = utils::parse_json_component(message.as_str());
|
let text = utils::parse_json_component(message.as_str());
|
||||||
println!("[{}] Server disconnected: {}", self.username, text);
|
info!("[{}] Server disconnected: {}", self.username, text);
|
||||||
// if text.contains("验证程序已启用") { // TODO 把这个搞进配置文件里面
|
// if text.contains("验证程序已启用") { // TODO 把这个搞进配置文件里面
|
||||||
// println!("[{}] Restart flag setted, will restart after 1.5 min", self.username);
|
// println!("[{}] Restart flag setted, will restart after 1.5 min", self.username);
|
||||||
// sleep(Duration::from_secs(90));
|
// sleep(Duration::from_secs(90));
|
||||||
@@ -205,7 +195,7 @@ impl<T: StreamType> Bot<T> {
|
|||||||
// }
|
// }
|
||||||
for i in self.config.reco_words(){
|
for i in self.config.reco_words(){
|
||||||
if text.contains(i.as_str()) {
|
if text.contains(i.as_str()) {
|
||||||
println!("[{}] Restart flag setted, will restart after 1.5 min", self.username);
|
info!("[{}] Restart flag setted, will restart after 1.5 min", self.username);
|
||||||
sleep(Duration::from_secs(90));
|
sleep(Duration::from_secs(90));
|
||||||
self.should_restart = true;
|
self.should_restart = true;
|
||||||
}
|
}
|
||||||
@@ -214,15 +204,31 @@ impl<T: StreamType> Bot<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理网络数据包
|
// 处理网络数据包
|
||||||
pub async fn handle_packets(&mut self, status_tx: tokio::sync::mpsc::UnboundedSender<u8>) -> Result<(), ProtocolError> {
|
pub async fn handle_packets(&mut self, status_tx: tokio::sync::mpsc::UnboundedSender<BotMessage>) -> Result<(), ProtocolError> {
|
||||||
while self.conn.lock().await.is_alive() {
|
while self.conn.lock().await.is_alive() && *self.alive.lock().await {
|
||||||
let mut packet = self.conn.lock().await.read_packet()?;
|
let mut packet = self.conn.lock().await.read_packet()?;
|
||||||
|
let mut message = BotMessage {
|
||||||
|
state: 0,
|
||||||
|
last_keepalive_sec: 0
|
||||||
|
};
|
||||||
|
let mut uuid_self = uuid::Uuid::from_str("550e8400-e29b-41d4-a716-446655440000").unwrap(); // 这个纯随机
|
||||||
|
let mut ent_self = 0;
|
||||||
match packet.id() {
|
match packet.id() {
|
||||||
0x02 => { // 成功登录
|
0x01 => { // spawn entity
|
||||||
|
let id = packet.read_i32_varint()?;
|
||||||
|
let uid = packet.read_uuid()?;
|
||||||
|
if uid.eq(&uuid_self) {
|
||||||
|
ent_self = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x02 => { // 成功登录(Login Success)
|
||||||
// login success
|
// login success
|
||||||
println!("[{}] Successfully logged in!",self.username);
|
info!("[{}] Successfully logged in!",self.username);
|
||||||
self.status = 1;
|
self.status = 1;
|
||||||
status_tx.send(1).unwrap();
|
message.state = 1;
|
||||||
|
message.last_keepalive_sec = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
||||||
|
status_tx.send(message).unwrap_or(());
|
||||||
|
uuid_self = packet.read_uuid()?;
|
||||||
}
|
}
|
||||||
0x03 => {// 设置压缩CompressionThreshold
|
0x03 => {// 设置压缩CompressionThreshold
|
||||||
// set compression
|
// set compression
|
||||||
@@ -234,25 +240,29 @@ impl<T: StreamType> Bot<T> {
|
|||||||
}
|
}
|
||||||
0x23 => { // KeepAlive包
|
0x23 => { // KeepAlive包
|
||||||
self.handle_keepalive(&mut packet).await?;
|
self.handle_keepalive(&mut packet).await?;
|
||||||
|
message.last_keepalive_sec = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
||||||
|
status_tx.send(message).unwrap_or(());
|
||||||
// println!("{}",self.status);
|
// println!("{}",self.status);
|
||||||
}
|
}
|
||||||
0x1A => {// 断连包
|
0x1A => {// 断连包
|
||||||
// disconnect
|
// disconnect
|
||||||
self.handle_disconnect(&mut packet).await?;
|
self.handle_disconnect(&mut packet).await?;
|
||||||
status_tx.send(2).unwrap();
|
message.state = 2;
|
||||||
|
status_tx.send(message).unwrap_or(());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
0x00 => {// 版本不匹配啥的就会走这
|
0x00 => {// 版本不匹配啥的就会走这
|
||||||
if self.status == 0{
|
if self.status == 0{
|
||||||
let text = packet.read_string()?;
|
let text = packet.read_string()?;
|
||||||
println!("[{}] Failed to login: {}", self.username, utils::parse_json_component(text.as_str()));
|
warn!("[{}] Failed to login: {}", self.username, utils::parse_json_component(text.as_str()));
|
||||||
status_tx.send(2);
|
message.state = 2;
|
||||||
|
status_tx.send(message).unwrap_or(());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0x38 => {// 去世包(自动复活)
|
0x38 => {// 去世包(自动复活)
|
||||||
// player died
|
// player died
|
||||||
println!("[{}] Player died,respawning...",self.username);
|
info!("[{}] Player died,respawning...",self.username);
|
||||||
self.conn.lock().await.write_packet(&Packet::build(0x07, |packet| {
|
self.conn.lock().await.write_packet(&Packet::build(0x07, |packet| {
|
||||||
packet.write_u8_varint(0)
|
packet.write_u8_varint(0)
|
||||||
})?)?
|
})?)?
|
||||||
@@ -266,28 +276,31 @@ impl<T: StreamType> Bot<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// !这里的self不与主线程的self相同
|
// !这里的self不与主线程的self相同
|
||||||
pub async fn update_worker(&mut self, mut status_rx: tokio::sync::mpsc::UnboundedReceiver<u8>){
|
pub async fn update_worker(&mut self, mut status_rx: tokio::sync::mpsc::UnboundedReceiver<BotMessage>){
|
||||||
let mut login_timestamp = 0;
|
let mut login_timestamp = 0;
|
||||||
let mut login_command_flag = false;
|
let mut login_command_flag = false;
|
||||||
let mut status = 0;
|
let mut message = BotMessage {
|
||||||
|
state: 0,
|
||||||
|
last_keepalive_sec: 0
|
||||||
|
};
|
||||||
let mut iter = 0;
|
let mut iter = 0;
|
||||||
let mut flag = true;
|
let mut flag = true;
|
||||||
println!("[{}/WORKER] Worker started!", self.username);
|
info!("[{}/WORKER] Worker started!", self.username);
|
||||||
while flag {
|
while flag {
|
||||||
if !status_rx.is_empty() {
|
if !status_rx.is_empty() {
|
||||||
status = status_rx.recv().await.unwrap();
|
message = status_rx.recv().await.unwrap();
|
||||||
}
|
}
|
||||||
if status == 1 && login_timestamp == 0 { // 刚刚登录完毕
|
if message.state == 1 && login_timestamp == 0 { // 刚刚登录完毕
|
||||||
login_timestamp = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64;
|
login_timestamp = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64;
|
||||||
}else if status == 1 { // 已登录
|
}else if message.state == 1 { // 已登录
|
||||||
if login_timestamp + 3000 <= time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64
|
if login_timestamp + 3000 <= time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64
|
||||||
&& !login_command_flag { // 登录3s后且未执行过登录命令
|
&& !login_command_flag { // 登录3s后且未执行过登录命令
|
||||||
let commands = self.config.login_commands().clone();
|
let commands = self.config.login_commands().clone();
|
||||||
for i in commands{
|
for i in commands{
|
||||||
self.send_command(i.to_string()).await.unwrap();
|
self.send_command(i.to_string()).await.unwrap_or(());
|
||||||
thread::sleep(Duration::from_secs(1));
|
thread::sleep(Duration::from_secs(1));
|
||||||
}
|
}
|
||||||
println!("[{}/WORKER] Login commands executed!",self.username);
|
info!("[{}/WORKER] Login commands executed!",self.username);
|
||||||
login_command_flag = true;
|
login_command_flag = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,17 +333,24 @@ impl<T: StreamType> Bot<T> {
|
|||||||
}
|
}
|
||||||
self.send_message(msg).await.unwrap_or(());
|
self.send_message(msg).await.unwrap_or(());
|
||||||
}
|
}
|
||||||
|
let timestamp = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
||||||
|
if message.last_keepalive_sec + 60 < timestamp { // 连接超时
|
||||||
|
(*self.alive.lock().await) = false;
|
||||||
|
warn!("[{}/WORKER] Bot timed out", self.username);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
iter += 1;
|
iter += 1;
|
||||||
}
|
}
|
||||||
sleep(Duration::from_millis(1));
|
sleep(Duration::from_millis(1));
|
||||||
flag = self.conn.lock().await.is_alive() && status!=2;
|
flag = self.conn.lock().await.is_alive() && message.state!=2;
|
||||||
}
|
}
|
||||||
println!("[{}/WORKER] Worker stopped.", self.username);
|
warn!("[{}/WORKER] Worker stopped.", self.username);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 运行bot
|
// 运行bot
|
||||||
pub async fn run(&mut self, status_tx: tokio::sync::mpsc::UnboundedSender<u8>) -> Result<(), ProtocolError> {
|
pub async fn run(&mut self, status_tx: tokio::sync::mpsc::UnboundedSender<BotMessage>) -> Result<(), ProtocolError> {
|
||||||
println!("[{}] Connecting to {} with proxy {}", self.username, self.server_addr, self.proxy_addr);
|
info!("[{}] Connecting to {} with proxy {}", self.username, self.server_addr, self.proxy_addr);
|
||||||
self.login().await.unwrap();
|
self.login().await.unwrap();
|
||||||
self.handle_packets(status_tx).await.unwrap_or(());
|
self.handle_packets(status_tx).await.unwrap_or(());
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::{fs::File, io::BufWriter};
|
use std::{fs::File, io::BufWriter};
|
||||||
|
use log::{info, warn, error};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@ pub struct Configuration {
|
|||||||
server_ip: String,
|
server_ip: String,
|
||||||
server_port: String,
|
server_port: String,
|
||||||
username_prefix: String,
|
username_prefix: String,
|
||||||
|
pub name_len_limit: Vec<i64>,
|
||||||
count: i32,
|
count: i32,
|
||||||
proxy_url: String,
|
proxy_url: String,
|
||||||
reco_words: Vec<String>,
|
reco_words: Vec<String>,
|
||||||
@@ -27,26 +29,26 @@ impl Configuration {
|
|||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
match serde_json::from_reader::<_,Configuration>(reader) { // serde可以直接解析出实现了Deserialize trait的类型 就很不错
|
match serde_json::from_reader::<_,Configuration>(reader) { // serde可以直接解析出实现了Deserialize trait的类型 就很不错
|
||||||
Ok(config) => {
|
Ok(config) => {
|
||||||
println!("[CONFIG] Server IP: {}", config.server_ip);
|
info!("Server IP: {}", config.server_ip);
|
||||||
println!("[CONFIG] Server Port: {}", config.server_port);
|
info!("Server Port: {}", config.server_port);
|
||||||
println!("[CONFIG] Username Prefix: {}", config.username_prefix);
|
info!("Username Prefix: {}", config.username_prefix);
|
||||||
println!("[CONFIG] Bot Count: {}", config.count);
|
info!("Bot Count: {}", config.count);
|
||||||
println!("[CONFIG] Proxy URL: {}", config.proxy_url);
|
info!("Proxy URL: {}", config.proxy_url);
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
eprintln!("[MAIN/CONF] Error parsing config file: {}", error);
|
error!("Error parsing config file: {}", error);
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
eprintln!("[MAIN/CONF] Unable to read config file, will use default values: {}", error);
|
warn!("Unable to read config file, will use default values: {}", error);
|
||||||
let file = File::create_new(filename).unwrap();
|
let file = File::create_new(filename).unwrap();
|
||||||
let writer = BufWriter::new(file);
|
let writer = BufWriter::new(file);
|
||||||
let mut serializer = serde_json::Serializer::pretty(writer);
|
let mut serializer = serde_json::Serializer::pretty(writer);
|
||||||
Self::default().serialize(&mut serializer).unwrap();
|
Self::default().serialize(&mut serializer).unwrap();
|
||||||
eprintln!("[Main/CONF] A configure file with default values is created.");
|
warn!("A configure file with default values is created.");
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,6 +59,7 @@ impl Configuration {
|
|||||||
server_ip: "m.earthvillage.top".to_string(),
|
server_ip: "m.earthvillage.top".to_string(),
|
||||||
server_port: "33009".to_string(),
|
server_port: "33009".to_string(),
|
||||||
username_prefix: "".to_string(),
|
username_prefix: "".to_string(),
|
||||||
|
name_len_limit: vec![4,8],
|
||||||
count: 300,
|
count: 300,
|
||||||
proxy_url: "http://uu-proxy.com/api/get_proxies?id=RZ7GS5ZYTA&size=1&schemes=socks5&support_https=false&format=json".to_string(),
|
proxy_url: "http://uu-proxy.com/api/get_proxies?id=RZ7GS5ZYTA&size=1&schemes=socks5&support_https=false&format=json".to_string(),
|
||||||
reco_words: vec!["AntiAttack".to_string()],
|
reco_words: vec!["AntiAttack".to_string()],
|
||||||
@@ -102,20 +105,3 @@ impl Configuration {
|
|||||||
self.random_prefix
|
self.random_prefix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Clone for Configuration {
|
|
||||||
// fn clone(&self) -> Self {
|
|
||||||
// Configuration {
|
|
||||||
// server_ip: self.server_ip.clone(),
|
|
||||||
// server_port: self.server_port.clone(),
|
|
||||||
// username_prefix: self.username_prefix.clone(),
|
|
||||||
// count: self.count,
|
|
||||||
// proxy_url: self.proxy_url.clone(),
|
|
||||||
// reco_words: self.reco_words.clone(),
|
|
||||||
// login_commands:self.login_commands.clone(),
|
|
||||||
// random_prefix: self.random_prefix,
|
|
||||||
// spam_file: self.spam_file.clone(),
|
|
||||||
// spam_delay_ms: self.spam_delay_ms,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
41
src/main.rs
41
src/main.rs
@@ -5,6 +5,7 @@ mod utils;
|
|||||||
mod configuration;
|
mod configuration;
|
||||||
|
|
||||||
use bot_socks5::BotVariable;
|
use bot_socks5::BotVariable;
|
||||||
|
use log::error;
|
||||||
use reqwest;
|
use reqwest;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
@@ -15,20 +16,11 @@ use tokio::sync::Mutex;
|
|||||||
use crate::utils::generate_username;
|
use crate::utils::generate_username;
|
||||||
use crate::configuration::Configuration;
|
use crate::configuration::Configuration;
|
||||||
|
|
||||||
// 暂且保留一下
|
|
||||||
// // 目标的ip地址(暂时不能解析dns)
|
|
||||||
// // 理论上你可以把它改成任何支持1.20.1的服务器
|
|
||||||
// const SERVER_ADDR: &str = "49.70.3.146:33009";
|
|
||||||
// // uu代理的api(用来实时获取代理)
|
|
||||||
// const UU_URL: &str = "http://uu-proxy.com/api/get_proxies?id=RZ7GS5ZYTA&size=1&schemes=socks5&support_https=false&format=json";
|
|
||||||
// // 用户名的开头
|
|
||||||
// // 这很不错了
|
|
||||||
// const USERNAME_PREFIX: &str = "Nikke_"; // 2 3 3
|
|
||||||
// // 假人数量
|
|
||||||
// const COUNT :i32 = 300;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
let mut logger_builder = env_logger::Builder::from_default_env();
|
||||||
|
logger_builder.filter_level(log::LevelFilter::Info);
|
||||||
|
logger_builder.init();
|
||||||
// 一个互斥锁,防止有多个线程同时请求uuproxy
|
// 一个互斥锁,防止有多个线程同时请求uuproxy
|
||||||
let thread_lock = Arc::new(Mutex::new(()));
|
let thread_lock = Arc::new(Mutex::new(()));
|
||||||
|
|
||||||
@@ -36,10 +28,6 @@ async fn main() {
|
|||||||
let configuration = Configuration::new("config.json");
|
let configuration = Configuration::new("config.json");
|
||||||
let configuration_rc = Arc::new(configuration);
|
let configuration_rc = Arc::new(configuration);
|
||||||
let mut spam_file = None;
|
let mut spam_file = None;
|
||||||
if configuration_rc.username_prefix().len() > 14 {
|
|
||||||
eprintln!("[CONFIG] Error: Username prefix should not longer than 14");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if !configuration_rc.clone().spam_file().is_empty() {
|
if !configuration_rc.clone().spam_file().is_empty() {
|
||||||
spam_file = Some(tokio::fs::File::open(configuration_rc.clone().spam_file()).await.unwrap());
|
spam_file = Some(tokio::fs::File::open(configuration_rc.clone().spam_file()).await.unwrap());
|
||||||
}
|
}
|
||||||
@@ -67,13 +55,6 @@ async fn main() {
|
|||||||
let configuration_rc_clone = configuration_rc.clone();
|
let configuration_rc_clone = configuration_rc.clone();
|
||||||
let variables_clone = variables.clone();
|
let variables_clone = variables.clone();
|
||||||
let rt_update_clone = rt_update.clone();
|
let rt_update_clone = rt_update.clone();
|
||||||
// let handle = tokio::spawn(async move {
|
|
||||||
// attack_thread(lock_clone).await;
|
|
||||||
// println!("[MAIN] Thread {} created", i);
|
|
||||||
// });
|
|
||||||
// 生成一个线程
|
|
||||||
// let handle = tokio::task::spawn(attack_thread(lock_clone,configuration_rc_clone,variables_clone));
|
|
||||||
// let handle;
|
|
||||||
if configuration_rc.use_thread_pool {
|
if configuration_rc.use_thread_pool {
|
||||||
rt.spawn(attack_thread(lock_clone,configuration_rc_clone,variables_clone,rt_update_clone));
|
rt.spawn(attack_thread(lock_clone,configuration_rc_clone,variables_clone,rt_update_clone));
|
||||||
}else{
|
}else{
|
||||||
@@ -89,13 +70,7 @@ async fn main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// handles.push(handle);
|
|
||||||
// println!("[MAIN] Thread {} created", i) // 这个太吵了(
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 等待所有任务完成(虽然大概也许可能这辈子都等不到)
|
|
||||||
// for _ in handles {
|
|
||||||
// }
|
|
||||||
let lock_clone = thread_lock.clone();
|
let lock_clone = thread_lock.clone();
|
||||||
let configuration_rc_clone = configuration_rc.clone();
|
let configuration_rc_clone = configuration_rc.clone();
|
||||||
let variables_clone = variables.clone();
|
let variables_clone = variables.clone();
|
||||||
@@ -129,7 +104,7 @@ async fn attack_thread(lock: Arc<Mutex<()>>, config: Arc<Configuration>, variabl
|
|||||||
};
|
};
|
||||||
if !proxy.is_object() {
|
if !proxy.is_object() {
|
||||||
flag = true;
|
flag = true;
|
||||||
eprintln!("[{}] Unable to get proxy,retrying...",username)
|
error!("[{}] Unable to get proxy,retrying...",username)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +133,7 @@ async fn attack_thread(lock: Arc<Mutex<()>>, config: Arc<Configuration>, variabl
|
|||||||
//println!("[{}] Connecting to {} with proxy {}", bot.username, bot.server_addr, bot.proxy_addr);
|
//println!("[{}] Connecting to {} with proxy {}", bot.username, bot.server_addr, bot.proxy_addr);
|
||||||
// 插入生成update_worker线程的代码
|
// 插入生成update_worker线程的代码
|
||||||
let mut bot_clone = bot.clone();
|
let mut bot_clone = bot.clone();
|
||||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<u8>();
|
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<bot_socks5::BotMessage>();
|
||||||
rt_update.spawn(async move {
|
rt_update.spawn(async move {
|
||||||
bot_clone.update_worker(rx).await;
|
bot_clone.update_worker(rx).await;
|
||||||
});
|
});
|
||||||
@@ -169,11 +144,11 @@ async fn attack_thread(lock: Arc<Mutex<()>>, config: Arc<Configuration>, variabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("[{}] Error running bot: {}", username.clone(), e);
|
error!("[{}] Error running bot: {}", username.clone(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if let Err(e) = bot_result {
|
}else if let Err(e) = bot_result {
|
||||||
eprintln!("[{}] Error creating bot: {}", username.clone(), e);
|
error!("[{}] Error creating bot: {}", username.clone(), e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,6 @@ pub fn generate_string(len_min: i64, len_max: i64) -> String {
|
|||||||
|
|
||||||
pub fn generate_username(config: &Arc<Configuration>) -> String {
|
pub fn generate_username(config: &Arc<Configuration>) -> String {
|
||||||
config.username_prefix().to_string() + generate_string(
|
config.username_prefix().to_string() + generate_string(
|
||||||
2,16-config.username_prefix().len() as i64
|
config.name_len_limit[0], config.name_len_limit[1]
|
||||||
).to_string().as_str()
|
).to_string().as_str()
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user