From d46af8b5d447f346b91b6b74376145632d60f70d Mon Sep 17 00:00:00 2001 From: RPRX <63339210+rprx@users.noreply.github.com> Date: Tue, 23 Mar 2021 09:25:35 +0000 Subject: [PATCH] Add WSS Browser Dialer support (#421) --- transport/internet/websocket/dialer.go | 49 +++++++++++++++++++++ transport/internet/websocket/dialer.html | 55 ++++++++++++++++++++++++ transport/internet/websocket/hub.go | 23 ++++++---- 3 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 transport/internet/websocket/dialer.html diff --git a/transport/internet/websocket/dialer.go b/transport/internet/websocket/dialer.go index 849beb5e..3dc56cc7 100644 --- a/transport/internet/websocket/dialer.go +++ b/transport/internet/websocket/dialer.go @@ -2,8 +2,12 @@ package websocket import ( "context" + _ "embed" "encoding/base64" + "fmt" "io" + "net/http" + "os" "time" "github.com/gorilla/websocket" @@ -15,6 +19,27 @@ import ( "github.com/xtls/xray-core/transport/internet/tls" ) +//go:embed dialer.html +var webpage []byte +var conns chan *websocket.Conn + +func init() { + if addr := os.Getenv("XRAY_BROWSER_DIALER"); addr != "" { + conns = make(chan *websocket.Conn, 256) + go http.ListenAndServe(addr, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/websocket" { + if conn, err := upgrader.Upgrade(w, r, nil); err == nil { + conns <- conn + } else { + fmt.Println("unexpected error") + } + } else { + w.Write(webpage) + } + })) + } +} + // Dial dials a WebSocket connection to the given destination. func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) { newError("creating connection to ", dest).WriteToLog(session.ExportIDToError(ctx)) @@ -66,6 +91,30 @@ func dialWebSocket(ctx context.Context, dest net.Destination, streamSettings *in } uri := protocol + "://" + host + wsSettings.GetNormalizedPath() + if conns != nil { + data := []byte(uri) + if ed != nil { + data = append(data, " "+base64.RawURLEncoding.EncodeToString(ed)...) + } + var conn *websocket.Conn + for { + conn = <-conns + if conn.WriteMessage(websocket.TextMessage, data) != nil { + conn.Close() + } else { + break + } + } + if _, p, err := conn.ReadMessage(); err != nil { + conn.Close() + return nil, err + } else if s := string(p); s != "ok" { + conn.Close() + return nil, newError(s) + } + return newConnection(conn, conn.RemoteAddr(), nil), nil + } + header := wsSettings.GetRequestHeader() if ed != nil { header.Set("Sec-WebSocket-Protocol", base64.StdEncoding.EncodeToString(ed)) diff --git a/transport/internet/websocket/dialer.html b/transport/internet/websocket/dialer.html new file mode 100644 index 00000000..bbeaec0c --- /dev/null +++ b/transport/internet/websocket/dialer.html @@ -0,0 +1,55 @@ + + +
+