github.com/metacubex/mihomo@v1.18.5/adapter/outbound/vless.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "crypto/tls" 6 "encoding/binary" 7 "errors" 8 "fmt" 9 "io" 10 "net" 11 "net/http" 12 "strconv" 13 "sync" 14 15 "github.com/metacubex/mihomo/common/convert" 16 N "github.com/metacubex/mihomo/common/net" 17 "github.com/metacubex/mihomo/common/utils" 18 "github.com/metacubex/mihomo/component/ca" 19 "github.com/metacubex/mihomo/component/dialer" 20 "github.com/metacubex/mihomo/component/proxydialer" 21 "github.com/metacubex/mihomo/component/resolver" 22 tlsC "github.com/metacubex/mihomo/component/tls" 23 C "github.com/metacubex/mihomo/constant" 24 "github.com/metacubex/mihomo/log" 25 "github.com/metacubex/mihomo/transport/gun" 26 "github.com/metacubex/mihomo/transport/socks5" 27 "github.com/metacubex/mihomo/transport/vless" 28 "github.com/metacubex/mihomo/transport/vmess" 29 30 vmessSing "github.com/metacubex/sing-vmess" 31 "github.com/metacubex/sing-vmess/packetaddr" 32 M "github.com/sagernet/sing/common/metadata" 33 ) 34 35 const ( 36 // max packet length 37 maxLength = 1024 << 3 38 ) 39 40 type Vless struct { 41 *Base 42 client *vless.Client 43 option *VlessOption 44 45 // for gun mux 46 gunTLSConfig *tls.Config 47 gunConfig *gun.Config 48 transport *gun.TransportWrap 49 50 realityConfig *tlsC.RealityConfig 51 } 52 53 type VlessOption struct { 54 BasicOption 55 Name string `proxy:"name"` 56 Server string `proxy:"server"` 57 Port int `proxy:"port"` 58 UUID string `proxy:"uuid"` 59 Flow string `proxy:"flow,omitempty"` 60 TLS bool `proxy:"tls,omitempty"` 61 ALPN []string `proxy:"alpn,omitempty"` 62 UDP bool `proxy:"udp,omitempty"` 63 PacketAddr bool `proxy:"packet-addr,omitempty"` 64 XUDP bool `proxy:"xudp,omitempty"` 65 PacketEncoding string `proxy:"packet-encoding,omitempty"` 66 Network string `proxy:"network,omitempty"` 67 RealityOpts RealityOptions `proxy:"reality-opts,omitempty"` 68 HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"` 69 HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"` 70 GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` 71 WSOpts WSOptions `proxy:"ws-opts,omitempty"` 72 WSPath string `proxy:"ws-path,omitempty"` 73 WSHeaders map[string]string `proxy:"ws-headers,omitempty"` 74 SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` 75 Fingerprint string `proxy:"fingerprint,omitempty"` 76 ServerName string `proxy:"servername,omitempty"` 77 ClientFingerprint string `proxy:"client-fingerprint,omitempty"` 78 } 79 80 func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { 81 var err error 82 83 if tlsC.HaveGlobalFingerprint() && len(v.option.ClientFingerprint) == 0 { 84 v.option.ClientFingerprint = tlsC.GetGlobalFingerprint() 85 } 86 87 switch v.option.Network { 88 case "ws": 89 host, port, _ := net.SplitHostPort(v.addr) 90 wsOpts := &vmess.WebsocketConfig{ 91 Host: host, 92 Port: port, 93 Path: v.option.WSOpts.Path, 94 MaxEarlyData: v.option.WSOpts.MaxEarlyData, 95 EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, 96 V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade, 97 V2rayHttpUpgradeFastOpen: v.option.WSOpts.V2rayHttpUpgradeFastOpen, 98 ClientFingerprint: v.option.ClientFingerprint, 99 Headers: http.Header{}, 100 } 101 102 if len(v.option.WSOpts.Headers) != 0 { 103 for key, value := range v.option.WSOpts.Headers { 104 wsOpts.Headers.Add(key, value) 105 } 106 } 107 if v.option.TLS { 108 wsOpts.TLS = true 109 tlsConfig := &tls.Config{ 110 MinVersion: tls.VersionTLS12, 111 ServerName: host, 112 InsecureSkipVerify: v.option.SkipCertVerify, 113 NextProtos: []string{"http/1.1"}, 114 } 115 116 wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) 117 if err != nil { 118 return nil, err 119 } 120 121 if v.option.ServerName != "" { 122 wsOpts.TLSConfig.ServerName = v.option.ServerName 123 } else if host := wsOpts.Headers.Get("Host"); host != "" { 124 wsOpts.TLSConfig.ServerName = host 125 } 126 } else { 127 if host := wsOpts.Headers.Get("Host"); host == "" { 128 wsOpts.Headers.Set("Host", convert.RandHost()) 129 convert.SetUserAgent(wsOpts.Headers) 130 } 131 } 132 c, err = vmess.StreamWebsocketConn(ctx, c, wsOpts) 133 case "http": 134 // readability first, so just copy default TLS logic 135 c, err = v.streamTLSConn(ctx, c, false) 136 if err != nil { 137 return nil, err 138 } 139 140 host, _, _ := net.SplitHostPort(v.addr) 141 httpOpts := &vmess.HTTPConfig{ 142 Host: host, 143 Method: v.option.HTTPOpts.Method, 144 Path: v.option.HTTPOpts.Path, 145 Headers: v.option.HTTPOpts.Headers, 146 } 147 148 c = vmess.StreamHTTPConn(c, httpOpts) 149 case "h2": 150 c, err = v.streamTLSConn(ctx, c, true) 151 if err != nil { 152 return nil, err 153 } 154 155 h2Opts := &vmess.H2Config{ 156 Hosts: v.option.HTTP2Opts.Host, 157 Path: v.option.HTTP2Opts.Path, 158 } 159 160 c, err = vmess.StreamH2Conn(c, h2Opts) 161 case "grpc": 162 c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig) 163 default: 164 // default tcp network 165 // handle TLS 166 c, err = v.streamTLSConn(ctx, c, false) 167 } 168 169 if err != nil { 170 return nil, err 171 } 172 173 return v.streamConn(c, metadata) 174 } 175 176 func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err error) { 177 if metadata.NetWork == C.UDP { 178 if v.option.PacketAddr { 179 metadata = &C.Metadata{ 180 NetWork: C.UDP, 181 Host: packetaddr.SeqPacketMagicAddress, 182 DstPort: 443, 183 } 184 } else { 185 metadata = &C.Metadata{ // a clear metadata only contains ip 186 NetWork: C.UDP, 187 DstIP: metadata.DstIP, 188 DstPort: metadata.DstPort, 189 } 190 } 191 conn, err = v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP)) 192 if v.option.PacketAddr { 193 conn = packetaddr.NewBindConn(conn) 194 } 195 } else { 196 conn, err = v.client.StreamConn(c, parseVlessAddr(metadata, false)) 197 } 198 if err != nil { 199 conn = nil 200 } 201 return 202 } 203 204 func (v *Vless) streamTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) { 205 if v.option.TLS { 206 host, _, _ := net.SplitHostPort(v.addr) 207 208 tlsOpts := vmess.TLSConfig{ 209 Host: host, 210 SkipCertVerify: v.option.SkipCertVerify, 211 FingerPrint: v.option.Fingerprint, 212 ClientFingerprint: v.option.ClientFingerprint, 213 Reality: v.realityConfig, 214 NextProtos: v.option.ALPN, 215 } 216 217 if isH2 { 218 tlsOpts.NextProtos = []string{"h2"} 219 } 220 221 if v.option.ServerName != "" { 222 tlsOpts.Host = v.option.ServerName 223 } 224 225 return vmess.StreamTLSConn(ctx, conn, &tlsOpts) 226 } 227 228 return conn, nil 229 } 230 231 // DialContext implements C.ProxyAdapter 232 func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { 233 // gun transport 234 if v.transport != nil && len(opts) == 0 { 235 c, err := gun.StreamGunWithTransport(v.transport, v.gunConfig) 236 if err != nil { 237 return nil, err 238 } 239 defer func(c net.Conn) { 240 safeConnClose(c, err) 241 }(c) 242 243 c, err = v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP)) 244 if err != nil { 245 return nil, err 246 } 247 248 return NewConn(c, v), nil 249 } 250 return v.DialContextWithDialer(ctx, dialer.NewDialer(v.Base.DialOptions(opts...)...), metadata) 251 } 252 253 // DialContextWithDialer implements C.ProxyAdapter 254 func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { 255 if len(v.option.DialerProxy) > 0 { 256 dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) 257 if err != nil { 258 return nil, err 259 } 260 } 261 c, err := dialer.DialContext(ctx, "tcp", v.addr) 262 if err != nil { 263 return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) 264 } 265 N.TCPKeepAlive(c) 266 defer func(c net.Conn) { 267 safeConnClose(c, err) 268 }(c) 269 270 c, err = v.StreamConnContext(ctx, c, metadata) 271 if err != nil { 272 return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) 273 } 274 return NewConn(c, v), err 275 } 276 277 // ListenPacketContext implements C.ProxyAdapter 278 func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { 279 // vless use stream-oriented udp with a special address, so we need a net.UDPAddr 280 if !metadata.Resolved() { 281 ip, err := resolver.ResolveIP(ctx, metadata.Host) 282 if err != nil { 283 return nil, errors.New("can't resolve ip") 284 } 285 metadata.DstIP = ip 286 } 287 var c net.Conn 288 // gun transport 289 if v.transport != nil && len(opts) == 0 { 290 c, err = gun.StreamGunWithTransport(v.transport, v.gunConfig) 291 if err != nil { 292 return nil, err 293 } 294 defer func(c net.Conn) { 295 safeConnClose(c, err) 296 }(c) 297 298 c, err = v.streamConn(c, metadata) 299 if err != nil { 300 return nil, fmt.Errorf("new vless client error: %v", err) 301 } 302 303 return v.ListenPacketOnStreamConn(ctx, c, metadata) 304 } 305 return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.Base.DialOptions(opts...)...), metadata) 306 } 307 308 // ListenPacketWithDialer implements C.ProxyAdapter 309 func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { 310 if len(v.option.DialerProxy) > 0 { 311 dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) 312 if err != nil { 313 return nil, err 314 } 315 } 316 317 // vless use stream-oriented udp with a special address, so we need a net.UDPAddr 318 if !metadata.Resolved() { 319 ip, err := resolver.ResolveIP(ctx, metadata.Host) 320 if err != nil { 321 return nil, errors.New("can't resolve ip") 322 } 323 metadata.DstIP = ip 324 } 325 326 c, err := dialer.DialContext(ctx, "tcp", v.addr) 327 if err != nil { 328 return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) 329 } 330 N.TCPKeepAlive(c) 331 defer func(c net.Conn) { 332 safeConnClose(c, err) 333 }(c) 334 335 c, err = v.StreamConnContext(ctx, c, metadata) 336 if err != nil { 337 return nil, fmt.Errorf("new vless client error: %v", err) 338 } 339 340 return v.ListenPacketOnStreamConn(ctx, c, metadata) 341 } 342 343 // SupportWithDialer implements C.ProxyAdapter 344 func (v *Vless) SupportWithDialer() C.NetWork { 345 return C.ALLNet 346 } 347 348 // ListenPacketOnStreamConn implements C.ProxyAdapter 349 func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { 350 // vless use stream-oriented udp with a special address, so we need a net.UDPAddr 351 if !metadata.Resolved() { 352 ip, err := resolver.ResolveIP(ctx, metadata.Host) 353 if err != nil { 354 return nil, errors.New("can't resolve ip") 355 } 356 metadata.DstIP = ip 357 } 358 359 if v.option.XUDP { 360 var globalID [8]byte 361 if metadata.SourceValid() { 362 globalID = utils.GlobalID(metadata.SourceAddress()) 363 } 364 return newPacketConn(N.NewThreadSafePacketConn( 365 vmessSing.NewXUDPConn(c, 366 globalID, 367 M.SocksaddrFromNet(metadata.UDPAddr())), 368 ), v), nil 369 } else if v.option.PacketAddr { 370 return newPacketConn(N.NewThreadSafePacketConn( 371 packetaddr.NewConn(&vlessPacketConn{ 372 Conn: c, rAddr: metadata.UDPAddr(), 373 }, M.SocksaddrFromNet(metadata.UDPAddr())), 374 ), v), nil 375 } 376 return newPacketConn(N.NewThreadSafePacketConn(&vlessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}), v), nil 377 } 378 379 // SupportUOT implements C.ProxyAdapter 380 func (v *Vless) SupportUOT() bool { 381 return true 382 } 383 384 func parseVlessAddr(metadata *C.Metadata, xudp bool) *vless.DstAddr { 385 var addrType byte 386 var addr []byte 387 switch metadata.AddrType() { 388 case socks5.AtypIPv4: 389 addrType = vless.AtypIPv4 390 addr = make([]byte, net.IPv4len) 391 copy(addr[:], metadata.DstIP.AsSlice()) 392 case socks5.AtypIPv6: 393 addrType = vless.AtypIPv6 394 addr = make([]byte, net.IPv6len) 395 copy(addr[:], metadata.DstIP.AsSlice()) 396 case socks5.AtypDomainName: 397 addrType = vless.AtypDomainName 398 addr = make([]byte, len(metadata.Host)+1) 399 addr[0] = byte(len(metadata.Host)) 400 copy(addr[1:], metadata.Host) 401 } 402 403 return &vless.DstAddr{ 404 UDP: metadata.NetWork == C.UDP, 405 AddrType: addrType, 406 Addr: addr, 407 Port: metadata.DstPort, 408 Mux: metadata.NetWork == C.UDP && xudp, 409 } 410 } 411 412 type vlessPacketConn struct { 413 net.Conn 414 rAddr net.Addr 415 remain int 416 mux sync.Mutex 417 cache [2]byte 418 } 419 420 func (c *vlessPacketConn) writePacket(payload []byte) (int, error) { 421 binary.BigEndian.PutUint16(c.cache[:], uint16(len(payload))) 422 423 if _, err := c.Conn.Write(c.cache[:]); err != nil { 424 return 0, err 425 } 426 427 return c.Conn.Write(payload) 428 } 429 430 func (c *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { 431 total := len(b) 432 if total == 0 { 433 return 0, nil 434 } 435 436 if total <= maxLength { 437 return c.writePacket(b) 438 } 439 440 offset := 0 441 442 for offset < total { 443 cursor := offset + maxLength 444 if cursor > total { 445 cursor = total 446 } 447 448 n, err := c.writePacket(b[offset:cursor]) 449 if err != nil { 450 return offset + n, err 451 } 452 453 offset = cursor 454 if offset == total { 455 break 456 } 457 } 458 459 return total, nil 460 } 461 462 func (c *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { 463 c.mux.Lock() 464 defer c.mux.Unlock() 465 466 if c.remain > 0 { 467 length := len(b) 468 if c.remain < length { 469 length = c.remain 470 } 471 472 n, err := c.Conn.Read(b[:length]) 473 if err != nil { 474 return 0, c.rAddr, err 475 } 476 477 c.remain -= n 478 return n, c.rAddr, nil 479 } 480 481 if _, err := c.Conn.Read(b[:2]); err != nil { 482 return 0, c.rAddr, err 483 } 484 485 total := int(binary.BigEndian.Uint16(b[:2])) 486 if total == 0 { 487 return 0, c.rAddr, nil 488 } 489 490 length := len(b) 491 if length > total { 492 length = total 493 } 494 495 if _, err := io.ReadFull(c.Conn, b[:length]); err != nil { 496 return 0, c.rAddr, errors.New("read packet error") 497 } 498 499 c.remain = total - length 500 501 return length, c.rAddr, nil 502 } 503 504 func NewVless(option VlessOption) (*Vless, error) { 505 var addons *vless.Addons 506 if option.Network != "ws" && len(option.Flow) >= 16 { 507 option.Flow = option.Flow[:16] 508 switch option.Flow { 509 case vless.XRV: 510 log.Warnln("To use %s, ensure your server is upgrade to Xray-core v1.8.0+", vless.XRV) 511 addons = &vless.Addons{ 512 Flow: option.Flow, 513 } 514 case vless.XRO, vless.XRD, vless.XRS: 515 log.Fatalln("Legacy XTLS protocol %s is deprecated and no longer supported", option.Flow) 516 default: 517 return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow) 518 } 519 } 520 521 switch option.PacketEncoding { 522 case "packetaddr", "packet": 523 option.PacketAddr = true 524 option.XUDP = false 525 default: // https://github.com/XTLS/Xray-core/pull/1567#issuecomment-1407305458 526 if !option.PacketAddr { 527 option.XUDP = true 528 } 529 } 530 if option.XUDP { 531 option.PacketAddr = false 532 } 533 534 client, err := vless.NewClient(option.UUID, addons) 535 if err != nil { 536 return nil, err 537 } 538 539 v := &Vless{ 540 Base: &Base{ 541 name: option.Name, 542 addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), 543 tp: C.Vless, 544 udp: option.UDP, 545 xudp: option.XUDP, 546 tfo: option.TFO, 547 mpTcp: option.MPTCP, 548 iface: option.Interface, 549 rmark: option.RoutingMark, 550 prefer: C.NewDNSPrefer(option.IPVersion), 551 }, 552 client: client, 553 option: &option, 554 } 555 556 v.realityConfig, err = v.option.RealityOpts.Parse() 557 if err != nil { 558 return nil, err 559 } 560 561 switch option.Network { 562 case "h2": 563 if len(option.HTTP2Opts.Host) == 0 { 564 option.HTTP2Opts.Host = append(option.HTTP2Opts.Host, "www.example.com") 565 } 566 case "grpc": 567 dialFn := func(network, addr string) (net.Conn, error) { 568 var err error 569 var cDialer C.Dialer = dialer.NewDialer(v.Base.DialOptions()...) 570 if len(v.option.DialerProxy) > 0 { 571 cDialer, err = proxydialer.NewByName(v.option.DialerProxy, cDialer) 572 if err != nil { 573 return nil, err 574 } 575 } 576 c, err := cDialer.DialContext(context.Background(), "tcp", v.addr) 577 if err != nil { 578 return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) 579 } 580 N.TCPKeepAlive(c) 581 return c, nil 582 } 583 584 gunConfig := &gun.Config{ 585 ServiceName: v.option.GrpcOpts.GrpcServiceName, 586 Host: v.option.ServerName, 587 ClientFingerprint: v.option.ClientFingerprint, 588 } 589 if option.ServerName == "" { 590 gunConfig.Host = v.addr 591 } 592 var tlsConfig *tls.Config 593 if option.TLS { 594 tlsConfig = ca.GetGlobalTLSConfig(&tls.Config{ 595 InsecureSkipVerify: v.option.SkipCertVerify, 596 ServerName: v.option.ServerName, 597 }) 598 if option.ServerName == "" { 599 host, _, _ := net.SplitHostPort(v.addr) 600 tlsConfig.ServerName = host 601 } 602 } 603 604 v.gunTLSConfig = tlsConfig 605 v.gunConfig = gunConfig 606 607 v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint, v.realityConfig) 608 } 609 610 return v, nil 611 }