Skip to main content

crowdstrike_cloudproto/services/ts/
acceptor.rs

1use crate::framing::CloudProtoError::ClosedByPeer;
2use crate::framing::{CloudProtoError, CloudProtoPacket, CloudProtoSocket, CloudProtoVersion};
3use crate::services::ts::{TsConnectInfo, TsConnectResponse, TsEventSocket, TsPacketKind};
4use crate::services::CloudProtoMagic;
5use bytes::Buf;
6use futures_util::{SinkExt, StreamExt};
7use std::io::Read;
8use tokio::io::{AsyncRead, AsyncWrite};
9
10/// Accept [`TsEventSocket`](TsEventSocket) connections
11pub struct TsEventAcceptor<IO: AsyncRead + AsyncWrite> {
12    io: CloudProtoSocket<IO>,
13}
14
15impl<IO> TsEventAcceptor<IO>
16where
17    IO: AsyncRead + AsyncWrite,
18{
19    /// Wait for an incoming TS client connection, and return the received [`TsConnectInfo`](TsConnectInfo)
20    pub async fn listen(
21        mut io: CloudProtoSocket<IO>,
22    ) -> Result<(Self, TsConnectInfo), CloudProtoError> {
23        let pkt = match io.next().await {
24            None => return Err(ClosedByPeer("TS client closed connection".into())),
25            Some(Err(e)) => return Err(e),
26            Some(Ok(pkt)) => pkt,
27        };
28        if pkt.magic != CloudProtoMagic::TS {
29            return Err(CloudProtoError::BadMagic(pkt.magic, CloudProtoMagic::TS));
30        }
31        if pkt.kind != TsPacketKind::Connect {
32            return Err(CloudProtoError::WrongConnectionPacketKind(
33                pkt.kind,
34                TsPacketKind::Connect.into(),
35            ));
36        }
37        if pkt.version != CloudProtoVersion::Connect {
38            return Err(CloudProtoError::BadVersion(
39                pkt.version,
40                CloudProtoVersion::Connect,
41            ));
42        }
43
44        if pkt.payload.len() != 4 * 16 + 8 {
45            return Err(CloudProtoError::PayloadInvalidSize(
46                pkt.payload.len(),
47                4 * 16 + 8,
48            ));
49        }
50        let mut info = TsConnectInfo {
51            cid: [0; 16],
52            unk0: [0; 16],
53            aid: [0; 16],
54            bootid: [0; 16],
55            pt: [0; 8],
56        };
57        let mut rd = pkt.payload.reader();
58        rd.read_exact(&mut info.cid)?;
59        rd.read_exact(&mut info.unk0)?;
60        rd.read_exact(&mut info.aid)?;
61        rd.read_exact(&mut info.bootid)?;
62        rd.read_exact(&mut info.pt)?;
63
64        Ok((Self { io }, info))
65    }
66
67    /// Accept an incoming TS client, establishing a connected socket
68    pub async fn accept(
69        mut self,
70        reply: TsConnectResponse,
71    ) -> Result<TsEventSocket<IO>, CloudProtoError> {
72        let mut payload = Vec::with_capacity(1 + 16);
73        payload.push(reply.agent_id_status as u8);
74        payload.extend_from_slice(&reply.aid);
75        let pkt = CloudProtoPacket {
76            magic: CloudProtoMagic::TS,
77            kind: TsPacketKind::ConnectionEstablished.into(),
78            version: CloudProtoVersion::Normal,
79            payload,
80        };
81        self.io.send(pkt).await?;
82
83        Ok(TsEventSocket::new(self.io))
84    }
85}