github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/infra/conf/v4/vless.go (about) 1 package v4 2 3 import ( 4 "encoding/json" 5 "path/filepath" 6 "runtime" 7 "strconv" 8 "strings" 9 "syscall" 10 11 "github.com/golang/protobuf/proto" 12 13 "github.com/v2fly/v2ray-core/v5/common/net" 14 "github.com/v2fly/v2ray-core/v5/common/protocol" 15 "github.com/v2fly/v2ray-core/v5/common/serial" 16 "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon" 17 "github.com/v2fly/v2ray-core/v5/proxy/vless" 18 "github.com/v2fly/v2ray-core/v5/proxy/vless/inbound" 19 "github.com/v2fly/v2ray-core/v5/proxy/vless/outbound" 20 ) 21 22 type VLessInboundFallback struct { 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 json.RawMessage `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 if account.Encryption != "" { 52 return nil, newError(`VLESS clients: "encryption" should not in inbound settings`) 53 } 54 55 user.Account = serial.ToTypedMessage(account) 56 config.Clients[idx] = user 57 } 58 59 if c.Decryption != "none" { 60 return nil, newError(`VLESS settings: please add/set "decryption":"none" to every settings`) 61 } 62 config.Decryption = c.Decryption 63 64 if c.Fallback != nil { 65 return nil, newError(`VLESS settings: please use "fallbacks":[{}] instead of "fallback":{}`) 66 } 67 for _, fb := range c.Fallbacks { 68 var i uint16 69 var s string 70 if err := json.Unmarshal(fb.Dest, &i); err == nil { 71 s = strconv.Itoa(int(i)) 72 } else { 73 _ = json.Unmarshal(fb.Dest, &s) 74 } 75 config.Fallbacks = append(config.Fallbacks, &inbound.Fallback{ 76 Alpn: fb.Alpn, 77 Path: fb.Path, 78 Type: fb.Type, 79 Dest: s, 80 Xver: fb.Xver, 81 }) 82 } 83 for _, fb := range config.Fallbacks { 84 /* 85 if fb.Alpn == "h2" && fb.Path != "" { 86 return nil, newError(`VLESS fallbacks: "alpn":"h2" doesn't support "path"`) 87 } 88 */ 89 if fb.Path != "" && fb.Path[0] != '/' { 90 return nil, newError(`VLESS fallbacks: "path" must be empty or start with "/"`) 91 } 92 if fb.Type == "" && fb.Dest != "" { 93 if fb.Dest == "serve-ws-none" { // nolint:gocritic 94 fb.Type = "serve" 95 } else if filepath.IsAbs(fb.Dest) || fb.Dest[0] == '@' { 96 fb.Type = "unix" 97 if strings.HasPrefix(fb.Dest, "@@") && (runtime.GOOS == "linux" || runtime.GOOS == "android") { 98 fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy 99 copy(fullAddr, fb.Dest[1:]) 100 fb.Dest = string(fullAddr) 101 } 102 } else { 103 if _, err := strconv.Atoi(fb.Dest); err == nil { 104 fb.Dest = "127.0.0.1:" + fb.Dest 105 } 106 if _, _, err := net.SplitHostPort(fb.Dest); err == nil { 107 fb.Type = "tcp" 108 } 109 } 110 } 111 if fb.Type == "" { 112 return nil, newError(`VLESS fallbacks: please fill in a valid value for every "dest"`) 113 } 114 if fb.Xver > 2 { 115 return nil, newError(`VLESS fallbacks: invalid PROXY protocol version, "xver" only accepts 0, 1, 2`) 116 } 117 } 118 119 return config, nil 120 } 121 122 type VLessOutboundVnext struct { 123 Address *cfgcommon.Address `json:"address"` 124 Port uint16 `json:"port"` 125 Users []json.RawMessage `json:"users"` 126 } 127 128 type VLessOutboundConfig struct { 129 Vnext []*VLessOutboundVnext `json:"vnext"` 130 } 131 132 // Build implements Buildable 133 func (c *VLessOutboundConfig) Build() (proto.Message, error) { 134 config := new(outbound.Config) 135 136 if len(c.Vnext) == 0 { 137 return nil, newError(`VLESS settings: "vnext" is empty`) 138 } 139 config.Vnext = make([]*protocol.ServerEndpoint, len(c.Vnext)) 140 for idx, rec := range c.Vnext { 141 if rec.Address == nil { 142 return nil, newError(`VLESS vnext: "address" is not set`) 143 } 144 if len(rec.Users) == 0 { 145 return nil, newError(`VLESS vnext: "users" is empty`) 146 } 147 spec := &protocol.ServerEndpoint{ 148 Address: rec.Address.Build(), 149 Port: uint32(rec.Port), 150 User: make([]*protocol.User, len(rec.Users)), 151 } 152 for idx, rawUser := range rec.Users { 153 user := new(protocol.User) 154 if err := json.Unmarshal(rawUser, user); err != nil { 155 return nil, newError(`VLESS users: invalid user`).Base(err) 156 } 157 account := new(vless.Account) 158 if err := json.Unmarshal(rawUser, account); err != nil { 159 return nil, newError(`VLESS users: invalid user`).Base(err) 160 } 161 162 if account.Encryption != "none" { 163 return nil, newError(`VLESS users: please add/set "encryption":"none" for every user`) 164 } 165 166 user.Account = serial.ToTypedMessage(account) 167 spec.User[idx] = user 168 } 169 config.Vnext[idx] = spec 170 } 171 172 return config, nil 173 }