sosistab/tcp/
mod.rs

1use std::{convert::TryInto, time::Duration};
2
3use async_dup::Arc;
4
5use c2_chacha::{stream_cipher::NewStreamCipher, stream_cipher::SyncStreamCipher, ChaCha8};
6
7use parking_lot::Mutex;
8
9use smol::io::BufReader;
10use smol::prelude::*;
11
12mod client;
13mod tls_helpers;
14pub use client::*;
15mod server;
16pub use server::*;
17
18use crate::{buffer::Buff, crypt::NgAead};
19
20const CONN_LIFETIME: Duration = Duration::from_secs(600);
21
22const TCP_UP_KEY: &[u8; 32] = b"uploadtcp-----------------------";
23const TCP_DN_KEY: &[u8; 32] = b"downloadtcp---------------------";
24
25type DynAsyncWrite = Box<dyn AsyncWrite + Unpin + Send + Sync + 'static>;
26type DynAsyncRead = Box<dyn AsyncRead + Unpin + Send + Sync + 'static>;
27
28/// Wrapped TCP connection, with a send and receive obfuscation key.
29#[derive(Clone)]
30struct ObfsTcp {
31    write: async_dup::Arc<async_dup::Mutex<DynAsyncWrite>>,
32    read: async_dup::Arc<async_dup::Mutex<BufReader<DynAsyncRead>>>,
33    send_chacha: Arc<Mutex<ChaCha8>>,
34    recv_chacha: Arc<Mutex<ChaCha8>>,
35}
36
37impl ObfsTcp {
38    /// creates an ObfsTCP given a shared secret and direction
39    fn new(ss: blake3::Hash, is_server: bool, write: DynAsyncWrite, read: DynAsyncRead) -> Self {
40        let up_chacha = Arc::new(Mutex::new(
41            ChaCha8::new_var(
42                blake3::keyed_hash(TCP_UP_KEY, ss.as_bytes()).as_bytes(),
43                &[0; 8],
44            )
45            .unwrap(),
46        ));
47        let dn_chacha = Arc::new(Mutex::new(
48            ChaCha8::new_var(
49                blake3::keyed_hash(TCP_DN_KEY, ss.as_bytes()).as_bytes(),
50                &[0; 8],
51            )
52            .unwrap(),
53        ));
54        let buf_read =
55            async_dup::Arc::new(async_dup::Mutex::new(BufReader::with_capacity(4096, read)));
56        if is_server {
57            Self {
58                write: async_dup::Arc::new(async_dup::Mutex::new(write)),
59                read: buf_read,
60                send_chacha: dn_chacha,
61                recv_chacha: up_chacha,
62            }
63        } else {
64            Self {
65                write: async_dup::Arc::new(async_dup::Mutex::new(write)),
66                read: buf_read,
67                send_chacha: up_chacha,
68                recv_chacha: dn_chacha,
69            }
70        }
71    }
72
73    async fn write(&self, msg: &[u8]) -> std::io::Result<()> {
74        assert!(msg.len() <= 2048);
75        let mut buf = [0u8; 2048];
76        let buf = &mut buf[..msg.len()];
77        buf.copy_from_slice(msg);
78        self.send_chacha.lock().apply_keystream(buf);
79        let mut inner = self.write.clone();
80        inner.write_all(buf).await?;
81        inner.flush().await?;
82        Ok(())
83    }
84
85    async fn read_exact(&self, buf: &mut [u8]) -> std::io::Result<()> {
86        self.read.lock().read_exact(buf).await?;
87        self.recv_chacha.lock().apply_keystream(buf);
88        Ok(())
89    }
90}
91
92async fn read_encrypted<R: AsyncRead + Unpin>(
93    decrypt: NgAead,
94    rdr: &mut R,
95) -> anyhow::Result<Buff> {
96    // read the length first
97    let mut length_buf = vec![0u8; NgAead::overhead() + 2];
98    rdr.read_exact(&mut length_buf).await?;
99    // decrypt the length
100    let length_buf = decrypt.decrypt(&length_buf)?;
101    if length_buf.len() != 2 {
102        anyhow::bail!("length must be 16 bits");
103    }
104    let length_buf = &length_buf[..];
105    // now read the actual body
106    let mut actual_buf = vec![0u8; u16::from_be_bytes(length_buf.try_into().unwrap()) as usize];
107    rdr.read_exact(&mut actual_buf).await?;
108    Ok(decrypt.decrypt(&actual_buf)?)
109}
110
111async fn write_encrypted<W: AsyncWrite + Unpin>(
112    encrypt: NgAead,
113    to_send: &[u8],
114    writer: &mut W,
115) -> anyhow::Result<()> {
116    let to_send = encrypt.encrypt(to_send);
117    let raw_length = (to_send.len() as u16).to_be_bytes();
118    writer.write_all(&encrypt.encrypt(&raw_length)).await?;
119    writer.write_all(&to_send).await?;
120    Ok(())
121}