mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
Xray-core: Dynamic Chrome User-Agent for all HTTP requests by default (overwriteable through config) (#5658)
https://github.com/XTLS/Xray-core/issues/4996#issuecomment-3855274627 https://github.com/XTLS/Xray-core/pull/5658#issuecomment-3857332687 --------- Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com> Co-authored-by: Fangliding <63339210+Fangliding@users.noreply.github.com>
This commit is contained in:
@@ -214,6 +214,7 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
||||
|
||||
req.Header.Add("Accept", "application/dns-message")
|
||||
req.Header.Add("Content-Type", "application/dns-message")
|
||||
req.Header.Set("User-Agent", utils.ChromeUA)
|
||||
req.Header.Set("X-Padding", utils.H2Base62Pad(crypto.RandBetween(100, 1000)))
|
||||
|
||||
hc := s.httpClient
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet/tagged"
|
||||
)
|
||||
@@ -61,6 +62,7 @@ func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
req.Header.Set("User-Agent", utils.ChromeUA)
|
||||
|
||||
start := time.Now()
|
||||
resp, err := s.httpClient.Do(req)
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/done"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/extension"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
@@ -162,7 +163,9 @@ func (o *Observer) probe(outbound string) ProbeResult {
|
||||
if o.config.ProbeUrl != "" {
|
||||
probeURL = o.config.ProbeUrl
|
||||
}
|
||||
response, err := httpClient.Get(probeURL)
|
||||
req, _ := http.NewRequest(http.MethodGet, probeURL, nil)
|
||||
req.Header.Set("User-Agent", utils.ChromeUA)
|
||||
response, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return errors.New("outbound failed to relay connection").Base(err)
|
||||
}
|
||||
|
||||
28
common/utils/browser.go
Normal file
28
common/utils/browser.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
func ChromeVersion() int {
|
||||
// Use only CPU info as seed for PRNG
|
||||
seed := int64(cpuid.CPU.Family + cpuid.CPU.Model + cpuid.CPU.PhysicalCores + cpuid.CPU.LogicalCores + cpuid.CPU.CacheLine)
|
||||
rng := rand.New(rand.NewSource(seed))
|
||||
// Start from Chrome 144 released on 2026.1.13
|
||||
releaseDate := time.Date(2026, 1, 13, 0, 0, 0, 0, time.UTC)
|
||||
version := 144
|
||||
now := time.Now()
|
||||
// Each version has random 25-45 day interval
|
||||
for releaseDate.Before(now) {
|
||||
releaseDate = releaseDate.AddDate(0, 0, rng.Intn(21)+25)
|
||||
version++
|
||||
}
|
||||
return version - 1
|
||||
}
|
||||
|
||||
// ChromeUA provides default browser User-Agent based on CPU-seeded PRNG.
|
||||
var ChromeUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + strconv.Itoa(ChromeVersion()) + ".0.0.0 Safari/537.36"
|
||||
2
go.mod
2
go.mod
@@ -9,6 +9,7 @@ require (
|
||||
github.com/golang/mock v1.7.0-rc.1
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/klauspost/cpuid/v2 v2.0.12
|
||||
github.com/miekg/dns v1.1.72
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pires/go-proxyproto v0.9.2
|
||||
@@ -39,7 +40,6 @@ require (
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/http"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/noop"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -40,11 +41,8 @@ func (v *AuthenticatorRequest) Build() (*http.RequestConfig, error) {
|
||||
Value: []string{"www.baidu.com", "www.bing.com"},
|
||||
},
|
||||
{
|
||||
Name: "User-Agent",
|
||||
Value: []string{
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46",
|
||||
},
|
||||
Name: "User-Agent",
|
||||
Value: []string{utils.ChromeUA},
|
||||
},
|
||||
{
|
||||
Name: "Accept-Encoding",
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
@@ -219,6 +220,9 @@ func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, u
|
||||
for _, h := range header {
|
||||
req.Header.Set(h.Key, h.Value)
|
||||
}
|
||||
if req.Header.Get("User-Agent") == "" {
|
||||
req.Header.Set("User-Agent", utils.ChromeUA)
|
||||
}
|
||||
|
||||
connectHTTP1 := func(rawConn net.Conn) (net.Conn, error) {
|
||||
req.Header.Set("Proxy-Connection", "Keep-Alive")
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/grpc/encoding"
|
||||
"github.com/xtls/xray-core/transport/internet/reality"
|
||||
@@ -167,9 +168,11 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
|
||||
dialOptions = append(dialOptions, grpc.WithInitialWindowSize(grpcSettings.InitialWindowsSize))
|
||||
}
|
||||
|
||||
if grpcSettings.UserAgent != "" {
|
||||
dialOptions = append(dialOptions, grpc.WithUserAgent(grpcSettings.UserAgent))
|
||||
userAgent := grpcSettings.UserAgent
|
||||
if userAgent == "" {
|
||||
userAgent = utils.ChromeUA
|
||||
}
|
||||
dialOptions = append(dialOptions, grpc.WithUserAgent(userAgent))
|
||||
|
||||
var grpcDestHost string
|
||||
if dest.Address.Family().IsDomain() {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
@@ -86,6 +87,9 @@ func dialhttpUpgrade(ctx context.Context, dest net.Destination, streamSettings *
|
||||
for key, value := range transportConfiguration.Header {
|
||||
AddHeader(req.Header, key, value)
|
||||
}
|
||||
if req.Header.Get("User-Agent") == "" {
|
||||
req.Header.Set("User-Agent", utils.ChromeUA)
|
||||
}
|
||||
req.Header.Set("Connection", "Upgrade")
|
||||
req.Header.Set("Upgrade", "websocket")
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"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/common/utils"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
@@ -222,7 +223,7 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
||||
if req == nil {
|
||||
return
|
||||
}
|
||||
req.Header.Set("User-Agent", fingerprint.Client) // TODO: User-Agent map
|
||||
req.Header.Set("User-Agent", utils.ChromeUA)
|
||||
if first && config.Show {
|
||||
fmt.Printf("REALITY localAddr: %v\treq.UserAgent(): %v\n", localAddr, req.UserAgent())
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
@@ -47,6 +48,9 @@ func (c *Config) GetRequestHeader() http.Header {
|
||||
for k, v := range c.Headers {
|
||||
header.Add(k, v)
|
||||
}
|
||||
if header.Get("User-Agent") == "" {
|
||||
header.Set("User-Agent", utils.ChromeUA)
|
||||
}
|
||||
return header
|
||||
}
|
||||
|
||||
|
||||
@@ -257,6 +257,7 @@ func dnsQuery(server string, domain string, sockopt *internet.SocketConfig) ([]b
|
||||
}
|
||||
req.Header.Set("Accept", "application/dns-message")
|
||||
req.Header.Set("Content-Type", "application/dns-message")
|
||||
req.Header.Set("User-Agent", utils.ChromeUA)
|
||||
req.Header.Set("X-Padding", utils.H2Base62Pad(crypto.RandBetween(100, 1000)))
|
||||
|
||||
resp, err := client.Do(req)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
@@ -23,6 +24,9 @@ func (c *Config) GetRequestHeader() http.Header {
|
||||
for k, v := range c.Header {
|
||||
header.Add(k, v)
|
||||
}
|
||||
if header.Get("User-Agent") == "" {
|
||||
header.Set("User-Agent", utils.ChromeUA)
|
||||
}
|
||||
return header
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user