1use crate::{
2 constants::*,
3 handshake::Obfs4NtorPublicKey,
4 proto::{Obfs4Stream, IAT},
5 Error, OBFS4_NAME,
6};
7use ptrs::{args::Args, FutureResult as F};
8
9use std::{
10 marker::PhantomData,
11 net::{SocketAddrV4, SocketAddrV6},
12 pin::Pin,
13 str::FromStr,
14 time::Duration,
15};
16
17use hex::FromHex;
18use ptrs::trace;
19use tokio::{
20 io::{AsyncRead, AsyncWrite},
21 net::TcpStream,
22};
23
24pub type Obfs4PT = Transport<TcpStream>;
25
26#[derive(Debug, Default)]
27pub struct Transport<T> {
28 _p: PhantomData<T>,
29}
30impl<T> Transport<T> {
31 pub const NAME: &'static str = OBFS4_NAME;
32}
33
34impl<T> ptrs::PluggableTransport<T> for Transport<T>
35where
36 T: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
37{
38 type ClientBuilder = crate::ClientBuilder;
39 type ServerBuilder = crate::ServerBuilder<T>;
40
41 fn name() -> String {
42 OBFS4_NAME.into()
43 }
44
45 fn client_builder() -> <Self as ptrs::PluggableTransport<T>>::ClientBuilder {
46 crate::ClientBuilder::default()
47 }
48
49 fn server_builder() -> <Self as ptrs::PluggableTransport<T>>::ServerBuilder {
50 crate::ServerBuilder::default()
51 }
52}
53
54impl<T> ptrs::ServerBuilder<T> for crate::ServerBuilder<T>
55where
56 T: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
57{
58 type ServerPT = crate::Server;
59 type Error = Error;
60 type Transport = Transport<T>;
61
62 fn build(&self) -> Self::ServerPT {
63 crate::ServerBuilder::build(self)
64 }
65
66 fn method_name() -> String {
67 OBFS4_NAME.into()
68 }
69
70 fn options(&mut self, opts: &Args) -> Result<&mut Self, Self::Error> {
71 let state = Self::parse_state(None::<&str>, opts)?;
74 self.identity_keys = state.private_key;
75 self.iat_mode(state.iat_mode);
76 trace!(
79 "node_pubkey: {}, node_id: {}, iat: {}",
80 hex::encode(self.identity_keys.pk.pk.as_bytes()),
81 hex::encode(self.identity_keys.pk.id.as_bytes()),
82 self.iat_mode,
83 );
84 Ok(self)
85 }
86
87 fn get_client_params(&self) -> String {
88 self.client_params()
89 }
90
91 fn statefile_location(&mut self, _path: &str) -> Result<&mut Self, Self::Error> {
92 Ok(self)
93 }
94
95 fn timeout(&mut self, _timeout: Option<Duration>) -> Result<&mut Self, Self::Error> {
96 Ok(self)
97 }
98
99 fn v4_bind_addr(&mut self, _addr: SocketAddrV4) -> Result<&mut Self, Self::Error> {
100 Ok(self)
101 }
102
103 fn v6_bind_addr(&mut self, _addr: SocketAddrV6) -> Result<&mut Self, Self::Error> {
104 Ok(self)
105 }
106}
107
108impl<T> ptrs::ClientBuilder<T> for crate::ClientBuilder
109where
110 T: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
111{
112 type ClientPT = crate::Client;
113 type Error = Error;
114 type Transport = Transport<T>;
115
116 fn method_name() -> String {
117 OBFS4_NAME.into()
118 }
119
120 fn build(&self) -> Self::ClientPT {
125 crate::ClientBuilder::build(self)
126 }
127
128 fn options(&mut self, opts: &Args) -> Result<&mut Self, Self::Error> {
131 let server_materials = match opts.retrieve(CERT_ARG) {
132 Some(cert_strs) => {
133 if cert_strs.is_empty() {
136 return Err(format!("missing argument '{NODE_ID_ARG}'").into());
137 }
138 trace!("cert string: {}", &cert_strs);
139 let ntor_pk = Obfs4NtorPublicKey::from_str(&cert_strs)?;
140 let pk: [u8; NODE_PUBKEY_LENGTH] = *ntor_pk.pk.as_bytes();
141 let id: [u8; NODE_ID_LENGTH] = ntor_pk.id.as_bytes().try_into().unwrap();
142 (pk, id)
143 }
144 None => {
145 let node_id_strs = opts
148 .retrieve(NODE_ID_ARG)
149 .ok_or(format!("missing argument '{NODE_ID_ARG}'"))?;
150 let id = <[u8; NODE_ID_LENGTH]>::from_hex(node_id_strs)
151 .map_err(|e| format!("malformed node id: {e}"))?;
152
153 let public_key_strs = opts
154 .retrieve(PUBLIC_KEY_ARG)
155 .ok_or(format!("missing argument '{PUBLIC_KEY_ARG}'"))?;
156
157 let pk = <[u8; 32]>::from_hex(public_key_strs)
158 .map_err(|e| format!("malformed public key: {e}"))?;
159 (pk, id)
161 }
162 };
163
164 let iat_strs = opts
166 .retrieve(IAT_ARG)
167 .ok_or(format!("missing argument '{IAT_ARG}'"))?;
168 let iat_mode = IAT::from_str(&iat_strs)?;
169
170 self.with_node_pubkey(server_materials.0)
171 .with_node_id(server_materials.1)
172 .with_iat_mode(iat_mode);
173 trace!(
174 "node_pubkey: {}, node_id: {}, iat: {}",
175 hex::encode(self.station_pubkey),
176 hex::encode(self.station_id),
177 iat_mode
178 );
179
180 Ok(self)
181 }
182
183 fn statefile_location(&mut self, _path: &str) -> Result<&mut Self, Self::Error> {
185 Ok(self)
186 }
187
188 fn timeout(&mut self, _timeout: Option<Duration>) -> Result<&mut Self, Self::Error> {
191 Ok(self)
192 }
193
194 fn v4_bind_addr(&mut self, _addr: SocketAddrV4) -> Result<&mut Self, Self::Error> {
198 Ok(self)
199 }
200
201 fn v6_bind_addr(&mut self, _addr: SocketAddrV6) -> Result<&mut Self, Self::Error> {
205 Ok(self)
206 }
207}
208
209impl<InRW, InErr> ptrs::ClientTransport<InRW, InErr> for crate::Client
212where
213 InRW: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
214 InErr: std::error::Error + Send + Sync + 'static,
215{
216 type OutRW = Obfs4Stream<InRW>;
217 type OutErr = Error;
218 type Builder = crate::ClientBuilder;
219
220 fn establish(self, input: Pin<F<InRW, InErr>>) -> Pin<F<Self::OutRW, Self::OutErr>> {
221 Box::pin(crate::Client::establish(self, input))
222 }
223
224 fn wrap(self, io: InRW) -> Pin<F<Self::OutRW, Self::OutErr>> {
225 Box::pin(crate::Client::wrap(self, io))
226 }
227
228 fn method_name() -> String {
229 OBFS4_NAME.into()
230 }
231}
232
233impl<InRW> ptrs::ServerTransport<InRW> for crate::Server
234where
235 InRW: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
236{
237 type OutRW = Obfs4Stream<InRW>;
238 type OutErr = Error;
239 type Builder = crate::ServerBuilder<InRW>;
240
241 fn reveal(self, io: InRW) -> Pin<F<Self::OutRW, Self::OutErr>> {
243 Box::pin(crate::Server::wrap(self, io))
244 }
245
246 fn method_name() -> String {
247 OBFS4_NAME.into()
248 }
249}
250
251#[cfg(test)]
252mod test {
253 use super::*;
254
255 #[test]
256 fn check_name() {
257 let pt_name = <Obfs4PT as ptrs::PluggableTransport<TcpStream>>::name();
258 assert_eq!(pt_name, Obfs4PT::NAME);
259
260 let cb_name = <crate::ClientBuilder as ptrs::ClientBuilder<TcpStream>>::method_name();
261 assert_eq!(cb_name, Obfs4PT::NAME);
262
263 let sb_name =
264 <crate::ServerBuilder<TcpStream> as ptrs::ServerBuilder<TcpStream>>::method_name();
265 assert_eq!(sb_name, Obfs4PT::NAME);
266
267 let ct_name =
268 <crate::Client as ptrs::ClientTransport<TcpStream, crate::Error>>::method_name();
269 assert_eq!(ct_name, Obfs4PT::NAME);
270
271 let st_name = <crate::Server as ptrs::ServerTransport<TcpStream>>::method_name();
272 assert_eq!(st_name, Obfs4PT::NAME);
273 }
274}