2020-11-25 19:01:53 +08:00
package conf
import (
"encoding/json"
2024-06-29 14:32:57 -04:00
"github.com/xtls/xray-core/common/errors"
2020-12-04 09:36:16 +08:00
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/socks"
2023-08-10 04:43:34 +00:00
"google.golang.org/protobuf/proto"
2020-11-25 19:01:53 +08:00
)
type SocksAccount struct {
Username string `json:"user"`
Password string `json:"pass"`
}
func ( v * SocksAccount ) Build () * socks . Account {
return & socks . Account {
Username : v . Username ,
Password : v . Password ,
}
}
const (
AuthMethodNoAuth = "noauth"
AuthMethodUserPass = "password"
)
type SocksServerConfig struct {
AuthMethod string `json:"auth"`
2026-05-07 19:10:48 +08:00
Users [] * SocksAccount `json:"users"`
2020-11-25 19:01:53 +08:00
Accounts [] * SocksAccount `json:"accounts"`
UDP bool `json:"udp"`
Host * Address `json:"ip"`
UserLevel uint32 `json:"userLevel"`
}
func ( v * SocksServerConfig ) Build () ( proto . Message , error ) {
config := new ( socks . ServerConfig )
switch v . AuthMethod {
case AuthMethodNoAuth :
config . AuthType = socks . AuthType_NO_AUTH
case AuthMethodUserPass :
config . AuthType = socks . AuthType_PASSWORD
default :
config . AuthType = socks . AuthType_NO_AUTH
}
2026-05-07 19:10:48 +08:00
if v . Accounts != nil {
v . Users = v . Accounts
}
// TODO: PB
if len ( v . Users ) > 0 {
config . Accounts = make ( map [ string ] string , len ( v . Users ))
for _ , account := range v . Users {
2020-11-25 19:01:53 +08:00
config . Accounts [ account . Username ] = account . Password
}
}
config . UdpEnabled = v . UDP
if v . Host != nil {
config . Address = v . Host . Build ()
}
config . UserLevel = v . UserLevel
return config , nil
}
type SocksRemoteConfig struct {
Address * Address `json:"address"`
Port uint16 `json:"port"`
Users [] json . RawMessage `json:"users"`
}
2021-10-19 12:57:14 -04:00
2020-11-25 19:01:53 +08:00
type SocksClientConfig struct {
2025-09-11 21:48:20 +08:00
Address * Address `json:"address"`
Port uint16 `json:"port"`
Level uint32 `json:"level"`
Email string `json:"email"`
Username string `json:"user"`
Password string `json:"pass"`
Servers [] * SocksRemoteConfig `json:"servers"`
2020-11-25 19:01:53 +08:00
}
func ( v * SocksClientConfig ) Build () ( proto . Message , error ) {
config := new ( socks . ClientConfig )
2025-09-11 21:48:20 +08:00
if v . Address != nil {
v . Servers = [] * SocksRemoteConfig {
{
Address : v . Address ,
Port : v . Port ,
},
}
2025-09-15 21:31:27 +08:00
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` )
2025-09-11 21:48:20 +08:00
}
2025-09-15 21:31:27 +08:00
for _ , 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` )
}
2020-11-25 19:01:53 +08:00
server := & protocol . ServerEndpoint {
Address : serverConfig . Address . Build (),
Port : uint32 ( serverConfig . Port ),
}
for _ , rawUser := range serverConfig . Users {
user := new ( protocol . User )
2025-09-11 21:48:20 +08:00
if v . Address != nil {
user . Level = v . Level
user . Email = v . Email
} else {
if err := json . Unmarshal ( rawUser , user ); err != nil {
2026-09-26 01:49:34 +08:00
return nil , errors . New ( "failed to parse Socks user" ). Base ( err )
2025-09-11 21:48:20 +08:00
}
2020-11-25 19:01:53 +08:00
}
account := new ( SocksAccount )
2025-09-11 21:48:20 +08:00
if v . Address != nil {
account . Username = v . Username
account . Password = v . Password
} else {
if err := json . Unmarshal ( rawUser , account ); err != nil {
2026-09-26 01:49:34 +08:00
return nil , errors . New ( "failed to parse socks account" ). Base ( err )
2025-09-11 21:48:20 +08:00
}
2020-11-25 19:01:53 +08:00
}
user . Account = serial . ToTypedMessage ( account . Build ())
2025-09-15 21:31:27 +08:00
server . User = user
break
2020-11-25 19:01:53 +08:00
}
2025-09-15 21:31:27 +08:00
config . Server = server
break
2020-11-25 19:01:53 +08:00
}
return config , nil
}