reality.go 8.7 KB

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