github.com/yaling888/clash@v1.53.0/adapter/outbound/trojan.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "net" 8 "net/http" 9 "strconv" 10 11 "golang.org/x/net/http2" 12 13 "github.com/yaling888/clash/common/convert" 14 "github.com/yaling888/clash/component/dialer" 15 C "github.com/yaling888/clash/constant" 16 "github.com/yaling888/clash/transport/crypto" 17 "github.com/yaling888/clash/transport/gun" 18 "github.com/yaling888/clash/transport/header" 19 "github.com/yaling888/clash/transport/quic" 20 "github.com/yaling888/clash/transport/trojan" 21 ) 22 23 var _ C.ProxyAdapter = (*Trojan)(nil) 24 25 type Trojan struct { 26 *Base 27 instance *trojan.Trojan 28 option *TrojanOption 29 30 // for gun mux 31 gunTLSConfig *tls.Config 32 gunConfig *gun.Config 33 transport *http2.Transport 34 35 quicAEAD *crypto.AEAD 36 } 37 38 type TrojanOption struct { 39 BasicOption 40 Name string `proxy:"name"` 41 Server string `proxy:"server"` 42 Port int `proxy:"port"` 43 Password string `proxy:"password"` 44 ALPN []string `proxy:"alpn,omitempty"` 45 SNI string `proxy:"sni,omitempty"` 46 SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` 47 UDP bool `proxy:"udp,omitempty"` 48 Network string `proxy:"network,omitempty"` 49 GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` 50 WSOpts WSOptions `proxy:"ws-opts,omitempty"` 51 HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"` 52 QUICOpts QUICOptions `proxy:"quic-opts,omitempty"` 53 AEADOpts crypto.AEADOption `proxy:"aead-opts,omitempty"` 54 RemoteDnsResolve bool `proxy:"remote-dns-resolve,omitempty"` 55 } 56 57 func (t *Trojan) plainStream(conn net.Conn) (net.Conn, error) { 58 switch t.option.Network { 59 case "ws": 60 host, port, _ := net.SplitHostPort(t.addr) 61 wsOpts := &trojan.WebsocketOption{ 62 Host: host, 63 Port: port, 64 Path: t.option.WSOpts.Path, 65 Headers: http.Header{}, 66 } 67 68 if t.option.SNI != "" { 69 wsOpts.Host = t.option.SNI 70 } 71 72 if len(t.option.WSOpts.Headers) != 0 { 73 for key, value := range t.option.WSOpts.Headers { 74 wsOpts.Headers.Add(key, value) 75 } 76 } 77 78 if wsOpts.Headers.Get("User-Agent") == "" { 79 wsOpts.Headers.Set("User-Agent", convert.RandUserAgent()) 80 } 81 82 return t.instance.StreamWebsocketConn(conn, wsOpts) 83 case "h2": 84 h2Opts := &trojan.HTTPOptions{ 85 Hosts: t.option.HTTP2Opts.Host, 86 Path: t.option.HTTP2Opts.Path, 87 Headers: http.Header{}, 88 } 89 90 if len(t.option.HTTP2Opts.Headers) != 0 { 91 for key, value := range t.option.HTTP2Opts.Headers { 92 h2Opts.Headers.Add(key, value) 93 } 94 } 95 96 if h2Opts.Headers.Get("User-Agent") == "" { 97 h2Opts.Headers.Set("User-Agent", convert.RandUserAgent()) 98 } 99 100 return t.instance.StreamH2Conn(conn, h2Opts) 101 case "quic": 102 quicOpts := &quic.Config{ 103 Host: t.option.Server, 104 Port: t.option.Port, 105 ALPN: t.option.ALPN, 106 ServerName: t.option.Server, 107 SkipCertVerify: t.option.SkipCertVerify, 108 Header: t.option.QUICOpts.Header, 109 AEAD: t.quicAEAD, 110 } 111 112 if t.option.SNI != "" { 113 quicOpts.ServerName = t.option.SNI 114 } 115 116 return quic.StreamQUICConn(conn, quicOpts) 117 } 118 119 return t.instance.StreamConn(conn) 120 } 121 122 func (t *Trojan) trojanStream(c net.Conn, metadata *C.Metadata) (net.Conn, error) { 123 var err error 124 if t.transport != nil { 125 c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig) 126 } else { 127 c, err = t.plainStream(c) 128 if err != nil { 129 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 130 } 131 c, err = crypto.StreamAEADConnOrNot(c, t.option.AEADOpts) 132 } 133 134 if err != nil { 135 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 136 } 137 138 if metadata.NetWork == C.UDP { 139 err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)) 140 return c, err 141 } 142 143 err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)) 144 return c, err 145 } 146 147 // StreamConn implements C.ProxyAdapter 148 func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { 149 return t.trojanStream(c, metadata) 150 } 151 152 // StreamPacketConn implements C.ProxyAdapter 153 func (t *Trojan) StreamPacketConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { 154 var err error 155 c, err = t.trojanStream(c, metadata) 156 if err != nil { 157 return c, err 158 } 159 160 pc := t.instance.PacketConn(c) 161 return WrapConn(pc), nil 162 } 163 164 // DialContext implements C.ProxyAdapter 165 func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { 166 var c net.Conn 167 168 // gun transport 169 if t.transport != nil && len(opts) == 0 { 170 c, err = gun.StreamGunWithTransport(t.transport, t.gunConfig) 171 if err != nil { 172 return nil, err 173 } 174 175 defer func(cc net.Conn, e error) { 176 safeConnClose(cc, e) 177 }(c, err) 178 179 if err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)); err != nil { 180 return nil, err 181 } 182 183 return NewConn(c, t), nil 184 } 185 186 c, err = t.dialContext(ctx, opts...) 187 if err != nil { 188 return nil, err 189 } 190 tcpKeepAlive(c) 191 192 defer func(cc net.Conn, e error) { 193 safeConnClose(cc, e) 194 }(c, err) 195 196 c, err = t.StreamConn(c, metadata) 197 if err != nil { 198 return nil, err 199 } 200 201 return NewConn(c, t), err 202 } 203 204 // ListenPacketContext implements C.ProxyAdapter 205 func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { 206 var c net.Conn 207 208 // gun transport 209 if t.transport != nil && len(opts) == 0 { 210 c, err = gun.StreamGunWithTransport(t.transport, t.gunConfig) 211 if err != nil { 212 return nil, err 213 } 214 215 defer func(cc net.Conn, e error) { 216 safeConnClose(cc, e) 217 }(c, err) 218 219 if err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)); err != nil { 220 return nil, err 221 } 222 223 pc := t.instance.PacketConn(c) 224 225 return NewPacketConn(pc, t), nil 226 } 227 228 c, err = t.dialContext(ctx, opts...) 229 if err != nil { 230 return nil, err 231 } 232 233 tcpKeepAlive(c) 234 235 defer func(cc net.Conn, e error) { 236 safeConnClose(cc, e) 237 }(c, err) 238 239 c, err = t.StreamPacketConn(c, metadata) 240 if err != nil { 241 return nil, err 242 } 243 244 return NewPacketConn(c.(net.PacketConn), t), nil 245 } 246 247 func (t *Trojan) dialContext(ctx context.Context, opts ...dialer.Option) (net.Conn, error) { 248 switch t.option.Network { 249 case "quic": 250 c, err := dialer.ListenPacket(ctx, "udp", "", t.Base.DialOptions(opts...)...) 251 if err != nil { 252 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 253 } 254 return c.(*net.UDPConn), nil 255 } 256 257 c, err := dialer.DialContext(ctx, "tcp", t.addr, t.Base.DialOptions(opts...)...) 258 if err != nil { 259 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 260 } 261 return c, nil 262 } 263 264 func NewTrojan(option TrojanOption) (*Trojan, error) { 265 if _, err := crypto.VerifyAEADOption(option.AEADOpts, true); err != nil { 266 return nil, err 267 } 268 269 addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) 270 271 tOption := &trojan.Option{ 272 Password: option.Password, 273 ALPN: option.ALPN, 274 ServerName: option.Server, 275 SkipCertVerify: option.SkipCertVerify, 276 } 277 278 if option.SNI != "" { 279 tOption.ServerName = option.SNI 280 } 281 282 t := &Trojan{ 283 Base: &Base{ 284 name: option.Name, 285 addr: addr, 286 tp: C.Trojan, 287 udp: option.UDP, 288 iface: option.Interface, 289 rmark: option.RoutingMark, 290 dns: option.RemoteDnsResolve, 291 }, 292 instance: trojan.New(tOption), 293 option: &option, 294 } 295 296 switch option.Network { 297 case "h2": 298 if len(option.HTTP2Opts.Host) == 0 { 299 option.HTTP2Opts.Host = append(option.HTTP2Opts.Host, tOption.ServerName) 300 } 301 case "grpc": 302 dialFn := func(network, addr string) (net.Conn, error) { 303 c, err := dialer.DialContext(context.Background(), "tcp", t.addr, t.Base.DialOptions()...) 304 if err != nil { 305 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 306 } 307 tcpKeepAlive(c) 308 return c, nil 309 } 310 311 tlsConfig := &tls.Config{ 312 NextProtos: option.ALPN, 313 MinVersion: tls.VersionTLS12, 314 InsecureSkipVerify: tOption.SkipCertVerify, 315 ServerName: tOption.ServerName, 316 } 317 318 t.transport = gun.NewHTTP2Client(dialFn, tlsConfig) 319 320 t.gunTLSConfig = tlsConfig 321 t.gunConfig = &gun.Config{ 322 ServiceName: option.GrpcOpts.GrpcServiceName, 323 Host: tOption.ServerName, 324 } 325 case "quic": 326 quicAEAD, err := crypto.NewAEAD(t.option.QUICOpts.Security, t.option.QUICOpts.Key, "v2ray-quic-salt") 327 if err != nil { 328 return nil, fmt.Errorf("invalid quic-opts: %w", err) 329 } 330 t.quicAEAD = quicAEAD 331 _, err = header.New(t.option.QUICOpts.Header) 332 if err != nil { 333 return nil, fmt.Errorf("invalid quic-opts: %w", err) 334 } 335 } 336 337 return t, nil 338 }