@@ -6,9 +6,10 @@ import (
6
6
"crypto/md5"
7
7
"hash/fnv"
8
8
"io"
9
+ "sync"
10
+ "time"
9
11
10
12
"golang.org/x/crypto/chacha20poly1305"
11
-
12
13
"v2ray.com/core/common/buf"
13
14
"v2ray.com/core/common/crypto"
14
15
"v2ray.com/core/common/errors"
@@ -18,6 +19,63 @@ import (
18
19
"v2ray.com/core/proxy/vmess"
19
20
)
20
21
22
+ type sessionId struct {
23
+ user [16 ]byte
24
+ key [16 ]byte
25
+ nonce [16 ]byte
26
+ }
27
+
28
+ type sessionHistory struct {
29
+ sync.RWMutex
30
+ cache map [sessionId ]time.Time
31
+ }
32
+
33
+ func newSessionHistory () * sessionHistory {
34
+ h := & sessionHistory {
35
+ cache : make (map [sessionId ]time.Time , 128 ),
36
+ }
37
+ go h .run ()
38
+ return h
39
+ }
40
+
41
+ func (h * sessionHistory ) Add (session sessionId ) {
42
+ h .Lock ()
43
+ h .cache [session ] = time .Now ().Add (time .Minute * 3 )
44
+ h .Unlock ()
45
+ }
46
+
47
+ func (h * sessionHistory ) Has (session sessionId ) bool {
48
+ h .RLock ()
49
+ defer h .RUnlock ()
50
+
51
+ if expire , found := h .cache [session ]; found {
52
+ return expire .After (time .Now ())
53
+ }
54
+ return false
55
+ }
56
+
57
+ func (h * sessionHistory ) run () {
58
+ for {
59
+ time .Sleep (time .Second * 30 )
60
+ session2Remove := make ([]sessionId , 0 , 16 )
61
+ now := time .Now ()
62
+ h .Lock ()
63
+ for session , expire := range h .cache {
64
+ if expire .Before (now ) {
65
+ session2Remove = append (session2Remove , session )
66
+ }
67
+ }
68
+ for _ , session := range session2Remove {
69
+ delete (h .cache , session )
70
+ }
71
+ h .Unlock ()
72
+ }
73
+ }
74
+
75
+ var (
76
+ globalSessionHistory = newSessionHistory ()
77
+ )
78
+
21
79
type ServerSession struct {
22
80
userValidator protocol.UserValidator
23
81
requestBodyKey []byte
@@ -56,8 +114,9 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
56
114
if err != nil {
57
115
return nil , errors .Base (err ).Message ("VMess|Server: Failed to get user account." )
58
116
}
117
+ vmessAccount := account .(* vmess.InternalAccount )
59
118
60
- aesStream := crypto .NewAesDecryptionStream (account .( * vmess. InternalAccount ) .ID .CmdKey (), iv )
119
+ aesStream := crypto .NewAesDecryptionStream (vmessAccount .ID .CmdKey (), iv )
61
120
decryptor := crypto .NewCryptionReader (aesStream , reader )
62
121
63
122
nBytes , err := io .ReadFull (decryptor , buffer [:41 ])
@@ -77,8 +136,17 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
77
136
78
137
v .requestBodyIV = append ([]byte (nil ), buffer [1 :17 ]... ) // 16 bytes
79
138
v .requestBodyKey = append ([]byte (nil ), buffer [17 :33 ]... ) // 16 bytes
80
- v .responseHeader = buffer [33 ] // 1 byte
81
- request .Option = protocol .RequestOption (buffer [34 ]) // 1 byte
139
+ var sid sessionId
140
+ copy (sid .user [:], vmessAccount .ID .Bytes ())
141
+ copy (sid .key [:], v .requestBodyKey )
142
+ copy (sid .nonce [:], v .requestBodyIV )
143
+ if globalSessionHistory .Has (sid ) {
144
+ return nil , errors .New ("VMess|Server: Duplicated session id. Possibly under reply attack." )
145
+ }
146
+ globalSessionHistory .Add (sid )
147
+
148
+ v .responseHeader = buffer [33 ] // 1 byte
149
+ request .Option = protocol .RequestOption (buffer [34 ]) // 1 byte
82
150
padingLen := int (buffer [35 ] >> 4 )
83
151
request .Security = protocol .NormSecurity (protocol .Security (buffer [35 ] & 0x0F ))
84
152
// 1 bytes reserved
0 commit comments