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  }