github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/reality/client.go (about) 1 package reality 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/aes" 7 "crypto/cipher" 8 "crypto/ecdh" 9 "crypto/ed25519" 10 "crypto/hmac" 11 "crypto/sha256" 12 "crypto/sha512" 13 "crypto/tls" 14 "crypto/x509" 15 "encoding/base64" 16 "encoding/binary" 17 "encoding/hex" 18 "fmt" 19 "io" 20 "math/rand/v2" 21 "net" 22 "net/http" 23 "reflect" 24 "strings" 25 "time" 26 "unsafe" 27 28 "github.com/Asutorufa/yuhaiin/pkg/log" 29 "github.com/Asutorufa/yuhaiin/pkg/net/netapi" 30 "github.com/Asutorufa/yuhaiin/pkg/protos/node/point" 31 "github.com/Asutorufa/yuhaiin/pkg/protos/node/protocol" 32 "github.com/Asutorufa/yuhaiin/pkg/utils/relay" 33 utls "github.com/refraction-networking/utls" 34 "golang.org/x/crypto/chacha20poly1305" 35 "golang.org/x/crypto/hkdf" 36 "golang.org/x/net/http2" 37 ) 38 39 //go:linkname aesgcmPreferred github.com/refraction-networking/utls.aesgcmPreferred 40 func aesgcmPreferred(ciphers []uint16) bool 41 42 type RealityClient struct { 43 netapi.EmptyDispatch 44 proxy netapi.Proxy 45 utls *utls.Config 46 publicKey []byte 47 shortID [8]byte 48 49 // TODO: remove debug log 50 Deubg bool 51 } 52 53 func init() { 54 point.RegisterProtocol(NewRealityClient) 55 } 56 57 func NewRealityClient(config *protocol.Protocol_Reality) point.WrapProxy { 58 return func(p netapi.Proxy) (netapi.Proxy, error) { 59 publicKey, err := base64.RawURLEncoding.DecodeString(config.Reality.PublicKey) 60 if err != nil { 61 return nil, fmt.Errorf("decode public_key failed: %w", err) 62 } 63 if len(publicKey) != 32 { 64 return nil, fmt.Errorf("invalid public_key") 65 } 66 var shortID [8]byte 67 decodedLen, err := hex.Decode(shortID[:], []byte(config.Reality.ShortId)) 68 if err != nil { 69 return nil, fmt.Errorf("decode short_id failed: %w", err) 70 } 71 if decodedLen > 8 { 72 return nil, fmt.Errorf("invalid short_id") 73 } 74 return &RealityClient{ 75 proxy: p, 76 utls: &utls.Config{ 77 ServerName: config.Reality.ServerName, 78 }, 79 publicKey: publicKey, 80 shortID: shortID, 81 Deubg: config.Reality.Debug, 82 }, nil 83 } 84 } 85 86 func (e *RealityClient) Conn(ctx context.Context, addr netapi.Address) (net.Conn, error) { 87 con, err := e.proxy.Conn(ctx, addr) 88 if err != nil { 89 return nil, err 90 } 91 92 conn, err := e.ClientHandshake(ctx, con) 93 if err != nil { 94 con.Close() 95 return nil, fmt.Errorf("handshake failed: %w", err) 96 } 97 98 return conn, nil 99 } 100 101 func (e *RealityClient) PacketConn(ctx context.Context, addr netapi.Address) (net.PacketConn, error) { 102 return e.proxy.PacketConn(ctx, addr) 103 } 104 105 func (e *RealityClient) ClientHandshake(ctx context.Context, conn net.Conn) (net.Conn, error) { 106 verifier := &realityVerifier{ 107 serverName: e.utls.ServerName, 108 } 109 uConfig := e.utls.Clone() 110 uConfig.InsecureSkipVerify = true 111 uConfig.SessionTicketsDisabled = true 112 uConfig.VerifyPeerCertificate = verifier.VerifyPeerCertificate 113 uConn := utls.UClient(conn, uConfig, utls.HelloChrome_Auto) 114 verifier.UConn = uConn 115 err := uConn.BuildHandshakeState() 116 if err != nil { 117 return nil, err 118 } 119 120 if len(uConfig.NextProtos) > 0 { 121 for _, extension := range uConn.Extensions { 122 if alpnExtension, isALPN := extension.(*utls.ALPNExtension); isALPN { 123 alpnExtension.AlpnProtocols = uConfig.NextProtos 124 break 125 } 126 } 127 } 128 129 hello := uConn.HandshakeState.Hello 130 hello.SessionId = make([]byte, 32) 131 copy(hello.Raw[39:], hello.SessionId) 132 133 var nowTime time.Time 134 if uConfig.Time != nil { 135 nowTime = uConfig.Time() 136 } else { 137 nowTime = time.Now() 138 } 139 binary.BigEndian.PutUint64(hello.SessionId, uint64(nowTime.Unix())) 140 141 hello.SessionId[0] = 1 142 hello.SessionId[1] = 8 143 hello.SessionId[2] = 1 144 binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix())) 145 copy(hello.SessionId[8:], e.shortID[:]) 146 147 if e.Deubg { 148 log.Debug("REALITY", "hello.sessionId[:16]", hello.SessionId[:16]) 149 } 150 peerKey, err := ecdh.X25519().NewPublicKey(e.publicKey) 151 // peerKey, err := uConn.HandshakeState.State13.EcdheKey.Curve().NewPublicKey(e.publicKey) 152 if err != nil { 153 return nil, fmt.Errorf("new ecdhe public key failed: %w", err) 154 } 155 authKey, err := uConn.HandshakeState.State13.EcdheKey.ECDH(peerKey) 156 if err != nil { 157 return nil, fmt.Errorf("ecdh key failed: %w", err) 158 } 159 verifier.authKey = authKey 160 _, err = hkdf.New(sha256.New, authKey, hello.Random[:20], []byte("REALITY")).Read(authKey) 161 if err != nil { 162 return nil, err 163 } 164 165 var aead cipher.AEAD 166 if aesgcmPreferred(hello.CipherSuites) { 167 block, _ := aes.NewCipher(authKey) 168 aead, _ = cipher.NewGCM(block) 169 } else { 170 aead, _ = chacha20poly1305.New(authKey) 171 } 172 173 aead.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw) 174 copy(hello.Raw[39:], hello.SessionId) 175 176 if e.Deubg { 177 log.Debug("REALITY", "hello.sessionId", hello.SessionId) 178 log.Debug("REALITY", "uConn.AuthKey", authKey) 179 } 180 181 err = uConn.HandshakeContext(ctx) 182 if err != nil { 183 return nil, fmt.Errorf("handshake failed: %w", err) 184 } 185 186 if e.Deubg { 187 log.Debug("REALITY", "Conn.Verified", verifier.verified) 188 } 189 190 if !verifier.verified { 191 go realityClientFallback(uConn, e.utls.ServerName, utls.HelloChrome_Auto) 192 return nil, fmt.Errorf("reality verification failed") 193 } 194 195 return uConn, nil 196 } 197 198 func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) { 199 defer uConn.Close() 200 client := &http.Client{ 201 Transport: &http2.Transport{ 202 DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) { 203 return uConn, nil 204 }, 205 }, 206 } 207 request, _ := http.NewRequest("GET", "https://"+serverName, nil) 208 request.Header.Set("User-Agent", fingerprint.Client) 209 request.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", rand.IntN(32)+30)}) 210 response, err := client.Do(request) 211 if err != nil { 212 return 213 } 214 _, _ = relay.Copy(io.Discard, response.Body) 215 response.Body.Close() 216 } 217 218 type realityVerifier struct { 219 *utls.UConn 220 serverName string 221 authKey []byte 222 verified bool 223 } 224 225 func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 226 p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates") 227 certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset)) 228 if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok { 229 h := hmac.New(sha512.New, c.authKey) 230 h.Write(pub) 231 if bytes.Equal(h.Sum(nil), certs[0].Signature) { 232 c.verified = true 233 return nil 234 } 235 } 236 opts := x509.VerifyOptions{ 237 DNSName: c.serverName, 238 Intermediates: x509.NewCertPool(), 239 } 240 for _, cert := range certs[1:] { 241 opts.Intermediates.AddCert(cert) 242 } 243 if _, err := certs[0].Verify(opts); err != nil { 244 return err 245 } 246 return nil 247 }