Skip to content

Commit cbade89

Browse files
authored
VLESS Encryption: Improve server-side tickets' expiration mechanism
#5067 (comment)
1 parent d20397c commit cbade89

File tree

5 files changed

+72
-31
lines changed

5 files changed

+72
-31
lines changed

infra/conf/vless.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,13 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
101101
if err != nil {
102102
return false
103103
}
104-
config.SecondsFrom = uint32(i)
105-
if len(t) > 1 {
104+
config.SecondsFrom = int64(i)
105+
if len(t) == 2 {
106106
i, err := strconv.Atoi(t[1])
107107
if err != nil {
108108
return false
109109
}
110-
config.SecondsTo = uint32(i)
110+
config.SecondsTo = int64(i)
111111
}
112112
padding := 0
113113
for _, r := range s[3:] {

proxy/vless/encryption/server.go

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,19 @@ type ServerInstance struct {
2828
Hash32s [][32]byte
2929
RelaysLength int
3030
XorMode uint32
31-
SecondsFrom uint32
32-
SecondsTo uint32
31+
SecondsFrom int64
32+
SecondsTo int64
3333
PaddingLens [][3]int
3434
PaddingGaps [][3]int
3535

3636
RWLock sync.RWMutex
37+
Closed bool
38+
Lasts map[int64][16]byte
39+
Tickets [][16]byte
3740
Sessions map[[16]byte]*ServerSession
3841
}
3942

40-
func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode, secondsFrom, secondsTo uint32, padding string) (err error) {
43+
func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode uint32, secondsFrom, secondsTo int64, padding string) (err error) {
4144
if i.NfsSKeys != nil {
4245
return errors.New("already initialized")
4346
}
@@ -68,8 +71,47 @@ func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode, secondsFrom, seco
6871
i.XorMode = xorMode
6972
i.SecondsFrom = secondsFrom
7073
i.SecondsTo = secondsTo
71-
i.Sessions = make(map[[16]byte]*ServerSession)
72-
return ParsePadding(padding, &i.PaddingLens, &i.PaddingGaps)
74+
err = ParsePadding(padding, &i.PaddingLens, &i.PaddingGaps)
75+
if err != nil {
76+
return
77+
}
78+
if i.SecondsFrom > 0 || i.SecondsTo > 0 {
79+
i.Lasts = make(map[int64][16]byte)
80+
i.Tickets = make([][16]byte, 0, 1024)
81+
i.Sessions = make(map[[16]byte]*ServerSession)
82+
go func() {
83+
for {
84+
time.Sleep(time.Minute)
85+
i.RWLock.Lock()
86+
if i.Closed {
87+
i.RWLock.Unlock()
88+
return
89+
}
90+
minute := time.Now().Unix() / 60
91+
last := i.Lasts[minute]
92+
delete(i.Lasts, minute)
93+
delete(i.Lasts, minute-1) // for insurance
94+
if last != [16]byte{} {
95+
for j, ticket := range i.Tickets {
96+
delete(i.Sessions, ticket)
97+
if ticket == last {
98+
i.Tickets = i.Tickets[j+1:]
99+
break
100+
}
101+
}
102+
}
103+
i.RWLock.Unlock()
104+
}
105+
}()
106+
}
107+
return
108+
}
109+
110+
func (i *ServerInstance) Close() (err error) {
111+
i.RWLock.Lock()
112+
i.Closed = true
113+
i.RWLock.Unlock()
114+
return
73115
}
74116

75117
func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn, error) {
@@ -224,33 +266,29 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
224266
c.AEAD = NewAEAD(pfsPublicKey, c.UnitedKey, c.UseAES)
225267
c.PeerAEAD = NewAEAD(encryptedPfsPublicKey[:1184+32], c.UnitedKey, c.UseAES)
226268

227-
ticket := make([]byte, 16)
228-
rand.Read(ticket)
229-
seconds := 0
269+
ticket := [16]byte{}
270+
rand.Read(ticket[:])
271+
var seconds int64
230272
if i.SecondsTo == 0 {
231-
seconds = int(i.SecondsFrom) * int(crypto.RandBetween(50, 100)) / 100
273+
seconds = i.SecondsFrom * crypto.RandBetween(50, 100) / 100
232274
} else {
233-
seconds = int(crypto.RandBetween(int64(i.SecondsFrom), int64(i.SecondsTo)))
275+
seconds = crypto.RandBetween(i.SecondsFrom, i.SecondsTo)
234276
}
235-
copy(ticket, EncodeLength(int(seconds)))
277+
copy(ticket[:], EncodeLength(int(seconds)))
236278
if seconds > 0 {
237279
i.RWLock.Lock()
238-
i.Sessions[[16]byte(ticket)] = &ServerSession{PfsKey: pfsKey}
280+
i.Lasts[(time.Now().Unix()+max(i.SecondsFrom, i.SecondsTo))/60+2] = ticket
281+
i.Tickets = append(i.Tickets, ticket)
282+
i.Sessions[ticket] = &ServerSession{PfsKey: pfsKey}
239283
i.RWLock.Unlock()
240-
go func() {
241-
time.Sleep(time.Duration(seconds)*time.Second + time.Minute)
242-
i.RWLock.Lock()
243-
delete(i.Sessions, [16]byte(ticket))
244-
i.RWLock.Unlock()
245-
}()
246284
}
247285

248286
pfsKeyExchangeLength := 1088 + 32 + 16
249287
encryptedTicketLength := 32
250288
paddingLength, paddingLens, paddingGaps := CreatPadding(i.PaddingLens, i.PaddingGaps)
251289
serverHello := make([]byte, pfsKeyExchangeLength+encryptedTicketLength+paddingLength)
252290
nfsAEAD.Seal(serverHello[:0], MaxNonce, pfsPublicKey, nil)
253-
c.AEAD.Seal(serverHello[:pfsKeyExchangeLength], nil, ticket, nil)
291+
c.AEAD.Seal(serverHello[:pfsKeyExchangeLength], nil, ticket[:], nil)
254292
padding := serverHello[pfsKeyExchangeLength+encryptedTicketLength:]
255293
c.AEAD.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
256294
c.AEAD.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
@@ -284,7 +322,7 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
284322
}
285323

286324
if i.XorMode == 2 {
287-
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, ticket), NewCTR(c.UnitedKey, iv), 0, 0)
325+
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, ticket[:]), NewCTR(c.UnitedKey, iv), 0, 0)
288326
}
289327
return c, nil
290328
}

proxy/vless/inbound/config.pb.go

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

proxy/vless/inbound/config.proto

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ message Config {
2323

2424
string decryption = 3;
2525
uint32 xorMode = 4;
26-
uint32 seconds_from = 5;
27-
uint32 seconds_to = 6;
26+
int64 seconds_from = 5;
27+
int64 seconds_to = 6;
2828
string padding = 7;
2929
}

proxy/vless/inbound/inbound.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ func isMuxAndNotXUDP(request *protocol.RequestHeader, first *buf.Buffer) bool {
176176

177177
// Close implements common.Closable.Close().
178178
func (h *Handler) Close() error {
179+
if h.decryption != nil {
180+
h.decryption.Close()
181+
}
179182
return errors.Combine(common.Close(h.validator))
180183
}
181184

0 commit comments

Comments
 (0)