Compare commits

..
12 changed files with 138 additions and 448 deletions
-11
View File
@@ -18,7 +18,6 @@ import (
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/browser_dialer"
)
// Server is an instance of Xray. At any time, there must be at most one Server instance running.
@@ -263,9 +262,6 @@ func (s *Instance) Close() error {
s.running = false
var errs []interface{}
if err := browser_dialer.StopCollectedDialerProxyURLs(); err != nil {
errs = append(errs, err)
}
for _, f := range s.features {
if err := f.Close(); err != nil {
errs = append(errs, err)
@@ -389,16 +385,9 @@ func (s *Instance) Start() error {
s.statusLock.Lock()
defer s.statusLock.Unlock()
if err := browser_dialer.StartCollectedDialerProxyURLs(); err != nil {
return err
}
s.running = true
for _, f := range s.features {
if err := f.Start(); err != nil {
s.running = false
if stopErr := browser_dialer.StopCollectedDialerProxyURLs(); stopErr != nil {
return errors.New("browser dialer cleanup after startup failure also failed: ", stopErr).Base(err)
}
return err
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ require (
github.com/sagernet/sing-shadowsocks v0.2.7
github.com/stretchr/testify v1.11.1
github.com/vishvananda/netlink v1.3.1
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f
github.com/xtls/reality v0.0.0-20260501094811-4379845b089d
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.50.0
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
+2
View File
@@ -69,6 +69,8 @@ github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zd
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f h1:iy2JRioxmUpoJ3SzbFPyTxHZMbR/rSHP7dOOgYaq1O8=
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI=
github.com/xtls/reality v0.0.0-20260501094811-4379845b089d h1:ca0n8upCDojatNr25id4npJBwUsMmLgtrvLYDj4J0Hg=
github.com/xtls/reality v0.0.0-20260501094811-4379845b089d/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
-30
View File
@@ -21,7 +21,6 @@ import (
"github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/browser_dialer"
"github.com/xtls/xray-core/transport/internet/finalmask/fragment"
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
"github.com/xtls/xray-core/transport/internet/finalmask/header/dns"
@@ -1971,35 +1970,6 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
}
config.ProtocolName = protocol
}
if c.SocketSettings != nil && c.SocketSettings.DialerProxy != "" {
if browser_dialer.IsBrowserDialerProxy(c.SocketSettings.DialerProxy) {
if config.ProtocolName != "websocket" && config.ProtocolName != "splithttp" {
return nil, errors.New("dialerProxy ", c.SocketSettings.DialerProxy, " only supports websocket or splithttp")
}
if strings.EqualFold(c.Security, "reality") {
return nil, errors.New("dialerProxy ", c.SocketSettings.DialerProxy, " does not support REALITY")
}
if config.ProtocolName == "splithttp" {
splitHTTPSettings := c.SplitHTTPSettings
if c.XHTTPSettings != nil {
splitHTTPSettings = c.XHTTPSettings
}
if splitHTTPSettings != nil {
splitHTTPSettingsCopy := *splitHTTPSettings
hs, err := splitHTTPSettingsCopy.Build()
if err != nil {
return nil, errors.New("failed to build XHTTP config for browser dialer validation").Base(err)
}
if splitHTTPConfig, ok := hs.(*splithttp.Config); ok && splitHTTPConfig.Mode != "auto" && splitHTTPConfig.Mode != "packet-up" {
return nil, errors.New("dialerProxy ", c.SocketSettings.DialerProxy, " only supports XHTTP modes \"auto\" or \"packet-up\", got: \"", splitHTTPConfig.Mode, "\"")
}
}
}
if err := browser_dialer.RegisterDialerProxyURL(c.SocketSettings.DialerProxy); err != nil {
return nil, errors.New("failed to collect browser dialer URL").Base(err)
}
}
}
switch strings.ToLower(c.Security) {
case "", "none":
+1 -7
View File
@@ -15,7 +15,6 @@ import (
"github.com/xtls/xray-core/common/serial"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/browser_dialer"
)
var (
@@ -438,6 +437,7 @@ func (c *Config) Override(o *Config, fn string) {
if o.Geodata != nil {
c.Geodata = o.Geodata
}
// update the Inbound in slice if the only one in override config has same tag
if len(o.InboundConfigs) > 0 {
for i := range o.InboundConfigs {
@@ -604,9 +604,6 @@ func (c *Config) Build() (*core.Config, error) {
if len(c.Transport) > 0 {
return nil, errors.PrintRemovedFeatureError("Global transport config", "streamSettings in inbounds and outbounds")
}
if err := browser_dialer.BeginCollectingDialerProxyURLs(); err != nil {
return nil, err
}
for _, rawInboundConfig := range inbounds {
ic, err := rawInboundConfig.Build()
@@ -629,9 +626,6 @@ func (c *Config) Build() (*core.Config, error) {
}
config.Outbound = append(config.Outbound, oc)
}
if err := browser_dialer.ConfigureCollectedDialerProxyURLs(); err != nil {
return nil, errors.New("failed to configure browser dialer").Base(err)
}
return config, nil
}
+96 -28
View File
@@ -1,33 +1,101 @@
package browser_dialer
import (
"bytes"
"context"
_ "embed"
"encoding/base64"
"encoding/json"
"net/http"
"sync"
"time"
"github.com/gorilla/websocket"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/uuid"
)
//go:embed dialer.html
var webpage []byte
type task struct {
Method string `json:"method"`
URL string `json:"url"`
Extra any `json:"extra,omitempty"`
StreamResponse bool `json:"streamResponse"`
Method string `json:"method"`
URL string `json:"url"`
Extra any `json:"extra,omitempty"`
StreamResponse bool `json:"streamResponse"`
}
var conns chan *websocket.Conn
var server *http.Server
var mu sync.Mutex
var upgrader = &websocket.Upgrader{
ReadBufferSize: 0,
WriteBufferSize: 0,
HandshakeTimeout: time.Second * 4,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// Used by external projects when using xray as a go module
func Reload() {
addr := platform.NewEnvFlag(platform.BrowserDialerAddress).GetValue(func() string { return "" })
mu.Lock()
defer mu.Unlock()
if server != nil {
server.Close()
}
if HasBrowserDialer() {
for len(conns) > 0 {
select {
case c := <-conns:
c.Close()
default:
}
}
conns = nil
}
if addr != "" {
token := uuid.New()
csrfToken := token.String()
webpage := bytes.ReplaceAll(webpage, []byte("csrfToken"), []byte(csrfToken))
conns = make(chan *websocket.Conn, 256)
server = &http.Server{
Addr: addr,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/websocket" {
if r.URL.Query().Get("token") == csrfToken {
if conn, err := upgrader.Upgrade(w, r, nil); err == nil {
conns <- conn
} else {
errors.LogError(context.Background(), "Browser dialer http upgrade unexpected error")
}
}
} else {
w.Header().Set("Access-Control-Allow-Origin", "*");
w.Write(webpage)
}
}),
}
go server.ListenAndServe()
}
}
func HasBrowserDialer() bool {
return conns != nil
}
type webSocketExtra struct {
Protocol string `json:"protocol,omitempty"`
}
func DialWSWithAddress(addr string, uri string, ed []byte) (*websocket.Conn, error) {
func DialWS(uri string, ed []byte) (*websocket.Conn, error) {
task := task{
Method: "WS",
URL: uri,
Method: "WS",
URL: uri,
StreamResponse: true,
}
@@ -37,7 +105,7 @@ func DialWSWithAddress(addr string, uri string, ed []byte) (*websocket.Conn, err
}
}
return dialTaskWithAddress(addr, task)
return dialTask(task)
}
type httpExtra struct {
@@ -74,26 +142,30 @@ func httpExtraFromHeadersAndCookies(headers http.Header, cookies []*http.Cookie)
return &extra
}
func DialGetWithAddress(addr string, uri string, headers http.Header, cookies []*http.Cookie) (*websocket.Conn, error) {
func DialGet(uri string, headers http.Header, cookies []*http.Cookie) (*websocket.Conn, error) {
task := task{
Method: "GET",
URL: uri,
Extra: httpExtraFromHeadersAndCookies(headers, cookies),
Method: "GET",
URL: uri,
Extra: httpExtraFromHeadersAndCookies(headers, cookies),
StreamResponse: true,
}
return dialTaskWithAddress(addr, task)
return dialTask(task)
}
func DialPacketWithAddress(addr string, method string, uri string, headers http.Header, cookies []*http.Cookie, payload []byte) error {
func DialPacket(method string, uri string, headers http.Header, cookies []*http.Cookie, payload []byte) error {
return dialWithBody(method, uri, headers, cookies, payload)
}
func dialWithBody(method string, uri string, headers http.Header, cookies []*http.Cookie, payload []byte) error {
task := task{
Method: method,
URL: uri,
Extra: httpExtraFromHeadersAndCookies(headers, cookies),
Method: method,
URL: uri,
Extra: httpExtraFromHeadersAndCookies(headers, cookies),
StreamResponse: false,
}
conn, err := dialTaskWithAddress(addr, task)
conn, err := dialTask(task)
if err != nil {
return err
}
@@ -112,21 +184,12 @@ func DialPacketWithAddress(addr string, method string, uri string, headers http.
return nil
}
func dialTaskWithAddress(addr string, task task) (*websocket.Conn, error) {
func dialTask(task task) (*websocket.Conn, error) {
data, err := json.Marshal(task)
if err != nil {
return nil, err
}
if addr == "" {
return nil, errors.New("browser dialer is not configured; set sockopt.dialerProxy to browser://host:port/uuid")
}
dialer, err := getDialerByAddress(addr)
if err != nil {
return nil, err
}
conns := dialer.conns
var conn *websocket.Conn
for {
conn = <-conns
@@ -155,3 +218,8 @@ func CheckOK(conn *websocket.Conn) error {
return nil
}
func init() {
Reload()
}
@@ -10,7 +10,7 @@
// Enable a much more aggressive JIT for performance gains
// Copyright (c) 2021 XRAY. Mozilla Public License 2.0.
let url = "ws://" + window.location.host + "/dialerPath";
let url = "ws://" + window.location.host + "/websocket?token=csrfToken";
let clientIdleCount = 0;
let upstreamGetCount = 0;
let upstreamWsCount = 0;
@@ -67,7 +67,7 @@
}
clientIdleCount += 1;
console.log("Prepare", url);
let ws = new WebSocket(url, "browser-dialer");
let ws = new WebSocket(url);
// arraybuffer is significantly faster in chrome than default
// blob, tested with chrome 123
ws.binaryType = "arraybuffer";
@@ -1,318 +0,0 @@
package browser_dialer
import (
"bytes"
"context"
stderrors "errors"
"net"
"net/http"
"net/url"
pathlib "path"
"strings"
"time"
"github.com/gorilla/websocket"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/uuid"
)
var dialersByAddress = map[string]*dialerInstance{}
var serversByListenAddr = map[string]*dialerServer{}
var initialized bool
var pendingURLs map[string]struct{}
const browserDialerSubprotocol = "browser-dialer"
var upgrader = &websocket.Upgrader{
ReadBufferSize: 0,
WriteBufferSize: 0,
HandshakeTimeout: time.Second * 4,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func CheckLegacyEnv() error {
envAddress := platform.NewEnvFlag(platform.BrowserDialerAddress).GetValue(func() string { return "" })
if envAddress == "" {
return nil
}
return errors.PrintRemovedFeatureError("env "+platform.BrowserDialerAddress, "sockopt.dialerProxy with browser://host:port/uuid")
}
func IsBrowserDialerProxy(raw string) bool {
_, _, ok := parseBrowserDialerAddress(raw)
return ok
}
func BeginCollectingDialerProxyURLs() error {
if initialized {
return errors.New("browser dialer does not support dynamic add/remove; restart is required after changing configuration")
}
if err := CheckLegacyEnv(); err != nil {
return err
}
pendingURLs = map[string]struct{}{}
return nil
}
func RegisterDialerProxyURL(raw string) error {
if !IsBrowserDialerProxy(raw) {
return nil
}
if pendingURLs == nil {
return errors.New("browser dialer url collection is not initialized")
}
pendingURLs[raw] = struct{}{}
return nil
}
func ConfigureCollectedDialerProxyURLs() error {
if initialized {
return errors.New("browser dialer does not support dynamic add/remove; restart is required after changing configuration")
}
if err := CheckLegacyEnv(); err != nil {
return err
}
listenAddrByPort := make(map[string]string, len(pendingURLs))
for browserDialerURL := range pendingURLs {
listenAddr, _, ok := parseBrowserDialerAddress(browserDialerURL)
if !ok {
return errors.New("invalid browser dialer url: ", browserDialerURL)
}
_, port, err := net.SplitHostPort(listenAddr)
if err != nil {
return errors.New("invalid browser dialer listen address: ", listenAddr)
}
if existingAddr, found := listenAddrByPort[port]; found && existingAddr != listenAddr {
return errors.New("browser dialer cannot use the same port with a different listen address: ", existingAddr, " and ", listenAddr)
}
listenAddrByPort[port] = listenAddr
}
for existingAddr := range serversByListenAddr {
_, existingPort, splitErr := net.SplitHostPort(existingAddr)
if splitErr != nil {
continue
}
if newAddr, found := listenAddrByPort[existingPort]; found && newAddr != existingAddr {
return errors.New("browser dialer cannot use the same port with a different listen address: ", existingAddr, " and ", newAddr)
}
}
for browserDialerURL := range pendingURLs {
if _, err := ensureDialerWithAddress(browserDialerURL); err != nil {
return errors.New("failed to initialize browser dialer listener for url ", browserDialerURL).Base(err)
}
}
return nil
}
// StartCollectedDialerProxyURLs starts listeners for browser dialer URLs
// prepared by ConfigureCollectedDialerProxyURLs.
// Subsequent calls after successful initialization return nil.
func StartCollectedDialerProxyURLs() error {
if initialized {
return nil
}
for listenAddr, server := range serversByListenAddr {
if err := server.start(); err != nil {
return errors.New("failed to start browser dialer listener on ", listenAddr).Base(err)
}
}
initialized = true
return nil
}
func StopCollectedDialerProxyURLs() error {
var stopErrs []string
for listenAddr, server := range serversByListenAddr {
if err := server.stop(); err != nil {
stopErrs = append(stopErrs, serial.Concat("failed to stop browser dialer listener on ", listenAddr, ": ", err))
}
}
dialersByAddress = map[string]*dialerInstance{}
serversByListenAddr = map[string]*dialerServer{}
pendingURLs = nil
initialized = false
if len(stopErrs) > 0 {
return errors.New(strings.Join(stopErrs, "; "))
}
return nil
}
type dialerInstance struct {
conns chan *websocket.Conn
page []byte
}
type dialerServer struct {
server *http.Server
pageRoutes map[string]*dialerInstance
started bool
}
func parseBrowserDialerAddress(addr string) (string, string, bool) {
if addr == "" {
return "", "", false
}
parsedAddr, err := url.Parse(addr)
if err != nil || !strings.EqualFold(parsedAddr.Scheme, "browser") || parsedAddr.Host == "" || parsedAddr.Path == "" || parsedAddr.RawQuery != "" || parsedAddr.Fragment != "" {
return "", "", false
}
listenAddr := parsedAddr.Host
if _, _, err := net.SplitHostPort(listenAddr); err != nil {
return "", "", false
}
path := strings.TrimSuffix(parsedAddr.Path, "/")
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
cleanPath := pathlib.Clean(path)
if cleanPath == "." || cleanPath == "/" || cleanPath != path {
return "", "", false
}
if strings.Count(cleanPath, "/") != 1 {
return "", "", false
}
id := strings.TrimPrefix(cleanPath, "/")
id = strings.ToLower(id)
parsedUUID, err := uuid.ParseString(id)
if err != nil || parsedUUID.String() != id {
return "", "", false
}
return listenAddr, "/" + id, true
}
func newDialerServer(listenAddr string) (*dialerServer, error) {
dialer := &dialerServer{
pageRoutes: make(map[string]*dialerInstance),
}
dialer.server = &http.Server{
Addr: listenAddr,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pageDialer := dialer.pageRoutes[r.URL.Path]
if pageDialer != nil && websocket.IsWebSocketUpgrade(r) {
ok := false
for _, protocol := range websocket.Subprotocols(r) {
if protocol == browserDialerSubprotocol {
ok = true
break
}
}
if !ok {
closeConnection(w)
return
}
if conn, err := upgrader.Upgrade(w, r, http.Header{"Sec-WebSocket-Protocol": []string{browserDialerSubprotocol}}); err == nil {
pageDialer.conns <- conn
} else {
errors.LogError(context.Background(), "Browser dialer http upgrade unexpected error: ", err)
}
return
}
if pageDialer != nil {
w.Header().Set("Access-Control-Allow-Origin", "*")
if _, err := w.Write(pageDialer.page); err != nil {
errors.LogError(context.Background(), "Browser dialer http page write unexpected error: ", err)
}
return
}
closeConnection(w)
}),
}
return dialer, nil
}
func (d *dialerServer) start() error {
if d.started {
return nil
}
listener, err := net.Listen("tcp", d.server.Addr)
if err != nil {
return err
}
d.started = true
go func() {
if err := d.server.Serve(listener); err != nil && !stderrors.Is(err, http.ErrServerClosed) {
errors.LogError(context.Background(), "Browser dialer http server unexpected error on ", d.server.Addr, ": ", err)
}
}()
return nil
}
func (d *dialerServer) stop() error {
if !d.started {
return nil
}
d.started = false
return d.server.Close()
}
func closeConnection(w http.ResponseWriter) {
hijacker, ok := w.(http.Hijacker)
if !ok {
return
}
conn, _, err := hijacker.Hijack()
if err != nil {
return
}
conn.Close()
}
func getDialerByAddress(addr string) (*dialerInstance, error) {
listenAddr, path, ok := parseBrowserDialerAddress(addr)
if !ok {
return nil, errors.New("invalid browser dialer url: ", addr)
}
key := listenAddr + path
if dialer, found := dialersByAddress[key]; found {
return dialer, nil
}
return nil, errors.New("browser dialer is not configured for url: ", addr)
}
func ensureDialerWithAddress(addr string) (*dialerInstance, error) {
listenAddr, path, ok := parseBrowserDialerAddress(addr)
if !ok {
return nil, errors.New("invalid browser dialer url: ", addr)
}
_, port, err := net.SplitHostPort(listenAddr)
if err != nil {
return nil, errors.New("invalid browser dialer listen address: ", listenAddr)
}
key := listenAddr + path
if dialer, found := dialersByAddress[key]; found {
return dialer, nil
}
server, found := serversByListenAddr[listenAddr]
if !found {
for existingAddr := range serversByListenAddr {
_, existingPort, splitErr := net.SplitHostPort(existingAddr)
if splitErr == nil && existingPort == port {
return nil, errors.New("browser dialer cannot use the same port with a different listen address: ", existingAddr, " and ", listenAddr)
}
}
newServer, serverErr := newDialerServer(listenAddr)
if serverErr != nil {
return nil, serverErr
}
server = newServer
serversByListenAddr[listenAddr] = server
}
dialer := &dialerInstance{
conns: make(chan *websocket.Conn, 256),
page: bytes.ReplaceAll(webpage, []byte("dialerPath"), []byte(strings.TrimPrefix(path, "/"))),
}
dialersByAddress[key] = dialer
server.pageRoutes[path] = dialer
return dialer, nil
}
-4
View File
@@ -14,7 +14,6 @@ import (
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet/browser_dialer"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/pipe"
)
@@ -270,9 +269,6 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
}
if len(sockopt.DialerProxy) > 0 {
if browser_dialer.IsBrowserDialerProxy(sockopt.DialerProxy) {
return nil, errors.New("dialerProxy ", sockopt.DialerProxy, " only supports WebSocket or splithttp").AtError()
}
if obm == nil {
return nil, errors.New("there is no outbound manager for dialerProxy").AtError()
}
@@ -15,7 +15,6 @@ import (
// BrowserDialerClient implements splithttp.DialerClient in terms of browser dialer
type BrowserDialerClient struct {
transportConfig *Config
browserDialer string
}
func (c *BrowserDialerClient) IsClosed() bool {
@@ -34,7 +33,7 @@ func (c *BrowserDialerClient) OpenStream(ctx context.Context, url string, sessio
c.transportConfig.FillStreamRequest(request, sessionId, "")
conn, err := browser_dialer.DialGetWithAddress(c.browserDialer, request.URL.String(), request.Header, request.Cookies())
conn, err := browser_dialer.DialGet(request.URL.String(), request.Header, request.Cookies())
dummyAddr := &net.IPAddr{}
if err != nil {
return nil, dummyAddr, dummyAddr, err
@@ -63,7 +62,7 @@ func (c *BrowserDialerClient) PostPacket(ctx context.Context, url string, sessio
}
}
err = browser_dialer.DialPacketWithAddress(c.browserDialer, method, request.URL.String(), request.Header, request.Cookies(), bytes)
err = browser_dialer.DialPacket(method, request.URL.String(), request.Header, request.Cookies(), bytes)
if err != nil {
return err
}
+14 -31
View File
@@ -40,20 +40,6 @@ type dialerConf struct {
*internet.MemoryStreamConfig
}
type errorDialerClient struct {
err error
}
func (c *errorDialerClient) IsClosed() bool { return true }
func (c *errorDialerClient) OpenStream(context.Context, string, string, io.Reader, bool) (io.ReadCloser, net.Addr, net.Addr, error) {
return nil, nil, nil, c.err
}
func (c *errorDialerClient) PostPacket(context.Context, string, string, string, buf.MultiBuffer) error {
return c.err
}
var (
globalDialerMap map[dialerConf]*XmuxManager
globalDialerAccess sync.Mutex
@@ -61,24 +47,9 @@ var (
func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (DialerClient, *XmuxClient) {
realityConfig := reality.ConfigFromStreamSettings(streamSettings)
browserDialer := ""
if streamSettings.SocketSettings != nil {
if browser_dialer.IsBrowserDialerProxy(streamSettings.SocketSettings.DialerProxy) {
browserDialer = streamSettings.SocketSettings.DialerProxy
}
}
if browserDialer != "" && realityConfig == nil {
transportConfig := streamSettings.ProtocolSettings.(*Config)
if transportConfig.Mode != "auto" && transportConfig.Mode != "packet-up" {
return &errorDialerClient{
err: errors.New("browserDialer with splithttp only supports modes \"auto\" or \"packet-up\", got: \"", transportConfig.Mode, "\""),
}, nil
}
return &BrowserDialerClient{
transportConfig: transportConfig,
browserDialer: browserDialer,
}, nil
if browser_dialer.HasBrowserDialer() && realityConfig == nil {
return &BrowserDialerClient{transportConfig: streamSettings.ProtocolSettings.(*Config)}, nil
}
globalDialerAccess.Lock()
@@ -402,6 +373,12 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if requestURL.Host == "" {
requestURL.Host = dest.Address.String()
}
if browser_dialer.HasBrowserDialer() && realityConfig == nil {
// For Browser Dialer's optimized IP and non-standard port
if !(requestURL.Scheme == "http" && dest.Port == 80) && !(requestURL.Scheme == "https" && dest.Port == 443) {
requestURL.Host += ":" + dest.Port.String()
}
}
requestURL.Path = transportConfiguration.GetNormalizedPath()
requestURL.RawQuery = transportConfiguration.GetNormalizedQuery()
@@ -463,6 +440,12 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if requestURL2.Host == "" {
requestURL2.Host = dest2.Address.String()
}
if browser_dialer.HasBrowserDialer() && realityConfig2 == nil {
// For Browser Dialer's optimized IP and non-standard port
if !(requestURL2.Scheme == "http" && dest2.Port == 80) && !(requestURL2.Scheme == "https" && dest2.Port == 443) {
requestURL2.Host += ":" + dest2.Port.String()
}
}
requestURL2.Path = config2.GetNormalizedPath()
requestURL2.RawQuery = config2.GetNormalizedQuery()
httpClient2, xmuxClient2 = getHTTPClient(ctx, dest2, memory2)
+20 -13
View File
@@ -111,20 +111,21 @@ func dialWebSocket(ctx context.Context, dest net.Destination, streamSettings *in
}
}
host := dest.NetAddr()
if (protocol == "ws" && dest.Port == 80) || (protocol == "wss" && dest.Port == 443) {
host = dest.Address.String()
}
uri := protocol + "://" + host + wsSettings.GetNormalizedPath()
browserDialer := ""
if streamSettings.SocketSettings != nil {
if browser_dialer.IsBrowserDialerProxy(streamSettings.SocketSettings.DialerProxy) {
browserDialer = streamSettings.SocketSettings.DialerProxy
if browser_dialer.HasBrowserDialer() {
// For Browser Dialer's optimized IP and non-standard port
host := wsSettings.Host
if host == "" && tConfig.ServerName != "" {
host = tConfig.ServerName
}
}
if browserDialer != "" {
conn, err := browser_dialer.DialWSWithAddress(browserDialer, uri, ed)
if host == "" {
host = dest.Address.String()
}
if !(protocol == "ws" && dest.Port == 80) && !(protocol == "wss" && dest.Port == 443) {
host += ":" + dest.Port.String()
}
uri := protocol + "://" + host + wsSettings.GetNormalizedPath()
conn, err := browser_dialer.DialWS(uri, ed)
if err != nil {
return nil, err
}
@@ -132,6 +133,12 @@ func dialWebSocket(ctx context.Context, dest net.Destination, streamSettings *in
return NewConnection(conn, conn.RemoteAddr(), nil, wsSettings.HeartbeatPeriod), nil
}
host := dest.Address.String()
if !(protocol == "ws" && dest.Port == 80) && !(protocol == "wss" && dest.Port == 443) {
host += ":" + dest.Port.String()
}
uri := protocol + "://" + host + wsSettings.GetNormalizedPath()
header := wsSettings.GetRequestHeader()
// See dialer.DialContext()
header.Set("Host", wsSettings.Host)