Skip to content

Commit 63d0cb1

Browse files
authored
Refactor: new Shadowsocks validator (#629)
* Refactor: new Shadowsocks validator * Fix NoneCliper cannot work * Feat: refine the size of drain * fix: fix validator after merge 'main' * fix: UDP user logic * style: refine code style
1 parent dd67699 commit 63d0cb1

File tree

4 files changed

+139
-187
lines changed

4 files changed

+139
-187
lines changed

proxy/shadowsocks/config.go

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import (
77
"crypto/md5"
88
"crypto/sha1"
99
"io"
10-
"reflect"
11-
"strconv"
1210

1311
"golang.org/x/crypto/chacha20poly1305"
1412
"golang.org/x/crypto/hkdf"
@@ -28,6 +26,10 @@ type MemoryAccount struct {
2826
replayFilter antireplay.GeneralizedReplayFilter
2927
}
3028

29+
var (
30+
ErrIVNotUnique = newError("IV is not unique")
31+
)
32+
3133
// Equals implements protocol.Account.Equals().
3234
func (a *MemoryAccount) Equals(another protocol.Account) bool {
3335
if account, ok := another.(*MemoryAccount); ok {
@@ -43,24 +45,7 @@ func (a *MemoryAccount) CheckIV(iv []byte) error {
4345
if a.replayFilter.Check(iv) {
4446
return nil
4547
}
46-
return newError("IV is not unique")
47-
}
48-
49-
func (a *MemoryAccount) GetCipherName() string {
50-
switch a.Cipher.(type) {
51-
case *AEADCipher:
52-
switch reflect.ValueOf(a.Cipher.(*AEADCipher).AEADAuthCreator).Pointer() {
53-
case reflect.ValueOf(createAesGcm).Pointer():
54-
keyBytes := a.Cipher.(*AEADCipher).KeyBytes
55-
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_GCM"
56-
case reflect.ValueOf(createChaCha20Poly1305).Pointer():
57-
return "CHACHA20_POLY1305"
58-
}
59-
case *NoneCipher:
60-
return "NONE"
61-
}
62-
63-
return ""
48+
return ErrIVNotUnique
6449
}
6550

6651
func createAesGcm(key []byte) cipher.AEAD {

proxy/shadowsocks/protocol.go

Lines changed: 44 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
package shadowsocks
22

33
import (
4-
"crypto/cipher"
5-
"crypto/hmac"
64
"crypto/rand"
7-
"crypto/sha256"
8-
"hash/crc32"
95
"io"
106

117
"github.com/xtls/xray-core/common"
@@ -54,91 +50,67 @@ func (r *FullReader) Read(p []byte) (n int, err error) {
5450

5551
// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
5652
func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
57-
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
58-
59-
behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil))
60-
53+
behaviorSeed := validator.GetBehaviorSeed()
6154
behaviorRand := dice.NewDeterministicDice(int64(behaviorSeed))
6255
BaseDrainSize := behaviorRand.Roll(3266)
6356
RandDrainMax := behaviorRand.Roll(64) + 1
6457
RandDrainRolled := dice.Roll(RandDrainMax)
6558
DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled
6659
readSizeRemain := DrainSize
6760

68-
var r2 buf.Reader
61+
var r buf.Reader
6962
buffer := buf.New()
7063
defer buffer.Release()
7164

72-
var user *protocol.MemoryUser
73-
var ivLen int32
74-
var iv []byte
75-
var err error
76-
77-
count := validator.Count()
78-
if count == 0 {
65+
if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
7966
readSizeRemain -= int(buffer.Len())
8067
DrainConnN(reader, readSizeRemain)
81-
return nil, nil, newError("invalid user")
82-
} else if count > 1 {
83-
var aead cipher.AEAD
84-
85-
if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
86-
readSizeRemain -= int(buffer.Len())
87-
DrainConnN(reader, readSizeRemain)
88-
return nil, nil, newError("failed to read 50 bytes").Base(err)
89-
}
68+
return nil, nil, newError("failed to read 50 bytes").Base(err)
69+
}
9070

91-
bs := buffer.Bytes()
92-
user, aead, _, ivLen, err = validator.Get(bs, protocol.RequestCommandTCP)
71+
bs := buffer.Bytes()
72+
user, aead, _, ivLen, err := validator.Get(bs, protocol.RequestCommandTCP)
9373

94-
if user != nil {
95-
if ivLen > 0 {
96-
iv = append([]byte(nil), bs[:ivLen]...)
97-
}
98-
reader = &FullReader{reader, bs[ivLen:]}
74+
switch err {
75+
case ErrNotFound:
76+
readSizeRemain -= int(buffer.Len())
77+
DrainConnN(reader, readSizeRemain)
78+
return nil, nil, newError("failed to match an user").Base(err)
79+
case ErrIVNotUnique:
80+
readSizeRemain -= int(buffer.Len())
81+
DrainConnN(reader, readSizeRemain)
82+
return nil, nil, newError("failed iv check").Base(err)
83+
default:
84+
reader = &FullReader{reader, bs[ivLen:]}
85+
readSizeRemain -= int(ivLen)
86+
87+
if aead != nil {
9988
auth := &crypto.AEADAuthenticator{
10089
AEAD: aead,
10190
NonceGenerator: crypto.GenerateInitialAEADNonce(),
10291
}
103-
r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
92+
r = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
10493
Auth: auth,
10594
}, reader, protocol.TransferTypeStream, nil)
10695
} else {
107-
readSizeRemain -= int(buffer.Len())
108-
DrainConnN(reader, readSizeRemain)
109-
return nil, nil, newError("failed to match an user").Base(err)
110-
}
111-
} else {
112-
user, ivLen = validator.GetOnlyUser()
113-
account := user.Account.(*MemoryAccount)
114-
hashkdf.Write(account.Key)
115-
if ivLen > 0 {
116-
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
117-
readSizeRemain -= int(buffer.Len())
96+
account := user.Account.(*MemoryAccount)
97+
iv := append([]byte(nil), buffer.BytesTo(ivLen)...)
98+
r, err = account.Cipher.NewDecryptionReader(account.Key, iv, reader)
99+
if err != nil {
118100
DrainConnN(reader, readSizeRemain)
119-
return nil, nil, newError("failed to read IV").Base(err)
101+
return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError()
120102
}
121-
iv = append([]byte(nil), buffer.BytesTo(ivLen)...)
122-
}
123-
124-
r, err := account.Cipher.NewDecryptionReader(account.Key, iv, reader)
125-
if err != nil {
126-
readSizeRemain -= int(buffer.Len())
127-
DrainConnN(reader, readSizeRemain)
128-
return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError()
129103
}
130-
r2 = r
131104
}
132105

133-
br := &buf.BufferedReader{Reader: r2}
106+
br := &buf.BufferedReader{Reader: r}
134107

135108
request := &protocol.RequestHeader{
136109
Version: Version,
137110
User: user,
138111
Command: protocol.RequestCommandTCP,
139112
}
140113

141-
readSizeRemain -= int(buffer.Len())
142114
buffer.Clear()
143115

144116
addr, port, err := addrParser.ReadAddressPort(buffer, br)
@@ -157,13 +129,6 @@ func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHe
157129
return nil, nil, newError("invalid remote address.")
158130
}
159131

160-
account := user.Account.(*MemoryAccount)
161-
if ivError := account.CheckIV(iv); ivError != nil {
162-
readSizeRemain -= int(buffer.Len())
163-
DrainConnN(reader, readSizeRemain)
164-
return nil, nil, newError("failed iv check").Base(ivError)
165-
}
166-
167132
return request, br, nil
168133
}
169134

@@ -273,34 +238,25 @@ func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.Reque
273238
return nil, nil, newError("len(bs) <= 32")
274239
}
275240

276-
var user *protocol.MemoryUser
277-
var err error
278-
279-
count := validator.Count()
280-
if count == 0 {
281-
return nil, nil, newError("invalid user")
282-
} else if count > 1 {
283-
var d []byte
284-
user, _, d, _, err = validator.Get(bs, protocol.RequestCommandUDP)
285-
286-
if user != nil {
241+
user, _, d, _, err := validator.Get(bs, protocol.RequestCommandUDP)
242+
switch err {
243+
case ErrIVNotUnique:
244+
return nil, nil, newError("failed iv check").Base(err)
245+
case ErrNotFound:
246+
return nil, nil, newError("failed to match an user").Base(err)
247+
default:
248+
account := user.Account.(*MemoryAccount)
249+
if account.Cipher.IsAEAD() {
287250
payload.Clear()
288251
payload.Write(d)
289252
} else {
290-
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
291-
}
292-
} else {
293-
user, _ = validator.GetOnlyUser()
294-
account := user.Account.(*MemoryAccount)
295-
296-
var iv []byte
297-
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
298-
// Keep track of IV as it gets removed from payload in DecodePacket.
299-
iv = make([]byte, account.Cipher.IVSize())
300-
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
301-
}
302-
if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
303-
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
253+
if account.Cipher.IVSize() > 0 {
254+
iv := make([]byte, account.Cipher.IVSize())
255+
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
256+
}
257+
if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
258+
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
259+
}
304260
}
305261
}
306262

proxy/shadowsocks/server.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,6 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
115115
panic("no inbound metadata")
116116
}
117117

118-
if s.validator.Count() == 1 {
119-
inbound.User, _ = s.validator.GetOnlyUser()
120-
}
121-
122118
var dest *net.Destination
123119

124120
reader := buf.NewPacketReader(conn)

0 commit comments

Comments
 (0)