Skip to content

Commit 2dc9729

Browse files
committed
VLESS outbound: Add pre-connect (early test, for Vision Seed)
https://t.me/projectXtls/1034
1 parent cb4f943 commit 2dc9729

File tree

5 files changed

+70
-16
lines changed

5 files changed

+70
-16
lines changed

infra/conf/vless.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ type VLessOutboundConfig struct {
212212
Seed string `json:"seed"`
213213
Encryption string `json:"encryption"`
214214
Reverse *vless.Reverse `json:"reverse"`
215+
Testpre uint32 `json:"testpre"`
215216
Vnext []*VLessOutboundVnext `json:"vnext"`
216217
}
217218

@@ -258,6 +259,7 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
258259
//account.Seed = c.Seed
259260
account.Encryption = c.Encryption
260261
account.Reverse = c.Reverse
262+
account.Testpre = c.Testpre
261263
} else {
262264
if err := json.Unmarshal(rawUser, account); err != nil {
263265
return nil, errors.New(`VLESS users: invalid user`).Base(err)

proxy/vless/account.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func (a *Account) AsAccount() (protocol.Account, error) {
2222
Seconds: a.Seconds,
2323
Padding: a.Padding,
2424
Reverse: a.Reverse,
25+
Testpre: a.Testpre,
2526
}, nil
2627
}
2728

@@ -38,6 +39,8 @@ type MemoryAccount struct {
3839
Padding string
3940

4041
Reverse *Reverse
42+
43+
Testpre uint32
4144
}
4245

4346
// Equals implements protocol.Account.Equals().
@@ -58,5 +61,6 @@ func (a *MemoryAccount) ToProto() proto.Message {
5861
Seconds: a.Seconds,
5962
Padding: a.Padding,
6063
Reverse: a.Reverse,
64+
Testpre: a.Testpre,
6165
}
6266
}

proxy/vless/account.pb.go

Lines changed: 18 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proxy/vless/account.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ message Account {
2222
string padding = 6;
2323

2424
Reverse reverse = 7;
25+
26+
uint32 testpre = 8;
2527
}

proxy/vless/outbound/outbound.go

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/base64"
88
"reflect"
99
"strings"
10+
"sync"
1011
"time"
1112
"unsafe"
1213

@@ -52,6 +53,10 @@ type Handler struct {
5253
cone bool
5354
encryption *encryption.ClientInstance
5455
reverse *Reverse
56+
57+
testpre uint32
58+
locker sync.Mutex
59+
conns []stat.Connection
5560
}
5661

5762
// New creates a new VLess outbound handler.
@@ -105,6 +110,8 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
105110
}()
106111
}
107112

113+
handler.testpre = a.Testpre
114+
108115
return handler, nil
109116
}
110117

@@ -128,15 +135,44 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
128135
rec := h.server
129136
var conn stat.Connection
130137

131-
if err := retry.ExponentialBackoff(5, 200).On(func() error {
132-
var err error
133-
conn, err = dialer.Dial(ctx, rec.Destination)
134-
if err != nil {
135-
return err
138+
if h.testpre > 0 && h.reverse == nil {
139+
h.locker.Lock()
140+
if h.conns == nil {
141+
h.conns = make([]stat.Connection, 0)
142+
go func() {
143+
for { // TODO: close & inactive
144+
time.Sleep(100 * time.Millisecond) // TODO: customize & randomize
145+
h.locker.Lock()
146+
if len(h.conns) >= int(h.testpre) {
147+
h.locker.Unlock()
148+
continue
149+
}
150+
h.locker.Unlock()
151+
if conn, err := dialer.Dial(context.Background(), rec.Destination); err == nil { // TODO: timeout & concurrency? & ctx mitm?
152+
h.locker.Lock()
153+
h.conns = append(h.conns, conn) // TODO: vision paddings
154+
h.locker.Unlock()
155+
}
156+
}
157+
}()
158+
} else if len(h.conns) > 0 {
159+
conn = h.conns[0]
160+
h.conns = h.conns[1:]
161+
}
162+
h.locker.Unlock()
163+
}
164+
165+
if conn == nil {
166+
if err := retry.ExponentialBackoff(5, 200).On(func() error {
167+
var err error
168+
conn, err = dialer.Dial(ctx, rec.Destination)
169+
if err != nil {
170+
return err
171+
}
172+
return nil
173+
}); err != nil {
174+
return errors.New("failed to find an available destination").Base(err).AtWarning()
136175
}
137-
return nil
138-
}); err != nil {
139-
return errors.New("failed to find an available destination").Base(err).AtWarning()
140176
}
141177
defer conn.Close()
142178

0 commit comments

Comments
 (0)