-
Notifications
You must be signed in to change notification settings - Fork 151
Expand file tree
/
Copy pathsalamander.rs
More file actions
175 lines (148 loc) · 4.65 KB
/
salamander.rs
File metadata and controls
175 lines (148 loc) · 4.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
use std::{
io::IoSliceMut,
ops::DerefMut,
sync::Arc,
task::{Context, Poll},
};
use blake2::{Blake2b, Digest};
use bytes::{BufMut, Bytes, BytesMut};
use digest::consts::U32;
use futures::ready;
use quinn::{
udp::{RecvMeta, Transmit},
AsyncUdpSocket, TokioRuntime,
};
use rand::Rng;
type Blake2b256 = Blake2b<U32>;
struct SalamanderObfs {
key: Vec<u8>,
}
impl SalamanderObfs {
/// create a new obfs
///
/// new() should init a blake2b256 hasher with key to reduce calculation,
/// but rust-analyzer can't recognize its type
pub fn new(key: Vec<u8>) -> Self {
Self { key }
}
pub fn obfs(&self, sale: &[u8], data: &mut [u8]) {
let mut hasher = Blake2b256::new();
hasher.update(&self.key);
hasher.update(sale);
let res: [u8; 32] = hasher.finalize().into();
data.iter_mut().enumerate().for_each(|(i, v)| {
*v ^= res[i % 32];
});
}
fn encrpyt(&self, data: &mut [u8]) -> Bytes {
let salt: [u8; 8] = rand::rng().random();
let mut res = BytesMut::with_capacity(8 + data.len());
res.put_slice(&salt);
self.obfs(&salt, data);
res.put_slice(data);
res.freeze()
}
fn decrpyt(&self, data: &mut [u8]) {
assert!(data.len() > 8, "data len must > 8");
let (salt, data) = data.split_at_mut(8);
self.obfs(salt, data);
// data.advance(8); // sadlly IoSliceMut::advance is unstable
}
}
pub struct Salamander {
inner: Arc<dyn AsyncUdpSocket>,
obfs: SalamanderObfs,
}
impl Salamander {
pub fn new(socket: std::net::UdpSocket, key: Vec<u8>) -> std::io::Result<Self> {
use quinn::Runtime;
let inner = TokioRuntime.wrap_udp_socket(socket)?;
std::io::Result::Ok(Self {
inner,
obfs: SalamanderObfs::new(key),
})
}
}
impl std::fmt::Debug for Salamander {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.inner.fmt(f)
}
}
impl AsyncUdpSocket for Salamander {
fn create_io_poller(
self: std::sync::Arc<Self>,
) -> std::pin::Pin<Box<dyn quinn::UdpPoller>> {
self.inner.clone().create_io_poller()
}
fn try_send(&self, transmit: &Transmit) -> std::io::Result<()> {
let mut v = transmit.to_owned();
// TODO: encrypt in place
let x = self.obfs.encrpyt(&mut v.contents.to_vec());
v.contents = &x;
self.inner.try_send(&v)
}
fn poll_recv(
&self,
cx: &mut Context,
bufs: &mut [IoSliceMut<'_>],
meta: &mut [RecvMeta],
) -> Poll<std::io::Result<usize>> {
// the number of udp packets received
let packet_nums = ready!(self.inner.poll_recv(cx, bufs, meta))?;
meta.iter().take(packet_nums).for_each(|v| {
tracing::trace!("meta addr {:?}, dst_ip: {:?}", v.addr, v.dst_ip);
});
bufs.iter_mut()
.zip(meta.iter_mut())
// first step take and then filter
.take(packet_nums)
.filter(|(_, meta)| meta.len > 8)
.for_each(|(v, meta)| {
let x = &mut v.deref_mut()[..meta.len];
// decrypt in place, and drop first 8 bytes
self.obfs.decrpyt(x);
let data = &mut x[8..];
unsafe {
// because IoSliceMut is transparent and .0 is also transparent, so it is a &[u8]
let b: IoSliceMut<'_> = std::mem::transmute(data);
*v = b;
}
// MUST update meta.len
meta.len -= 8;
});
Poll::Ready(Ok(packet_nums))
}
fn local_addr(&self) -> std::io::Result<std::net::SocketAddr> {
self.inner.local_addr()
}
fn may_fragment(&self) -> bool {
self.inner.may_fragment()
}
}
#[test]
#[ignore = "crash on Windows"]
fn test_skip() {
let mut data = b"12345678AA".to_vec();
let obfs = SalamanderObfs::new(b"123456".to_vec());
let bufs = &mut [IoSliceMut::new(&mut data)];
bufs.iter_mut().filter(|x| x.len() > 8).for_each(|v| {
obfs.decrpyt(v);
let data: &mut [u8] = v.as_mut();
let data = &mut data[8..];
unsafe {
let b: IoSliceMut<'_> = std::mem::transmute(data);
*v = b;
}
println!("{:?}", v);
});
}
#[test]
fn test_obfs() {
let obfs = SalamanderObfs::new(b"obfs".to_vec());
let mut data = b"hhh".to_vec();
let x = obfs.encrpyt(&mut data);
let mut x = x.to_vec();
let res = &mut IoSliceMut::new(&mut x);
obfs.decrpyt(res);
assert!(std::str::from_utf8(res[8..].as_ref()).unwrap() == "hhh");
}