|
|
|
package conf
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
|
|
|
|
"v2ray.com/core/common/net"
|
|
|
|
"v2ray.com/core/common/protocol"
|
|
|
|
"v2ray.com/core/common/serial"
|
|
|
|
"v2ray.com/core/proxy/vless"
|
|
|
|
"v2ray.com/core/proxy/vless/inbound"
|
|
|
|
"v2ray.com/core/proxy/vless/outbound"
|
|
|
|
)
|
|
|
|
|
|
|
|
type VLessInboundFallback struct {
|
|
|
|
Addr *Address `json:"addr"`
|
|
|
|
Port uint16 `json:"port"`
|
|
|
|
Unix string `json:"unix"`
|
|
|
|
Xver uint16 `json:"xver"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type VLessInboundConfig struct {
|
|
|
|
Users []json.RawMessage `json:"clients"`
|
|
|
|
Decryption string `json:"decryption"`
|
|
|
|
Fallback *VLessInboundFallback `json:"fallback"`
|
|
|
|
Fallback_h2 *VLessInboundFallback `json:"fallback_h2"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build implements Buildable
|
|
|
|
func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|
|
|
|
|
|
|
config := new(inbound.Config)
|
|
|
|
|
|
|
|
if c.Decryption != "none" {
|
|
|
|
return nil, newError(`please add/set "decryption":"none" directly to every VLESS "settings"`)
|
|
|
|
}
|
|
|
|
config.Decryption = c.Decryption
|
|
|
|
|
|
|
|
if c.Fallback != nil {
|
|
|
|
if c.Fallback.Xver > 2 {
|
|
|
|
return nil, newError(`VLESS "fallback": invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
|
|
|
|
}
|
|
|
|
if c.Fallback.Unix != "" {
|
|
|
|
if c.Fallback.Unix[0] == '@' {
|
|
|
|
c.Fallback.Unix = "\x00" + c.Fallback.Unix[1:]
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if c.Fallback.Port == 0 {
|
|
|
|
return nil, newError(`please fill in a valid value for "port" in VLESS "fallback"`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if c.Fallback.Addr == nil {
|
|
|
|
c.Fallback.Addr = &Address{
|
|
|
|
Address: net.ParseAddress("127.0.0.1"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
config.Fallback = &inbound.Fallback{
|
|
|
|
Addr: c.Fallback.Addr.Build(),
|
|
|
|
Port: uint32(c.Fallback.Port),
|
|
|
|
Unix: c.Fallback.Unix,
|
|
|
|
Xver: uint32(c.Fallback.Xver),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Fallback_h2 != nil {
|
|
|
|
if config.Fallback == nil {
|
|
|
|
return nil, newError(`VLESS "fallback_h2" can't exist alone without "fallback"`)
|
|
|
|
}
|
|
|
|
if c.Fallback_h2.Xver > 2 {
|
|
|
|
return nil, newError(`VLESS "fallback_h2": invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
|
|
|
|
}
|
|
|
|
if c.Fallback_h2.Unix != "" {
|
|
|
|
if c.Fallback_h2.Unix[0] == '@' {
|
|
|
|
c.Fallback_h2.Unix = "\x00" + c.Fallback_h2.Unix[1:]
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if c.Fallback_h2.Port == 0 {
|
|
|
|
return nil, newError(`please fill in a valid value for "port" in VLESS "fallback_h2"`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if c.Fallback_h2.Addr == nil {
|
|
|
|
c.Fallback_h2.Addr = &Address{
|
|
|
|
Address: net.ParseAddress("127.0.0.1"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
config.FallbackH2 = &inbound.FallbackH2{
|
|
|
|
Addr: c.Fallback_h2.Addr.Build(),
|
|
|
|
Port: uint32(c.Fallback_h2.Port),
|
|
|
|
Unix: c.Fallback_h2.Unix,
|
|
|
|
Xver: uint32(c.Fallback_h2.Xver),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
config.User = make([]*protocol.User, len(c.Users))
|
|
|
|
for idx, rawData := range c.Users {
|
|
|
|
user := new(protocol.User)
|
|
|
|
if err := json.Unmarshal(rawData, user); err != nil {
|
|
|
|
return nil, newError("invalid VLESS user").Base(err)
|
|
|
|
}
|
|
|
|
account := new(vless.Account)
|
|
|
|
if err := json.Unmarshal(rawData, account); err != nil {
|
|
|
|
return nil, newError("invalid VLESS user").Base(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if account.Schedulers != "" {
|
|
|
|
return nil, newError(`VLESS attr "schedulers" is not available in this version`)
|
|
|
|
}
|
|
|
|
if account.Encryption != "" {
|
|
|
|
return nil, newError(`VLESS attr "encryption" should not in inbound settings`)
|
|
|
|
}
|
|
|
|
|
|
|
|
user.Account = serial.ToTypedMessage(account)
|
|
|
|
config.User[idx] = user
|
|
|
|
}
|
|
|
|
|
|
|
|
return config, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type VLessOutboundTarget struct {
|
|
|
|
Address *Address `json:"address"`
|
|
|
|
Port uint16 `json:"port"`
|
|
|
|
Users []json.RawMessage `json:"users"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type VLessOutboundConfig struct {
|
|
|
|
Receivers []*VLessOutboundTarget `json:"vnext"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build implements Buildable
|
|
|
|
func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
|
|
|
|
|
|
|
config := new(outbound.Config)
|
|
|
|
|
|
|
|
if len(c.Receivers) == 0 {
|
|
|
|
return nil, newError("0 VLESS receiver configured")
|
|
|
|
}
|
|
|
|
serverSpecs := make([]*protocol.ServerEndpoint, len(c.Receivers))
|
|
|
|
for idx, rec := range c.Receivers {
|
|
|
|
if len(rec.Users) == 0 {
|
|
|
|
return nil, newError("0 user configured for VLESS outbound")
|
|
|
|
}
|
|
|
|
if rec.Address == nil {
|
|
|
|
return nil, newError("address is not set in VLESS outbound config")
|
|
|
|
}
|
|
|
|
spec := &protocol.ServerEndpoint{
|
|
|
|
Address: rec.Address.Build(),
|
|
|
|
Port: uint32(rec.Port),
|
|
|
|
}
|
|
|
|
for _, rawUser := range rec.Users {
|
|
|
|
user := new(protocol.User)
|
|
|
|
if err := json.Unmarshal(rawUser, user); err != nil {
|
|
|
|
return nil, newError("invalid VLESS user").Base(err)
|
|
|
|
}
|
|
|
|
account := new(vless.Account)
|
|
|
|
if err := json.Unmarshal(rawUser, account); err != nil {
|
|
|
|
return nil, newError("invalid VLESS user").Base(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if account.Schedulers != "" {
|
|
|
|
return nil, newError(`VLESS attr "schedulers" is not available in this version`)
|
|
|
|
}
|
|
|
|
if account.Encryption != "none" {
|
|
|
|
return nil, newError(`please add/set "encryption":"none" for every VLESS user in "users"`)
|
|
|
|
}
|
|
|
|
|
|
|
|
user.Account = serial.ToTypedMessage(account)
|
|
|
|
spec.User = append(spec.User, user)
|
|
|
|
}
|
|
|
|
serverSpecs[idx] = spec
|
|
|
|
}
|
|
|
|
config.Receiver = serverSpecs
|
|
|
|
|
|
|
|
return config, nil
|
|
|
|
}
|