github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/infra/conf/vless.go (about) 1 package conf 2 3 import ( 4 "encoding/json" 5 "path/filepath" 6 "runtime" 7 "strconv" 8 "strings" 9 "syscall" 10 11 "github.com/xtls/xray-core/common/net" 12 "github.com/xtls/xray-core/common/protocol" 13 "github.com/xtls/xray-core/common/serial" 14 "github.com/xtls/xray-core/common/uuid" 15 "github.com/xtls/xray-core/proxy/vless" 16 "github.com/xtls/xray-core/proxy/vless/inbound" 17 "github.com/xtls/xray-core/proxy/vless/outbound" 18 "google.golang.org/protobuf/proto" 19 ) 20 21 type VLessInboundFallback struct { 22 Name string `json:"name"` 23 Alpn string `json:"alpn"` 24 Path string `json:"path"` 25 Type string `json:"type"` 26 Dest json.RawMessage `json:"dest"` 27 Xver uint64 `json:"xver"` 28 } 29 30 type VLessInboundConfig struct { 31 Clients []json.RawMessage `json:"clients"` 32 Decryption string `json:"decryption"` 33 Fallback *VLessInboundFallback `json:"fallback"` 34 Fallbacks []*VLessInboundFallback `json:"fallbacks"` 35 } 36 37 // Build implements Buildable 38 func (c *VLessInboundConfig) Build() (proto.Message, error) { 39 config := new(inbound.Config) 40 config.Clients = make([]*protocol.User, len(c.Clients)) 41 for idx, rawUser := range c.Clients { 42 user := new(protocol.User) 43 if err := json.Unmarshal(rawUser, user); err != nil { 44 return nil, newError(`VLESS clients: invalid user`).Base(err) 45 } 46 account := new(vless.Account) 47 if err := json.Unmarshal(rawUser, account); err != nil { 48 return nil, newError(`VLESS clients: invalid user`).Base(err) 49 } 50 51 u, err := uuid.ParseString(account.Id) 52 if err != nil { 53 return nil, err 54 } 55 account.Id = u.String() 56 57 switch account.Flow { 58 case "", vless.XRV: 59 default: 60 return nil, newError(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`) 61 } 62 63 if account.Encryption != "" { 64 return nil, newError(`VLESS clients: "encryption" should not in inbound settings`) 65 } 66 67 user.Account = serial.ToTypedMessage(account) 68 config.Clients[idx] = user 69 } 70 71 if c.Decryption != "none" { 72 return nil, newError(`VLESS settings: please add/set "decryption":"none" to every settings`) 73 } 74 config.Decryption = c.Decryption 75 76 if c.Fallback != nil { 77 return nil, newError(`VLESS settings: please use "fallbacks":[{}] instead of "fallback":{}`) 78 } 79 for _, fb := range c.Fallbacks { 80 var i uint16 81 var s string 82 if err := json.Unmarshal(fb.Dest, &i); err == nil { 83 s = strconv.Itoa(int(i)) 84 } else { 85 _ = json.Unmarshal(fb.Dest, &s) 86 } 87 config.Fallbacks = append(config.Fallbacks, &inbound.Fallback{ 88 Name: fb.Name, 89 Alpn: fb.Alpn, 90 Path: fb.Path, 91 Type: fb.Type, 92 Dest: s, 93 Xver: fb.Xver, 94 }) 95 } 96 for _, fb := range config.Fallbacks { 97 /* 98 if fb.Alpn == "h2" && fb.Path != "" { 99 return nil, newError(`VLESS fallbacks: "alpn":"h2" doesn't support "path"`) 100 } 101 */ 102 if fb.Path != "" && fb.Path[0] != '/' { 103 return nil, newError(`VLESS fallbacks: "path" must be empty or start with "/"`) 104 } 105 if fb.Type == "" && fb.Dest != "" { 106 if fb.Dest == "serve-ws-none" { 107 fb.Type = "serve" 108 } else if filepath.IsAbs(fb.Dest) || fb.Dest[0] == '@' { 109 fb.Type = "unix" 110 if strings.HasPrefix(fb.Dest, "@@") && (runtime.GOOS == "linux" || runtime.GOOS == "android") { 111 fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy 112 copy(fullAddr, fb.Dest[1:]) 113 fb.Dest = string(fullAddr) 114 } 115 } else { 116 if _, err := strconv.Atoi(fb.Dest); err == nil { 117 fb.Dest = "127.0.0.1:" + fb.Dest 118 } 119 if _, _, err := net.SplitHostPort(fb.Dest); err == nil { 120 fb.Type = "tcp" 121 } 122 } 123 } 124 if fb.Type == "" { 125 return nil, newError(`VLESS fallbacks: please fill in a valid value for every "dest"`) 126 } 127 if fb.Xver > 2 { 128 return nil, newError(`VLESS fallbacks: invalid PROXY protocol version, "xver" only accepts 0, 1, 2`) 129 } 130 } 131 132 return config, nil 133 } 134 135 type VLessOutboundVnext struct { 136 Address *Address `json:"address"` 137 Port uint16 `json:"port"` 138 Users []json.RawMessage `json:"users"` 139 } 140 141 type VLessOutboundConfig struct { 142 Vnext []*VLessOutboundVnext `json:"vnext"` 143 } 144 145 // Build implements Buildable 146 func (c *VLessOutboundConfig) Build() (proto.Message, error) { 147 config := new(outbound.Config) 148 149 if len(c.Vnext) == 0 { 150 return nil, newError(`VLESS settings: "vnext" is empty`) 151 } 152 config.Vnext = make([]*protocol.ServerEndpoint, len(c.Vnext)) 153 for idx, rec := range c.Vnext { 154 if rec.Address == nil { 155 return nil, newError(`VLESS vnext: "address" is not set`) 156 } 157 if len(rec.Users) == 0 { 158 return nil, newError(`VLESS vnext: "users" is empty`) 159 } 160 spec := &protocol.ServerEndpoint{ 161 Address: rec.Address.Build(), 162 Port: uint32(rec.Port), 163 User: make([]*protocol.User, len(rec.Users)), 164 } 165 for idx, rawUser := range rec.Users { 166 user := new(protocol.User) 167 if err := json.Unmarshal(rawUser, user); err != nil { 168 return nil, newError(`VLESS users: invalid user`).Base(err) 169 } 170 account := new(vless.Account) 171 if err := json.Unmarshal(rawUser, account); err != nil { 172 return nil, newError(`VLESS users: invalid user`).Base(err) 173 } 174 175 u, err := uuid.ParseString(account.Id) 176 if err != nil { 177 return nil, err 178 } 179 account.Id = u.String() 180 181 switch account.Flow { 182 case "", vless.XRV, vless.XRV + "-udp443": 183 default: 184 return nil, newError(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`) 185 } 186 187 if account.Encryption != "none" { 188 return nil, newError(`VLESS users: please add/set "encryption":"none" for every user`) 189 } 190 191 user.Account = serial.ToTypedMessage(account) 192 spec.User[idx] = user 193 } 194 config.Vnext[idx] = spec 195 } 196 197 return config, nil 198 }