Skip to main content

borer_core/proto/
padding.rs

1use anyhow::Context;
2use bytes::{BufMut, BytesMut};
3use rand::{Rng, RngCore};
4use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
5
6/// Trojan padding frame used to disguise connection metadata.
7#[derive(Debug)]
8pub struct Padding {
9    len: u16,
10}
11
12impl Padding {
13    /// Create a padding frame with a random length in `start..end`.
14    pub fn new(start: u16, end: u16) -> Self {
15        let mut rng = rand::rng();
16        let len = rng.random_range(start..end);
17        Self { len }
18    }
19
20    /// Read a padding frame from the stream.
21    pub async fn read_from<R>(stream: &mut R) -> anyhow::Result<Self>
22    where
23        R: AsyncRead + Unpin,
24    {
25        let len = stream.read_u16().await?;
26        let mut buf = vec![0; len as usize];
27        stream.read_exact(&mut buf).await?;
28        Ok(Padding { len })
29    }
30
31    /// Write this padding frame to the stream.
32    pub async fn write_to<W>(&self, w: &mut W) -> anyhow::Result<()>
33    where
34        W: AsyncWrite + Unpin,
35    {
36        let mut buf = BytesMut::with_capacity(self.serialized_len());
37        self.write_to_buf(&mut buf);
38        w.write_all(&buf)
39            .await
40            .context("padding Write buf failed")?;
41
42        Ok(())
43    }
44
45    pub fn write_to_buf<B: BufMut>(&self, buf: &mut B) {
46        let rand_buf = self.rand_buf();
47        buf.put_u16(self.len);
48        buf.put_slice(&rand_buf);
49    }
50
51    pub fn serialized_len(&self) -> usize {
52        2 + self.len as usize
53    }
54
55    pub fn rand_buf(&self) -> Vec<u8> {
56        let mut rng = rand::rng();
57        let mut buf = vec![0; self.len as usize];
58        rng.fill_bytes(&mut buf);
59        buf
60    }
61}
62
63impl Default for Padding {
64    fn default() -> Self {
65        Self::new(256, 2048)
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use std::io::Cursor;
72
73    use bytes::{Buf, BytesMut};
74
75    use super::Padding;
76
77    #[test]
78    fn serialized_len_matches_written_buffer_length() {
79        let padding = Padding::new(8, 9);
80        let mut buf = BytesMut::new();
81
82        padding.write_to_buf(&mut buf);
83
84        assert_eq!(buf.len(), padding.serialized_len());
85        assert_eq!(buf.get_u16() as usize + 2, padding.serialized_len());
86    }
87
88    #[tokio::test]
89    async fn read_from_round_trips_written_bytes() {
90        let padding = Padding::new(8, 9);
91        let mut raw = BytesMut::new();
92        padding.write_to_buf(&mut raw);
93        let expected_len = padding.serialized_len();
94
95        let mut cursor = Cursor::new(raw.to_vec());
96        let actual = Padding::read_from(&mut cursor).await.unwrap();
97
98        assert_eq!(actual.serialized_len(), expected_len);
99    }
100}