Skip to content

Commit

Permalink
feat: support wildcard sni
Browse files Browse the repository at this point in the history
  • Loading branch information
ihciah committed Mar 8, 2023
1 parent 6285b05 commit 3232408
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 48 deletions.
50 changes: 25 additions & 25 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "MIT/Apache-2.0"
name = "shadow-tls"
readme = "README.md"
repository = "https://github.com/ihciah/shadow-tls"
version = "0.2.18"
version = "0.2.19"

[dependencies]
monoio = {version = "0.0.9"}
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ services:
# ALPN(optional): set alpns(like http/1.1, http/1.1;h2, recommend to leave it blank if you don't know it)
# THREADS(optional): set threads number(recommend to leave it blank)
# DISABLE_NODELAY(optional): disable TCP_NODELAY(recommend to leave it blank)
# WILDCARD_SNI: Use sni:443 as handshake server(off/authed/all)

# Note:
# Multiple SNIs is supported now.
Expand Down
5 changes: 5 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ then
then
parameter="$parameter --tls $TLS"
fi

if [ ! -z "$WILDCARD_SNI" ]
then
parameter="$parameter --wildcard-sni $WILDCARD_SNI"
fi
fi

if [ "$MODE" = "client" ]
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{fmt::Display, thread::JoinHandle};
pub use crate::{
client::{ShadowTlsClient, TlsExtConfig, TlsNames},
server::{ShadowTlsServer, TlsAddrs},
util::V3Mode,
util::{V3Mode, WildcardSNI},
};

pub enum RunningArgs {
Expand Down
35 changes: 25 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

use std::{collections::HashMap, process::exit};

use clap::{Parser, Subcommand};
use clap::{Parser, Subcommand, ValueEnum};
use tracing_subscriber::{filter::LevelFilter, fmt, prelude::*, EnvFilter};

use shadow_tls::{
sip003::parse_sip003_options, RunningArgs, TlsAddrs, TlsExtConfig, TlsNames, V3Mode,
WildcardSNI,
};

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -86,6 +87,12 @@ enum Commands {
tls_addr: TlsAddrs,
#[clap(long = "password", help = "Password")]
password: String,
#[clap(
long = "wildcard-sni",
default_value = "off",
help = "Use sni:443 as handshake server without predefining mapping(useful for bypass billing system like airplane wifi without modifying server config)"
)]
wildcard_sni: WildcardSNI,
},
}

Expand Down Expand Up @@ -124,16 +131,20 @@ impl From<Args> for RunningArgs {
Commands::Server {
listen,
server_addr,
tls_addr,
password,
} => Self::Server {
listen_addr: listen,
target_addr: server_addr,
tls_addr,
mut tls_addr,
password,
nodelay: !args.opts.disable_nodelay,
v3,
},
wildcard_sni,
} => {
tls_addr.set_wildcard_sni(wildcard_sni);
Self::Server {
listen_addr: listen,
target_addr: server_addr,
tls_addr,
password,
nodelay: !args.opts.disable_nodelay,
v3,
}
}
}
}
}
Expand Down Expand Up @@ -189,12 +200,16 @@ pub(crate) fn get_sip003_arg() -> Option<Args> {
.expect("tls param must be specified(like tls=xxx.com:443)");
let tls_addrs = parse_server_addrs(tls_addr)
.expect("tls param parse failed(like tls=xxx.com:443 or tls=yyy.com:1.2.3.4:443;zzz.com:443;xxx.com)");
let wildcard_sni =
WildcardSNI::from_str(opts.get("tls").map(AsRef::as_ref).unwrap_or_default(), true)
.expect("wildcard_sni format error");
Args {
cmd: crate::Commands::Server {
listen: format!("{ss_remote_host}:{ss_remote_port}"),
server_addr: format!("{ss_local_host}:{ss_local_port}"),
tls_addr: tls_addrs,
password: passwd.to_owned(),
wildcard_sni,
},
opts: args_opts,
}
Expand Down
46 changes: 35 additions & 11 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::{
bind_with_pretty_error, copy_bidirectional, copy_until_eof, kdf, mod_tcp_conn, prelude::*,
support_tls13, verified_relay, xor_slice, CursorExt, Hmac, V3Mode,
},
WildcardSNI,
};

/// ShadowTlsServer.
Expand All @@ -44,19 +45,31 @@ pub struct ShadowTlsServer<LA, TA> {
pub struct TlsAddrs {
dispatch: rustc_hash::FxHashMap<String, String>,
fallback: String,
wildcard_sni: WildcardSNI,
}

impl TlsAddrs {
fn find(&self, key: Option<&str>) -> &str {
fn find<'a>(&'a self, key: Option<&str>, auth: bool) -> Cow<'a, str> {
match key {
Some(k) => self.dispatch.get(k).unwrap_or(&self.fallback),
None => &self.fallback,
Some(k) => match self.dispatch.get(k) {
Some(v) => Cow::Borrowed(v),
None => match self.wildcard_sni {
WildcardSNI::Authed if auth => Cow::Owned(format!("{k}:443")),
WildcardSNI::All => Cow::Owned(format!("{k}:443")),
_ => Cow::Borrowed(&self.fallback),
},
},
None => Cow::Borrowed(&self.fallback),
}
}

fn is_empty(&self) -> bool {
self.dispatch.is_empty()
}

pub fn set_wildcard_sni(&mut self, wildcard_sni: WildcardSNI) {
self.wildcard_sni = wildcard_sni;
}
}

impl TryFrom<&str> for TlsAddrs {
Expand Down Expand Up @@ -103,7 +116,11 @@ impl TryFrom<&str> for TlsAddrs {
bail!("duplicate server addrs part found");
}
}
Ok(TlsAddrs { dispatch, fallback })
Ok(TlsAddrs {
dispatch,
fallback,
wildcard_sni: Default::default(),
})
}
}

Expand Down Expand Up @@ -186,8 +203,10 @@ impl<LA, TA> ShadowTlsServer<LA, TA> {

// choose handshake server addr and connect
let server_name = server_name.and_then(|s| String::from_utf8(s).ok());
let addr = self.tls_addr.find(server_name.as_ref().map(AsRef::as_ref));
let mut out_stream = TcpStream::connect(addr).await?;
let addr = self
.tls_addr
.find(server_name.as_ref().map(AsRef::as_ref), true);
let mut out_stream = TcpStream::connect(addr.as_ref()).await?;
mod_tcp_conn(&mut out_stream, true, self.nodelay);
tracing::debug!("handshake server connected: {addr}");

Expand Down Expand Up @@ -247,8 +266,10 @@ impl<LA, TA> ShadowTlsServer<LA, TA> {

// connect handshake server
let server_name = sni.and_then(|s| String::from_utf8(s).ok());
let addr = self.tls_addr.find(server_name.as_ref().map(AsRef::as_ref));
let mut handshake_stream = TcpStream::connect(addr).await?;
let addr = self
.tls_addr
.find(server_name.as_ref().map(AsRef::as_ref), client_hello_pass);
let mut handshake_stream = TcpStream::connect(addr.as_ref()).await?;
mod_tcp_conn(&mut handshake_stream, true, self.nodelay);
tracing::debug!("handshake server connected: {addr}");
tracing::trace!("ClientHello frame {first_client_frame:?}");
Expand Down Expand Up @@ -887,7 +908,8 @@ mod tests {
TlsAddrs::try_from("google.com").unwrap(),
TlsAddrs {
dispatch: map![],
fallback: s!("google.com:443")
fallback: s!("google.com:443"),
wildcard_sni: Default::default(),
}
);
assert_eq!(
Expand All @@ -897,7 +919,8 @@ mod tests {
"feishu.cn" => "feishu.cn:443",
"cloudflare.com" => "1.1.1.1:80",
],
fallback: s!("google.com:443")
fallback: s!("google.com:443"),
wildcard_sni: Default::default(),
}
);
assert_eq!(
Expand All @@ -906,7 +929,8 @@ mod tests {
dispatch: map![
"captive.apple.com" => "captive.apple.com:443",
],
fallback: s!("feishu.cn:80")
fallback: s!("feishu.cn:80"),
wildcard_sni: Default::default(),
}
);
}
Expand Down
16 changes: 16 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ impl V3Mode {
}
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, clap::ValueEnum)]
pub enum WildcardSNI {
/// Disabled
Off,
/// For authenticated client only(may be differentiable); in v2 protocol it is eq to all.
Authed,
/// For all request(may cause service abused but not differentiable)
All,
}

impl Default for WildcardSNI {
fn default() -> Self {
Self::Off
}
}

pub(crate) async fn copy_until_eof<R, W>(mut read_half: R, mut write_half: W) -> std::io::Result<()>
where
R: monoio::io::AsyncReadRent,
Expand Down

0 comments on commit 3232408

Please sign in to comment.