github.com/xraypb/Xray-core@v1.8.1/transport/internet/reality/reality.go (about)

     1  package reality
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/aes"
     7  	"crypto/cipher"
     8  	"crypto/ed25519"
     9  	"crypto/hmac"
    10  	"crypto/rand"
    11  	"crypto/sha256"
    12  	"crypto/sha512"
    13  	gotls "crypto/tls"
    14  	"crypto/x509"
    15  	"encoding/binary"
    16  	"fmt"
    17  	"io"
    18  	"math/big"
    19  	"net/http"
    20  	"reflect"
    21  	"regexp"
    22  	"strings"
    23  	"sync"
    24  	"time"
    25  	"unsafe"
    26  
    27  	utls "github.com/refraction-networking/utls"
    28  	"github.com/xraypb/Xray-core/common/errors"
    29  	"github.com/xraypb/Xray-core/common/net"
    30  	"github.com/xraypb/Xray-core/core"
    31  	"github.com/xraypb/Xray-core/transport/internet/tls"
    32  	"github.com/xtls/reality"
    33  	"golang.org/x/crypto/hkdf"
    34  	"golang.org/x/net/http2"
    35  )
    36  
    37  //go:generate go run github.com/xraypb/Xray-core/common/errors/errorgen
    38  
    39  type Conn struct {
    40  	*reality.Conn
    41  }
    42  
    43  func (c *Conn) HandshakeAddress() net.Address {
    44  	if err := c.Handshake(); err != nil {
    45  		return nil
    46  	}
    47  	state := c.ConnectionState()
    48  	if state.ServerName == "" {
    49  		return nil
    50  	}
    51  	return net.ParseAddress(state.ServerName)
    52  }
    53  
    54  func Server(c net.Conn, config *reality.Config) (net.Conn, error) {
    55  	realityConn, err := reality.Server(context.Background(), c, config)
    56  	return &Conn{Conn: realityConn}, err
    57  }
    58  
    59  type UConn struct {
    60  	*utls.UConn
    61  	ServerName string
    62  	AuthKey    []byte
    63  	Verified   bool
    64  }
    65  
    66  func (c *UConn) HandshakeAddress() net.Address {
    67  	if err := c.Handshake(); err != nil {
    68  		return nil
    69  	}
    70  	state := c.ConnectionState()
    71  	if state.ServerName == "" {
    72  		return nil
    73  	}
    74  	return net.ParseAddress(state.ServerName)
    75  }
    76  
    77  func (c *UConn) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
    78  	p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
    79  	certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset))
    80  	if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
    81  		h := hmac.New(sha512.New, c.AuthKey)
    82  		h.Write(pub)
    83  		if bytes.Equal(h.Sum(nil), certs[0].Signature) {
    84  			c.Verified = true
    85  			return nil
    86  		}
    87  	}
    88  	opts := x509.VerifyOptions{
    89  		DNSName:       c.ServerName,
    90  		Intermediates: x509.NewCertPool(),
    91  	}
    92  	for _, cert := range certs[1:] {
    93  		opts.Intermediates.AddCert(cert)
    94  	}
    95  	if _, err := certs[0].Verify(opts); err != nil {
    96  		return err
    97  	}
    98  	return nil
    99  }
   100  
   101  func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destination) (net.Conn, error) {
   102  	localAddr := c.LocalAddr().String()
   103  	uConn := &UConn{}
   104  	utlsConfig := &utls.Config{
   105  		VerifyPeerCertificate:  uConn.VerifyPeerCertificate,
   106  		ServerName:             config.ServerName,
   107  		InsecureSkipVerify:     true,
   108  		SessionTicketsDisabled: true,
   109  	}
   110  	if utlsConfig.ServerName == "" {
   111  		utlsConfig.ServerName = dest.Address.String()
   112  	}
   113  	uConn.ServerName = utlsConfig.ServerName
   114  	fingerprint := tls.GetFingerprint(config.Fingerprint)
   115  	if fingerprint == nil {
   116  		return nil, newError("REALITY: failed to get fingerprint").AtError()
   117  	}
   118  	uConn.UConn = utls.UClient(c, utlsConfig, *fingerprint)
   119  	{
   120  		uConn.BuildHandshakeState()
   121  		hello := uConn.HandshakeState.Hello
   122  		hello.SessionId = make([]byte, 32)
   123  		copy(hello.Raw[39:], hello.SessionId) // the location of session ID
   124  		hello.SessionId[0] = core.Version_x
   125  		hello.SessionId[1] = core.Version_y
   126  		hello.SessionId[2] = core.Version_z
   127  		binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
   128  		copy(hello.SessionId[8:], config.ShortId)
   129  		if config.Show {
   130  			fmt.Printf("REALITY localAddr: %v\thello.SessionId[:16]: %v\n", localAddr, hello.SessionId[:16])
   131  		}
   132  		uConn.AuthKey = uConn.HandshakeState.State13.EcdheParams.SharedKey(config.PublicKey)
   133  		if uConn.AuthKey == nil {
   134  			return nil, errors.New("REALITY: SharedKey == nil")
   135  		}
   136  		if _, err := hkdf.New(sha256.New, uConn.AuthKey, hello.Random[:20], []byte("REALITY")).Read(uConn.AuthKey); err != nil {
   137  			return nil, err
   138  		}
   139  		if config.Show {
   140  			fmt.Printf("REALITY localAddr: %v\tuConn.AuthKey[:16]: %v\n", localAddr, uConn.AuthKey[:16])
   141  		}
   142  		block, _ := aes.NewCipher(uConn.AuthKey)
   143  		aead, _ := cipher.NewGCM(block)
   144  		aead.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw)
   145  		copy(hello.Raw[39:], hello.SessionId)
   146  	}
   147  	if err := uConn.Handshake(); err != nil {
   148  		return nil, err
   149  	}
   150  	if config.Show {
   151  		fmt.Printf("REALITY localAddr: %v\tuConn.Verified: %v\n", localAddr, uConn.Verified)
   152  	}
   153  	if !uConn.Verified {
   154  		go func() {
   155  			client := &http.Client{
   156  				Transport: &http2.Transport{
   157  					DialTLSContext: func(ctx context.Context, network, addr string, cfg *gotls.Config) (net.Conn, error) {
   158  						fmt.Printf("REALITY localAddr: %v\tDialTLSContext\n", localAddr)
   159  						return uConn, nil
   160  					},
   161  				},
   162  			}
   163  			prefix := []byte("https://" + uConn.ServerName)
   164  			maps.Lock()
   165  			if maps.maps == nil {
   166  				maps.maps = make(map[string]map[string]bool)
   167  			}
   168  			paths := maps.maps[uConn.ServerName]
   169  			if paths == nil {
   170  				paths = make(map[string]bool)
   171  				paths[config.SpiderX] = true
   172  				maps.maps[uConn.ServerName] = paths
   173  			}
   174  			firstURL := string(prefix) + getPathLocked(paths)
   175  			maps.Unlock()
   176  			get := func(first bool) {
   177  				var (
   178  					req  *http.Request
   179  					resp *http.Response
   180  					err  error
   181  					body []byte
   182  				)
   183  				if first {
   184  					req, _ = http.NewRequest("GET", firstURL, nil)
   185  				} else {
   186  					maps.Lock()
   187  					req, _ = http.NewRequest("GET", string(prefix)+getPathLocked(paths), nil)
   188  					maps.Unlock()
   189  				}
   190  				req.Header.Set("User-Agent", fingerprint.Client) // TODO: User-Agent map
   191  				if first && config.Show {
   192  					fmt.Printf("REALITY localAddr: %v\treq.UserAgent(): %v\n", localAddr, req.UserAgent())
   193  				}
   194  				times := 1
   195  				if !first {
   196  					times = int(randBetween(config.SpiderY[4], config.SpiderY[5]))
   197  				}
   198  				for j := 0; j < times; j++ {
   199  					if !first && j == 0 {
   200  						req.Header.Set("Referer", firstURL)
   201  					}
   202  					req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(randBetween(config.SpiderY[0], config.SpiderY[1])))})
   203  					if resp, err = client.Do(req); err != nil {
   204  						break
   205  					}
   206  					req.Header.Set("Referer", req.URL.String())
   207  					if body, err = io.ReadAll(resp.Body); err != nil {
   208  						break
   209  					}
   210  					maps.Lock()
   211  					for _, m := range href.FindAllSubmatch(body, -1) {
   212  						m[1] = bytes.TrimPrefix(m[1], prefix)
   213  						if !bytes.Contains(m[1], dot) {
   214  							paths[string(m[1])] = true
   215  						}
   216  					}
   217  					req.URL.Path = getPathLocked(paths)
   218  					if config.Show {
   219  						fmt.Printf("REALITY localAddr: %v\treq.Referer(): %v\n", localAddr, req.Referer())
   220  						fmt.Printf("REALITY localAddr: %v\tlen(body): %v\n", localAddr, len(body))
   221  						fmt.Printf("REALITY localAddr: %v\tlen(paths): %v\n", localAddr, len(paths))
   222  					}
   223  					maps.Unlock()
   224  					if !first {
   225  						time.Sleep(time.Duration(randBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval
   226  					}
   227  				}
   228  			}
   229  			get(true)
   230  			concurrency := int(randBetween(config.SpiderY[2], config.SpiderY[3]))
   231  			for i := 0; i < concurrency; i++ {
   232  				go get(false)
   233  			}
   234  			// Do not close the connection
   235  		}()
   236  		time.Sleep(time.Duration(randBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return
   237  		return nil, errors.New("REALITY: processed invalid connection")
   238  	}
   239  	return uConn, nil
   240  }
   241  
   242  var (
   243  	href = regexp.MustCompile(`href="([/h].*?)"`)
   244  	dot  = []byte(".")
   245  )
   246  
   247  var maps struct {
   248  	sync.Mutex
   249  	maps map[string]map[string]bool
   250  }
   251  
   252  func getPathLocked(paths map[string]bool) string {
   253  	stopAt := int(randBetween(0, int64(len(paths)-1)))
   254  	i := 0
   255  	for s := range paths {
   256  		if i == stopAt {
   257  			return s
   258  		}
   259  		i++
   260  	}
   261  	return "/"
   262  }
   263  
   264  func randBetween(left int64, right int64) int64 {
   265  	if left == right {
   266  		return left
   267  	}
   268  	bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left))
   269  	return left + bigInt.Int64()
   270  }