github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/infra/conf/trojan.go (about) 1 package conf 2 3 import ( 4 "encoding/json" 5 "runtime" 6 "strconv" 7 "syscall" 8 9 "github.com/golang/protobuf/proto" // nolint: staticcheck 10 11 "v2ray.com/core/common/net" 12 "v2ray.com/core/common/protocol" 13 "v2ray.com/core/common/serial" 14 "v2ray.com/core/proxy/trojan" 15 ) 16 17 // TrojanServerTarget is configuration of a single trojan server 18 type TrojanServerTarget struct { 19 Address *Address `json:"address"` 20 Port uint16 `json:"port"` 21 Password string `json:"password"` 22 Email string `json:"email"` 23 Level byte `json:"level"` 24 } 25 26 // TrojanClientConfig is configuration of trojan servers 27 type TrojanClientConfig struct { 28 Servers []*TrojanServerTarget `json:"servers"` 29 } 30 31 // Build implements Buildable 32 func (c *TrojanClientConfig) Build() (proto.Message, error) { 33 config := new(trojan.ClientConfig) 34 35 if len(c.Servers) == 0 { 36 return nil, newError("0 Trojan server configured.") 37 } 38 39 serverSpecs := make([]*protocol.ServerEndpoint, len(c.Servers)) 40 for idx, rec := range c.Servers { 41 if rec.Address == nil { 42 return nil, newError("Trojan server address is not set.") 43 } 44 if rec.Port == 0 { 45 return nil, newError("Invalid Trojan port.") 46 } 47 if rec.Password == "" { 48 return nil, newError("Trojan password is not specified.") 49 } 50 account := &trojan.Account{ 51 Password: rec.Password, 52 } 53 trojan := &protocol.ServerEndpoint{ 54 Address: rec.Address.Build(), 55 Port: uint32(rec.Port), 56 User: []*protocol.User{ 57 { 58 Level: uint32(rec.Level), 59 Email: rec.Email, 60 Account: serial.ToTypedMessage(account), 61 }, 62 }, 63 } 64 65 serverSpecs[idx] = trojan 66 } 67 68 config.Server = serverSpecs 69 70 return config, nil 71 } 72 73 // TrojanInboundFallback is fallback configuration 74 type TrojanInboundFallback struct { 75 Alpn string `json:"alpn"` 76 Path string `json:"path"` 77 Type string `json:"type"` 78 Dest json.RawMessage `json:"dest"` 79 Xver uint64 `json:"xver"` 80 } 81 82 // TrojanUserConfig is user configuration 83 type TrojanUserConfig struct { 84 Password string `json:"password"` 85 Level byte `json:"level"` 86 Email string `json:"email"` 87 } 88 89 // TrojanServerConfig is Inbound configuration 90 type TrojanServerConfig struct { 91 Clients []*TrojanUserConfig `json:"clients"` 92 Fallback json.RawMessage `json:"fallback"` 93 Fallbacks []*TrojanInboundFallback `json:"fallbacks"` 94 } 95 96 // Build implements Buildable 97 func (c *TrojanServerConfig) Build() (proto.Message, error) { 98 config := new(trojan.ServerConfig) 99 100 if len(c.Clients) == 0 { 101 return nil, newError("No trojan user settings.") 102 } 103 104 config.Users = make([]*protocol.User, len(c.Clients)) 105 for idx, rawUser := range c.Clients { 106 user := new(protocol.User) 107 account := &trojan.Account{ 108 Password: rawUser.Password, 109 } 110 111 user.Email = rawUser.Email 112 user.Level = uint32(rawUser.Level) 113 user.Account = serial.ToTypedMessage(account) 114 config.Users[idx] = user 115 } 116 117 if c.Fallback != nil { 118 return nil, newError(`Trojan settings: please use "fallbacks":[{}] instead of "fallback":{}`) 119 } 120 for _, fb := range c.Fallbacks { 121 var i uint16 122 var s string 123 if err := json.Unmarshal(fb.Dest, &i); err == nil { 124 s = strconv.Itoa(int(i)) 125 } else { 126 _ = json.Unmarshal(fb.Dest, &s) 127 } 128 config.Fallbacks = append(config.Fallbacks, &trojan.Fallback{ 129 Alpn: fb.Alpn, 130 Path: fb.Path, 131 Type: fb.Type, 132 Dest: s, 133 Xver: fb.Xver, 134 }) 135 } 136 for _, fb := range config.Fallbacks { 137 /* 138 if fb.Alpn == "h2" && fb.Path != "" { 139 return nil, newError(`Trojan fallbacks: "alpn":"h2" doesn't support "path"`) 140 } 141 */ 142 if fb.Path != "" && fb.Path[0] != '/' { 143 return nil, newError(`Trojan fallbacks: "path" must be empty or start with "/"`) 144 } 145 if fb.Type == "" && fb.Dest != "" { 146 if fb.Dest == "serve-ws-none" { 147 fb.Type = "serve" 148 } else { 149 switch fb.Dest[0] { 150 case '@', '/': 151 fb.Type = "unix" 152 if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && runtime.GOOS == "linux" { 153 fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work in front of haproxy 154 copy(fullAddr, fb.Dest[1:]) 155 fb.Dest = string(fullAddr) 156 } 157 default: 158 if _, err := strconv.Atoi(fb.Dest); err == nil { 159 fb.Dest = "127.0.0.1:" + fb.Dest 160 } 161 if _, _, err := net.SplitHostPort(fb.Dest); err == nil { 162 fb.Type = "tcp" 163 } 164 } 165 } 166 } 167 if fb.Type == "" { 168 return nil, newError(`Trojan fallbacks: please fill in a valid value for every "dest"`) 169 } 170 if fb.Xver > 2 { 171 return nil, newError(`Trojan fallbacks: invalid PROXY protocol version, "xver" only accepts 0, 1, 2`) 172 } 173 } 174 175 return config, nil 176 }