Add reality client fallback

This commit is contained in:
世界 2023-02-28 20:55:14 +08:00
parent d0e9443031
commit 3b4e811907
No known key found for this signature in database
GPG key ID: CD109927C34A63C4

View file

@ -4,19 +4,25 @@ package tls
import ( import (
"bytes" "bytes"
"context"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/ed25519" "crypto/ed25519"
"crypto/hmac" "crypto/hmac"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
"crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/base64" "encoding/base64"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io"
mRand "math/rand"
"net" "net"
"net/http"
"reflect" "reflect"
"strings"
"time" "time"
"unsafe" "unsafe"
@ -24,12 +30,14 @@ import (
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/debug" "github.com/sagernet/sing/common/debug"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
aTLS "github.com/sagernet/sing/common/tls"
utls "github.com/sagernet/utls" utls "github.com/sagernet/utls"
"golang.org/x/crypto/hkdf" "golang.org/x/crypto/hkdf"
"golang.org/x/net/http2"
) )
var _ Config = (*RealityClientConfig)(nil) var _ ConfigCompat = (*RealityClientConfig)(nil)
type RealityClientConfig struct { type RealityClientConfig struct {
uClient *UTLSClientConfig uClient *UTLSClientConfig
@ -85,6 +93,10 @@ func (e *RealityClientConfig) Config() (*STDConfig, error) {
} }
func (e *RealityClientConfig) Client(conn net.Conn) (Conn, error) { func (e *RealityClientConfig) Client(conn net.Conn) (Conn, error) {
return ClientHandshake(context.Background(), conn, e)
}
func (e *RealityClientConfig) ClientHandshake(ctx context.Context, conn net.Conn) (aTLS.Conn, error) {
verifier := &realityVerifier{ verifier := &realityVerifier{
serverName: e.uClient.ServerName(), serverName: e.uClient.ServerName(),
} }
@ -137,9 +149,43 @@ func (e *RealityClientConfig) Client(conn net.Conn) (Conn, error) {
fmt.Printf("REALITY uConn.AuthKey: %v\n", authKey) fmt.Printf("REALITY uConn.AuthKey: %v\n", authKey)
} }
err = uConn.HandshakeContext(ctx)
if err != nil {
return nil, err
}
if debug.Enabled {
fmt.Printf("REALITY Conn.Verified: %v\n", verifier.verified)
}
if !verifier.verified {
go realityClientFallback(uConn, e.uClient.ServerName(), e.uClient.id)
return nil, E.New("reality verification failed")
}
return &utlsConnWrapper{uConn}, nil return &utlsConnWrapper{uConn}, nil
} }
func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) {
defer uConn.Close()
client := &http.Client{
Transport: &http2.Transport{
DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) {
return uConn, nil
},
},
}
request, _ := http.NewRequest("GET", "https://"+serverName, nil)
request.Header.Set("User-Agent", fingerprint.Client)
request.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", mRand.Intn(32)+30)})
response, err := client.Do(request)
if err != nil {
return
}
_, _ = io.Copy(io.Discard, response.Body)
response.Body.Close()
}
func (e *RealityClientConfig) SetSessionIDGenerator(generator func(clientHello []byte, sessionID []byte) error) { func (e *RealityClientConfig) SetSessionIDGenerator(generator func(clientHello []byte, sessionID []byte) error) {
e.uClient.config.SessionIDGenerator = generator e.uClient.config.SessionIDGenerator = generator
} }
@ -180,8 +226,5 @@ func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChain
if _, err := certs[0].Verify(opts); err != nil { if _, err := certs[0].Verify(opts); err != nil {
return err return err
} }
if !c.verified {
return E.New("reality verification failed")
}
return nil return nil
} }