github.com/yaling888/clash@v1.53.0/adapter/outbound/vmess.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "crypto/tls" 6 "errors" 7 "fmt" 8 "net" 9 "net/http" 10 "strconv" 11 "strings" 12 13 "golang.org/x/net/http2" 14 15 "github.com/yaling888/clash/common/convert" 16 "github.com/yaling888/clash/component/dialer" 17 "github.com/yaling888/clash/component/resolver" 18 C "github.com/yaling888/clash/constant" 19 "github.com/yaling888/clash/transport/crypto" 20 "github.com/yaling888/clash/transport/gun" 21 "github.com/yaling888/clash/transport/h1" 22 "github.com/yaling888/clash/transport/h2" 23 "github.com/yaling888/clash/transport/header" 24 "github.com/yaling888/clash/transport/quic" 25 "github.com/yaling888/clash/transport/socks5" 26 tls2 "github.com/yaling888/clash/transport/tls" 27 "github.com/yaling888/clash/transport/vmess" 28 ) 29 30 var _ C.ProxyAdapter = (*Vmess)(nil) 31 32 type Vmess struct { 33 *Base 34 client *vmess.Client 35 option *VmessOption 36 37 // for gun mux 38 gunTLSConfig *tls.Config 39 gunConfig *gun.Config 40 transport *http2.Transport 41 42 quicAEAD *crypto.AEAD 43 } 44 45 type VmessOption struct { 46 BasicOption 47 Name string `proxy:"name"` 48 Server string `proxy:"server"` 49 Port int `proxy:"port"` 50 UUID string `proxy:"uuid"` 51 AlterID int `proxy:"alterId"` 52 Cipher string `proxy:"cipher"` 53 UDP bool `proxy:"udp,omitempty"` 54 Network string `proxy:"network,omitempty"` 55 TLS bool `proxy:"tls,omitempty"` 56 SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` 57 ALPN []string `proxy:"alpn,omitempty"` 58 ServerName string `proxy:"servername,omitempty"` 59 HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"` 60 HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"` 61 GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` 62 WSOpts WSOptions `proxy:"ws-opts,omitempty"` 63 QUICOpts QUICOptions `proxy:"quic-opts,omitempty"` 64 RandomHost bool `proxy:"rand-host,omitempty"` 65 RemoteDnsResolve bool `proxy:"remote-dns-resolve,omitempty"` 66 } 67 68 type HTTPOptions struct { 69 Method string `proxy:"method,omitempty"` 70 Path []string `proxy:"path,omitempty"` 71 Headers map[string][]string `proxy:"headers,omitempty"` 72 } 73 74 type HTTP2Options struct { 75 Host []string `proxy:"host,omitempty"` 76 Path string `proxy:"path,omitempty"` 77 Headers map[string]string `proxy:"headers,omitempty"` 78 } 79 80 type GrpcOptions struct { 81 GrpcServiceName string `proxy:"grpc-service-name,omitempty"` 82 } 83 84 type WSOptions struct { 85 Path string `proxy:"path,omitempty"` 86 Headers map[string]string `proxy:"headers,omitempty"` 87 MaxEarlyData int `proxy:"max-early-data,omitempty"` 88 EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"` 89 } 90 91 type QUICOptions struct { 92 Security string `proxy:"cipher,omitempty"` 93 Key string `proxy:"key,omitempty"` 94 Header string `proxy:"obfs,omitempty"` 95 } 96 97 // StreamConn implements C.ProxyAdapter 98 func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { 99 var err error 100 switch v.option.Network { 101 case "ws": 102 host, port, _ := net.SplitHostPort(v.addr) 103 wsOpts := &vmess.WebsocketConfig{ 104 Host: host, 105 Port: port, 106 Headers: http.Header{}, 107 Path: v.option.WSOpts.Path, 108 MaxEarlyData: v.option.WSOpts.MaxEarlyData, 109 EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, 110 } 111 112 if len(v.option.WSOpts.Headers) != 0 { 113 for key, value := range v.option.WSOpts.Headers { 114 wsOpts.Headers.Add(key, value) 115 } 116 } 117 118 if v.option.TLS { 119 wsOpts.TLS = true 120 wsOpts.TLSConfig = &tls.Config{ 121 ServerName: host, 122 InsecureSkipVerify: v.option.SkipCertVerify, 123 NextProtos: []string{"http/1.1"}, 124 } 125 if v.option.ServerName != "" { 126 wsOpts.TLSConfig.ServerName = v.option.ServerName 127 wsOpts.Host = v.option.ServerName 128 } else if host1 := wsOpts.Headers.Get("Host"); host1 != "" { 129 wsOpts.TLSConfig.ServerName = host1 130 wsOpts.Host = host1 131 } 132 } else if v.option.RandomHost || wsOpts.Headers.Get("Host") == "" { 133 wsOpts.Headers.Set("Host", convert.RandHost()) 134 } 135 136 if wsOpts.Headers.Get("User-Agent") == "" { 137 wsOpts.Headers.Set("User-Agent", convert.RandUserAgent()) 138 } 139 c, err = vmess.StreamWebsocketConn(c, wsOpts) 140 case "http": 141 host := v.option.Server 142 // readability first, so just copy default TLS logic 143 if v.option.TLS { 144 tlsOpts := &tls2.Config{ 145 Host: host, 146 SkipCertVerify: v.option.SkipCertVerify, 147 } 148 149 if v.option.ServerName != "" { 150 tlsOpts.Host = v.option.ServerName 151 } 152 153 c, err = tls2.StreamTLSConn(c, tlsOpts) 154 if err != nil { 155 return nil, err 156 } 157 } 158 159 httpOpts := &h1.HTTPConfig{ 160 Host: host, 161 Method: v.option.HTTPOpts.Method, 162 Path: v.option.HTTPOpts.Path, 163 Headers: make(map[string][]string), 164 } 165 166 if len(v.option.HTTPOpts.Headers) != 0 { 167 for key, value := range v.option.HTTPOpts.Headers { 168 httpOpts.Headers[key] = value 169 } 170 } 171 172 if !v.option.TLS && (v.option.RandomHost || len(v.option.HTTPOpts.Headers["Host"]) == 0) { 173 httpOpts.Headers["Host"] = []string{convert.RandHost()} 174 } 175 176 if len(v.option.HTTPOpts.Headers["User-Agent"]) == 0 { 177 httpOpts.Headers["User-Agent"] = []string{convert.RandUserAgent()} 178 } 179 c = h1.StreamHTTPConn(c, httpOpts) 180 case "h2": 181 tlsOpts := tls2.Config{ 182 Host: v.option.Server, 183 SkipCertVerify: v.option.SkipCertVerify, 184 NextProtos: []string{"h2"}, 185 } 186 187 if v.option.ServerName != "" { 188 tlsOpts.Host = v.option.ServerName 189 } 190 191 c, err = tls2.StreamTLSConn(c, &tlsOpts) 192 if err != nil { 193 return nil, err 194 } 195 196 h2Opts := &h2.Config{ 197 Hosts: v.option.HTTP2Opts.Host, 198 Path: v.option.HTTP2Opts.Path, 199 Headers: http.Header{}, 200 } 201 202 if len(v.option.HTTP2Opts.Headers) != 0 { 203 for key, value := range v.option.HTTP2Opts.Headers { 204 h2Opts.Headers.Add(key, value) 205 } 206 } 207 208 if h2Opts.Headers.Get("User-Agent") == "" { 209 h2Opts.Headers.Set("User-Agent", convert.RandUserAgent()) 210 } 211 212 c, err = h2.StreamH2Conn(c, h2Opts) 213 case "grpc": 214 c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) 215 case "quic": 216 quicOpts := &quic.Config{ 217 Host: v.option.Server, 218 Port: v.option.Port, 219 ALPN: v.option.ALPN, 220 ServerName: v.option.Server, 221 SkipCertVerify: v.option.SkipCertVerify, 222 Header: v.option.QUICOpts.Header, 223 AEAD: v.quicAEAD, 224 } 225 226 if v.option.ServerName != "" { 227 quicOpts.ServerName = v.option.ServerName 228 } 229 230 c, err = quic.StreamQUICConn(c, quicOpts) 231 default: 232 // handle TLS 233 if v.option.TLS { 234 host, _, _ := net.SplitHostPort(v.addr) 235 tlsOpts := &tls2.Config{ 236 Host: host, 237 SkipCertVerify: v.option.SkipCertVerify, 238 } 239 240 if v.option.ServerName != "" { 241 tlsOpts.Host = v.option.ServerName 242 } 243 244 c, err = tls2.StreamTLSConn(c, tlsOpts) 245 } 246 } 247 248 if err != nil { 249 return nil, err 250 } 251 252 return v.client.StreamConn(c, parseVmessAddr(metadata)) 253 } 254 255 // StreamPacketConn implements C.ProxyAdapter 256 func (v *Vmess) StreamPacketConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { 257 // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr 258 if !metadata.Resolved() { 259 rAddrs, err := resolver.LookupIP(context.Background(), metadata.Host) 260 if err != nil { 261 return c, fmt.Errorf("can't resolve ip, %w", err) 262 } 263 metadata.DstIP = rAddrs[0] 264 } 265 266 var err error 267 c, err = v.StreamConn(c, metadata) 268 if err != nil { 269 return c, fmt.Errorf("new vmess client error: %w", err) 270 } 271 272 return WrapConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}), nil 273 } 274 275 // DialContext implements C.ProxyAdapter 276 func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { 277 // gun transport 278 if v.transport != nil && len(opts) == 0 { 279 c, err := gun.StreamGunWithTransport(v.transport, v.gunConfig) 280 if err != nil { 281 return nil, err 282 } 283 defer func(cc net.Conn, e error) { 284 safeConnClose(cc, e) 285 }(c, err) 286 287 c, err = v.client.StreamConn(c, parseVmessAddr(metadata)) 288 if err != nil { 289 return nil, err 290 } 291 292 return NewConn(c, v), nil 293 } 294 295 c, err := v.dialContext(ctx, opts...) 296 if err != nil { 297 return nil, err 298 } 299 tcpKeepAlive(c) 300 defer func(cc net.Conn, e error) { 301 safeConnClose(cc, e) 302 }(c, err) 303 304 c, err = v.StreamConn(c, metadata) 305 return NewConn(c, v), err 306 } 307 308 // ListenPacketContext implements C.ProxyAdapter 309 func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { 310 var c net.Conn 311 // gun transport 312 if v.transport != nil && len(opts) == 0 { 313 // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr 314 if !metadata.Resolved() { 315 rAddrs, err := resolver.LookupIP(context.Background(), metadata.Host) 316 if err != nil { 317 return nil, fmt.Errorf("can't resolve ip, %w", err) 318 } 319 metadata.DstIP = rAddrs[0] 320 } 321 322 c, err = gun.StreamGunWithTransport(v.transport, v.gunConfig) 323 if err != nil { 324 return nil, err 325 } 326 defer func(cc net.Conn, e error) { 327 safeConnClose(cc, e) 328 }(c, err) 329 330 c, err = v.client.StreamConn(c, parseVmessAddr(metadata)) 331 if err != nil { 332 return nil, fmt.Errorf("new vmess client error: %w", err) 333 } 334 335 return NewPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil 336 } 337 338 c, err = v.dialContext(ctx, opts...) 339 if err != nil { 340 return nil, err 341 } 342 343 tcpKeepAlive(c) 344 defer func(cc net.Conn, e error) { 345 safeConnClose(cc, e) 346 }(c, err) 347 348 c, err = v.StreamPacketConn(c, metadata) 349 if err != nil { 350 return nil, fmt.Errorf("new vmess client error: %w", err) 351 } 352 353 return NewPacketConn(c.(net.PacketConn), v), nil 354 } 355 356 func (v *Vmess) dialContext(ctx context.Context, opts ...dialer.Option) (net.Conn, error) { 357 switch v.option.Network { 358 case "quic": 359 c, err := dialer.ListenPacket(ctx, "udp", "", v.Base.DialOptions(opts...)...) 360 if err != nil { 361 return nil, fmt.Errorf("%s connect error: %w", v.addr, err) 362 } 363 return c.(*net.UDPConn), nil 364 } 365 366 c, err := dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...) 367 if err != nil { 368 return nil, fmt.Errorf("%s connect error: %w", v.addr, err) 369 } 370 return c, nil 371 } 372 373 func NewVmess(option VmessOption) (*Vmess, error) { 374 security := strings.ToLower(option.Cipher) 375 client, err := vmess.NewClient(vmess.Config{ 376 UUID: option.UUID, 377 AlterID: uint16(option.AlterID), 378 Security: security, 379 HostName: option.Server, 380 Port: strconv.Itoa(option.Port), 381 IsAead: option.AlterID == 0, 382 }) 383 if err != nil { 384 return nil, err 385 } 386 387 switch option.Network { 388 case "h2", "grpc", "quic": 389 if !option.TLS { 390 return nil, fmt.Errorf("TLS must be true with h2/grpc/quic network") 391 } 392 } 393 394 v := &Vmess{ 395 Base: &Base{ 396 name: option.Name, 397 addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), 398 tp: C.Vmess, 399 udp: option.UDP, 400 iface: option.Interface, 401 rmark: option.RoutingMark, 402 dns: option.RemoteDnsResolve, 403 }, 404 client: client, 405 option: &option, 406 } 407 408 host := option.Server 409 if option.ServerName != "" { 410 host = option.ServerName 411 } 412 413 switch option.Network { 414 case "h2": 415 if len(option.HTTP2Opts.Host) == 0 { 416 option.HTTP2Opts.Host = append(option.HTTP2Opts.Host, host) 417 } 418 case "grpc": 419 dialFn := func(network, addr string) (net.Conn, error) { 420 c, err := dialer.DialContext(context.Background(), "tcp", v.addr, v.Base.DialOptions()...) 421 if err != nil { 422 return nil, fmt.Errorf("%s connect error: %w", v.addr, err) 423 } 424 tcpKeepAlive(c) 425 return c, nil 426 } 427 428 gunConfig := &gun.Config{ 429 ServiceName: v.option.GrpcOpts.GrpcServiceName, 430 Host: v.option.ServerName, 431 } 432 tlsConfig := &tls.Config{ 433 InsecureSkipVerify: v.option.SkipCertVerify, 434 ServerName: v.option.ServerName, 435 } 436 437 if v.option.ServerName == "" { 438 host, _, _ := net.SplitHostPort(v.addr) 439 tlsConfig.ServerName = host 440 gunConfig.Host = host 441 } 442 443 v.gunTLSConfig = tlsConfig 444 v.gunConfig = gunConfig 445 v.transport = gun.NewHTTP2Client(dialFn, tlsConfig) 446 case "quic": 447 quicAEAD, err := crypto.NewAEAD(v.option.QUICOpts.Security, v.option.QUICOpts.Key, "v2ray-quic-salt") 448 if err != nil { 449 return nil, fmt.Errorf("invalid quic-opts: %w", err) 450 } 451 v.quicAEAD = quicAEAD 452 _, err = header.New(v.option.QUICOpts.Header) 453 if err != nil { 454 return nil, fmt.Errorf("invalid quic-opts: %w", err) 455 } 456 } 457 458 return v, nil 459 } 460 461 func parseVmessAddr(metadata *C.Metadata) *vmess.DstAddr { 462 var addrType byte 463 var addr []byte 464 switch metadata.AddrType() { 465 case socks5.AtypIPv4: 466 addrType = vmess.AtypIPv4 467 addr = make([]byte, net.IPv4len) 468 copy(addr[:], metadata.DstIP.AsSlice()) 469 case socks5.AtypIPv6: 470 addrType = vmess.AtypIPv6 471 addr = make([]byte, net.IPv6len) 472 copy(addr[:], metadata.DstIP.AsSlice()) 473 case socks5.AtypDomainName: 474 addrType = vmess.AtypDomainName 475 addr = make([]byte, len(metadata.Host)+1) 476 addr[0] = byte(len(metadata.Host)) 477 copy(addr[1:], metadata.Host) 478 } 479 480 return &vmess.DstAddr{ 481 UDP: metadata.NetWork == C.UDP, 482 AddrType: addrType, 483 Addr: addr, 484 Port: uint(metadata.DstPort), 485 } 486 } 487 488 type vmessPacketConn struct { 489 net.Conn 490 rAddr net.Addr 491 } 492 493 func (uc *vmessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { 494 realAddr := uc.rAddr.(*net.UDPAddr) 495 destAddr := addr.(*net.UDPAddr) 496 if !realAddr.IP.Equal(destAddr.IP) || realAddr.Port != destAddr.Port { 497 return 0, errors.New("udp packet dropped due to mismatched remote address") 498 } 499 return uc.Conn.Write(b) 500 } 501 502 func (uc *vmessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { 503 n, err := uc.Conn.Read(b) 504 return n, uc.rAddr, err 505 }