mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-08-23 01:56:48 +08:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e15dff94b5 | ||
![]() |
e466b0497c | ||
![]() |
b9cb93d3c2 | ||
![]() |
8d46f7e14c | ||
![]() |
4b616f5cd0 | ||
![]() |
06b4a7ce4d | ||
![]() |
4c12e1686b | ||
![]() |
225d151cd3 | ||
![]() |
d451078e72 | ||
![]() |
ce2384cccc | ||
![]() |
be43f66b63 | ||
![]() |
71a6d89c23 | ||
![]() |
89792aee9d | ||
![]() |
b786a50aee | ||
![]() |
b38a53e629 |
@@ -45,11 +45,13 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
||||
case strings.EqualFold(u.String(), "localhost"):
|
||||
return NewLocalNameServer(queryStrategy), nil
|
||||
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode
|
||||
return NewDoHNameServer(u, dispatcher, queryStrategy, false)
|
||||
return NewDoHNameServer(u, queryStrategy, dispatcher, false), nil
|
||||
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode
|
||||
return NewDoHNameServer(u, dispatcher, queryStrategy, true)
|
||||
return NewDoHNameServer(u, queryStrategy, dispatcher, true), nil
|
||||
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
|
||||
return NewDoHLocalNameServer(u, queryStrategy), nil
|
||||
return NewDoHNameServer(u, queryStrategy, nil, false), nil
|
||||
case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode
|
||||
return NewDoHNameServer(u, queryStrategy, nil, true), nil
|
||||
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
|
||||
return NewQUICNameServer(u, queryStrategy)
|
||||
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
||||
|
@@ -8,10 +8,13 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
utls "github.com/refraction-networking/utls"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -31,7 +34,6 @@ import (
|
||||
// which is compatible with traditional dns over udp(RFC1035),
|
||||
// thus most of the DOH implementation is copied from udpns.go
|
||||
type DoHNameServer struct {
|
||||
dispatcher routing.Dispatcher
|
||||
sync.RWMutex
|
||||
ips map[string]*record
|
||||
pub *pubsub.Service
|
||||
@@ -42,108 +44,18 @@ type DoHNameServer struct {
|
||||
queryStrategy QueryStrategy
|
||||
}
|
||||
|
||||
// NewDoHNameServer creates DOH server object for remote resolving.
|
||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy, h2c bool) (*DoHNameServer, error) {
|
||||
// NewDoHNameServer creates DOH/DOHL client object for remote/local resolving.
|
||||
func NewDoHNameServer(url *url.URL, queryStrategy QueryStrategy, dispatcher routing.Dispatcher, h2c bool) *DoHNameServer {
|
||||
url.Scheme = "https"
|
||||
errors.LogInfo(context.Background(), "DNS: created Remote DNS-over-HTTPS client for ", url.String(), ", with h2c ", h2c)
|
||||
s := baseDOHNameServer(url, "DOH", queryStrategy)
|
||||
|
||||
s.dispatcher = dispatcher
|
||||
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
dest, err := net.ParseDestination(network + ":" + addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dnsCtx := toDnsContext(ctx, s.dohURL)
|
||||
if h2c {
|
||||
dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance
|
||||
dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname())
|
||||
}
|
||||
link, err := s.dispatcher.Dispatch(dnsCtx, dest)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cc := common.ChainedClosable{}
|
||||
if cw, ok := link.Writer.(common.Closable); ok {
|
||||
cc = append(cc, cw)
|
||||
}
|
||||
if cr, ok := link.Reader.(common.Closable); ok {
|
||||
cc = append(cc, cr)
|
||||
}
|
||||
return cnc.NewConnection(
|
||||
cnc.ConnectionInputMulti(link.Writer),
|
||||
cnc.ConnectionOutputMulti(link.Reader),
|
||||
cnc.ConnectionOnClose(cc),
|
||||
), nil
|
||||
mode := "DOH"
|
||||
if dispatcher == nil {
|
||||
mode = "DOHL"
|
||||
}
|
||||
|
||||
s.httpClient = &http.Client{
|
||||
Timeout: time.Second * 180,
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConns: 30,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 30 * time.Second,
|
||||
ForceAttemptHTTP2: true,
|
||||
DialContext: dialContext,
|
||||
},
|
||||
}
|
||||
if h2c {
|
||||
s.httpClient.Transport = &http2.Transport{
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
return dialContext(ctx, network, addr)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// NewDoHLocalNameServer creates DOH client object for local resolving
|
||||
func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameServer {
|
||||
url.Scheme = "https"
|
||||
s := baseDOHNameServer(url, "DOHL", queryStrategy)
|
||||
tr := &http.Transport{
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
ForceAttemptHTTP2: true,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
dest, err := net.ParseDestination(network + ":" + addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := internet.DialSystem(ctx, dest, nil)
|
||||
log.Record(&log.AccessMessage{
|
||||
From: "DNS",
|
||||
To: s.dohURL,
|
||||
Status: log.AccessAccepted,
|
||||
Detour: "local",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
},
|
||||
}
|
||||
s.httpClient = &http.Client{
|
||||
Timeout: time.Second * 180,
|
||||
Transport: tr,
|
||||
}
|
||||
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-HTTPS client for ", url.String())
|
||||
return s
|
||||
}
|
||||
|
||||
func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer {
|
||||
errors.LogInfo(context.Background(), "DNS: created ", mode, " client for ", url.String(), ", with h2c ", h2c)
|
||||
s := &DoHNameServer{
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: prefix + "//" + url.Host,
|
||||
name: mode + "//" + url.Host,
|
||||
dohURL: url.String(),
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
@@ -151,6 +63,65 @@ func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy)
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
}
|
||||
s.httpClient = &http.Client{
|
||||
Transport: &http2.Transport{
|
||||
IdleConnTimeout: net.ConnIdleTimeout,
|
||||
ReadIdleTimeout: net.ChromeH2KeepAlivePeriod,
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
dest, err := net.ParseDestination(network + ":" + addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var conn net.Conn
|
||||
if dispatcher != nil {
|
||||
dnsCtx := toDnsContext(ctx, s.dohURL)
|
||||
if h2c {
|
||||
dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance
|
||||
dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname())
|
||||
}
|
||||
link, err := dispatcher.Dispatch(dnsCtx, dest)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cc := common.ChainedClosable{}
|
||||
if cw, ok := link.Writer.(common.Closable); ok {
|
||||
cc = append(cc, cw)
|
||||
}
|
||||
if cr, ok := link.Reader.(common.Closable); ok {
|
||||
cc = append(cc, cr)
|
||||
}
|
||||
conn = cnc.NewConnection(
|
||||
cnc.ConnectionInputMulti(link.Writer),
|
||||
cnc.ConnectionOutputMulti(link.Reader),
|
||||
cnc.ConnectionOnClose(cc),
|
||||
)
|
||||
} else {
|
||||
log.Record(&log.AccessMessage{
|
||||
From: "DNS",
|
||||
To: s.dohURL,
|
||||
Status: log.AccessAccepted,
|
||||
Detour: "local",
|
||||
})
|
||||
conn, err = internet.DialSystem(ctx, dest, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if !h2c {
|
||||
conn = utls.UClient(conn, &utls.Config{ServerName: url.Hostname()}, utls.HelloChrome_Auto)
|
||||
if err := conn.(*utls.UConn).HandshakeContext(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return conn, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -310,6 +281,8 @@ 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("X-Padding", strings.Repeat("X", int(crypto.RandBetween(100, 1000))))
|
||||
|
||||
hc := s.httpClient
|
||||
|
||||
resp, err := hc.Do(req.WithContext(ctx))
|
||||
|
@@ -17,7 +17,7 @@ func TestDOHNameServer(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
@@ -34,7 +34,7 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
@@ -62,7 +62,7 @@ func TestDOHNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4)
|
||||
s := NewDoHNameServer(url, QueryStrategy_USE_IP4, nil, false)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
@@ -85,7 +85,7 @@ func TestDOHNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6)
|
||||
s := NewDoHNameServer(url, QueryStrategy_USE_IP6, nil, false)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
|
@@ -273,7 +273,16 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if h.senderSettings.ViaCidr == "" {
|
||||
ob.Gateway = h.senderSettings.Via.AsAddress()
|
||||
if h.senderSettings.Via.AsAddress().Family().IsDomain() && h.senderSettings.Via.AsAddress().Domain() == "origin" {
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
|
||||
if err == nil {
|
||||
ob.Gateway = net.ParseAddress(origin)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ob.Gateway = h.senderSettings.Via.AsAddress()
|
||||
}
|
||||
} else { //Get a random address.
|
||||
ob.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr)
|
||||
}
|
||||
|
@@ -1,2 +1,15 @@
|
||||
// Package crypto provides common crypto libraries for Xray.
|
||||
package crypto // import "github.com/xtls/xray-core/common/crypto"
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func RandBetween(from int64, to int64) int64 {
|
||||
if from == to {
|
||||
return from
|
||||
}
|
||||
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
|
||||
return from + bigInt.Int64()
|
||||
}
|
||||
|
@@ -1,2 +1,14 @@
|
||||
// Package net is a drop-in replacement to Golang's net package, with some more functionalities.
|
||||
package net // import "github.com/xtls/xray-core/common/net"
|
||||
|
||||
import "time"
|
||||
|
||||
// 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
|
||||
|
@@ -18,8 +18,8 @@ import (
|
||||
|
||||
var (
|
||||
Version_x byte = 25
|
||||
Version_y byte = 2
|
||||
Version_z byte = 18
|
||||
Version_y byte = 3
|
||||
Version_z byte = 3
|
||||
)
|
||||
|
||||
var (
|
||||
|
10
go.mod
10
go.mod
@@ -1,18 +1,18 @@
|
||||
module github.com/xtls/xray-core
|
||||
|
||||
go 1.23
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0
|
||||
github.com/cloudflare/circl v1.6.0
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||
github.com/golang/mock v1.7.0-rc.1
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/miekg/dns v1.1.63
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pires/go-proxyproto v0.8.0
|
||||
github.com/quic-go/quic-go v0.49.0
|
||||
github.com/quic-go/quic-go v0.50.0
|
||||
github.com/refraction-networking/utls v1.6.7
|
||||
github.com/sagernet/sing v0.5.1
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
@@ -22,7 +22,7 @@ require (
|
||||
github.com/vishvananda/netlink v1.3.0
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/crypto v0.35.0
|
||||
golang.org/x/net v0.35.0
|
||||
golang.org/x/sync v0.11.0
|
||||
golang.org/x/sys v0.30.0
|
||||
@@ -31,7 +31,7 @@ require (
|
||||
google.golang.org/protobuf v1.36.5
|
||||
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0
|
||||
h12.io/socks v1.0.3
|
||||
lukechampine.com/blake3 v1.3.0
|
||||
lukechampine.com/blake3 v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
16
go.sum
16
go.sum
@@ -24,8 +24,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
@@ -54,8 +54,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94=
|
||||
github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s=
|
||||
github.com/quic-go/quic-go v0.50.0 h1:3H/ld1pa3CYhkcc20TPIyG1bNsdhn9qZBGN3b9/UyUo=
|
||||
github.com/quic-go/quic-go v0.50.0/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
|
||||
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
|
||||
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
@@ -95,8 +95,8 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
@@ -160,5 +160,5 @@ gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0 h1:P+U/06iIKPQ3DLcg+zBfSCia
|
||||
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0/go.mod h1:NQHVAzMwvZ+Qe3ElSiHmq9RUm1MdNHpUZ52fiEqvn+0=
|
||||
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w=
|
||||
lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0=
|
||||
|
@@ -711,6 +711,7 @@ type SocketConfig struct {
|
||||
Interface string `json:"interface"`
|
||||
TcpMptcp bool `json:"tcpMptcp"`
|
||||
CustomSockopt []*CustomSockoptConfig `json:"customSockopt"`
|
||||
AddressPortStrategy string `json:"addressPortStrategy"`
|
||||
}
|
||||
|
||||
// Build implements Buildable.
|
||||
@@ -780,6 +781,26 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
customSockopts = append(customSockopts, customSockopt)
|
||||
}
|
||||
|
||||
addressPortStrategy := internet.AddressPortStrategy_None
|
||||
switch strings.ToLower(c.AddressPortStrategy) {
|
||||
case "none", "":
|
||||
addressPortStrategy = internet.AddressPortStrategy_None
|
||||
case "srvportonly":
|
||||
addressPortStrategy = internet.AddressPortStrategy_SrvPortOnly
|
||||
case "srvaddressonly":
|
||||
addressPortStrategy = internet.AddressPortStrategy_SrvAddressOnly
|
||||
case "srvportandaddress":
|
||||
addressPortStrategy = internet.AddressPortStrategy_SrvPortAndAddress
|
||||
case "txtportonly":
|
||||
addressPortStrategy = internet.AddressPortStrategy_TxtPortOnly
|
||||
case "txtaddressonly":
|
||||
addressPortStrategy = internet.AddressPortStrategy_TxtAddressOnly
|
||||
case "txtportandaddress":
|
||||
addressPortStrategy = internet.AddressPortStrategy_TxtPortAndAddress
|
||||
default:
|
||||
return nil, errors.New("unsupported address and port strategy: ", c.AddressPortStrategy)
|
||||
}
|
||||
|
||||
return &internet.SocketConfig{
|
||||
Mark: c.Mark,
|
||||
Tfo: tfo,
|
||||
@@ -798,6 +819,7 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
Interface: c.Interface,
|
||||
TcpMptcp: c.TcpMptcp,
|
||||
CustomSockopt: customSockopts,
|
||||
AddressPortStrategy: addressPortStrategy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@@ -292,7 +292,9 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||
senderSettings.ViaCidr = strings.Split(*c.SendThrough, "/")[1]
|
||||
} else {
|
||||
if address.Family().IsDomain() {
|
||||
return nil, errors.New("unable to send through: " + address.String())
|
||||
if address.Address.Domain() != "origin" {
|
||||
return nil, errors.New("unable to send through: " + address.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
senderSettings.Via = address.Build()
|
||||
|
@@ -89,12 +89,11 @@ func whichProtoc(suffix, targetedVersion string) (string, error) {
|
||||
|
||||
path, err := exec.LookPath(protoc)
|
||||
if err != nil {
|
||||
errStr := fmt.Sprintf(`
|
||||
return "", fmt.Errorf(`
|
||||
Command "%s" not found.
|
||||
Make sure that %s is in your system path or current path.
|
||||
Download %s v%s or later from https://github.com/protocolbuffers/protobuf/releases
|
||||
`, protoc, protoc, protoc, targetedVersion)
|
||||
return "", fmt.Errorf(errStr)
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
@@ -50,17 +50,17 @@ func executeTypedMessageToJson(cmd *base.Command, args []string) {
|
||||
|
||||
reader, err := confloader.LoadConfig(cmd.Flag.Arg(0))
|
||||
if err != nil {
|
||||
base.Fatalf(err.Error())
|
||||
base.Fatalf("failed to load config: %s", err)
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
base.Fatalf(err.Error())
|
||||
base.Fatalf("failed to read config: %s", err)
|
||||
}
|
||||
|
||||
tm := cserial.TypedMessage{}
|
||||
if err = json.Unmarshal(b, &tm); err != nil {
|
||||
base.Fatalf(err.Error())
|
||||
base.Fatalf("failed to unmarshal config: %s", err)
|
||||
}
|
||||
|
||||
if j, ok := creflect.MarshalToJson(&tm, injectTypeInfo); ok {
|
||||
|
@@ -53,12 +53,12 @@ func executeConvertConfigsToProtobuf(cmd *base.Command, args []string) {
|
||||
}
|
||||
|
||||
if len(unnamedArgs) < 1 {
|
||||
base.Fatalf("empty config list")
|
||||
base.Fatalf("invalid config list length: %d", len(unnamedArgs))
|
||||
}
|
||||
|
||||
pbConfig, err := core.LoadConfig("auto", unnamedArgs)
|
||||
if err != nil {
|
||||
base.Fatalf(err.Error())
|
||||
base.Fatalf("failed to load config: %s", err)
|
||||
}
|
||||
|
||||
if optDump {
|
||||
|
@@ -4,12 +4,12 @@ import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/pires/go-proxyproto"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -414,7 +414,7 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
noise = n.Packet
|
||||
} else {
|
||||
//Random noise
|
||||
noise, err = GenerateRandomBytes(randBetween(int64(n.LengthMin),
|
||||
noise, err = GenerateRandomBytes(crypto.RandBetween(int64(n.LengthMin),
|
||||
int64(n.LengthMax)))
|
||||
}
|
||||
if err != nil {
|
||||
@@ -423,7 +423,7 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
|
||||
|
||||
if n.DelayMin != 0 || n.DelayMax != 0 {
|
||||
time.Sleep(time.Duration(randBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond)
|
||||
time.Sleep(time.Duration(crypto.RandBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
|
||||
buf := make([]byte, 1024)
|
||||
var hello []byte
|
||||
for from := 0; ; {
|
||||
to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
|
||||
to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
|
||||
if to > len(data) {
|
||||
to = len(data)
|
||||
}
|
||||
@@ -466,7 +466,7 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
|
||||
hello = append(hello, buf[:5+l]...)
|
||||
} else {
|
||||
_, err := f.writer.Write(buf[:5+l])
|
||||
time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
|
||||
time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -493,13 +493,13 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
|
||||
return f.writer.Write(b)
|
||||
}
|
||||
for from := 0; ; {
|
||||
to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
|
||||
to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
|
||||
if to > len(b) {
|
||||
to = len(b)
|
||||
}
|
||||
n, err := f.writer.Write(b[from:to])
|
||||
from += n
|
||||
time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
|
||||
time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
|
||||
if err != nil {
|
||||
return from, err
|
||||
}
|
||||
@@ -509,14 +509,6 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// stolen from github.com/xtls/xray-core/transport/internet/reality
|
||||
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()
|
||||
}
|
||||
func GenerateRandomBytes(n int64) ([]byte, error) {
|
||||
b := make([]byte, n)
|
||||
_, err := rand.Read(b)
|
||||
|
@@ -547,8 +547,8 @@ func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
|
||||
conn = pc.Raw()
|
||||
// 8192 > 4096, there is no need to process pc's bufReader
|
||||
}
|
||||
if uc, ok := conn.(*internet.UDSWrapperConn); ok {
|
||||
conn = uc.Conn
|
||||
if uc, ok := conn.(*internet.UnixConnWrapper); ok {
|
||||
conn = uc.UnixConn
|
||||
}
|
||||
}
|
||||
return conn, readCounter, writerCounter
|
||||
|
@@ -95,6 +95,67 @@ func (DomainStrategy) EnumDescriptor() ([]byte, []int) {
|
||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type AddressPortStrategy int32
|
||||
|
||||
const (
|
||||
AddressPortStrategy_None AddressPortStrategy = 0
|
||||
AddressPortStrategy_SrvPortOnly AddressPortStrategy = 1
|
||||
AddressPortStrategy_SrvAddressOnly AddressPortStrategy = 2
|
||||
AddressPortStrategy_SrvPortAndAddress AddressPortStrategy = 3
|
||||
AddressPortStrategy_TxtPortOnly AddressPortStrategy = 4
|
||||
AddressPortStrategy_TxtAddressOnly AddressPortStrategy = 5
|
||||
AddressPortStrategy_TxtPortAndAddress AddressPortStrategy = 6
|
||||
)
|
||||
|
||||
// Enum value maps for AddressPortStrategy.
|
||||
var (
|
||||
AddressPortStrategy_name = map[int32]string{
|
||||
0: "None",
|
||||
1: "SrvPortOnly",
|
||||
2: "SrvAddressOnly",
|
||||
3: "SrvPortAndAddress",
|
||||
4: "TxtPortOnly",
|
||||
5: "TxtAddressOnly",
|
||||
6: "TxtPortAndAddress",
|
||||
}
|
||||
AddressPortStrategy_value = map[string]int32{
|
||||
"None": 0,
|
||||
"SrvPortOnly": 1,
|
||||
"SrvAddressOnly": 2,
|
||||
"SrvPortAndAddress": 3,
|
||||
"TxtPortOnly": 4,
|
||||
"TxtAddressOnly": 5,
|
||||
"TxtPortAndAddress": 6,
|
||||
}
|
||||
)
|
||||
|
||||
func (x AddressPortStrategy) Enum() *AddressPortStrategy {
|
||||
p := new(AddressPortStrategy)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x AddressPortStrategy) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (AddressPortStrategy) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_transport_internet_config_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (AddressPortStrategy) Type() protoreflect.EnumType {
|
||||
return &file_transport_internet_config_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x AddressPortStrategy) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AddressPortStrategy.Descriptor instead.
|
||||
func (AddressPortStrategy) EnumDescriptor() ([]byte, []int) {
|
||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type SocketConfig_TProxyMode int32
|
||||
|
||||
const (
|
||||
@@ -131,11 +192,11 @@ func (x SocketConfig_TProxyMode) String() string {
|
||||
}
|
||||
|
||||
func (SocketConfig_TProxyMode) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_transport_internet_config_proto_enumTypes[1].Descriptor()
|
||||
return file_transport_internet_config_proto_enumTypes[2].Descriptor()
|
||||
}
|
||||
|
||||
func (SocketConfig_TProxyMode) Type() protoreflect.EnumType {
|
||||
return &file_transport_internet_config_proto_enumTypes[1]
|
||||
return &file_transport_internet_config_proto_enumTypes[2]
|
||||
}
|
||||
|
||||
func (x SocketConfig_TProxyMode) Number() protoreflect.EnumNumber {
|
||||
@@ -434,23 +495,24 @@ type SocketConfig struct {
|
||||
Tproxy SocketConfig_TProxyMode `protobuf:"varint,3,opt,name=tproxy,proto3,enum=xray.transport.internet.SocketConfig_TProxyMode" json:"tproxy,omitempty"`
|
||||
// ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket
|
||||
// option. This option is for UDP only.
|
||||
ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"`
|
||||
BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"`
|
||||
BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"`
|
||||
AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"`
|
||||
DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
||||
DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"`
|
||||
TcpKeepAliveInterval int32 `protobuf:"varint,10,opt,name=tcp_keep_alive_interval,json=tcpKeepAliveInterval,proto3" json:"tcp_keep_alive_interval,omitempty"`
|
||||
TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"`
|
||||
TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"`
|
||||
Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"`
|
||||
V6Only bool `protobuf:"varint,14,opt,name=v6only,proto3" json:"v6only,omitempty"`
|
||||
TcpWindowClamp int32 `protobuf:"varint,15,opt,name=tcp_window_clamp,json=tcpWindowClamp,proto3" json:"tcp_window_clamp,omitempty"`
|
||||
TcpUserTimeout int32 `protobuf:"varint,16,opt,name=tcp_user_timeout,json=tcpUserTimeout,proto3" json:"tcp_user_timeout,omitempty"`
|
||||
TcpMaxSeg int32 `protobuf:"varint,17,opt,name=tcp_max_seg,json=tcpMaxSeg,proto3" json:"tcp_max_seg,omitempty"`
|
||||
Penetrate bool `protobuf:"varint,18,opt,name=penetrate,proto3" json:"penetrate,omitempty"`
|
||||
TcpMptcp bool `protobuf:"varint,19,opt,name=tcp_mptcp,json=tcpMptcp,proto3" json:"tcp_mptcp,omitempty"`
|
||||
CustomSockopt []*CustomSockopt `protobuf:"bytes,20,rep,name=customSockopt,proto3" json:"customSockopt,omitempty"`
|
||||
ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"`
|
||||
BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"`
|
||||
BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"`
|
||||
AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"`
|
||||
DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
||||
DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"`
|
||||
TcpKeepAliveInterval int32 `protobuf:"varint,10,opt,name=tcp_keep_alive_interval,json=tcpKeepAliveInterval,proto3" json:"tcp_keep_alive_interval,omitempty"`
|
||||
TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"`
|
||||
TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"`
|
||||
Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"`
|
||||
V6Only bool `protobuf:"varint,14,opt,name=v6only,proto3" json:"v6only,omitempty"`
|
||||
TcpWindowClamp int32 `protobuf:"varint,15,opt,name=tcp_window_clamp,json=tcpWindowClamp,proto3" json:"tcp_window_clamp,omitempty"`
|
||||
TcpUserTimeout int32 `protobuf:"varint,16,opt,name=tcp_user_timeout,json=tcpUserTimeout,proto3" json:"tcp_user_timeout,omitempty"`
|
||||
TcpMaxSeg int32 `protobuf:"varint,17,opt,name=tcp_max_seg,json=tcpMaxSeg,proto3" json:"tcp_max_seg,omitempty"`
|
||||
Penetrate bool `protobuf:"varint,18,opt,name=penetrate,proto3" json:"penetrate,omitempty"`
|
||||
TcpMptcp bool `protobuf:"varint,19,opt,name=tcp_mptcp,json=tcpMptcp,proto3" json:"tcp_mptcp,omitempty"`
|
||||
CustomSockopt []*CustomSockopt `protobuf:"bytes,20,rep,name=customSockopt,proto3" json:"customSockopt,omitempty"`
|
||||
AddressPortStrategy AddressPortStrategy `protobuf:"varint,21,opt,name=address_port_strategy,json=addressPortStrategy,proto3,enum=xray.transport.internet.AddressPortStrategy" json:"address_port_strategy,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SocketConfig) Reset() {
|
||||
@@ -623,6 +685,13 @@ func (x *SocketConfig) GetCustomSockopt() []*CustomSockopt {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SocketConfig) GetAddressPortStrategy() AddressPortStrategy {
|
||||
if x != nil {
|
||||
return x.AddressPortStrategy
|
||||
}
|
||||
return AddressPortStrategy_None
|
||||
}
|
||||
|
||||
var File_transport_internet_config_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_transport_internet_config_proto_rawDesc = []byte{
|
||||
@@ -678,7 +747,7 @@ var file_transport_internet_config_proto_rawDesc = []byte{
|
||||
0x28, 0x09, 0x52, 0x03, 0x6f, 0x70, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x22, 0x9b, 0x07, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x65, 0x22, 0xfd, 0x07, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
|
||||
0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x66, 0x6f, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x03, 0x74, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x06, 0x74, 0x70, 0x72, 0x6f,
|
||||
@@ -732,28 +801,44 @@ var file_transport_internet_config_proto_rawDesc = []byte{
|
||||
0x74, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74,
|
||||
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
|
||||
0x74, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x52,
|
||||
0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x22, 0x2f,
|
||||
0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03,
|
||||
0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10,
|
||||
0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a,
|
||||
0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||
0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a,
|
||||
0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45,
|
||||
0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50,
|
||||
0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10,
|
||||
0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x05, 0x12,
|
||||
0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x06, 0x12, 0x0d, 0x0a,
|
||||
0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09,
|
||||
0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x46,
|
||||
0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x46,
|
||||
0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x0a, 0x42, 0x67, 0x0a, 0x1b, 0x63,
|
||||
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65,
|
||||
0x72, 0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x12, 0x60,
|
||||
0x0a, 0x15, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50,
|
||||
0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x13, 0x61, 0x64, 0x64,
|
||||
0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07,
|
||||
0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10,
|
||||
0x02, 0x2a, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61,
|
||||
0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12,
|
||||
0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55,
|
||||
0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f,
|
||||
0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34,
|
||||
0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10,
|
||||
0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x06, 0x12,
|
||||
0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x07, 0x12, 0x0d,
|
||||
0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x08, 0x12, 0x0e, 0x0a,
|
||||
0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x09, 0x12, 0x0e, 0x0a,
|
||||
0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x0a, 0x2a, 0x97, 0x01,
|
||||
0x0a, 0x13, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12,
|
||||
0x0f, 0x0a, 0x0b, 0x53, 0x72, 0x76, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x01,
|
||||
0x12, 0x12, 0x0a, 0x0e, 0x53, 0x72, 0x76, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e,
|
||||
0x6c, 0x79, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x72, 0x76, 0x50, 0x6f, 0x72, 0x74, 0x41,
|
||||
0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x54,
|
||||
0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e,
|
||||
0x54, 0x78, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x05,
|
||||
0x12, 0x15, 0x0a, 0x11, 0x54, 0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x41, 0x6e, 0x64, 0x41, 0x64,
|
||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x06, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63,
|
||||
0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72,
|
||||
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -768,33 +853,35 @@ func file_transport_internet_config_proto_rawDescGZIP() []byte {
|
||||
return file_transport_internet_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
||||
var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_transport_internet_config_proto_goTypes = []any{
|
||||
(DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy
|
||||
(SocketConfig_TProxyMode)(0), // 1: xray.transport.internet.SocketConfig.TProxyMode
|
||||
(*TransportConfig)(nil), // 2: xray.transport.internet.TransportConfig
|
||||
(*StreamConfig)(nil), // 3: xray.transport.internet.StreamConfig
|
||||
(*ProxyConfig)(nil), // 4: xray.transport.internet.ProxyConfig
|
||||
(*CustomSockopt)(nil), // 5: xray.transport.internet.CustomSockopt
|
||||
(*SocketConfig)(nil), // 6: xray.transport.internet.SocketConfig
|
||||
(*serial.TypedMessage)(nil), // 7: xray.common.serial.TypedMessage
|
||||
(*net.IPOrDomain)(nil), // 8: xray.common.net.IPOrDomain
|
||||
(AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy
|
||||
(SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode
|
||||
(*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig
|
||||
(*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig
|
||||
(*ProxyConfig)(nil), // 5: xray.transport.internet.ProxyConfig
|
||||
(*CustomSockopt)(nil), // 6: xray.transport.internet.CustomSockopt
|
||||
(*SocketConfig)(nil), // 7: xray.transport.internet.SocketConfig
|
||||
(*serial.TypedMessage)(nil), // 8: xray.common.serial.TypedMessage
|
||||
(*net.IPOrDomain)(nil), // 9: xray.common.net.IPOrDomain
|
||||
}
|
||||
var file_transport_internet_config_proto_depIdxs = []int32{
|
||||
7, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage
|
||||
8, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain
|
||||
2, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig
|
||||
7, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage
|
||||
6, // 4: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig
|
||||
1, // 5: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode
|
||||
8, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage
|
||||
9, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain
|
||||
3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig
|
||||
8, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage
|
||||
7, // 4: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig
|
||||
2, // 5: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode
|
||||
0, // 6: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||
5, // 7: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt
|
||||
8, // [8:8] is the sub-list for method output_type
|
||||
8, // [8:8] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
6, // 7: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt
|
||||
1, // 8: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy
|
||||
9, // [9:9] is the sub-list for method output_type
|
||||
9, // [9:9] is the sub-list for method input_type
|
||||
9, // [9:9] is the sub-list for extension type_name
|
||||
9, // [9:9] is the sub-list for extension extendee
|
||||
0, // [0:9] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_config_proto_init() }
|
||||
@@ -807,7 +894,7 @@ func file_transport_internet_config_proto_init() {
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_transport_internet_config_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumEnums: 3,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
|
@@ -23,6 +23,16 @@ enum DomainStrategy {
|
||||
FORCE_IP64 = 10;
|
||||
}
|
||||
|
||||
enum AddressPortStrategy {
|
||||
None = 0;
|
||||
SrvPortOnly = 1;
|
||||
SrvAddressOnly = 2;
|
||||
SrvPortAndAddress = 3;
|
||||
TxtPortOnly = 4;
|
||||
TxtAddressOnly = 5;
|
||||
TxtPortAndAddress = 6;
|
||||
}
|
||||
|
||||
message TransportConfig {
|
||||
// Transport protocol name.
|
||||
string protocol_name = 3;
|
||||
@@ -116,4 +126,6 @@ message SocketConfig {
|
||||
bool tcp_mptcp = 19;
|
||||
|
||||
repeated CustomSockopt customSockopt = 20;
|
||||
|
||||
AddressPortStrategy address_port_strategy = 21;
|
||||
}
|
||||
|
@@ -2,6 +2,9 @@ package internet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
gonet "net"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
@@ -140,6 +143,93 @@ func redirect(ctx context.Context, dst net.Destination, obt string) net.Conn {
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (*net.Destination, error) {
|
||||
if sockopt.AddressPortStrategy == AddressPortStrategy_None {
|
||||
return nil, nil
|
||||
}
|
||||
newDest := dest
|
||||
var OverridePort, OverrideAddress bool
|
||||
var OverrideBy string
|
||||
switch sockopt.AddressPortStrategy {
|
||||
case AddressPortStrategy_SrvPortOnly:
|
||||
OverridePort = true
|
||||
OverrideAddress = false
|
||||
OverrideBy = "srv"
|
||||
case AddressPortStrategy_SrvAddressOnly:
|
||||
OverridePort = false
|
||||
OverrideAddress = true
|
||||
OverrideBy = "srv"
|
||||
case AddressPortStrategy_SrvPortAndAddress:
|
||||
OverridePort = true
|
||||
OverrideAddress = true
|
||||
OverrideBy = "srv"
|
||||
case AddressPortStrategy_TxtPortOnly:
|
||||
OverridePort = true
|
||||
OverrideAddress = false
|
||||
OverrideBy = "txt"
|
||||
case AddressPortStrategy_TxtAddressOnly:
|
||||
OverridePort = false
|
||||
OverrideAddress = true
|
||||
OverrideBy = "txt"
|
||||
case AddressPortStrategy_TxtPortAndAddress:
|
||||
OverridePort = true
|
||||
OverrideAddress = true
|
||||
OverrideBy = "txt"
|
||||
default:
|
||||
return nil, errors.New("unknown AddressPortStrategy")
|
||||
}
|
||||
|
||||
if !dest.Address.Family().IsDomain() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if OverrideBy == "srv" {
|
||||
errors.LogDebug(ctx, "query SRV record for "+dest.Address.String())
|
||||
parts := strings.SplitN(dest.Address.String(), ".", 3)
|
||||
if len(parts) != 3 {
|
||||
return nil, errors.New("invalid address format", dest.Address.String())
|
||||
}
|
||||
_, srvRecords, err := gonet.DefaultResolver.LookupSRV(context.Background(), parts[0][1:], parts[1][1:], parts[2])
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to lookup SRV record").Base(err)
|
||||
}
|
||||
errors.LogDebug(ctx, "SRV record: "+fmt.Sprintf("addr=%s, port=%d, priority=%d, weight=%d", srvRecords[0].Target, srvRecords[0].Port, srvRecords[0].Priority, srvRecords[0].Weight))
|
||||
if OverridePort {
|
||||
newDest.Port = net.Port(srvRecords[0].Port)
|
||||
}
|
||||
if OverrideAddress {
|
||||
newDest.Address = net.ParseAddress(srvRecords[0].Target)
|
||||
}
|
||||
return &newDest, nil
|
||||
}
|
||||
if OverrideBy == "txt" {
|
||||
errors.LogDebug(ctx, "query TXT record for "+dest.Address.String())
|
||||
txtRecords, err := gonet.DefaultResolver.LookupTXT(ctx, dest.Address.String())
|
||||
if err != nil {
|
||||
errors.LogError(ctx, "failed to lookup SRV record: "+err.Error())
|
||||
return nil, errors.New("failed to lookup SRV record").Base(err)
|
||||
}
|
||||
for _, txtRecord := range txtRecords {
|
||||
errors.LogDebug(ctx, "TXT record: "+txtRecord)
|
||||
addr_s, port_s, _ := net.SplitHostPort(string(txtRecord))
|
||||
addr := net.ParseAddress(addr_s)
|
||||
port, err := net.PortFromString(port_s)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if OverridePort {
|
||||
newDest.Port = port
|
||||
}
|
||||
if OverrideAddress {
|
||||
newDest.Address = addr
|
||||
}
|
||||
return &newDest, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// DialSystem calls system dialer to create a network connection.
|
||||
func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
|
||||
var src net.Address
|
||||
@@ -152,6 +242,11 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
|
||||
return effectiveSystemDialer.Dial(ctx, src, dest, sockopt)
|
||||
}
|
||||
|
||||
if newDest, err := checkAddressPortStrategy(ctx, dest, sockopt); err == nil && newDest != nil {
|
||||
errors.LogInfo(ctx, "replace destination with "+newDest.String())
|
||||
dest = *newDest
|
||||
}
|
||||
|
||||
if canLookupIP(ctx, dest, sockopt) {
|
||||
ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src)
|
||||
if err == nil && len(ips) > 0 {
|
||||
|
@@ -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,
|
||||
|
@@ -24,8 +24,6 @@ import (
|
||||
"github.com/xtls/xray-core/transport/internet/reality"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
)
|
||||
|
||||
type requestHandler struct {
|
||||
@@ -47,21 +45,6 @@ type httpSession struct {
|
||||
isFullyConnected *done.Instance
|
||||
}
|
||||
|
||||
func (h *requestHandler) maybeReapSession(isFullyConnected *done.Instance, sessionId string) {
|
||||
shouldReap := done.New()
|
||||
go func() {
|
||||
time.Sleep(30 * time.Second)
|
||||
shouldReap.Close()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-isFullyConnected.Wait():
|
||||
return
|
||||
case <-shouldReap.Wait():
|
||||
h.sessions.Delete(sessionId)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *requestHandler) upsertSession(sessionId string) *httpSession {
|
||||
// fast path
|
||||
currentSessionAny, ok := h.sessions.Load(sessionId)
|
||||
@@ -84,7 +67,21 @@ func (h *requestHandler) upsertSession(sessionId string) *httpSession {
|
||||
}
|
||||
|
||||
h.sessions.Store(sessionId, s)
|
||||
go h.maybeReapSession(s.isFullyConnected, sessionId)
|
||||
|
||||
shouldReap := done.New()
|
||||
go func() {
|
||||
time.Sleep(30 * time.Second)
|
||||
shouldReap.Close()
|
||||
}()
|
||||
go func() {
|
||||
select {
|
||||
case <-shouldReap.Wait():
|
||||
h.sessions.Delete(sessionId)
|
||||
s.uploadQueue.Close()
|
||||
case <-s.isFullyConnected.Wait():
|
||||
}
|
||||
}()
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -183,12 +180,13 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||
writer.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
uploadDone := done.New()
|
||||
httpSC := &httpServerConn{
|
||||
Instance: done.New(),
|
||||
Reader: request.Body,
|
||||
ResponseWriter: writer,
|
||||
}
|
||||
err = currentSession.uploadQueue.Push(Packet{
|
||||
Reader: &httpRequestBodyReader{
|
||||
requestReader: request.Body,
|
||||
uploadDone: uploadDone,
|
||||
},
|
||||
Reader: httpSC,
|
||||
})
|
||||
if err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "failed to upload (PushReader)")
|
||||
@@ -200,25 +198,21 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||
scStreamUpServerSecs := h.config.GetNormalizedScStreamUpServerSecs()
|
||||
if referrer != "" && scStreamUpServerSecs.To > 0 {
|
||||
go func() {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
for {
|
||||
_, err := writer.Write(bytes.Repeat([]byte{'X'}, int(h.config.GetNormalizedXPaddingBytes().rand())))
|
||||
_, err := httpSC.Write(bytes.Repeat([]byte{'X'}, int(h.config.GetNormalizedXPaddingBytes().rand())))
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
writer.(http.Flusher).Flush()
|
||||
time.Sleep(time.Duration(scStreamUpServerSecs.rand()) * time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
select {
|
||||
case <-request.Context().Done():
|
||||
case <-uploadDone.Wait():
|
||||
case <-httpSC.Wait():
|
||||
}
|
||||
}
|
||||
uploadDone.Close()
|
||||
httpSC.Close()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -262,11 +256,6 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
} else if request.Method == "GET" || sessionId == "" { // stream-down, stream-one
|
||||
responseFlusher, ok := writer.(http.Flusher)
|
||||
if !ok {
|
||||
panic("expected http.ResponseWriter to be an http.Flusher")
|
||||
}
|
||||
|
||||
if sessionId != "" {
|
||||
// after GET is done, the connection is finished. disable automatic
|
||||
// session reaping, and handle it in defer
|
||||
@@ -287,20 +276,18 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||
}
|
||||
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
writer.(http.Flusher).Flush()
|
||||
|
||||
responseFlusher.Flush()
|
||||
|
||||
downloadDone := done.New()
|
||||
|
||||
httpSC := &httpServerConn{
|
||||
Instance: done.New(),
|
||||
Reader: request.Body,
|
||||
ResponseWriter: writer,
|
||||
}
|
||||
conn := splitConn{
|
||||
writer: &httpResponseBodyWriter{
|
||||
responseWriter: writer,
|
||||
downloadDone: downloadDone,
|
||||
responseFlusher: responseFlusher,
|
||||
},
|
||||
reader: request.Body,
|
||||
localAddr: h.localAddr,
|
||||
writer: httpSC,
|
||||
reader: httpSC,
|
||||
remoteAddr: remoteAddr,
|
||||
localAddr: h.localAddr,
|
||||
}
|
||||
if sessionId != "" { // if not stream-one
|
||||
conn.reader = currentSession.uploadQueue
|
||||
@@ -311,7 +298,7 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||
// "A ResponseWriter may not be used after [Handler.ServeHTTP] has returned."
|
||||
select {
|
||||
case <-request.Context().Done():
|
||||
case <-downloadDone.Wait():
|
||||
case <-httpSC.Wait():
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
@@ -321,45 +308,30 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||
}
|
||||
}
|
||||
|
||||
type httpRequestBodyReader struct {
|
||||
requestReader io.ReadCloser
|
||||
uploadDone *done.Instance
|
||||
}
|
||||
|
||||
func (c *httpRequestBodyReader) Read(b []byte) (int, error) {
|
||||
return c.requestReader.Read(b)
|
||||
}
|
||||
|
||||
func (c *httpRequestBodyReader) Close() error {
|
||||
defer c.uploadDone.Close()
|
||||
return c.requestReader.Close()
|
||||
}
|
||||
|
||||
type httpResponseBodyWriter struct {
|
||||
type httpServerConn struct {
|
||||
sync.Mutex
|
||||
responseWriter http.ResponseWriter
|
||||
responseFlusher http.Flusher
|
||||
downloadDone *done.Instance
|
||||
*done.Instance
|
||||
io.Reader // no need to Close request.Body
|
||||
http.ResponseWriter
|
||||
}
|
||||
|
||||
func (c *httpResponseBodyWriter) Write(b []byte) (int, error) {
|
||||
func (c *httpServerConn) Write(b []byte) (int, error) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
if c.downloadDone.Done() {
|
||||
if c.Done() {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
n, err := c.responseWriter.Write(b)
|
||||
n, err := c.ResponseWriter.Write(b)
|
||||
if err == nil {
|
||||
c.responseFlusher.Flush()
|
||||
c.ResponseWriter.(http.Flusher).Flush()
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *httpResponseBodyWriter) Close() error {
|
||||
func (c *httpServerConn) Close() error {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.downloadDone.Close()
|
||||
return nil
|
||||
return c.Instance.Close()
|
||||
}
|
||||
|
||||
type Listener struct {
|
||||
@@ -452,11 +424,15 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
|
||||
|
||||
handler.localAddr = l.listener.Addr()
|
||||
|
||||
// h2cHandler can handle both plaintext HTTP/1.1 and h2c
|
||||
// server can handle both plaintext HTTP/1.1 and h2c
|
||||
protocols := new(http.Protocols)
|
||||
protocols.SetHTTP1(true)
|
||||
protocols.SetUnencryptedHTTP2(true)
|
||||
l.server = http.Server{
|
||||
Handler: h2c.NewHandler(handler, &http2.Server{}),
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: time.Second * 4,
|
||||
MaxHeaderBytes: 8192,
|
||||
Protocols: protocols,
|
||||
}
|
||||
go func() {
|
||||
if err := l.server.Serve(l.listener); err != nil {
|
||||
|
@@ -3,10 +3,8 @@ package splithttp_test
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
gotls "crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
gonet "net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"testing"
|
||||
@@ -23,7 +21,6 @@ import (
|
||||
. "github.com/xtls/xray-core/transport/internet/splithttp"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
func Test_ListenXHAndDial(t *testing.T) {
|
||||
@@ -201,17 +198,11 @@ func Test_ListenXHAndDial_H2C(t *testing.T) {
|
||||
common.Must(err)
|
||||
defer listen.Close()
|
||||
|
||||
protocols := new(http.Protocols)
|
||||
protocols.SetUnencryptedHTTP2(true)
|
||||
client := http.Client{
|
||||
Transport: &http2.Transport{
|
||||
// So http2.Transport doesn't complain the URL scheme isn't 'https'
|
||||
AllowHTTP: true,
|
||||
// even with AllowHTTP, http2.Transport will attempt to establish
|
||||
// the connection using DialTLSContext. Disable TLS with custom
|
||||
// dial context.
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *gotls.Config) (gonet.Conn, error) {
|
||||
var d gonet.Dialer
|
||||
return d.DialContext(ctx, network, addr)
|
||||
},
|
||||
Transport: &http.Transport{
|
||||
Protocols: protocols,
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -20,6 +20,7 @@ type Packet struct {
|
||||
|
||||
type uploadQueue struct {
|
||||
reader io.ReadCloser
|
||||
nomore bool
|
||||
pushedPackets chan Packet
|
||||
writeCloseMutex sync.Mutex
|
||||
heap uploadHeap
|
||||
@@ -42,19 +43,15 @@ func (h *uploadQueue) Push(p Packet) error {
|
||||
h.writeCloseMutex.Lock()
|
||||
defer h.writeCloseMutex.Unlock()
|
||||
|
||||
runtime.Gosched()
|
||||
if h.reader != nil && p.Reader != nil {
|
||||
p.Reader.Close()
|
||||
return errors.New("h.reader already exists")
|
||||
}
|
||||
|
||||
if h.closed {
|
||||
if p.Reader != nil {
|
||||
p.Reader.Close()
|
||||
}
|
||||
return errors.New("packet queue closed")
|
||||
}
|
||||
|
||||
if h.nomore {
|
||||
return errors.New("h.reader already exists")
|
||||
}
|
||||
if p.Reader != nil {
|
||||
h.nomore = true
|
||||
}
|
||||
h.pushedPackets <- p
|
||||
return nil
|
||||
}
|
||||
@@ -65,9 +62,20 @@ func (h *uploadQueue) Close() error {
|
||||
|
||||
if !h.closed {
|
||||
h.closed = true
|
||||
runtime.Gosched() // hope Read() gets the packet
|
||||
f:
|
||||
for {
|
||||
select {
|
||||
case p := <-h.pushedPackets:
|
||||
if p.Reader != nil {
|
||||
h.reader = p.Reader
|
||||
}
|
||||
default:
|
||||
break f
|
||||
}
|
||||
}
|
||||
close(h.pushedPackets)
|
||||
}
|
||||
runtime.Gosched()
|
||||
if h.reader != nil {
|
||||
return h.reader.Close()
|
||||
}
|
||||
|
@@ -44,32 +44,32 @@ func getControlFunc(ctx context.Context, sockopt *SocketConfig, controllers []co
|
||||
// For some reason, other component of ray will assume the listener is a TCP listener and have valid remote address.
|
||||
// But in fact it doesn't. So we need to wrap the listener to make it return 0.0.0.0(unspecified) as remote address.
|
||||
// If other issues encountered, we should able to fix it here.
|
||||
type listenUDSWrapper struct {
|
||||
net.Listener
|
||||
type UnixListenerWrapper struct {
|
||||
*net.UnixListener
|
||||
locker *FileLocker
|
||||
}
|
||||
|
||||
func (l *listenUDSWrapper) Accept() (net.Conn, error) {
|
||||
conn, err := l.Listener.Accept()
|
||||
func (l *UnixListenerWrapper) Accept() (net.Conn, error) {
|
||||
conn, err := l.UnixListener.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &UDSWrapperConn{Conn: conn}, nil
|
||||
return &UnixConnWrapper{UnixConn: conn.(*net.UnixConn)}, nil
|
||||
}
|
||||
|
||||
func (l *listenUDSWrapper) Close() error {
|
||||
func (l *UnixListenerWrapper) Close() error {
|
||||
if l.locker != nil {
|
||||
l.locker.Release()
|
||||
l.locker = nil
|
||||
}
|
||||
return l.Listener.Close()
|
||||
return l.UnixListener.Close()
|
||||
}
|
||||
|
||||
type UDSWrapperConn struct {
|
||||
net.Conn
|
||||
type UnixConnWrapper struct {
|
||||
*net.UnixConn
|
||||
}
|
||||
|
||||
func (conn *UDSWrapperConn) RemoteAddr() net.Addr {
|
||||
func (conn *UnixConnWrapper) RemoteAddr() net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: []byte{0, 0, 0, 0},
|
||||
}
|
||||
@@ -136,7 +136,7 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S
|
||||
locker.Release()
|
||||
return nil, err
|
||||
}
|
||||
l = &listenUDSWrapper{Listener: l, locker: locker}
|
||||
l = &UnixListenerWrapper{UnixListener: l.(*net.UnixListener), locker: locker}
|
||||
if filePerm == nil {
|
||||
return l, nil
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -151,10 +151,14 @@ func init() {
|
||||
weights := utls.DefaultWeights
|
||||
weights.TLSVersMax_Set_VersionTLS13 = 1
|
||||
weights.FirstKeyShare_Set_CurveP256 = 0
|
||||
randomized := utls.HelloRandomized
|
||||
randomized := utls.HelloRandomizedALPN
|
||||
randomized.Seed, _ = utls.NewPRNGSeed()
|
||||
randomized.Weights = &weights
|
||||
randomizednoalpn := utls.HelloRandomizedNoALPN
|
||||
randomizednoalpn.Seed, _ = utls.NewPRNGSeed()
|
||||
randomizednoalpn.Weights = &weights
|
||||
PresetFingerprints["randomized"] = &randomized
|
||||
PresetFingerprints["randomizednoalpn"] = &randomizednoalpn
|
||||
}
|
||||
|
||||
func GetFingerprint(name string) (fingerprint *utls.ClientHelloID) {
|
||||
@@ -175,17 +179,18 @@ func GetFingerprint(name string) (fingerprint *utls.ClientHelloID) {
|
||||
|
||||
var PresetFingerprints = map[string]*utls.ClientHelloID{
|
||||
// Recommended preset options in GUI clients
|
||||
"chrome": &utls.HelloChrome_Auto,
|
||||
"firefox": &utls.HelloFirefox_Auto,
|
||||
"safari": &utls.HelloSafari_Auto,
|
||||
"ios": &utls.HelloIOS_Auto,
|
||||
"android": &utls.HelloAndroid_11_OkHttp,
|
||||
"edge": &utls.HelloEdge_Auto,
|
||||
"360": &utls.Hello360_Auto,
|
||||
"qq": &utls.HelloQQ_Auto,
|
||||
"random": nil,
|
||||
"randomized": nil,
|
||||
"unsafe": nil,
|
||||
"chrome": &utls.HelloChrome_Auto,
|
||||
"firefox": &utls.HelloFirefox_Auto,
|
||||
"safari": &utls.HelloSafari_Auto,
|
||||
"ios": &utls.HelloIOS_Auto,
|
||||
"android": &utls.HelloAndroid_11_OkHttp,
|
||||
"edge": &utls.HelloEdge_Auto,
|
||||
"360": &utls.Hello360_Auto,
|
||||
"qq": &utls.HelloQQ_Auto,
|
||||
"random": nil,
|
||||
"randomized": nil,
|
||||
"randomizednoalpn": nil,
|
||||
"unsafe": nil,
|
||||
}
|
||||
|
||||
var ModernFingerprints = map[string]*utls.ClientHelloID{
|
||||
@@ -193,12 +198,14 @@ var ModernFingerprints = map[string]*utls.ClientHelloID{
|
||||
"hellofirefox_99": &utls.HelloFirefox_99,
|
||||
"hellofirefox_102": &utls.HelloFirefox_102,
|
||||
"hellofirefox_105": &utls.HelloFirefox_105,
|
||||
"hellofirefox_120": &utls.HelloFirefox_120,
|
||||
"hellochrome_83": &utls.HelloChrome_83,
|
||||
"hellochrome_87": &utls.HelloChrome_87,
|
||||
"hellochrome_96": &utls.HelloChrome_96,
|
||||
"hellochrome_100": &utls.HelloChrome_100,
|
||||
"hellochrome_102": &utls.HelloChrome_102,
|
||||
"hellochrome_106_shuffle": &utls.HelloChrome_106_Shuffle,
|
||||
"hellochrome_120": &utls.HelloChrome_120,
|
||||
"helloios_13": &utls.HelloIOS_13,
|
||||
"helloios_14": &utls.HelloIOS_14,
|
||||
"helloedge_85": &utls.HelloEdge_85,
|
||||
|
Reference in New Issue
Block a user