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