diff --git a/infra/conf/transport_internet.go b/infra/conf/transport_internet.go index e1387de8..b56a0aa9 100644 --- a/infra/conf/transport_internet.go +++ b/infra/conf/transport_internet.go @@ -1080,6 +1080,10 @@ type SocketConfig struct { // Build implements Buildable. func (c *SocketConfig) Build() (*internet.SocketConfig, error) { + if c.BrowserDialer != "" { + return nil, errors.PrintRemovedFeatureError("sockopt.browserDialer", "root browserDialers + sockopt.dialerProxy") + } + tfo := int32(0) // don't invoke setsockopt() for TFO if c.TFO != nil { switch v := c.TFO.(type) { @@ -1196,7 +1200,6 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) { AddressPortStrategy: addressPortStrategy, HappyEyeballs: happyEyeballs, TrustedXForwardedFor: c.TrustedXForwardedFor, - BrowserDialer: c.BrowserDialer, }, nil } @@ -1974,25 +1977,30 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) { config.ProtocolName = protocol } if c.SocketSettings != nil && c.SocketSettings.BrowserDialer != "" { - if config.ProtocolName != "websocket" && config.ProtocolName != "splithttp" { - return nil, errors.New("sockopt.browserDialer only supports websocket or splithttp") - } - if strings.EqualFold(c.Security, "reality") { - return nil, errors.New("sockopt.browserDialer does not support REALITY") - } - if config.ProtocolName == "splithttp" { - splitHTTPSettings := c.SplitHTTPSettings - if c.XHTTPSettings != nil { - splitHTTPSettings = c.XHTTPSettings + return nil, errors.PrintRemovedFeatureError("sockopt.browserDialer", "root browserDialers + sockopt.dialerProxy") + } + if c.SocketSettings != nil && c.SocketSettings.DialerProxy != "" { + if _, ok := browser_dialer.GetAddressByTag(c.SocketSettings.DialerProxy); ok { + if config.ProtocolName != "websocket" && config.ProtocolName != "splithttp" { + return nil, errors.New("dialerProxy tag ", c.SocketSettings.DialerProxy, " maps to browserDialers and only supports websocket or splithttp") } - if splitHTTPSettings != nil { - splitHTTPSettingsCopy := *splitHTTPSettings - hs, err := splitHTTPSettingsCopy.Build() - if err != nil { - return nil, errors.New("failed to build XHTTP config for browserDialer validation.").Base(err) + if strings.EqualFold(c.Security, "reality") { + return nil, errors.New("dialerProxy tag ", c.SocketSettings.DialerProxy, " maps to browserDialers and does not support REALITY") + } + if config.ProtocolName == "splithttp" { + splitHTTPSettings := c.SplitHTTPSettings + if c.XHTTPSettings != nil { + splitHTTPSettings = c.XHTTPSettings } - if splitHTTPConfig, ok := hs.(*splithttp.Config); ok && splitHTTPConfig.Mode != "auto" && splitHTTPConfig.Mode != "packet-up" { - return nil, errors.New("sockopt.browserDialer only supports XHTTP modes \"auto\" or \"packet-up\", got: \"", splitHTTPConfig.Mode, "\"") + if splitHTTPSettings != nil { + splitHTTPSettingsCopy := *splitHTTPSettings + hs, err := splitHTTPSettingsCopy.Build() + if err != nil { + return nil, errors.New("failed to build XHTTP config for browserDialers validation.").Base(err) + } + if splitHTTPConfig, ok := hs.(*splithttp.Config); ok && splitHTTPConfig.Mode != "auto" && splitHTTPConfig.Mode != "packet-up" { + return nil, errors.New("dialerProxy tag ", c.SocketSettings.DialerProxy, " maps to browserDialers and only supports XHTTP modes \"auto\" or \"packet-up\", got: \"", splitHTTPConfig.Mode, "\"") + } } } } @@ -2113,9 +2121,6 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) { if err != nil { return nil, errors.New("Failed to build sockopt.").Base(err) } - if err := browser_dialer.EnsureDialerWithAddress(ss.BrowserDialer); err != nil { - return nil, errors.New("Failed to start Browser Dialer listener.").Base(err) - } config.SocketSettings = ss } diff --git a/infra/conf/xray.go b/infra/conf/xray.go index 4d8443e1..938bdd76 100644 --- a/infra/conf/xray.go +++ b/infra/conf/xray.go @@ -614,6 +614,9 @@ 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.CheckLegacyEnv(); err != nil { + return nil, err + } browserDialerTags := make(map[string]string, len(c.BrowserDialers)) for _, browserDialer := range c.BrowserDialers { diff --git a/transport/internet/browser_dialer/dialer.go b/transport/internet/browser_dialer/dialer.go index 0882d6b2..644d0c4d 100644 --- a/transport/internet/browser_dialer/dialer.go +++ b/transport/internet/browser_dialer/dialer.go @@ -62,8 +62,20 @@ func GetAddressByTag(tag string) (string, bool) { return addr, ok } +func CheckLegacyEnv() error { + envAddress := platform.NewEnvFlag(platform.BrowserDialerAddress).GetValue(func() string { return "" }) + if envAddress == "" { + return nil + } + return errors.PrintRemovedFeatureError("env "+platform.BrowserDialerAddress, "root browserDialers + sockopt.dialerProxy") +} + func ConfigureDialerTags(tags map[string]string) error { + if err := CheckLegacyEnv(); err != nil { + return err + } next := make(map[string]string, len(tags)) + listenAddrByPort := make(map[string]string, len(tags)) for tag, addr := range tags { if tag == "" { return errors.New("browserDialers tag cannot be empty") @@ -71,11 +83,36 @@ func ConfigureDialerTags(tags map[string]string) error { if addr == "" { return errors.New("browserDialers url cannot be empty for tag: ", tag) } - if err := EnsureDialerWithAddress(addr); err != nil { - return errors.New("invalid browserDialers entry for tag ", tag).Base(err) + listenAddr, _, ok := parseBrowserDialerAddress(addr) + if !ok { + return errors.New("invalid browserDialers entry for tag ", tag, ": ", addr) } + _, port, err := net.SplitHostPort(listenAddr) + if err != nil { + return errors.New("invalid browserDialers listen address for tag ", tag, ": ", listenAddr) + } + if existingAddr, found := listenAddrByPort[port]; found && existingAddr != listenAddr { + return errors.New("browserDialers cannot use the same port with a different listen address: ", existingAddr, " and ", listenAddr) + } + listenAddrByPort[port] = listenAddr next[tag] = addr } + mu.RLock() + defer mu.RUnlock() + for existingAddr := range dialerServers { + _, existingPort, splitErr := net.SplitHostPort(existingAddr) + if splitErr != nil { + continue + } + if newAddr, found := listenAddrByPort[existingPort]; found && newAddr != existingAddr { + return errors.New("browserDialers cannot use the same port with a different listen address: ", existingAddr, " and ", newAddr) + } + } + for tag, addr := range next { + if err := EnsureDialerWithAddress(addr); err != nil { + return errors.New("failed to initialize browserDialers listener for tag ", tag).Base(err) + } + } mu.Lock() dialerTags = next @@ -203,11 +240,11 @@ func closeConnection(w http.ResponseWriter) { func getDialerByAddress(addr string) (*dialerInstance, error) { listenAddr, path, ok := parseBrowserDialerAddress(addr) if !ok { - return nil, errors.New("invalid sockopt.browserDialer: ", addr) + return nil, errors.New("invalid browserDialers url: ", addr) } _, port, err := net.SplitHostPort(listenAddr) if err != nil { - return nil, errors.New("invalid sockopt.browserDialer listen address: ", listenAddr) + return nil, errors.New("invalid browserDialers listen address: ", listenAddr) } key := listenAddr + path @@ -230,7 +267,7 @@ func getDialerByAddress(addr string) (*dialerInstance, error) { for existingAddr := range dialerServers { _, existingPort, splitErr := net.SplitHostPort(existingAddr) if splitErr == nil && existingPort == port { - return nil, errors.New("sockopt.browserDialer cannot use the same port with a different listen address: ", existingAddr, " and ", listenAddr) + return nil, errors.New("browserDialers cannot use the same port with a different listen address: ", existingAddr, " and ", listenAddr) } } newServer, serverErr := newDialerServer(listenAddr) @@ -353,11 +390,11 @@ func dialTaskWithAddress(addr string, task task) (*websocket.Conn, error) { } if addr == "" { - return nil, errors.New("browser dialer is not configured; set sockopt.browserDialer") + return nil, errors.New("browser dialer is not configured; set root browserDialers and use sockopt.dialerProxy tag") } dialer, err := getDialerByAddress(addr) if err != nil || dialer == nil { - return nil, errors.New("browser dialer is not configured for sockopt.browserDialer: ", addr) + return nil, errors.New("browser dialer is not configured for browserDialers url: ", addr) } conns := dialer.conns @@ -389,15 +426,3 @@ func CheckOK(conn *websocket.Conn) error { return nil } - -func notifyRemovedEnv() { - envAddress := platform.NewEnvFlag(platform.BrowserDialerAddress).GetValue(func() string { return "" }) - if envAddress == "" { - return - } - errors.LogWarning(context.Background(), errors.PrintRemovedFeatureError("env "+platform.BrowserDialerAddress, "sockopt.browserDialer")) -} - -func init() { - notifyRemovedEnv() -} diff --git a/transport/internet/splithttp/dialer.go b/transport/internet/splithttp/dialer.go index abbcce31..425ebbab 100644 --- a/transport/internet/splithttp/dialer.go +++ b/transport/internet/splithttp/dialer.go @@ -63,11 +63,8 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in realityConfig := reality.ConfigFromStreamSettings(streamSettings) browserDialer := "" if streamSettings.SocketSettings != nil { - browserDialer = streamSettings.SocketSettings.BrowserDialer - if browserDialer == "" { - if taggedDialer, ok := browser_dialer.GetAddressByTag(streamSettings.SocketSettings.DialerProxy); ok { - browserDialer = taggedDialer - } + if taggedDialer, ok := browser_dialer.GetAddressByTag(streamSettings.SocketSettings.DialerProxy); ok { + browserDialer = taggedDialer } } diff --git a/transport/internet/websocket/dialer.go b/transport/internet/websocket/dialer.go index 6c7019cf..f7bc4968 100644 --- a/transport/internet/websocket/dialer.go +++ b/transport/internet/websocket/dialer.go @@ -119,11 +119,8 @@ func dialWebSocket(ctx context.Context, dest net.Destination, streamSettings *in browserDialer := "" if streamSettings.SocketSettings != nil { - browserDialer = streamSettings.SocketSettings.BrowserDialer - if browserDialer == "" { - if taggedDialer, ok := browser_dialer.GetAddressByTag(streamSettings.SocketSettings.DialerProxy); ok { - browserDialer = taggedDialer - } + if taggedDialer, ok := browser_dialer.GetAddressByTag(streamSettings.SocketSettings.DialerProxy); ok { + browserDialer = taggedDialer } } if browser_dialer.HasBrowserDialerWithAddress(browserDialer) {