mirror of https://github.com/XTLS/Xray-core
				
				
				
			
		
			
				
	
	
		
			215 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
package conf
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"runtime"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"syscall"
 | 
						|
 | 
						|
	"github.com/golang/protobuf/proto"
 | 
						|
	"github.com/xtls/xray-core/common/net"
 | 
						|
	"github.com/xtls/xray-core/common/protocol"
 | 
						|
	"github.com/xtls/xray-core/common/serial"
 | 
						|
	"github.com/xtls/xray-core/common/uuid"
 | 
						|
	"github.com/xtls/xray-core/proxy/vless"
 | 
						|
	"github.com/xtls/xray-core/proxy/vless/inbound"
 | 
						|
	"github.com/xtls/xray-core/proxy/vless/outbound"
 | 
						|
)
 | 
						|
 | 
						|
type VLessInboundFallback struct {
 | 
						|
	Name string          `json:"name"`
 | 
						|
	Alpn string          `json:"alpn"`
 | 
						|
	Path string          `json:"path"`
 | 
						|
	Type string          `json:"type"`
 | 
						|
	Dest json.RawMessage `json:"dest"`
 | 
						|
	Xver uint64          `json:"xver"`
 | 
						|
}
 | 
						|
 | 
						|
type VLessInboundConfig struct {
 | 
						|
	Clients    []json.RawMessage       `json:"clients"`
 | 
						|
	Decryption string                  `json:"decryption"`
 | 
						|
	Fallback   *VLessInboundFallback   `json:"fallback"`
 | 
						|
	Fallbacks  []*VLessInboundFallback `json:"fallbacks"`
 | 
						|
}
 | 
						|
 | 
						|
// Build implements Buildable
 | 
						|
func (c *VLessInboundConfig) Build() (proto.Message, error) {
 | 
						|
	config := new(inbound.Config)
 | 
						|
	config.Clients = make([]*protocol.User, len(c.Clients))
 | 
						|
	for idx, rawUser := range c.Clients {
 | 
						|
		user := new(protocol.User)
 | 
						|
		if err := json.Unmarshal(rawUser, user); err != nil {
 | 
						|
			return nil, newError(`VLESS clients: invalid user`).Base(err)
 | 
						|
		}
 | 
						|
		account := new(vless.Account)
 | 
						|
		if err := json.Unmarshal(rawUser, account); err != nil {
 | 
						|
			return nil, newError(`VLESS clients: invalid user`).Base(err)
 | 
						|
		}
 | 
						|
 | 
						|
		u, err := uuid.ParseString(account.Id)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		account.Id = u.String()
 | 
						|
 | 
						|
		accountFlow := account.Flow
 | 
						|
		flows := strings.Split(account.Flow, ",")
 | 
						|
		for _, f := range flows {
 | 
						|
			t := strings.TrimSpace(f)
 | 
						|
			if t != "none" {
 | 
						|
				accountFlow = t
 | 
						|
			}
 | 
						|
		}
 | 
						|
		switch accountFlow {
 | 
						|
		case "", vless.XRO, vless.XRD, vless.XRV:
 | 
						|
		case vless.XRS:
 | 
						|
			return nil, newError(`VLESS clients: inbound doesn't support "xtls-rprx-splice" in this version, please use "xtls-rprx-direct" instead`)
 | 
						|
		default:
 | 
						|
			return nil, newError(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
 | 
						|
		}
 | 
						|
 | 
						|
		if account.Encryption != "" {
 | 
						|
			return nil, newError(`VLESS clients: "encryption" should not in inbound settings`)
 | 
						|
		}
 | 
						|
 | 
						|
		user.Account = serial.ToTypedMessage(account)
 | 
						|
		config.Clients[idx] = user
 | 
						|
	}
 | 
						|
 | 
						|
	if c.Decryption != "none" {
 | 
						|
		return nil, newError(`VLESS settings: please add/set "decryption":"none" to every settings`)
 | 
						|
	}
 | 
						|
	config.Decryption = c.Decryption
 | 
						|
 | 
						|
	if c.Fallback != nil {
 | 
						|
		return nil, newError(`VLESS settings: please use "fallbacks":[{}] instead of "fallback":{}`)
 | 
						|
	}
 | 
						|
	for _, fb := range c.Fallbacks {
 | 
						|
		var i uint16
 | 
						|
		var s string
 | 
						|
		if err := json.Unmarshal(fb.Dest, &i); err == nil {
 | 
						|
			s = strconv.Itoa(int(i))
 | 
						|
		} else {
 | 
						|
			_ = json.Unmarshal(fb.Dest, &s)
 | 
						|
		}
 | 
						|
		config.Fallbacks = append(config.Fallbacks, &inbound.Fallback{
 | 
						|
			Name: fb.Name,
 | 
						|
			Alpn: fb.Alpn,
 | 
						|
			Path: fb.Path,
 | 
						|
			Type: fb.Type,
 | 
						|
			Dest: s,
 | 
						|
			Xver: fb.Xver,
 | 
						|
		})
 | 
						|
	}
 | 
						|
	for _, fb := range config.Fallbacks {
 | 
						|
		/*
 | 
						|
			if fb.Alpn == "h2" && fb.Path != "" {
 | 
						|
				return nil, newError(`VLESS fallbacks: "alpn":"h2" doesn't support "path"`)
 | 
						|
			}
 | 
						|
		*/
 | 
						|
		if fb.Path != "" && fb.Path[0] != '/' {
 | 
						|
			return nil, newError(`VLESS fallbacks: "path" must be empty or start with "/"`)
 | 
						|
		}
 | 
						|
		if fb.Type == "" && fb.Dest != "" {
 | 
						|
			if fb.Dest == "serve-ws-none" {
 | 
						|
				fb.Type = "serve"
 | 
						|
			} else {
 | 
						|
				switch fb.Dest[0] {
 | 
						|
				case '@', '/':
 | 
						|
					fb.Type = "unix"
 | 
						|
					if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
 | 
						|
						fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
 | 
						|
						copy(fullAddr, fb.Dest[1:])
 | 
						|
						fb.Dest = string(fullAddr)
 | 
						|
					}
 | 
						|
				default:
 | 
						|
					if _, err := strconv.Atoi(fb.Dest); err == nil {
 | 
						|
						fb.Dest = "127.0.0.1:" + fb.Dest
 | 
						|
					}
 | 
						|
					if _, _, err := net.SplitHostPort(fb.Dest); err == nil {
 | 
						|
						fb.Type = "tcp"
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if fb.Type == "" {
 | 
						|
			return nil, newError(`VLESS fallbacks: please fill in a valid value for every "dest"`)
 | 
						|
		}
 | 
						|
		if fb.Xver > 2 {
 | 
						|
			return nil, newError(`VLESS fallbacks: invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return config, nil
 | 
						|
}
 | 
						|
 | 
						|
type VLessOutboundVnext struct {
 | 
						|
	Address *Address          `json:"address"`
 | 
						|
	Port    uint16            `json:"port"`
 | 
						|
	Users   []json.RawMessage `json:"users"`
 | 
						|
}
 | 
						|
 | 
						|
type VLessOutboundConfig struct {
 | 
						|
	Vnext []*VLessOutboundVnext `json:"vnext"`
 | 
						|
}
 | 
						|
 | 
						|
// Build implements Buildable
 | 
						|
func (c *VLessOutboundConfig) Build() (proto.Message, error) {
 | 
						|
	config := new(outbound.Config)
 | 
						|
 | 
						|
	if len(c.Vnext) == 0 {
 | 
						|
		return nil, newError(`VLESS settings: "vnext" is empty`)
 | 
						|
	}
 | 
						|
	config.Vnext = make([]*protocol.ServerEndpoint, len(c.Vnext))
 | 
						|
	for idx, rec := range c.Vnext {
 | 
						|
		if rec.Address == nil {
 | 
						|
			return nil, newError(`VLESS vnext: "address" is not set`)
 | 
						|
		}
 | 
						|
		if len(rec.Users) == 0 {
 | 
						|
			return nil, newError(`VLESS vnext: "users" is empty`)
 | 
						|
		}
 | 
						|
		spec := &protocol.ServerEndpoint{
 | 
						|
			Address: rec.Address.Build(),
 | 
						|
			Port:    uint32(rec.Port),
 | 
						|
			User:    make([]*protocol.User, len(rec.Users)),
 | 
						|
		}
 | 
						|
		for idx, rawUser := range rec.Users {
 | 
						|
			user := new(protocol.User)
 | 
						|
			if err := json.Unmarshal(rawUser, user); err != nil {
 | 
						|
				return nil, newError(`VLESS users: invalid user`).Base(err)
 | 
						|
			}
 | 
						|
			account := new(vless.Account)
 | 
						|
			if err := json.Unmarshal(rawUser, account); err != nil {
 | 
						|
				return nil, newError(`VLESS users: invalid user`).Base(err)
 | 
						|
			}
 | 
						|
 | 
						|
			u, err := uuid.ParseString(account.Id)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			account.Id = u.String()
 | 
						|
 | 
						|
			switch account.Flow {
 | 
						|
			case "", vless.XRO, vless.XRO + "-udp443", vless.XRD, vless.XRD + "-udp443", vless.XRV, vless.XRV + "-udp443":
 | 
						|
			case vless.XRS, vless.XRS + "-udp443":
 | 
						|
				if runtime.GOOS != "linux" && runtime.GOOS != "android" {
 | 
						|
					return nil, newError(`VLESS users: "` + account.Flow + `" only support linux in this version`)
 | 
						|
				}
 | 
						|
			default:
 | 
						|
				return nil, newError(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)
 | 
						|
			}
 | 
						|
 | 
						|
			if account.Encryption != "none" {
 | 
						|
				return nil, newError(`VLESS users: please add/set "encryption":"none" for every user`)
 | 
						|
			}
 | 
						|
 | 
						|
			user.Account = serial.ToTypedMessage(account)
 | 
						|
			spec.User[idx] = user
 | 
						|
		}
 | 
						|
		config.Vnext[idx] = spec
 | 
						|
	}
 | 
						|
 | 
						|
	return config, nil
 | 
						|
}
 |