() * (reconnects as f32) * 1000.0) as u64;
 96 | 
 97 |     let mut outbound = match TcpStream::connect(proxy_addr).await {
 98 |         Ok(o) => o,
 99 |         Err(_) => return Ok(()),
100 |     };
101 |     let (mut read_inbound, mut write_inbound) = inbound.split();
102 |     let (read_outbound, mut write_outbound) = outbound.split();
103 | 
104 |     let client_to_server = async {
105 |         // uses read_inbound and write_outbound
106 | 
107 |         // println!("start");
108 |         // wait lag before actually letting them connect
109 |         tokio::time::sleep(StdDuration::from_millis(simulated_ping)).await;
110 | 
111 |         for packet in get_all_packets(&mut read_inbound, &mut write_outbound).await {
112 |             let logger = logger.clone();
113 |             let ip = split[0].to_string();
114 |             let p = packet.clone();
115 |             tokio::spawn(async move { logger.write().await.handle_connect(p, &ip).await });
116 |         }
117 | 
118 |         // copy packets from ri to wo
119 |         let packet_queue: VecDeque<(BytesMut, tokio::time::Instant)> = VecDeque::new();
120 |         let packet_queue = Arc::new(std::sync::Mutex::new(packet_queue));
121 | 
122 |         let task_packet_queue = packet_queue.clone();
123 | 
124 |         // read from the queue and write to write_outbound
125 |         let read_from_queue = async move {
126 |             loop {
127 |                 // check if there's something in the packet queue every simulated_ping ms
128 |                 tokio::time::sleep(StdDuration::from_millis(simulated_ping)).await;
129 |                 // if there is, wait until the packet is ready to be sent and send it
130 |                 loop {
131 |                     let queue_front = packet_queue.lock().unwrap().pop_front();
132 |                     if let Some((bytes, sent_at)) = &queue_front {
133 |                         let sending_at = *sent_at + StdDuration::from_millis(simulated_ping);
134 |                         tokio::time::sleep_until(sending_at).await;
135 |                         if write_outbound.write_all(bytes.as_ref()).await.is_err() {
136 |                             break;
137 |                         }
138 |                     } else {
139 |                         break;
140 |                     }
141 |                 }
142 |             }
143 |         };
144 | 
145 |         let write_to_queue = async move {
146 |             let mut framed = FramedRead::new(read_inbound, BytesCodec::new());
147 |             while let Some(message) = framed.next().await {
148 |                 match message {
149 |                     Ok(bytes) => {
150 |                         task_packet_queue
151 |                             .lock()
152 |                             .unwrap()
153 |                             .push_back((bytes, tokio::time::Instant::now()));
154 |                     }
155 |                     Err(_) => break,
156 |                 }
157 |             }
158 |         };
159 | 
160 |         tokio::join!(read_from_queue, write_to_queue);
161 |     };
162 | 
163 |     let server_to_client = async {
164 |         let mut outbound_framed = FramedRead::new(read_outbound, BytesCodec::new());
165 |         // copy packets from ro to wi
166 |         while let Some(message) = outbound_framed.next().await {
167 |             match message {
168 |                 Ok(bytes) => {
169 |                     if write_inbound.write_all(&bytes).await.is_err() {
170 |                         break;
171 |                     }
172 |                 }
173 |                 Err(_) => break,
174 |             }
175 |         }
176 | 
177 |         write_inbound.shutdown().await
178 |     };
179 | 
180 |     let _ = tokio::try_join!(
181 |         tokio::time::timeout(StdDuration::from_secs(timeout_seconds), client_to_server),
182 |         tokio::time::timeout(StdDuration::from_secs(timeout_seconds), server_to_client)
183 |     );
184 | 
185 |     // so it times out
186 |     tokio::time::sleep(StdDuration::from_millis(5 * 60 * 1000)).await;
187 | 
188 |     Ok(())
189 | }
190 | 
--------------------------------------------------------------------------------
/src/packet.rs:
--------------------------------------------------------------------------------
  1 | // minecraft honeypot does honeypot things for minecraft and proxies which is cool
  2 | // Copyright (C) 2022 cleonyc
  3 | 
  4 | // This program is free software: you can redistribute it and/or modify
  5 | // it under the terms of the GNU General Public License as published by
  6 | // the Free Software Foundation, either version 3 of the License, or
  7 | // (at your option) any later version.
  8 | 
  9 | // This program is distributed in the hope that it will be useful,
 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 | // GNU General Public License for more details.
 13 | 
 14 | // You should have received a copy of the GNU General Public License
 15 | // along with this program.  If not, see .
 16 | 
 17 | use azalea_protocol::packets::handshake::ServerboundHandshakePacket;
 18 | use azalea_protocol::packets::login::ServerboundLoginPacket;
 19 | use azalea_protocol::read::read_packet;
 20 | use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
 21 | 
 22 | // pub async fn read_packet<'a, P: ProtocolPacket, R>(
 23 | //     stream: &'a mut R,
 24 | // ) -> anyhow::Result<(Option, Vec)>
 25 | // where
 26 | //     R: AsyncRead + std::marker::Unpin + std::marker::Send + std::marker::Sync,
 27 | // {
 28 | //     // let start_time = std::time::Instant::now();
 29 | 
 30 | //     // println!("decrypting packet ({}ms)", start_time.elapsed().as_millis());
 31 | //     // if we were given a cipher, decrypt the packet
 32 | //     let buf = frame_splitter(stream).await.unwrap();
 33 | //     println!("24");
 34 | //     // println!("splitting packet ({}ms)", start_time.elapsed().as_millis());
 35 | //     if buf.1.len() == 0 {
 36 | //         return Ok((None, buf.1));
 37 | //     }
 38 | //     let mut orig = buf.1.clone();
 39 | //     println!("31");
 40 | //     // println!("decoding packet ({}ms)", start_time.elapsed().as_millis());
 41 | //     let packet: (Option, Vec) = packet_decoder(&mut buf.0.as_slice()).await?;
 42 | //     println!("34");
 43 | //     // println!("decoded packet ({}ms)", start_time.elapsed().as_millis());
 44 | //     // orig.push(packet.1);
 45 | //     Ok((packet.0, orig))
 46 | // }
 47 | 
 48 | async fn frame_splitter(mut stream: &mut R) -> anyhow::Result<(Vec, Vec)>
 49 | where
 50 |     R: AsyncRead + std::marker::Unpin + std::marker::Send,
 51 | {
 52 |     // Packet Length
 53 |     // println!("called");
 54 |     let res = match read_varint_async(&mut stream).await {
 55 |         Ok(len) => len,
 56 |         Err(_) => {
 57 |             // println!("err reading varint");
 58 |             return Ok((vec![], vec![]));
 59 |         }
 60 |     };
 61 |     // println!("fs varint read: {}", res.0);
 62 | 
 63 |     if res.0 > 1024 || res.0 == 0 {
 64 |         return Ok((vec![], res.1));
 65 |     }
 66 |     let mut read = vec![];
 67 |     let length = res.0;
 68 |     while read.len() < length.try_into().unwrap() {
 69 |         let mut buf = [0; 1];
 70 |         match stream.read_exact(&mut buf).await {
 71 |             Ok(_) => read.push(buf[0]),
 72 |             Err(_) => {
 73 |                 break;
 74 |             }
 75 |         };
 76 |     }
 77 | 
 78 |     let mut orig = res.1;
 79 |     // println!("74: orig starts {:?}, appending: {:?}", orig, read);
 80 | 
 81 |     orig.append(&mut (read.clone()));
 82 |     let (valid_packet, _) = safe_check_packet_id(&mut read.as_slice()).await;
 83 |     if !valid_packet {
 84 |         return Ok((vec![], orig));
 85 |     }
 86 |     Ok((read, orig))
 87 | }
 88 | 
 89 | // async fn packet_decoder(
 90 | //     mut stream: &mut R,
 91 | // ) -> anyhow::Result<(Option, Vec)>
 92 | // where
 93 | //     R: AsyncRead + std::marker::Unpin + std::marker::Send + std::io::Read,
 94 | // {
 95 | //     // Packet ID
 96 | //     let packet_id = read_varint_async(&mut stream).await?;
 97 | //     if packet_id.0 != 0x00 {
 98 | //         return Ok((None, packet_id.1));
 99 | //     }
100 | //     let read = P::read(packet_id.0.try_into().unwrap(), stream)?;
101 | 
102 | //     Ok((Some(read), vec![]))
103 | // }
104 | // fast varints modified from https://github.com/luojia65/mc-varint/blob/master/src/lib.rs#L67
105 | /// Read a single varint from the reader and return the value, along with the number of bytes read
106 | pub async fn read_varint_async(
107 |     reader: &mut (dyn AsyncRead + Unpin + Send),
108 | ) -> anyhow::Result<(i32, Vec)> {
109 |     let mut buffer = [0];
110 |     let mut orig = vec![];
111 |     let mut ans = 0;
112 |     for i in 0..5 {
113 |         if let Ok(n) = reader.read(&mut buffer).await && n > 0 {
114 |             ans |= ((buffer[0] & 0b0111_1111) as i32) << (7 * i);
115 |             orig.push(buffer[0]);
116 |             if buffer[0] & 0b1000_0000 == 0 {
117 |                 return Ok((ans, orig));
118 |             }
119 |         };
120 |     }
121 |     Ok((ans, orig))
122 | }
123 | pub async fn safe_check_packet_id(reader: &mut (dyn AsyncRead + Unpin + Send)) -> (bool, Vec) {
124 |     let packet_id = match read_varint_async(reader).await {
125 |         Ok(packet_id) => packet_id,
126 |         Err(_) => return (false, vec![]),
127 |     };
128 |     if packet_id.0 != 0x00 {
129 |         return (false, packet_id.1);
130 |     };
131 |     (true, packet_id.1)
132 | }
133 | #[derive(Clone, Debug)]
134 | pub enum PossiblePacket {
135 |     LoginStart { packet: ServerboundLoginPacket },
136 |     Status { packet: ServerboundHandshakePacket },
137 | }
138 | pub async fn try_get_packet(
139 |     stream: &mut R,
140 |     writer: &mut W,
141 | ) -> Option
142 | where
143 |     R: AsyncRead + std::marker::Unpin + std::marker::Send,
144 |     W: AsyncWrite + std::marker::Unpin + std::marker::Send,
145 | {
146 |     let (read_bytes, original_bytes) = frame_splitter(stream).await.unwrap();
147 |     // println!("138: orig from frame_splitter: {:?}", original_bytes);
148 |     // 1024 bytes *should* be the theoretical maximum for login or status packets that we care about
149 |     // might break if it's an actual valid user key, we'll see
150 |     if original_bytes.len() > 20000 || original_bytes.is_empty() || read_bytes.is_empty() {
151 |         // println!("bad byte len");
152 |         writer.write_all(&original_bytes).await.unwrap();
153 |         // io::copy(stream, writer).await.unwrap();
154 |         return None;
155 |     }
156 |     if let Ok(packet) = read_packet::(
157 |         &mut original_bytes.clone().as_slice(),
158 |         None,
159 |         &mut None,
160 |     )
161 |     .await
162 |     {
163 |         writer.write_all(&original_bytes).await.unwrap();
164 |         // io::copy(stream, writer).await.unwrap();
165 |         // println!("returning! <3");
166 |         return Some(PossiblePacket::Status { packet });
167 |     };
168 |     if let Ok(packet) = read_packet::(
169 |         &mut adapt_from_1_18(&original_bytes.clone()).as_slice(),
170 |         None,
171 |         &mut None,
172 |     )
173 |     .await
174 |     {
175 |         // println!("\n\n\n\n\n\n\n\n\nreturning! (login) <3");
176 |         writer.write_all(&original_bytes).await.unwrap();
177 |         // io::copy(stream, writer).await.unwrap();
178 |         // println!("returning! L<3");
179 |         return Some(PossiblePacket::LoginStart { packet });
180 |     }
181 | 
182 |     // println!("returning! :(");
183 |     writer.write_all(&original_bytes).await.unwrap();
184 |     // io::copy(stream, writer).await.unwrap();
185 |     None
186 | }
187 | pub async fn get_all_packets(
188 |     stream: &mut R,
189 |     writer: &mut W,
190 | ) -> Vec
191 | where
192 |     R: AsyncRead + std::marker::Unpin + std::marker::Send,
193 |     W: AsyncWrite + std::marker::Unpin + std::marker::Send,
194 | {
195 |     let mut ret = vec![];
196 |     while let Some(packet) = try_get_packet(stream, writer).await {
197 |         ret.push(packet);
198 |     }
199 |     ret
200 | }
201 | 
202 | fn adapt_from_1_18(bytes: &[u8]) -> Vec {
203 |     let mut clone = Vec::with_capacity(bytes.len() + 2);
204 |     clone.extend_from_slice(bytes);
205 |     clone[0] += 2;
206 |     clone.extend_from_slice(&[0x00, 0x00]);
207 |     clone
208 | }
209 | 
210 | #[cfg(test)]
211 | mod tests {
212 |     use azalea_protocol::{
213 |         packets::handshake::client_intention_packet::ClientIntentionPacket, write::write_packet,
214 |     };
215 |     use rand::Rng;
216 |     use tokio::io::AsyncWriteExt;
217 | 
218 |     use crate::packet::{adapt_from_1_18, get_all_packets, try_get_packet};
219 | 
220 |     #[tokio::test]
221 |     async fn test_adapt_1_18() {
222 |         assert_eq!(
223 |             adapt_from_1_18(&[6, 0, 4, 50, 57, 55, 56]),
224 |             vec![8, 0, 4, 50, 57, 55, 56, 0, 0]
225 |         );
226 |     }
227 |     #[tokio::test]
228 |     async fn check_packets() {
229 |         // let hello_packet = ServerboundHelloPacket {
230 |         //     username: "2978".to_string(),
231 |         //     public_key: None,
232 |         //     profile_id: None,
233 |         // }
234 |         // .get();
235 |         let mut random_data: [u8; 2048] = [0; 2048];
236 |         rand::thread_rng().fill(&mut random_data);
237 |         let random_data_orig = random_data;
238 |         {
239 |             let mut buf = vec![];
240 | 
241 |             write_packet(
242 |                 ClientIntentionPacket {
243 |                     protocol_version: 758,
244 |                     hostname: "localhost".to_string(),
245 |                     port: 25565,
246 |                     intention: azalea_protocol::packets::ConnectionProtocol::Login,
247 |                 }
248 |                 .get(),
249 |                 &mut buf,
250 |                 None,
251 |                 &mut None,
252 |             )
253 |             .await
254 |             .unwrap();
255 |             // old 1.18.2 hello packet
256 |             buf.write_all(&[6, 0, 4, 50, 57, 55, 56]).await.unwrap();
257 | 
258 |             // write_packet(hello_packet, &mut buf, None, &mut None)
259 |             //     .await
260 |             //     .unwrap();
261 |             let mut orig_data = vec![];
262 |             let packets = get_all_packets(&mut buf.as_slice(), &mut orig_data).await;
263 |             assert_eq!(packets.len(), 2);
264 |             println!("packets: {:?}", packets);
265 |             assert_eq!(buf, orig_data);
266 |         }
267 |         {
268 |             let mut modded_rand_data: &[u8] = &random_data;
269 |             let mut orig_data = vec![];
270 |             let packet = try_get_packet(&mut modded_rand_data, &mut orig_data).await;
271 |             assert!(packet.is_none());
272 |             assert_eq!(orig_data, random_data_orig);
273 |         }
274 |     }
275 | }
276 | 
277 | // fn combine(first: &Vec, second: &Vec) -> Vec {
278 | //     // println!("combining {:?} with {:?}", first, second);
279 | //     let mut new = vec![];
280 | //     new.append(&mut first.clone());
281 | //     new.append(&mut second.clone());
282 | //     new
283 | // }
284 | 
--------------------------------------------------------------------------------
/src/webhook.rs:
--------------------------------------------------------------------------------
  1 | // minecraft honeypot does honeypot things for minecraft and proxies which is cool
  2 | // Copyright (C) 2022 cleonyc
  3 | 
  4 | // This program is free software: you can redistribute it and/or modify
  5 | // it under the terms of the GNU General Public License as published by
  6 | // the Free Software Foundation, either version 3 of the License, or
  7 | // (at your option) any later version.
  8 | 
  9 | // This program is distributed in the hope that it will be useful,
 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 | // GNU General Public License for more details.
 13 | 
 14 | // You should have received a copy of the GNU General Public License
 15 | // along with this program.  If not, see .
 16 | use isahc::{AsyncReadResponseExt, HttpClient, Request};
 17 | use serde_json::Value;
 18 | use webhook::{client::WebhookClient, models::Message};
 19 | 
 20 | use crate::database::{Client, Database, Login, Ping};
 21 | 
 22 | #[derive(Clone)]
 23 | pub struct SummaryWebhook {
 24 |     url: String,
 25 |     pub message_ids: Vec,
 26 |     client: HttpClient,
 27 | }
 28 | impl SummaryWebhook {
 29 |     pub async fn new(
 30 |         url: String,
 31 |         message_ids: Vec,
 32 |         database: Database,
 33 |     ) -> anyhow::Result {
 34 |         let client = HttpClient::new()?;
 35 |         let mut ret = Self {
 36 |             url,
 37 |             message_ids,
 38 |             client,
 39 |         };
 40 |         ret.update(database.clone()).await?;
 41 | 
 42 |         Ok(ret)
 43 |     }
 44 | 
 45 |     pub async fn update(&mut self, database: Database) -> anyhow::Result<()> {
 46 |         let gen_messages = gen_summmary_messages(database.clone());
 47 |         if gen_messages.len() != self.message_ids.len() {
 48 |             for msg in gen_messages.iter().skip(self.message_ids.len()) {
 49 |                 let req = Request::post(&format!("{}?wait=true", self.url.trim_end_matches('/')))
 50 |                     .header("Content-Type", "application/json")
 51 |                     .body(serde_json::to_string(&msg)?)?;
 52 |                 let mut resp = self.client.send_async(req).await?;
 53 |                 let json: Value = resp.json().await?;
 54 |                 let id: u64 = json["id"]
 55 |                     .as_str()
 56 |                     .expect("bad id in response from discord when creating webhook, what the fuck")
 57 |                     .parse()
 58 |                     .expect("apparently the id from the response is not a number (WTF??)");
 59 |                 self.message_ids.push(id);
 60 |             }
 61 |         }
 62 |         for (index, msg) in gen_summmary_messages(database.clone()).iter().enumerate() {
 63 |             self.client
 64 |                 .send_async(
 65 |                     Request::patch(&format!(
 66 |                         "{}/messages/{}",
 67 |                         self.url.clone(),
 68 |                         self.message_ids[index]
 69 |                     ))
 70 |                     .header("Content-Type", "application/json")
 71 |                     // this is the best way to handle rate limits:
 72 |                     .header("x-pls-no-rate-limit", "owo")
 73 |                     .body(serde_json::to_string(&msg)?)?,
 74 |                 )
 75 |                 .await?;
 76 |         }
 77 |         Ok(())
 78 |     }
 79 | }
 80 | fn gen_summmary_messages(database: Database) -> Vec {
 81 |     let mut ret = vec![];
 82 |     for (chunk_num, chunk) in database.data.chunks(25).enumerate() {
 83 |         let mut m = Message::new();
 84 |         m.embed(|e| {
 85 |             if chunk_num == 0 {
 86 |                 e.title("Clients");
 87 |             }
 88 |             for client in chunk
 89 |             {
 90 |                 e.field(
 91 |                     &format!("`{}`", &client.ip),
 92 |                     &format!(
 93 |                         "Pings: `{}` ({}), Logins: `{}` ({}), `{}`",
 94 |                         client.pings.len(),
 95 |                         if client.pings.is_empty() {
 96 |                             "N/A".to_string()
 97 |                         } else {
 98 |                             format!(
 99 |                                 "",
100 |                                 client
101 |                                     .pings
102 |                                     .iter()
103 |                                     .reduce(|a, b| if a.time > b.time { b } else { a })
104 |                                     .unwrap()
105 |                                     .time
106 |                                     .unix_timestamp()
107 |                             )
108 |                         },
109 |                         client.logins.len(),
110 |                         if client.logins.is_empty() {
111 |                             "N/A".to_string()
112 |                         } else {
113 |                             format!(
114 |                                 "",
115 |                                 client
116 |                                     .logins
117 |                                     .iter()
118 |                                     .reduce(|a, b| if a.time > b.time { b } else { a })
119 |                                     .unwrap()
120 |                                     .time
121 |                                     .unix_timestamp()
122 |                             )
123 |                         },
124 |                         client.ipinfo
125 |                     ),
126 |                     false,
127 |                 );
128 |             }
129 |             e
130 |         });
131 |         ret.push(m)
132 |     }
133 |     ret
134 | }
135 | #[derive(Clone)]
136 | pub struct ConWebhook {
137 |     url: String,
138 | }
139 | impl ConWebhook {
140 |     pub fn new(url: String) -> Self {
141 |         Self { url }
142 |     }
143 |     pub async fn handle_login(&self, client: Client, login: Login) -> anyhow::Result<()> {
144 |         WebhookClient::new(&self.url)
145 |             .send(|m| {
146 |                 m.content(
147 |                     format!(
148 |                         "`{}` joined the server
149 | {} | {}
150 | {}
151 |                 ",
152 |                         login.username,
153 |                         pretty_ip(&client.ip),
154 |                         client.ipinfo,
155 |                         if client.logins.len() == 1 {
156 |                             "**First Login**".to_string()
157 |                         } else {
158 |                             format!("Previous logins: `{}`", client.logins.len())
159 |                         }
160 |                     )
161 |                     .trim(),
162 |                 )
163 |             })
164 |             .await
165 |             .expect("failed to send webhook");
166 |         Ok(())
167 |     }
168 |     pub async fn handle_ping(&self, client: Client, ping: Ping) -> anyhow::Result<()> {
169 |         WebhookClient::new(&self.url)
170 |             .send(|m| {
171 |                 m.content(&format!(
172 |                     "Ping from {}, Con: {}, Target: {}",
173 |                     pretty_ip(&client.ip),
174 |                     client.ipinfo,
175 |                     ping.target
176 |                 ))
177 |             })
178 |             .await
179 |             .unwrap();
180 |         Ok(())
181 |     }
182 | }
183 | 
184 | fn pretty_ip(ip: &str) -> String {
185 |     format!("[`{}`]()", ip, ip)
186 | }
187 | 
--------------------------------------------------------------------------------