Refactor: Add Shadowsocks Validator (#233)

This commit is contained in:
秋のかえで 2021-02-12 23:17:31 +08:00 committed by GitHub
parent 1b87264c53
commit df39991bb3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 230 additions and 93 deletions

View file

@ -54,12 +54,9 @@ func (r *FullReader) Read(p []byte) (n int, err error) {
}
// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
user := users[0]
account := user.Account.(*MemoryAccount)
func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
hashkdf.Write(account.Key)
behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil))
@ -71,10 +68,20 @@ func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.R
readSizeRemain := DrainSize
var r2 buf.Reader
buffer := buf.New()
defer buffer.Release()
if len(users) > 1 {
buffer := buf.New()
defer buffer.Release()
var user *protocol.MemoryUser
var ivLen int32
var err error
count := validator.Count()
if count == 0 {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("invalid user")
} else if count > 1 {
var aead cipher.AEAD
if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
readSizeRemain -= int(buffer.Len())
@ -83,45 +90,26 @@ func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.R
}
bs := buffer.Bytes()
user, aead, _, ivLen, err = validator.Get(bs, protocol.RequestCommandTCP)
var aeadCipher *AEADCipher
var ivLen int32
subkey := make([]byte, 32)
length := make([]byte, 16)
var aead cipher.AEAD
var err error
for _, user = range users {
account = user.Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
_, err = aead.Open(length[:0], length[4:16], bs[ivLen:ivLen+18], nil)
if err == nil {
reader = &FullReader{reader, bs[ivLen:]}
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: crypto.GenerateInitialAEADNonce(),
}
r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, reader, protocol.TransferTypeStream, nil)
break
if user != nil {
reader = &FullReader{reader, bs[ivLen:]}
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: crypto.GenerateInitialAEADNonce(),
}
}
if err != nil {
r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, reader, protocol.TransferTypeStream, nil)
} else {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to match an user").Base(err)
}
}
buffer := buf.New()
defer buffer.Release()
if r2 == nil {
ivLen := account.Cipher.IVSize()
} else {
user, ivLen = validator.GetOnlyUser()
account := user.Account.(*MemoryAccount)
hashkdf.Write(account.Key)
var iv []byte
if ivLen > 0 {
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
@ -261,40 +249,31 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload []byte) (*buf.Buff
return buffer, nil
}
func DecodeUDPPacket(users []*protocol.MemoryUser, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
bs := payload.Bytes()
if len(bs) <= 32 {
return nil, nil, newError("len(bs) <= 32")
}
var user *protocol.MemoryUser
var account *MemoryAccount
var err error
if len(users) > 1 {
bs := payload.Bytes()
if len(bs) <= 32 {
return nil, nil, newError("len(bs) <= 32")
}
var aeadCipher *AEADCipher
var ivLen int32
subkey := make([]byte, 32)
data := make([]byte, 8192)
var aead cipher.AEAD
count := validator.Count()
if count == 0 {
return nil, nil, newError("invalid user")
} else if count > 1 {
var d []byte
for _, user = range users {
account = user.Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
d, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
if err == nil {
payload.Clear()
payload.Write(d)
break
}
user, _, d, _, err = validator.Get(bs, protocol.RequestCommandUDP)
if user != nil {
payload.Clear()
payload.Write(d)
} else {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
}
} else {
user = users[0]
account = user.Account.(*MemoryAccount)
user, _ = validator.GetOnlyUser()
account := user.Account.(*MemoryAccount)
var iv []byte
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
@ -302,12 +281,9 @@ func DecodeUDPPacket(users []*protocol.MemoryUser, payload *buf.Buffer) (*protoc
iv = make([]byte, account.Cipher.IVSize())
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
}
err = account.Cipher.DecodePacket(account.Key, payload)
}
if err != nil {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
}
}
request := &protocol.RequestHeader{
@ -341,7 +317,10 @@ func (v *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
buffer.Release()
return nil, err
}
u, payload, err := DecodeUDPPacket([]*protocol.MemoryUser{v.User}, buffer)
validator := new(Validator)
validator.Add(v.User)
u, payload, err := DecodeUDPPacket(validator, buffer)
if err != nil {
buffer.Release()
return nil, err