mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 09:18:34 +00:00
DNS DoH: Use Chrome's fingerprint & keepAlivePeriod, Add header padding by default
https://github.com/XTLS/Xray-core/discussions/4430#discussioncomment-12374292
This commit is contained in:
parent
b9cb93d3c2
commit
e466b0497c
11 changed files with 130 additions and 162 deletions
|
@ -8,7 +8,6 @@ import (
|
|||
"crypto/ecdh"
|
||||
"crypto/ed25519"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
gotls "crypto/tls"
|
||||
|
@ -16,7 +15,6 @@ import (
|
|||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
@ -27,6 +25,7 @@ import (
|
|||
|
||||
utls "github.com/refraction-networking/utls"
|
||||
"github.com/xtls/reality"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/core"
|
||||
|
@ -213,13 +212,13 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||
}
|
||||
times := 1
|
||||
if !first {
|
||||
times = int(randBetween(config.SpiderY[4], config.SpiderY[5]))
|
||||
times = int(crypto.RandBetween(config.SpiderY[4], config.SpiderY[5]))
|
||||
}
|
||||
for j := 0; j < times; j++ {
|
||||
if !first && j == 0 {
|
||||
req.Header.Set("Referer", firstURL)
|
||||
}
|
||||
req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(randBetween(config.SpiderY[0], config.SpiderY[1])))})
|
||||
req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(crypto.RandBetween(config.SpiderY[0], config.SpiderY[1])))})
|
||||
if resp, err = client.Do(req); err != nil {
|
||||
break
|
||||
}
|
||||
|
@ -243,18 +242,18 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||
}
|
||||
maps.Unlock()
|
||||
if !first {
|
||||
time.Sleep(time.Duration(randBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval
|
||||
time.Sleep(time.Duration(crypto.RandBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval
|
||||
}
|
||||
}
|
||||
}
|
||||
get(true)
|
||||
concurrency := int(randBetween(config.SpiderY[2], config.SpiderY[3]))
|
||||
concurrency := int(crypto.RandBetween(config.SpiderY[2], config.SpiderY[3]))
|
||||
for i := 0; i < concurrency; i++ {
|
||||
go get(false)
|
||||
}
|
||||
// Do not close the connection
|
||||
}()
|
||||
time.Sleep(time.Duration(randBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return
|
||||
time.Sleep(time.Duration(crypto.RandBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return
|
||||
return nil, errors.New("REALITY: processed invalid connection").AtWarning()
|
||||
}
|
||||
return uConn, nil
|
||||
|
@ -271,7 +270,7 @@ var maps struct {
|
|||
}
|
||||
|
||||
func getPathLocked(paths map[string]struct{}) string {
|
||||
stopAt := int(randBetween(0, int64(len(paths)-1)))
|
||||
stopAt := int(crypto.RandBetween(0, int64(len(paths)-1)))
|
||||
i := 0
|
||||
for s := range paths {
|
||||
if i == stopAt {
|
||||
|
@ -281,11 +280,3 @@ func getPathLocked(paths map[string]struct{}) string {
|
|||
}
|
||||
return "/"
|
||||
}
|
||||
|
||||
func randBetween(left int64, right int64) int64 {
|
||||
if left == right {
|
||||
return left
|
||||
}
|
||||
bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left))
|
||||
return left + bigInt.Int64()
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package splithttp
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
|
@ -184,9 +183,5 @@ func init() {
|
|||
}
|
||||
|
||||
func (c RangeConfig) rand() int32 {
|
||||
if c.From == c.To {
|
||||
return c.From
|
||||
}
|
||||
bigInt, _ := rand.Int(rand.Reader, big.NewInt(int64(c.To-c.From)))
|
||||
return c.From + int32(bigInt.Int64())
|
||||
return int32(crypto.RandBetween(int64(c.From), int64(c.To)))
|
||||
}
|
||||
|
|
|
@ -30,16 +30,6 @@ import (
|
|||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
// defines the maximum time an idle TCP session can survive in the tunnel, so
|
||||
// it should be consistent across HTTP versions and with other transports.
|
||||
const connIdleTimeout = 300 * time.Second
|
||||
|
||||
// consistent with quic-go
|
||||
const quicgoH3KeepAlivePeriod = 10 * time.Second
|
||||
|
||||
// consistent with chrome
|
||||
const chromeH2KeepAlivePeriod = 45 * time.Second
|
||||
|
||||
type dialerConf struct {
|
||||
net.Destination
|
||||
*internet.MemoryStreamConfig
|
||||
|
@ -154,13 +144,13 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
|||
|
||||
if httpVersion == "3" {
|
||||
if keepAlivePeriod == 0 {
|
||||
keepAlivePeriod = quicgoH3KeepAlivePeriod
|
||||
keepAlivePeriod = net.QuicgoH3KeepAlivePeriod
|
||||
}
|
||||
if keepAlivePeriod < 0 {
|
||||
keepAlivePeriod = 0
|
||||
}
|
||||
quicConfig := &quic.Config{
|
||||
MaxIdleTimeout: connIdleTimeout,
|
||||
MaxIdleTimeout: net.ConnIdleTimeout,
|
||||
|
||||
// these two are defaults of quic-go/http3. the default of quic-go (no
|
||||
// http3) is different, so it is hardcoded here for clarity.
|
||||
|
@ -168,7 +158,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
|||
MaxIncomingStreams: -1,
|
||||
KeepAlivePeriod: keepAlivePeriod,
|
||||
}
|
||||
transport = &http3.RoundTripper{
|
||||
transport = &http3.Transport{
|
||||
QUICConfig: quicConfig,
|
||||
TLSClientConfig: gotlsConfig,
|
||||
Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
||||
|
@ -198,7 +188,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
|||
return nil, err
|
||||
}
|
||||
default:
|
||||
udpConn = &internet.FakePacketConn{c}
|
||||
udpConn = &internet.FakePacketConn{Conn: c}
|
||||
udpAddr, err = net.ResolveUDPAddr("udp", c.RemoteAddr().String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -210,7 +200,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
|||
}
|
||||
} else if httpVersion == "2" {
|
||||
if keepAlivePeriod == 0 {
|
||||
keepAlivePeriod = chromeH2KeepAlivePeriod
|
||||
keepAlivePeriod = net.ChromeH2KeepAlivePeriod
|
||||
}
|
||||
if keepAlivePeriod < 0 {
|
||||
keepAlivePeriod = 0
|
||||
|
@ -219,7 +209,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
|||
DialTLSContext: func(ctxInner context.Context, network string, addr string, cfg *gotls.Config) (net.Conn, error) {
|
||||
return dialContext(ctxInner)
|
||||
},
|
||||
IdleConnTimeout: connIdleTimeout,
|
||||
IdleConnTimeout: net.ConnIdleTimeout,
|
||||
ReadIdleTimeout: keepAlivePeriod,
|
||||
}
|
||||
} else {
|
||||
|
@ -230,7 +220,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
|||
transport = &http.Transport{
|
||||
DialTLSContext: httpDialContext,
|
||||
DialContext: httpDialContext,
|
||||
IdleConnTimeout: connIdleTimeout,
|
||||
IdleConnTimeout: net.ConnIdleTimeout,
|
||||
// chunked transfer download with KeepAlives is buggy with
|
||||
// http.Client and our custom dial context.
|
||||
DisableKeepAlives: true,
|
||||
|
|
|
@ -207,7 +207,7 @@ type Config struct {
|
|||
// @Critical
|
||||
PinnedPeerCertificateChainSha256 [][]byte `protobuf:"bytes,13,rep,name=pinned_peer_certificate_chain_sha256,json=pinnedPeerCertificateChainSha256,proto3" json:"pinned_peer_certificate_chain_sha256,omitempty"`
|
||||
// @Document Some certificate public key sha256 hashes.
|
||||
// @Document After normal validation (required), if the verified cert's public key hash does not match any of these values, the connection will be aborted.
|
||||
// @Document After normal validation (required), if one of certs in verified chain matches one of these values, the connection will be eventually accepted.
|
||||
// @Critical
|
||||
PinnedPeerCertificatePublicKeySha256 [][]byte `protobuf:"bytes,14,rep,name=pinned_peer_certificate_public_key_sha256,json=pinnedPeerCertificatePublicKeySha256,proto3" json:"pinned_peer_certificate_public_key_sha256,omitempty"`
|
||||
MasterKeyLog string `protobuf:"bytes,15,opt,name=master_key_log,json=masterKeyLog,proto3" json:"master_key_log,omitempty"`
|
||||
|
|
|
@ -76,7 +76,7 @@ message Config {
|
|||
repeated bytes pinned_peer_certificate_chain_sha256 = 13;
|
||||
|
||||
/* @Document Some certificate public key sha256 hashes.
|
||||
@Document After normal validation (required), if the verified cert's public key hash does not match any of these values, the connection will be aborted.
|
||||
@Document After normal validation (required), if one of certs in verified chain matches one of these values, the connection will be eventually accepted.
|
||||
@Critical
|
||||
*/
|
||||
repeated bytes pinned_peer_certificate_public_key_sha256 = 14;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue