diff --git a/infra/conf/http.go b/infra/conf/http.go index 84155d54..63294ca1 100644 --- a/infra/conf/http.go +++ b/infra/conf/http.go @@ -64,25 +64,24 @@ type HTTPClientConfig struct { func (v *HTTPClientConfig) Build() (proto.Message, error) { config := new(http.ClientConfig) if v.Address != nil { - if len(v.Username) == 0 { - v.Servers = []*HTTPRemoteConfig{ - { - Address: v.Address, - Port: v.Port, - }, - } - } else { - v.Servers = []*HTTPRemoteConfig{ - { - Address: v.Address, - Port: v.Port, - Users: []json.RawMessage{{}}, - }, - } + v.Servers = []*HTTPRemoteConfig{ + { + Address: v.Address, + Port: v.Port, + }, } + if len(v.Username) > 0 { + v.Servers[0].Users = []json.RawMessage{{}} + } + } + if len(v.Servers) != 1 { + return nil, errors.New(`HTTP settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple HTTP outbounds and routing balancer instead`) } config.Server = make([]*protocol.ServerEndpoint, len(v.Servers)) for idx, serverConfig := range v.Servers { + if len(serverConfig.Users) > 1 { + return nil, errors.New(`HTTP servers: "users" should have one member at most. Multiple members in "users" should use multiple HTTP outbounds and routing balancer instead`) + } server := &protocol.ServerEndpoint{ Address: serverConfig.Address.Build(), Port: uint32(serverConfig.Port), diff --git a/infra/conf/shadowsocks.go b/infra/conf/shadowsocks.go index a05c1dc5..04e60bd0 100644 --- a/infra/conf/shadowsocks.go +++ b/infra/conf/shadowsocks.go @@ -172,16 +172,16 @@ type ShadowsocksServerTarget struct { } type ShadowsocksClientConfig struct { - Address *Address `json:"address"` - Port uint16 `json:"port"` - Level byte `json:"level"` - Email string `json:"email"` - Cipher string `json:"method"` - Password string `json:"password"` - IVCheck bool `json:"ivCheck"` - UoT bool `json:"uot"` - UoTVersion int `json:"uotVersion"` - Servers []*ShadowsocksServerTarget `json:"servers"` + Address *Address `json:"address"` + Port uint16 `json:"port"` + Level byte `json:"level"` + Email string `json:"email"` + Cipher string `json:"method"` + Password string `json:"password"` + IVCheck bool `json:"ivCheck"` + UoT bool `json:"uot"` + UoTVersion int `json:"uotVersion"` + Servers []*ShadowsocksServerTarget `json:"servers"` } func (v *ShadowsocksClientConfig) Build() (proto.Message, error) { @@ -200,8 +200,8 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) { }, } } - if len(v.Servers) == 0 { - return nil, errors.New("0 Shadowsocks server configured.") + if len(v.Servers) != 1 { + return nil, errors.New(`Shadowsocks settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Shadowsocks outbounds and routing balancer instead`) } if len(v.Servers) == 1 { diff --git a/infra/conf/socks.go b/infra/conf/socks.go index 1d7c6249..fa5d2bf3 100644 --- a/infra/conf/socks.go +++ b/infra/conf/socks.go @@ -82,25 +82,24 @@ type SocksClientConfig struct { func (v *SocksClientConfig) Build() (proto.Message, error) { config := new(socks.ClientConfig) if v.Address != nil { - if len(v.Username) == 0 { - v.Servers = []*SocksRemoteConfig{ - { - Address: v.Address, - Port: v.Port, - }, - } - } else { - v.Servers = []*SocksRemoteConfig{ - { - Address: v.Address, - Port: v.Port, - Users: []json.RawMessage{{}}, - }, - } + v.Servers = []*SocksRemoteConfig{ + { + Address: v.Address, + Port: v.Port, + }, } + if len(v.Username) > 0 { + v.Servers[0].Users = []json.RawMessage{{}} + } + } + if len(v.Servers) != 1 { + return nil, errors.New(`SOCKS settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple SOCKS outbounds and routing balancer instead`) } config.Server = make([]*protocol.ServerEndpoint, len(v.Servers)) for idx, serverConfig := range v.Servers { + if len(serverConfig.Users) > 1 { + return nil, errors.New(`SOCKS servers: "users" should have one member at most. Multiple members in "users" should use multiple SOCKS outbounds and routing balancer instead`) + } server := &protocol.ServerEndpoint{ Address: serverConfig.Address.Build(), Port: uint32(serverConfig.Port), diff --git a/infra/conf/trojan.go b/infra/conf/trojan.go index d7d4ea17..b495bab4 100644 --- a/infra/conf/trojan.go +++ b/infra/conf/trojan.go @@ -28,13 +28,13 @@ type TrojanServerTarget struct { // TrojanClientConfig is configuration of trojan servers type TrojanClientConfig struct { - Address *Address `json:"address"` - Port uint16 `json:"port"` - Level byte `json:"level"` - Email string `json:"email"` - Password string `json:"password"` - Flow string `json:"flow"` - Servers []*TrojanServerTarget `json:"servers"` + Address *Address `json:"address"` + Port uint16 `json:"port"` + Level byte `json:"level"` + Email string `json:"email"` + Password string `json:"password"` + Flow string `json:"flow"` + Servers []*TrojanServerTarget `json:"servers"` } // Build implements Buildable @@ -51,8 +51,8 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) { }, } } - if len(c.Servers) == 0 { - return nil, errors.New("0 Trojan server configured.") + if len(c.Servers) != 1 { + return nil, errors.New(`Trojan settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Trojan outbounds and routing balancer instead`) } config := &trojan.ClientConfig{ diff --git a/infra/conf/vless.go b/infra/conf/vless.go index aa410e5c..b45b9057 100644 --- a/infra/conf/vless.go +++ b/infra/conf/vless.go @@ -228,7 +228,7 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) { } } if len(c.Vnext) != 1 { - return nil, errors.New(`VLESS settings: "vnext" should have one and only one member`) + return nil, errors.New(`VLESS settings: "vnext" should have one and only one member. Multiple endpoints in "vnext" should use multiple VLESS outbounds and routing balancer instead`) } config.Vnext = make([]*protocol.ServerEndpoint, len(c.Vnext)) for idx, rec := range c.Vnext { @@ -236,7 +236,7 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) { return nil, errors.New(`VLESS vnext: "address" is not set`) } if len(rec.Users) != 1 { - return nil, errors.New(`VLESS vnext: "users" should have one and only one member`) + return nil, errors.New(`VLESS vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VLESS outbounds and routing balancer instead`) } spec := &protocol.ServerEndpoint{ Address: rec.Address.Build(), diff --git a/infra/conf/vmess.go b/infra/conf/vmess.go index c0171c4b..71eafaa2 100644 --- a/infra/conf/vmess.go +++ b/infra/conf/vmess.go @@ -139,16 +139,16 @@ func (c *VMessOutboundConfig) Build() (proto.Message, error) { }, } } - if len(c.Receivers) == 0 { - return nil, errors.New("0 VMess receiver configured") + if len(c.Receivers) != 1 { + return nil, errors.New(`VMess settings: "vnext" should have one and only one member. Multiple endpoints in "vnext" should use multiple VMess outbounds and routing balancer instead`) } serverSpecs := make([]*protocol.ServerEndpoint, len(c.Receivers)) for idx, rec := range c.Receivers { - if len(rec.Users) == 0 { - return nil, errors.New("0 user configured for VMess outbound") + if len(rec.Users) != 1 { + return nil, errors.New(`VMess vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VMess outbounds and routing balancer instead`) } if rec.Address == nil { - return nil, errors.New("address is not set in VMess outbound config") + return nil, errors.New(`VMess vnext: "address" is not set`) } spec := &protocol.ServerEndpoint{ Address: rec.Address.Build(),