Skip to content

Commit

Permalink
refactor: seprate lib and main; add tests; not send alert on tls1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
ihciah committed Feb 25, 2023
1 parent bc26f7a commit 442441e
Show file tree
Hide file tree
Showing 14 changed files with 761 additions and 374 deletions.
94 changes: 94 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: CI

on:
push:
paths-ignore:
- '**.md'
- '**.png'
pull_request:
paths-ignore:
- '**.md'
- '**.png'

env:
RUST_TOOLCHAIN: nightly
TOOLCHAIN_PROFILE: minimal

jobs:
lints:
name: Run cargo fmt and cargo clippy
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
profile: ${{ env.TOOLCHAIN_PROFILE }}
toolchain: ${{ env.RUST_TOOLCHAIN }}
override: true
components: rustfmt, clippy
- name: Cache
uses: Swatinem/rust-cache@v1
- name: Run cargo fmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Run cargo check with no default features
uses: actions-rs/cargo@v1
with:
command: check
args: --no-default-features
- name: Run cargo check with all features
uses: actions-rs/cargo@v1
with:
command: check
args: --all-features
- name: Run cargo clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: -- -D warnings
test:
name: Run cargo test
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
profile: ${{ env.TOOLCHAIN_PROFILE }}
toolchain: ${{ env.RUST_TOOLCHAIN }}
override: true
- name: Cache
uses: Swatinem/rust-cache@v1
- name: Run cargo test --no-run
uses: actions-rs/cargo@v1
with:
command: test
args: --all-features --no-run
- name: Run cargo test
run: sudo bash -c "ulimit -Sl 512 && ulimit -Hl 512 && sudo -u runner RUSTUP_TOOLCHAIN=nightly /home/runner/.cargo/bin/cargo test --all-features"

test-macos:
name: Run cargo test on macos
runs-on: macos-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
profile: ${{ env.TOOLCHAIN_PROFILE }}
toolchain: ${{ env.RUST_TOOLCHAIN }}
override: true
- name: Cache
uses: Swatinem/rust-cache@v1
- name: Run cargo test
uses: actions-rs/cargo@v1
with:
command: test
args: --all-features
toolchain: ${{ env.RUST_TOOLCHAIN }}
2 changes: 1 addition & 1 deletion 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.17"
version = "0.2.18"

[dependencies]
monoio = {version = "0.0.9"}
Expand Down
24 changes: 17 additions & 7 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use rustls_fork_shadow_tls::{OwnedTrustAnchor, RootCertStore, ServerName};
use crate::{
helper_v2::{copy_with_application_data, copy_without_application_data, HashedReadStream},
util::{
bind_with_pretty_error, kdf, mod_tcp_conn, prelude::*, verified_relay, xor_slice, Hmac,
V3Mode,
bind_with_pretty_error, kdf, mod_tcp_conn, prelude::*, support_tls13, verified_relay,
xor_slice, Hmac, V3Mode,
},
};

Expand All @@ -41,6 +41,7 @@ pub struct ShadowTlsClient<LA, TA> {
pub struct TlsNames(Vec<ServerName>);

impl TlsNames {
#[inline]
pub fn random_choose(&self) -> &ServerName {
self.0.choose(&mut rand::thread_rng()).unwrap()
}
Expand Down Expand Up @@ -68,17 +69,14 @@ impl std::fmt::Display for TlsNames {
}
}

pub fn parse_client_names(addrs: &str) -> anyhow::Result<TlsNames> {
TlsNames::try_from(addrs)
}

#[derive(Default, Debug)]
pub struct TlsExtConfig {
alpn: Option<Vec<Vec<u8>>>,
}

impl TlsExtConfig {
#[allow(unused)]
#[inline]
pub fn new(alpn: Option<Vec<Vec<u8>>>) -> TlsExtConfig {
TlsExtConfig { alpn }
}
Expand Down Expand Up @@ -223,6 +221,7 @@ impl<LA, TA> ShadowTlsClient<LA, TA> {
tracing::debug!("handshake success");
let (stream, session) = tls_stream.into_parts();
let authorized = stream.authorized();
let tls13 = stream.tls13;
let maybe_srh = stream
.state()
.as_ref()
Expand All @@ -245,7 +244,15 @@ impl<LA, TA> ShadowTlsClient<LA, TA> {
let hmac_sr_s = Hmac::new(&self.password, (&sr, b"S"));
let hmac_sr_c = Hmac::new(&self.password, (&sr, b"C"));

verified_relay(in_stream, stream, hmac_sr_c, hmac_sr_s, Some(hmac_sr)).await;
verified_relay(
in_stream,
stream,
hmac_sr_c,
hmac_sr_s,
Some(hmac_sr),
!tls13,
)
.await;
Ok(())
}

Expand Down Expand Up @@ -288,6 +295,7 @@ struct StreamWrapper<S> {

read_state: Option<State>,
read_authorized: bool,
tls13: bool,
}

#[derive(Clone)]
Expand All @@ -308,6 +316,7 @@ impl<S> StreamWrapper<S> {

read_state: None,
read_authorized: false,
tls13: false,
}
}

Expand Down Expand Up @@ -384,6 +393,7 @@ impl<S: AsyncReadRent> StreamWrapper<S> {
hmac,
key,
});
self.tls13 = support_tls13(&buf);
}
}
APPLICATION_DATA => {
Expand Down
44 changes: 22 additions & 22 deletions src/helper_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ use monoio::{

use crate::util::prelude::*;

pub const HMAC_SIZE_V2: usize = 8;
pub(crate) const HMAC_SIZE_V2: usize = 8;

pub trait HashedStream {
pub(crate) trait HashedStream {
fn hash_stream(&self) -> [u8; 20];
}

pub struct HashedReadStream<S> {
pub(crate) struct HashedReadStream<S> {
raw: S,
hmac: hmac::Hmac<sha1::Sha1>,
}
Expand All @@ -39,18 +39,18 @@ pub struct HashedReadStream<S> {
unsafe impl<S: monoio::io::Split> monoio::io::Split for HashedReadStream<S> {}

impl<S> HashedReadStream<S> {
pub fn new(raw: S, password: &[u8]) -> Result<Self, hmac::digest::InvalidLength> {
pub(crate) fn new(raw: S, password: &[u8]) -> Result<Self, hmac::digest::InvalidLength> {
Ok(Self {
raw,
hmac: hmac::Hmac::new_from_slice(password)?,
})
}

pub fn into_inner(self) -> S {
pub(crate) fn into_inner(self) -> S {
self.raw
}

pub fn hash(&self) -> [u8; 20] {
pub(crate) fn hash(&self) -> [u8; 20] {
self.hmac
.clone()
.finalize()
Expand Down Expand Up @@ -90,18 +90,18 @@ impl<S: AsWriteFd> AsWriteFd for HashedWriteStream<S> {
}

impl<S> HashedWriteStream<S> {
pub fn new(raw: S, password: &[u8]) -> Result<Self, hmac::digest::InvalidLength> {
pub(crate) fn new(raw: S, password: &[u8]) -> Result<Self, hmac::digest::InvalidLength> {
Ok(Self {
raw,
hmac: Rc::new(RefCell::new((true, hmac::Hmac::new_from_slice(password)?))),
})
}

pub fn into_inner(self) -> S {
pub(crate) fn into_inner(self) -> S {
self.raw
}

pub fn hash(&self) -> [u8; 20] {
pub(crate) fn hash(&self) -> [u8; 20] {
self.hmac
.borrow()
.clone()
Expand All @@ -113,15 +113,15 @@ impl<S> HashedWriteStream<S> {
.expect("unexpected digest length")
}

pub fn hmac_handler(&self) -> HmacHandler {
pub(crate) fn hmac_handler(&self) -> HmacHandler {
HmacHandler(self.hmac.clone())
}
}

pub struct HmacHandler(Rc<RefCell<(bool, hmac::Hmac<sha1::Sha1>)>>);
pub(crate) struct HmacHandler(Rc<RefCell<(bool, hmac::Hmac<sha1::Sha1>)>>);

impl HmacHandler {
pub fn hash(&self) -> [u8; 20] {
pub(crate) fn hash(&self) -> [u8; 20] {
self.0
.borrow()
.clone()
Expand All @@ -133,7 +133,7 @@ impl HmacHandler {
.expect("unexpected digest length")
}

pub fn disable(&mut self) {
pub(crate) fn disable(&mut self) {
self.0.borrow_mut().0 = false;
}
}
Expand Down Expand Up @@ -278,15 +278,15 @@ impl<S: AsyncWriteRent> AsyncWriteRent for HashedWriteStream<S> {
/// from handshake server even when client side
/// finished switching. Client must be able to filter
/// out these packets.
pub struct SessionFilterStream<C, S> {
pub(crate) struct SessionFilterStream<C, S> {
session: C,
stream: S,
direct: bool,
direct_buffer: Option<(Vec<u8>, usize)>,
}

impl<C, S> SessionFilterStream<C, S> {
pub fn new(session: C, stream: S) -> Self {
pub(crate) fn new(session: C, stream: S) -> Self {
Self {
session,
stream,
Expand Down Expand Up @@ -400,7 +400,7 @@ pin_project_lite::pin_project! {
/// ErrGroup works like ErrGroup in golang.
/// If the two futures all finished with Ok, self is finished with Ok.
/// If any one of them finished with Err, self is finished with Err.
pub struct ErrGroup<FA, FB, A, B, E> {
pub(crate) struct ErrGroup<FA, FB, A, B, E> {
#[pin]
future_a: FA,
#[pin]
Expand All @@ -416,7 +416,7 @@ where
FA: Future<Output = Result<A, E>>,
FB: Future<Output = Result<B, E>>,
{
pub fn new(future_a: FA, future_b: FB) -> Self {
pub(crate) fn new(future_a: FA, future_b: FB) -> Self {
Self {
future_a,
future_b,
Expand Down Expand Up @@ -464,7 +464,7 @@ where

pin_project_lite::pin_project! {
/// FirstRetGroup returns if the first future is ready.
pub struct FirstRetGroup<FA, FB, B, E> {
pub(crate) struct FirstRetGroup<FA, FB, B, E> {
#[pin]
future_a: FA,
#[pin]
Expand All @@ -474,7 +474,7 @@ pin_project_lite::pin_project! {
}
}

pub enum FutureOrOutput<F, R, E>
pub(crate) enum FutureOrOutput<F, R, E>
where
F: Future<Output = Result<R, E>>,
{
Expand All @@ -487,7 +487,7 @@ where
FA: Future<Output = Result<A, E>>,
FB: Future<Output = Result<B, E>>,
{
pub fn new(future_a: FA, future_b: FB) -> Self {
pub(crate) fn new(future_a: FA, future_b: FB) -> Self {
Self {
future_a,
future_b: Some(future_b),
Expand Down Expand Up @@ -526,7 +526,7 @@ where
}
}

pub async fn copy_with_application_data<'a, const N: usize, R, W>(
pub(crate) async fn copy_with_application_data<'a, const N: usize, R, W>(
reader: &'a mut R,
writer: &'a mut W,
write_prefix: Option<[u8; N]>,
Expand Down Expand Up @@ -601,7 +601,7 @@ where
Ok(transfered)
}

pub async fn copy_without_application_data<'a, R, W>(
pub(crate) async fn copy_without_application_data<'a, R, W>(
reader: &'a mut R,
writer: &'a mut W,
) -> std::io::Result<u64>
Expand Down
Loading

0 comments on commit 442441e

Please sign in to comment.