From 98b77afb91e6ab105cb0574753d8cddd647024ce Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 2 Sep 2019 14:03:10 +0100 Subject: [PATCH] websocket over TLS --- example_config/ckclient.json | 2 +- go.mod | 2 ++ internal/client/TLS.go | 8 ++++---- internal/client/state.go | 10 +++++----- internal/client/websocket.go | 22 +++++++++++++++++----- 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/example_config/ckclient.json b/example_config/ckclient.json index 8abcf8f..1c3b4d7 100644 --- a/example_config/ckclient.json +++ b/example_config/ckclient.json @@ -1,5 +1,5 @@ { - "Transport": "TLS", + "Transport": "direct", "ProxyMethod":"shadowsocks", "EncryptionMethod":"plain", "UID":"5nneblJy6lniPJfr81LuYQ==", diff --git a/go.mod b/go.mod index 742e412..edc231a 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,13 @@ module github.com/cbeuw/Cloak go 1.12 require ( + github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63 // indirect github.com/boltdb/bolt v1.3.1 github.com/gorilla/mux v1.7.3 github.com/gorilla/websocket v1.4.1 github.com/juju/ratelimit v1.0.1 github.com/kr/pretty v0.1.0 // indirect + github.com/refraction-networking/utls v0.0.0-20190824032329-cc2996c81813 github.com/sirupsen/logrus v1.4.2 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect diff --git a/internal/client/TLS.go b/internal/client/TLS.go index 162c50f..7fd9f75 100644 --- a/internal/client/TLS.go +++ b/internal/client/TLS.go @@ -37,16 +37,16 @@ func addExtRec(typ []byte, data []byte) []byte { return ret } -type TLS struct { +type DirectTLS struct { Transport } -func (*TLS) HasRecordLayer() bool { return true } -func (*TLS) UnitReadFunc() func(net.Conn, []byte) (int, error) { return util.ReadTLS } +func (DirectTLS) HasRecordLayer() bool { return true } +func (DirectTLS) UnitReadFunc() func(net.Conn, []byte) (int, error) { return util.ReadTLS } // PrepareConnection handles the TLS handshake for a given conn and returns the sessionKey // if the server proceed with Cloak authentication -func (*TLS) PrepareConnection(sta *State, conn net.Conn) (preparedConn net.Conn, sessionKey []byte, err error) { +func (DirectTLS) PrepareConnection(sta *State, conn net.Conn) (preparedConn net.Conn, sessionKey []byte, err error) { preparedConn = conn hd, sharedSecret := makeHiddenData(sta) chOnly := sta.browser.composeClientHello(hd) diff --git a/internal/client/state.go b/internal/client/state.go index bb663c1..98388a4 100644 --- a/internal/client/state.go +++ b/internal/client/state.go @@ -119,12 +119,12 @@ func (sta *State) ParseConfig(conf string) (err error) { } switch strings.ToLower(preParse.Transport) { - case "tls": - sta.Transport = &TLS{} - case "websocket": - sta.Transport = &WebSocket{} + case "direct": + sta.Transport = DirectTLS{} + case "cdn": + sta.Transport = WSOverTLS{} default: - sta.Transport = &TLS{} + sta.Transport = &DirectTLS{} } sta.ProxyMethod = preParse.ProxyMethod diff --git a/internal/client/websocket.go b/internal/client/websocket.go index bc1315a..64094e2 100644 --- a/internal/client/websocket.go +++ b/internal/client/websocket.go @@ -9,17 +9,29 @@ import ( "net" "net/http" "net/url" + + utls "github.com/refraction-networking/utls" ) -type WebSocket struct { +type WSOverTLS struct { Transport } -func (*WebSocket) HasRecordLayer() bool { return false } -func (*WebSocket) UnitReadFunc() func(net.Conn, []byte) (int, error) { return util.ReadWebSocket } +func (WSOverTLS) HasRecordLayer() bool { return false } +func (WSOverTLS) UnitReadFunc() func(net.Conn, []byte) (int, error) { return util.ReadWebSocket } + +func (WSOverTLS) PrepareConnection(sta *State, conn net.Conn) (preparedConn net.Conn, sessionKey []byte, err error) { + utlsConfig := &utls.Config{ + ServerName: sta.ServerName, + InsecureSkipVerify: true, + } + uconn := utls.UClient(conn, utlsConfig, utls.HelloChrome_Auto) + err = uconn.Handshake() + preparedConn = uconn + if err != nil { + return + } -func (WebSocket) PrepareConnection(sta *State, conn net.Conn) (preparedConn net.Conn, sessionKey []byte, err error) { - preparedConn = conn u, err := url.Parse("ws://" + sta.RemoteHost + ":" + sta.RemotePort) //TODO IPv6 if err != nil { return preparedConn, nil, fmt.Errorf("failed to parse ws url: %v", err)