Skip to content

Commit

Permalink
feat: http in implement shadowsocks/simple-obfs
Browse files Browse the repository at this point in the history
  • Loading branch information
spacemeowx2 committed Aug 22, 2022
1 parent 15d16ca commit 47719fe
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 34 deletions.
1 change: 1 addition & 0 deletions protocol/obfs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ tokio = "1.0"
pin-project-lite = "0.2.6"
futures = "0.3"
rand = "0.8.3"
base64 = "0.13.0"
49 changes: 36 additions & 13 deletions protocol/obfs/src/http_simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,22 @@ use rd_interface::{
};
use tokio::io::AsyncRead;

fn def_method() -> String {
"GET".to_string()
}

fn def_uri() -> String {
"/".to_string()
}

#[rd_config]
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct HttpSimple {
obfs_param: String,
#[serde(default = "def_method")]
method: String,
#[serde(default = "def_uri")]
uri: String,
host: String,
}

impl Obfs for HttpSimple {
Expand All @@ -28,7 +40,7 @@ impl Obfs for HttpSimple {
_ctx: &mut rd_interface::Context,
_addr: &Address,
) -> Result<TcpStream> {
Ok(Connect::new(tcp, &self.obfs_param).into_dyn())
Ok(Connect::new(tcp, self.clone()).into_dyn())
}

fn tcp_accept(&self, _tcp: TcpStream, _addr: std::net::SocketAddr) -> Result<TcpStream> {
Expand All @@ -53,17 +65,17 @@ pin_project! {
inner: TcpStream,
write: WriteState,
read: ReadState,
obfs_param: String,
param: HttpSimple,
}
}

impl Connect {
fn new(tcp: TcpStream, param: &str) -> Connect {
fn new(tcp: TcpStream, param: HttpSimple) -> Connect {
Connect {
inner: tcp,
write: WriteState::Wait,
read: ReadState::Read(vec![0u8; 8192], 0),
obfs_param: param.to_string(),
param,
}
}
}
Expand Down Expand Up @@ -128,17 +140,28 @@ impl ITcpStream for Connect {
loop {
match &mut self.write {
WriteState::Wait => {
let head_len = thread_rng().gen_range(0..64usize).min(buf.len());
let head = &buf[..head_len];
let body = &buf[head_len..];
let major = thread_rng().next_u32() % 51;
let minor = thread_rng().next_u32() % 2;

let key_bytes: [u8; 16] = thread_rng().gen();
let key = base64::encode(key_bytes);

let mut cursor = Cursor::new(Vec::<u8>::with_capacity(1024));
cursor.write_fmt(format_args!(
"GET /{path} HTTP/1.1\r\nHost: {host}\r\n\r\n",
path = UrlEncode(head),
host = self.obfs_param
"{method} {path} HTTP/1.1\r
Host: {host}\r
User-Agent: curl/7.{major}.{minor}\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Key: {key}\r
Content-Length: {len}\r
\r\n",
method = self.param.method,
path = self.param.uri,
host = self.param.host,
len = buf.len(),
))?;
cursor.write_all(body)?;
cursor.write_all(buf)?;

let buf = cursor.into_inner();

Expand Down
14 changes: 4 additions & 10 deletions protocol/obfs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,23 @@ pub trait Obfs {

#[rd_config]
#[derive(Debug)]
#[serde(rename_all = "snake_case", tag = "obfs_type")]
#[serde(rename_all = "snake_case")]
pub enum ObfsType {
HttpSimple(http_simple::HttpSimple),
Http(http_simple::HttpSimple),
Plain(plain::Plain),
}

impl Default for ObfsType {
fn default() -> Self {
ObfsType::Plain(plain::Plain)
}
}

impl Obfs for ObfsType {
fn tcp_connect(&self, tcp: TcpStream, ctx: &mut Context, addr: &Address) -> Result<TcpStream> {
match self {
ObfsType::HttpSimple(i) => i.tcp_connect(tcp, ctx, addr),
ObfsType::Http(i) => i.tcp_connect(tcp, ctx, addr),
ObfsType::Plain(i) => i.tcp_connect(tcp, ctx, addr),
}
}

fn tcp_accept(&self, tcp: TcpStream, addr: SocketAddr) -> Result<TcpStream> {
match self {
ObfsType::HttpSimple(i) => i.tcp_accept(tcp, addr),
ObfsType::Http(i) => i.tcp_accept(tcp, addr),
ObfsType::Plain(i) => i.tcp_accept(tcp, addr),
}
}
Expand Down
2 changes: 1 addition & 1 deletion protocol/obfs/src/obfs_net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type BoxObfs = Arc<dyn Obfs + Send + Sync + 'static>;
pub struct ObfsNetConfig {
#[serde(default)]
pub net: NetRef,
#[serde(default, flatten)]
#[serde(flatten)]
pub obfs_type: ObfsType,
}

Expand Down
14 changes: 4 additions & 10 deletions src/config/importer/clash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,15 @@ impl Clash {

if let (Some(plugin), Some(plugin_opts)) = (params.plugin, params.plugin_opts) {
if plugin == "obfs" {
// only http is supported
if let Some("http") = plugin_opts.get("mode").map(AsRef::as_ref) {
} else {
return Err(anyhow!("obfs only support http"));
}
// TODO: support other modes
let mode_param = plugin_opts
.get("host")
let obfs_mode = plugin_opts
.get("mode")
.map(|i| i.to_string())
.unwrap_or_default();

let obfs_net = Net::new(
"obfs",
json!({
"obfs_type": "http_simple",
"obfs_param": mode_param,
obfs_mode: plugin_opts,
}),
);

Expand Down

0 comments on commit 47719fe

Please sign in to comment.