1use anyhow::{anyhow, bail, Context, Result};
3use bytes::{Bytes, BytesMut};
4use serde::{Deserialize, Serialize};
5use std::fmt::{self, Display, Formatter};
6use std::str::FromStr;
7use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
8use tracing::{debug, trace};
9use urlencoding::encode;
10
11use crate::fair_channel::FairGroup;
12use crate::utils::get_version_number;
13pub use prost::Message as ProstMessage;
14
15pub trait Endpoint {
16 fn credentials(&self) -> String;
17 fn as_url(&self) -> String;
18}
19
20pub trait DefaultPort {
21 fn default_port(&self) -> Option<u16>;
22}
23
24pub fn parse_enum<E: FromStr + Into<i32>>(name: &str) -> Result<i32> {
25 let proto = E::from_str(name).map_err(|_| anyhow!("Invalid enum: {}", name))?;
26 Ok(proto.into())
27}
28
29pub fn str_enum<E: TryFrom<i32> + ToString>(e: i32) -> String {
30 e.try_into()
31 .map(|e: E| e.to_string())
32 .unwrap_or("unknown".to_string())
33}
34
35include!(concat!(env!("OUT_DIR"), "/protocol.rs"));
36
37impl ErrorKind {
38 pub fn is_fatal(self) -> bool {
43 match self {
44 ErrorKind::Fatal | ErrorKind::AuthFailed => true,
45 ErrorKind::HandshakeFailed
46 | ErrorKind::PermissionDenied
47 | ErrorKind::PublishFailed
48 | ErrorKind::ExecuteFailed
49 | ErrorKind::ServerError
50 | ErrorKind::UpgradeFailed
51 | ErrorKind::LeaseBusy => false,
52 }
53 }
54}
55
56pub struct Data {
57 pub data: Bytes,
58 pub socket_addr: Option<std::net::SocketAddr>,
59}
60
61impl Display for Protocol {
62 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
63 match self {
64 Protocol::Http => write!(f, "http"),
65 Protocol::Https => write!(f, "https"),
66 Protocol::Tcp => write!(f, "tcp"),
67 Protocol::Udp => write!(f, "udp"),
68 Protocol::OneC => write!(f, "1c"),
69 Protocol::Minecraft => write!(f, "minecraft"),
70 Protocol::Webdav => write!(f, "webdav"),
71 Protocol::Rtsp => write!(f, "rtsp"),
72 Protocol::Rdp => write!(f, "rdp"),
73 Protocol::Vnc => write!(f, "vnc"),
74 Protocol::Ssh => write!(f, "ssh"),
75 }
76 }
77}
78
79impl FromStr for Protocol {
80 type Err = anyhow::Error;
81
82 fn from_str(s: &str) -> Result<Self> {
83 match s {
84 "http" => Ok(Protocol::Http),
85 "https" => Ok(Protocol::Https),
86 "tcp" => Ok(Protocol::Tcp),
87 "udp" => Ok(Protocol::Udp),
88 "1c" => Ok(Protocol::OneC),
89 "minecraft" => Ok(Protocol::Minecraft),
90 "webdav" => Ok(Protocol::Webdav),
91 "rtsp" => Ok(Protocol::Rtsp),
92 "rdp" => Ok(Protocol::Rdp),
93 "vnc" => Ok(Protocol::Vnc),
94 "ssh" => Ok(Protocol::Ssh),
95 _ => bail!("Invalid protocol: {}", s),
96 }
97 }
98}
99
100impl DefaultPort for Protocol {
101 fn default_port(&self) -> Option<u16> {
102 match self {
103 Protocol::Http => Some(80),
104 Protocol::Https => Some(443),
105 Protocol::Tcp => None,
106 Protocol::Udp => None,
107 Protocol::OneC => None,
108 Protocol::Minecraft => Some(25565),
109 Protocol::Webdav => None,
110 Protocol::Rtsp => Some(554),
111 Protocol::Rdp => Some(3389),
112 Protocol::Vnc => Some(5900),
113 Protocol::Ssh => Some(22),
114 }
115 }
116}
117
118impl FromStr for Role {
119 type Err = anyhow::Error;
120
121 fn from_str(s: &str) -> Result<Self> {
122 match s {
123 "none" => Ok(Role::Nobody),
124 "admin" => Ok(Role::Admin),
125 "reader" => Ok(Role::Reader),
126 "writer" => Ok(Role::Writer),
127 _ => bail!("Invalid access: {}", s),
128 }
129 }
130}
131
132impl Display for Role {
133 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
134 match self {
135 Role::Nobody => write!(f, "none"),
136 Role::Admin => write!(f, "admin"),
137 Role::Reader => write!(f, "reader"),
138 Role::Writer => write!(f, "writer"),
139 }
140 }
141}
142
143impl FromStr for Auth {
144 type Err = anyhow::Error;
145
146 fn from_str(s: &str) -> Result<Self> {
147 match s {
148 "none" => Ok(Auth::None),
149 "basic" => Ok(Auth::Basic),
150 "form" => Ok(Auth::Form),
151 _ => bail!("Invalid auth: {}", s),
152 }
153 }
154}
155
156impl Display for Auth {
157 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
158 match self {
159 Auth::None => write!(f, "none"),
160 Auth::Basic => write!(f, "basic"),
161 Auth::Form => write!(f, "form"),
162 }
163 }
164}
165
166impl FromStr for ProxyProtocol {
167 type Err = anyhow::Error;
168
169 fn from_str(s: &str) -> Result<Self> {
170 match s {
171 "none" => Ok(ProxyProtocol::None),
172 "v2" => Ok(ProxyProtocol::V2),
173 _ => bail!("Invalid proxy protocol: {}", s),
174 }
175 }
176}
177
178impl Display for ProxyProtocol {
179 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
180 match self {
181 ProxyProtocol::None => write!(f, "none"),
182 ProxyProtocol::V2 => write!(f, "v2"),
183 }
184 }
185}
186
187impl FromStr for FilterAction {
188 type Err = anyhow::Error;
189
190 fn from_str(s: &str) -> Result<Self> {
191 match s {
192 "allow" => Ok(FilterAction::FilterAllow),
193 "deny" => Ok(FilterAction::FilterDeny),
194 "redirect" => Ok(FilterAction::FilterRedirect),
195 "log" => Ok(FilterAction::FilterLog),
196 _ => bail!("Invalid filter action: {}", s),
197 }
198 }
199}
200
201impl PartialEq for ClientEndpoint {
202 fn eq(&self, other: &Self) -> bool {
203 self.local_proto == other.local_proto
204 && self.local_addr == other.local_addr
205 && self.local_port == other.local_port
206 }
207}
208
209impl Display for ClientEndpoint {
210 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
211 if let Some(name) = self.description.as_ref() {
212 if !name.is_empty() {
213 write!(f, "[{}] ", name)?;
214 }
215 }
216 write!(f, "{}", self.as_url())
217 }
218}
219
220impl Endpoint for ClientEndpoint {
221 fn credentials(&self) -> String {
222 let mut s = String::new();
223 let username = self.username.as_deref().unwrap_or_default();
224 let password = self.password.as_deref().unwrap_or_default();
225 if !username.is_empty() {
226 s.push_str(&encode(username));
227 }
228 if !password.is_empty() {
229 s.push(':');
230 s.push_str(&encode(password));
231 }
232 if !s.is_empty() {
233 s.push('@');
234 }
235 s
236 }
237
238 fn as_url(&self) -> String {
239 match self.local_proto.try_into().unwrap() {
240 Protocol::OneC | Protocol::Minecraft | Protocol::Webdav => {
241 let credentials = self.credentials();
242 format!(
243 "{}://{}{}",
244 str_enum::<Protocol>(self.local_proto),
245 credentials,
246 self.local_addr
247 )
248 }
249 Protocol::Http
250 | Protocol::Https
251 | Protocol::Tcp
252 | Protocol::Udp
253 | Protocol::Rtsp
254 | Protocol::Rdp
255 | Protocol::Vnc
256 | Protocol::Ssh => {
257 let credentials = self.credentials();
258 format!(
259 "{}://{}{}:{}{}",
260 str_enum::<Protocol>(self.local_proto),
261 credentials,
262 self.local_addr,
263 self.local_port,
264 self.local_path
265 )
266 }
267 }
268 }
269}
270
271impl Endpoint for ServerEndpoint {
272 fn credentials(&self) -> String {
273 String::new()
274 }
275
276 fn as_url(&self) -> String {
277 format!(
278 "{}://{}:{}",
279 str_enum::<Protocol>(self.remote_proto),
280 self.remote_addr,
281 self.remote_port,
282 )
283 }
284}
285
286impl Display for ServerEndpoint {
287 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
288 let client = self.client.as_ref().unwrap();
289 if self.error.is_empty() {
290 write!(
291 f,
292 "{} -> {}://{}{}:{}{}",
293 client,
294 Protocol::try_from(self.remote_proto).unwrap(),
295 client.credentials(),
296 self.remote_addr,
297 self.remote_port,
298 client.local_path
299 )
300 } else {
301 write!(f, "{} -> {}", client, self.error)
302 }
303 }
304}
305
306impl AgentInfo {
307 pub fn is_support_server_control(&self) -> bool {
308 get_version_number(&self.version) >= get_version_number("2.1.1")
309 }
310
311 pub fn is_support_backpressure(&self) -> bool {
312 get_version_number(&self.version) >= get_version_number("2.2.0")
313 }
314
315 pub fn get_unique_id(&self) -> String {
316 if self.hwid.is_empty() {
317 self.agent_id.clone()
318 } else {
319 self.hwid.clone()
320 }
321 }
322}
323
324impl PartialEq for ServerEndpoint {
325 fn eq(&self, other: &Self) -> bool {
326 self.client == other.client
327 }
328}
329
330pub async fn read_message<T: AsyncRead + Unpin>(conn: &mut T) -> Result<message::Message> {
332 let mut buf = [0u8; std::mem::size_of::<u32>()];
333 conn.read_exact(&mut buf).await?;
334 let len = u32::from_le_bytes(buf) as usize;
335 if !(1..=1024 * 1024 * 10).contains(&len) {
336 bail!("Invalid message length: {}", len);
337 }
338 let mut buf = vec![0u8; len];
339 conn.read_exact(&mut buf).await?;
340
341 let proto_msg =
342 Message::decode(buf.as_slice()).context("Failed to decode Protocol Buffers message")?;
343
344 Ok(proto_msg.message.unwrap())
345}
346
347pub async fn write_message<T: AsyncWrite + Unpin>(
348 conn: &mut T,
349 msg: &message::Message,
350) -> Result<()> {
351 let proto_msg = Message {
352 message: Some(msg.clone()),
353 };
354
355 debug!("Sending proto message: {:?}", msg);
356
357 let mut buf = BytesMut::new();
358 proto_msg
359 .encode(&mut buf)
360 .context("Failed to encode Protocol Buffers message")?;
361
362 let len = buf.len() as u32;
363 let len_bytes = len.to_le_bytes();
364
365 conn.write_all(&len_bytes).await?;
366 conn.write_all(&buf).await?;
367 conn.flush().await?;
368 Ok(())
369}
370
371impl FairGroup for message::Message {
372 fn group_id(&self) -> Option<u32> {
373 match self {
374 message::Message::DataChannelData(lhs) => Some(lhs.channel_id),
375 message::Message::DataChannelDataUdp(lhs) => Some(lhs.channel_id),
376 message::Message::DataChannelEof(lhs) => Some(lhs.channel_id),
377 message::Message::DataChannelAck(lhs) => Some(lhs.channel_id),
378 _ => None,
379 }
380 }
381
382 fn get_size(&self) -> Option<usize> {
383 match self {
384 message::Message::DataChannelData(data) => Some(data.data.len()),
385 message::Message::DataChannelDataUdp(data) => Some(data.data.len()),
386 _ => None, }
388 }
389}
390
391pub type UdpPacketLen = u16; #[derive(Deserialize, Serialize, Debug)]
394pub struct UdpHeader {
395 from: std::net::SocketAddr,
396 len: UdpPacketLen,
397}
398
399#[derive(Debug)]
400pub struct UdpTraffic {
401 pub from: std::net::SocketAddr,
402 pub data: Bytes,
403}
404
405impl UdpTraffic {
406 pub async fn write<T: AsyncWrite + Unpin>(&self, writer: &mut T) -> Result<()> {
407 let hdr = UdpHeader {
408 from: self.from,
409 len: self.data.len() as UdpPacketLen,
410 };
411
412 let v = bincode::serde::encode_to_vec(&hdr, bincode::config::legacy()).unwrap();
413
414 trace!("Write {:?} of length {}", hdr, v.len());
415 writer.write_u8(v.len() as u8).await?;
416 writer.write_all(&v).await?;
417
418 writer.write_all(&self.data).await?;
419
420 Ok(())
421 }
422
423 #[allow(dead_code)]
424 pub async fn write_slice<T: AsyncWrite + Unpin>(
425 writer: &mut T,
426 from: std::net::SocketAddr,
427 data: &[u8],
428 ) -> Result<()> {
429 let hdr = UdpHeader {
430 from,
431 len: data.len() as UdpPacketLen,
432 };
433
434 let v = bincode::serde::encode_to_vec(&hdr, bincode::config::legacy()).unwrap();
435
436 trace!("Write {:?} of length {}", hdr, v.len());
437 writer.write_u8(v.len() as u8).await?;
438 writer.write_all(&v).await?;
439
440 writer.write_all(data).await?;
441
442 Ok(())
443 }
444
445 pub async fn read<T: AsyncRead + Unpin>(reader: &mut T, hdr_len: u8) -> Result<UdpTraffic> {
446 let mut buf = vec![0; hdr_len as usize];
447 reader
448 .read_exact(&mut buf)
449 .await
450 .with_context(|| "Failed to read udp header")?;
451
452 let hdr: UdpHeader = bincode::serde::decode_from_slice(&buf, bincode::config::legacy())
453 .with_context(|| "Failed to deserialize UdpHeader")?
454 .0;
455
456 trace!("hdr {:?}", hdr);
457
458 let mut data = BytesMut::new();
459 data.resize(hdr.len as usize, 0);
460 reader.read_exact(&mut data).await?;
461
462 Ok(UdpTraffic {
463 from: hdr.from,
464 data: data.freeze(),
465 })
466 }
467}
468
469#[cfg(test)]
470mod tests {
471 use super::*;
472
473 #[test]
481 fn lease_busy_is_retryable_not_fatal() {
482 assert!(ErrorKind::Fatal.is_fatal());
483 assert!(ErrorKind::AuthFailed.is_fatal());
484 assert!(
485 !ErrorKind::LeaseBusy.is_fatal(),
486 "a busy lease is temporary by construction; treating it as fatal \
487 is the CLOUDPUB-1339 incident"
488 );
489 assert!(!ErrorKind::HandshakeFailed.is_fatal());
490 }
491}