Giter Site home page Giter Site logo

gowee / noisy-shuttle Goto Github PK

View Code? Open in Web Editor NEW
145.0 6.0 15.0 260 KB

Secure proxy service indistinguishable from whitelisted TLS website

Rust 100.00%
http-proxy noise-protocol shadowsocks censorship-circumvention gfw proxy tunnel shadow-tls socks5 tls

noisy-shuttle's Introduction

noisy-shuttle

Build GitHub Release

noisy-shuttle establishes an AEAD-encrypted secure tunnel with forward secrecy for circumventing Internet censorship. It is designed to be indistinguishable from TLS traffic with any chosen website for camouflage by copying authentic TLS handshake messages.

A shuttle server authenticates clients based on tokens piggybacked by some fields of TLS ClientHello and falling back to dumb relay when authentication failed, preventing active probing.

It is inspired by the brilliant idea of shadow-tls and built upon snow (the Rust implementation of Noise protocol).

Features

  • Eavesdropper-verifiable authentic TLS handshakes with any chosen camouflage website, requiring no certificates

    • Basically indistinguishable from legit TLS traffic
  • PSK-based covert authentication piggybacked by TLS client random and session id field

    • Immune to active probes by falling back to dumb relay between a malicious client and the camouflage website
  • AEAD encrypted traffic with forward secrecy via ECDHE

    • Never worry about the traffic being recorded by the big brother for long
  • Customizable TLS client fingerprints specified via Cli option

Handshaking procedures

  • shuttle client contrives a legit TLS ClientHello and sends it to shuttle server. Unlike in a typical TLS handshake, the client random and session id field of the ClientHello totaling 64 bytes, which should have been randomly generated, are filled with an ephemeral X25519 public key and an AEAD tag as a part of the Noise NNPsk0 handshake. And then it proceeds to perform real TLS handshakes with the special ClientHello as typical.
  • When shuttle server received a ClientHello, it tries to pull the public key and the AEAD tag from the ClientHello and authenticate them with Noise against a pre-shared key. shuttle server then forwards the ClientHello to a camouflage website and relays subsequent TLS handshake messages between shuttle client and the camouflage server until TLS handshaking is done.
  • If the client is successfully authenticated previously, shuttle server sends back a corresponding public key and an AEAD tag as a part of the Noise NNPsk0 handshake and transmutes the connection into a Noise-encrypted tunnel—otherwise, shuttle server keeping relaying traffic dumbly between the unidentified client and the camouflage server.
  • After finishing TLS handshakes, shuttle client pulls the public key and the AEAD tag replied by shuttle server from the connection. Till now, an ECDHE key exchange is done between shuttle client and shuttle server. Then shuttle client also transmutes the connection into a Noise-encrypted tunnel. From the point of view of an eavesdropper, the whole procedure is authentic and verifiable TLS handshakes between shuttle client and a camouflage website.

Cli

Server:

# server               listen_addr   camouflage_addr   password
./noisy-shuttle server 0.0.0.0:443 www.example.com:443 Teap0taa -v

camouflage_addr is to where TLS handshaking requests from clients are forwarded and from where responses are forwarded backed to clients. Typically, it should be a well-known website that looks "innocent". Its port CANNOT be omitted.

Client:

# client                listen_addr        remote_addr             sni        password
./noisy-shuttle client 127.0.0.1:1080 server.addr.example:443 www.example.com Teap0taa -v

The client would serve a SOCKS5/HTTP (adaptive) proxy at listen_addr.

remote_addr is where the shuttle server is located.

sni should match camouflage_addr specified server-side.

Or optionally specifying a TLS fingerprint (chrome):

./noisy-shuttle client 127.0.0.1:1080 server.addr.example:443 www.example.com Teap0taa --tls-ja3 769,2570-4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,2570-0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513-2570-21,2570-29-23-24,0 --tls-alpn h2,http/1.1 --tls-sigalgos 1027,2052,1025,1283,2053,1281,2054,1537 --tls-versions 2570,772,771 --tls-keyshare 2570

TODO

  • connection multiplex or connection reuse?
  • Embed e, ee into server-side CCS in TLS 1.2
  • Handle TLS1.3 response from camouflage server properly
  • Elligator for public key
  • Utilize Keyshare?
  • Specify TLS fingerprint (JA3)
  • TLS GREASE
  • Configurable actions for unauthenticated client
  • Random packet padding and even packets

noisy-shuttle's People

Contributors

gowee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

noisy-shuttle's Issues

[feature request] connection reuse and forwarding traffic to a SOCKS5 proxy

  1. Implement Connection Reuse:
    Currently, we encounter SSL handshake rejections due to fast connection handshakes, resulting in decreased speed and a poor user experience. While MUX partially addresses this issue, it introduces speed problems. To improve this, we suggest implementing connection reuse by enhancing the trojan protocol. This involves adding a command to signal the end of the current connection and keeping it in a connection pool for future use. Additionally, implementing a mechanism to periodically check connection status would ensure stability, especially in situations like NAT session deletion or receiving a reset.

  2. Support Forwarding Traffic to a SOCKS5 Proxy:
    In certain scenarios, using the server that accepts the handshake as the outbound traffic server is undesirable, particularly when the server IP is not clean, and may cause restricting access to specific websites(Currently, Netflix restricts access based on client IP addresses. However, it would be beneficial to also support traffic forwarding to a SOCKS5 server. This would enable users to leverage V2Ray's capabilities for sniffing and making routing decisions based on domain names.
    ). However, forwarding all traffic to the backend server can create a heavy load. To address this, we propose adding support for a SOCKS5 client to selectively proxy traffic, excluding shadow-TLS handshake traffic. This would offer flexibility in routing traffic, load balancing, and maintaining network integrity.

UDP Support

This project is really great but It seems that the project does not support UDP (udp over tcp). Do you have any plans to add it?

License

Hi @Gowee - is there an active license for this codebase? I don't see anything explicitly documented in the README or code headers.

When running as a client, can the value of the remote_addr field be an IP address?

I read the document:
# client listen_addr remote_addr sni password
./noisy-shuttle client 127.0.0.1:1080 server.addr.example:443 www.example.com Teap0taa -v

The command I am executing on the client is
./noisy-shuttle client 0.0.0.0:1080 131.205.189.100:443 www.bing.com TYhdJS8u -v

There is no errors occur on startup

But when I make a http request via the socks5 proxy 127.0.0.1:1080 on the client
curl --socks5 127.0.0.1:1080 www.google.com

It tell me the request is failed

client logs:
failed to establish snowy tunnel: Not or invalid Server Hello

server logs
INFO serve{peer=54.45.88.4:57742}: fallback relay (unauthenticated)

Find a better strategy for calculating HTTP/2 flow control window

A tight window limits bandwidth, while a loose window undermines the effectiveness of flow control, resulting in higher latency & jitter.

The current implementation (in dev branch) is ported from hyper, which appears to be nonoptimal.

Similar strategies are also used in other libraries:

Dotnet: https://github.com/dotnet/runtime/pull/54755/files
gRPC: https://github.com/grpc/grpc-go/blob/master/internal/transport/bdp_estimator.go
cURL: curl/curl@a4d8888
Chromium: https://source.chromium.org/search?q=kSpdySessionMaxRecvWindowSize&sq=
Nginx: https://github.com/nginx/nginx/blob/b489ba83e9be446923facfe1a2fe392be3095d1f/src/http/v2/ngx_http_v2.c#L244
Go: https://github.com/golang/net/blob/47caaff48d7cdfbc45b155988009eb57a72bbeaf/http2/server.go#L158

Use the same ephemeral key for Noise and TLS key exchange

For simplicity of implementation and flexibility of ClientHello fingerprint, the tunnel implementation till now (v0.2.1) puts Noise ephemeral public key into client random. This provides no protection against active probing with replay attack aiming to distinguish camouflaged handshakes & traffic from authentic TLS stream, because the server has no way to tell whether the client actually owns the private key before sending back a responding Noise handshake. To mitigate it, the tunnel maintains a time-based LRU replay filter.

It is possible to use the same ephemeral key for both Noise and TLS key exchange (TLS 1.3 KeyShare or TLS 1.2 ClientKeyExchange). In this way, replayed ephemeral key and AEAD tag won't be effective by nature since a malicious client who has no corresponding private key won't able to finish the TLS handshake or verify any encrypted traffic at all.

The new proposed idea is more complex than the previous one to implement. And it does introduce some compatibility issues. Here are some considerations.

  • Two ephemeral keys should be generated, one for KeyShare and one for ClientKeyExchange. The one actually used would be determined by the negotiated protocol version.
  • It hinders possible future support of TLS session resumption (session id/session ticket in TLS 1.2 or PSK in TLS 1.3) since there might be no key exchange in such cases.
  • Much more care is needed to extract the KX key from TLS 1.2 ClientKeyExchange so that the handshake relay function state won't be distinguished.

For the second point, to allow session resumption, a possible workaround is to maintain an association of TLS session tokens (ticket/id/PSK) and the session key negotiated by Noise on server-side in addition to the session storage of client-side TLS implementation. When initiating a TLS handshake, the client signs (HMAC) its session token. Whenever the server determines a TLS session is resumed, it extracts the Noise session key for encryption of later traffic from its association storage. A malicious client who attempts to replay previously-recorded resumption would have no TLS session key cached for the corresponding TLS session token, preventing it from verifying server response in order to distinguish anything. But maintaining the extra session association seems not to be easier than maintaining the current replay filter LRU, not to mention the case where the server forgets a session token sent by a legit client (e.g. after a server restarting).

Reverse tunnel option?

Hi,
I was wondering if you have considered adding a reverse tunnel option?

I have remote systems behind NAT and it would be useful for them to create a tunnel to a central system that can then connect back over the tunnel (to SSH usually).

I'm having a look at the code to do it myself but I'm a Rust newb so it's hard going :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.