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" `
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 :
2024-06-29 14:32:57 -04:00
// errors.New("unknown socks auth method: ", v.AuthMethod, ". Default to noauth.").AtWarning().WriteToLog()
2020-11-25 19:01:53 +08:00
config . AuthType = socks . AuthType_NO_AUTH
}
if len ( v . Accounts ) > 0 {
config . Accounts = make ( map [ string ] string , len ( v . Accounts ) )
for _ , account := range v . Accounts {
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 {
return nil , errors . New ( "failed to parse Socks user" ) . Base ( err ) . AtError ( )
}
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 {
return nil , errors . New ( "failed to parse socks account" ) . Base ( err ) . AtError ( )
}
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
}