Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions app/proxyman/outbound/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,12 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
conn, err := internet.Dial(ctx, dest, h.streamSettings)
conn = h.getStatCouterConnection(conn)
outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1]
ob.Conn = conn
if outbounds != nil {
ob := outbounds[len(outbounds)-1]
ob.Conn = conn
} else {
// for Vision's pre-connect
}
return conn, err
}

Expand Down
9 changes: 9 additions & 0 deletions infra/conf/vless.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type VLessInboundConfig struct {
Decryption string `json:"decryption"`
Fallbacks []*VLessInboundFallback `json:"fallbacks"`
Flow string `json:"flow"`
Testseed []uint32 `json:"testseed"`
}

// Build implements Buildable
Expand Down Expand Up @@ -73,6 +74,10 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
return nil, errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
}

if len(account.Testseed) < 4 {
account.Testseed = c.Testseed
}

if account.Encryption != "" {
return nil, errors.New(`VLESS clients: "encryption" should not be in inbound settings`)
}
Expand Down Expand Up @@ -212,6 +217,8 @@ type VLessOutboundConfig struct {
Seed string `json:"seed"`
Encryption string `json:"encryption"`
Reverse *vless.Reverse `json:"reverse"`
Testpre uint32 `json:"testpre"`
Testseed []uint32 `json:"testseed"`
Vnext []*VLessOutboundVnext `json:"vnext"`
}

Expand Down Expand Up @@ -258,6 +265,8 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
//account.Seed = c.Seed
account.Encryption = c.Encryption
account.Reverse = c.Reverse
account.Testpre = c.Testpre
account.Testseed = c.Testseed
} else {
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, errors.New(`VLESS users: invalid user`).Base(err)
Expand Down
26 changes: 16 additions & 10 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,11 +296,16 @@ type VisionWriter struct {
// internal
writeOnceUserUUID []byte
directWriteCounter stats.Counter

testseed []uint32
}

func NewVisionWriter(writer buf.Writer, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, ob *session.Outbound) *VisionWriter {
func NewVisionWriter(writer buf.Writer, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, ob *session.Outbound, testseed []uint32) *VisionWriter {
w := make([]byte, len(trafficState.UserUUID))
copy(w, trafficState.UserUUID)
if len(testseed) < 4 {
testseed = []uint32{900, 500, 900, 256}
}
return &VisionWriter{
Writer: writer,
trafficState: trafficState,
Expand All @@ -309,6 +314,7 @@ func NewVisionWriter(writer buf.Writer, trafficState *TrafficState, isUplink boo
isUplink: isUplink,
conn: conn,
ob: ob,
testseed: testseed,
}
}

Expand Down Expand Up @@ -347,7 +353,7 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {

if *isPadding {
if len(mb) == 1 && mb[0] == nil {
mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx) // we do a long padding to hide vless header
mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx, w.testseed) // we do a long padding to hide vless header
return w.Writer.WriteMultiBuffer(mb)
}
mb = ReshapeMultiBuffer(w.ctx, mb)
Expand All @@ -364,13 +370,13 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
command = CommandPaddingDirect
}
}
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx)
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx, w.testseed)
*isPadding = false // padding going to end
longPadding = false
continue
} else if !w.trafficState.IsTLS12orAbove && w.trafficState.NumberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
*isPadding = false
mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx)
mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx, w.testseed)
break
}
var command byte = CommandPaddingContinue
Expand All @@ -380,7 +386,7 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
command = CommandPaddingDirect
}
}
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, longPadding, w.ctx)
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, longPadding, w.ctx, w.testseed)
}
}
return w.Writer.WriteMultiBuffer(mb)
Expand Down Expand Up @@ -422,20 +428,20 @@ func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBu
}

// XtlsPadding add padding to eliminate length signature during tls handshake
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer {
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context, testseed []uint32) *buf.Buffer {
var contentLen int32 = 0
var paddingLen int32 = 0
if b != nil {
contentLen = b.Len()
}
if contentLen < 900 && longPadding {
l, err := rand.Int(rand.Reader, big.NewInt(500))
if contentLen < int32(testseed[0]) && longPadding {
l, err := rand.Int(rand.Reader, big.NewInt(int64(testseed[1])))
if err != nil {
errors.LogDebugInner(ctx, err, "failed to generate padding")
}
paddingLen = int32(l.Int64()) + 900 - contentLen
paddingLen = int32(l.Int64()) + int32(testseed[2]) - contentLen
} else {
l, err := rand.Int(rand.Reader, big.NewInt(256))
l, err := rand.Int(rand.Reader, big.NewInt(int64(testseed[3])))
if err != nil {
errors.LogDebugInner(ctx, err, "failed to generate padding")
}
Expand Down
7 changes: 7 additions & 0 deletions proxy/vless/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ func (a *Account) AsAccount() (protocol.Account, error) {
Seconds: a.Seconds,
Padding: a.Padding,
Reverse: a.Reverse,
Testpre: a.Testpre,
Testseed: a.Testseed,
}, nil
}

Expand All @@ -38,6 +40,9 @@ type MemoryAccount struct {
Padding string

Reverse *Reverse

Testpre uint32
Testseed []uint32
}

// Equals implements protocol.Account.Equals().
Expand All @@ -58,5 +63,7 @@ func (a *MemoryAccount) ToProto() proto.Message {
Seconds: a.Seconds,
Padding: a.Padding,
Reverse: a.Reverse,
Testpre: a.Testpre,
Testseed: a.Testseed,
}
}
35 changes: 27 additions & 8 deletions proxy/vless/account.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions proxy/vless/account.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ message Account {
string padding = 6;

Reverse reverse = 7;

uint32 testpre = 8;
repeated uint32 testseed = 9;
}
2 changes: 1 addition & 1 deletion proxy/vless/encoding/addons.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func EncodeBodyAddons(writer buf.Writer, request *protocol.RequestHeader, reques
return NewMultiLengthPacketWriter(writer)
}
if requestAddons.Flow == vless.XRV {
return proxy.NewVisionWriter(writer, state, isUplink, context, conn, ob)
return proxy.NewVisionWriter(writer, state, isUplink, context, conn, ob, request.User.Account.(*vless.MemoryAccount).Testseed)
}
return writer
}
Expand Down
55 changes: 47 additions & 8 deletions proxy/vless/outbound/outbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/base64"
"reflect"
"strings"
"sync"
"time"
"unsafe"

Expand All @@ -15,6 +16,7 @@ import (
"github.com/xtls/xray-core/app/reverse"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
xctx "github.com/xtls/xray-core/common/ctx"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net"
Expand Down Expand Up @@ -52,6 +54,10 @@ type Handler struct {
cone bool
encryption *encryption.ClientInstance
reverse *Reverse

testpre uint32
initpre sync.Once
preConns chan stat.Connection
}

// New creates a new VLess outbound handler.
Expand Down Expand Up @@ -105,11 +111,16 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
}()
}

handler.testpre = a.Testpre

return handler, nil
}

// Close implements common.Closable.Close().
func (h *Handler) Close() error {
if h.preConns != nil {
close(h.preConns)
}
if h.reverse != nil {
return h.reverse.Close()
}
Expand All @@ -128,18 +139,46 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
rec := h.server
var conn stat.Connection

if err := retry.ExponentialBackoff(5, 200).On(func() error {
var err error
conn, err = dialer.Dial(ctx, rec.Destination)
if err != nil {
return err
if h.testpre > 0 && h.reverse == nil {
h.initpre.Do(func() {
h.preConns = make(chan stat.Connection)
for range h.testpre { // TODO: randomize
go func() {
defer func() { recover() }()
ctx = xctx.ContextWithID(context.Background(), session.NewID())
for {
time.Sleep(time.Millisecond * 200) // TODO: randomize
conn, err := dialer.Dial(ctx, rec.Destination)
if err != nil {
errors.LogWarningInner(ctx, err, "pre-connect failed")
continue
}
h.preConns <- conn
}
}()
}
})
if conn = <-h.preConns; conn == nil {
return errors.New("closed handler").AtWarning()
}
}

if conn == nil {
if err := retry.ExponentialBackoff(5, 200).On(func() error {
var err error
conn, err = dialer.Dial(ctx, rec.Destination)
if err != nil {
return err
}
return nil
}); err != nil {
return errors.New("failed to find an available destination").Base(err).AtWarning()
}
return nil
}); err != nil {
return errors.New("failed to find an available destination").Base(err).AtWarning()
}
defer conn.Close()

ob.Conn = conn // for Vision's pre-connect

iConn := conn
if statConn, ok := iConn.(*stat.CounterConnection); ok {
iConn = statConn.Connection
Expand Down
Loading