remove deprecate ciphers in shadowsocks (#710)

* remove deprecate ciphers in shadowsocks

Co-authored-by: Kslr <kslrwang@gmail.com>
This commit is contained in:
yuhan6665 2021-09-16 16:13:07 -04:00 committed by GitHub
parent 1adfc2720a
commit 00bcd40c34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 77 additions and 543 deletions

View File

@ -12,14 +12,6 @@ import (
func cipherFromString(c string) shadowsocks.CipherType { func cipherFromString(c string) shadowsocks.CipherType {
switch strings.ToLower(c) { switch strings.ToLower(c) {
case "aes-256-cfb":
return shadowsocks.CipherType_AES_256_CFB
case "aes-128-cfb":
return shadowsocks.CipherType_AES_128_CFB
case "chacha20":
return shadowsocks.CipherType_CHACHA20
case "chacha20-ietf":
return shadowsocks.CipherType_CHACHA20_IETF
case "aes-128-gcm", "aead_aes_128_gcm": case "aes-128-gcm", "aead_aes_128_gcm":
return shadowsocks.CipherType_AES_128_GCM return shadowsocks.CipherType_AES_128_GCM
case "aes-256-gcm", "aead_aes_256_gcm": case "aes-256-gcm", "aead_aes_256_gcm":

View File

@ -18,14 +18,14 @@ func TestShadowsocksServerConfigParsing(t *testing.T) {
runMultiTestCase(t, []TestCase{ runMultiTestCase(t, []TestCase{
{ {
Input: `{ Input: `{
"method": "aes-128-gcm", "method": "aes-256-GCM",
"password": "xray-password" "password": "xray-password"
}`, }`,
Parser: loadJSON(creator), Parser: loadJSON(creator),
Output: &shadowsocks.ServerConfig{ Output: &shadowsocks.ServerConfig{
Users: []*protocol.User{{ Users: []*protocol.User{{
Account: serial.ToTypedMessage(&shadowsocks.Account{ Account: serial.ToTypedMessage(&shadowsocks.Account{
CipherType: shadowsocks.CipherType_AES_128_GCM, CipherType: shadowsocks.CipherType_AES_256_GCM,
Password: "xray-password", Password: "xray-password",
}), }),
}}, }},

View File

@ -35,20 +35,12 @@ func (a *MemoryAccount) Equals(another protocol.Account) bool {
func (a *MemoryAccount) GetCipherName() string { func (a *MemoryAccount) GetCipherName() string {
switch a.Cipher.(type) { switch a.Cipher.(type) {
case *AesCfb:
keyBytes := a.Cipher.(*AesCfb).KeyBytes
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_CFB"
case *ChaCha20:
if a.Cipher.(*ChaCha20).IVBytes == 8 {
return "CHACHA20"
}
return "CHACHA20_IETF"
case *AEADCipher: case *AEADCipher:
switch reflect.ValueOf(a.Cipher.(*AEADCipher).AEADAuthCreator).Pointer() { switch reflect.ValueOf(a.Cipher.(*AEADCipher).AEADAuthCreator).Pointer() {
case reflect.ValueOf(createAesGcm).Pointer(): case reflect.ValueOf(createAesGcm).Pointer():
keyBytes := a.Cipher.(*AEADCipher).KeyBytes keyBytes := a.Cipher.(*AEADCipher).KeyBytes
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_GCM" return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_GCM"
case reflect.ValueOf(createChacha20Poly1305).Pointer(): case reflect.ValueOf(createChaCha20Poly1305).Pointer():
return "CHACHA20_POLY1305" return "CHACHA20_POLY1305"
} }
case *NoneCipher: case *NoneCipher:
@ -66,22 +58,14 @@ func createAesGcm(key []byte) cipher.AEAD {
return gcm return gcm
} }
func createChacha20Poly1305(key []byte) cipher.AEAD { func createChaCha20Poly1305(key []byte) cipher.AEAD {
chacha20, err := chacha20poly1305.New(key) ChaChaPoly1305, err := chacha20poly1305.New(key)
common.Must(err) common.Must(err)
return chacha20 return ChaChaPoly1305
} }
func (a *Account) getCipher() (Cipher, error) { func (a *Account) getCipher() (Cipher, error) {
switch a.CipherType { switch a.CipherType {
case CipherType_AES_128_CFB:
return &AesCfb{KeyBytes: 16}, nil
case CipherType_AES_256_CFB:
return &AesCfb{KeyBytes: 32}, nil
case CipherType_CHACHA20:
return &ChaCha20{IVBytes: 8}, nil
case CipherType_CHACHA20_IETF:
return &ChaCha20{IVBytes: 12}, nil
case CipherType_AES_128_GCM: case CipherType_AES_128_GCM:
return &AEADCipher{ return &AEADCipher{
KeyBytes: 16, KeyBytes: 16,
@ -98,7 +82,7 @@ func (a *Account) getCipher() (Cipher, error) {
return &AEADCipher{ return &AEADCipher{
KeyBytes: 32, KeyBytes: 32,
IVBytes: 32, IVBytes: 32,
AEADAuthCreator: createChacha20Poly1305, AEADAuthCreator: createChaCha20Poly1305,
}, nil }, nil
case CipherType_NONE: case CipherType_NONE:
return NoneCipher{}, nil return NoneCipher{}, nil
@ -109,13 +93,13 @@ func (a *Account) getCipher() (Cipher, error) {
// AsAccount implements protocol.AsAccount. // AsAccount implements protocol.AsAccount.
func (a *Account) AsAccount() (protocol.Account, error) { func (a *Account) AsAccount() (protocol.Account, error) {
cipher, err := a.getCipher() Cipher, err := a.getCipher()
if err != nil { if err != nil {
return nil, newError("failed to get cipher").Base(err) return nil, newError("failed to get cipher").Base(err)
} }
return &MemoryAccount{ return &MemoryAccount{
Cipher: cipher, Cipher: Cipher,
Key: passwordToCipherKey([]byte(a.Password), cipher.KeySize()), Key: passwordToCipherKey([]byte(a.Password), Cipher.KeySize()),
}, nil }, nil
} }
@ -130,53 +114,6 @@ type Cipher interface {
DecodePacket(key []byte, b *buf.Buffer) error DecodePacket(key []byte, b *buf.Buffer) error
} }
// AesCfb represents all AES-CFB ciphers.
type AesCfb struct {
KeyBytes int32
}
func (*AesCfb) IsAEAD() bool {
return false
}
func (v *AesCfb) KeySize() int32 {
return v.KeyBytes
}
func (v *AesCfb) IVSize() int32 {
return 16
}
func (v *AesCfb) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
stream := crypto.NewAesEncryptionStream(key, iv)
return &buf.SequentialWriter{Writer: crypto.NewCryptionWriter(stream, writer)}, nil
}
func (v *AesCfb) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
stream := crypto.NewAesDecryptionStream(key, iv)
return &buf.SingleReader{
Reader: crypto.NewCryptionReader(stream, reader),
}, nil
}
func (v *AesCfb) EncodePacket(key []byte, b *buf.Buffer) error {
iv := b.BytesTo(v.IVSize())
stream := crypto.NewAesEncryptionStream(key, iv)
stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
return nil
}
func (v *AesCfb) DecodePacket(key []byte, b *buf.Buffer) error {
if b.Len() <= v.IVSize() {
return newError("insufficient data: ", b.Len())
}
iv := b.BytesTo(v.IVSize())
stream := crypto.NewAesDecryptionStream(key, iv)
stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
b.Advance(v.IVSize())
return nil
}
type AEADCipher struct { type AEADCipher struct {
KeyBytes int32 KeyBytes int32
IVBytes int32 IVBytes int32
@ -245,56 +182,12 @@ func (c *AEADCipher) DecodePacket(key []byte, b *buf.Buffer) error {
return nil return nil
} }
type ChaCha20 struct {
IVBytes int32
}
func (*ChaCha20) IsAEAD() bool {
return false
}
func (v *ChaCha20) KeySize() int32 {
return 32
}
func (v *ChaCha20) IVSize() int32 {
return v.IVBytes
}
func (v *ChaCha20) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
stream := crypto.NewChaCha20Stream(key, iv)
return &buf.SequentialWriter{Writer: crypto.NewCryptionWriter(stream, writer)}, nil
}
func (v *ChaCha20) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
stream := crypto.NewChaCha20Stream(key, iv)
return &buf.SingleReader{Reader: crypto.NewCryptionReader(stream, reader)}, nil
}
func (v *ChaCha20) EncodePacket(key []byte, b *buf.Buffer) error {
iv := b.BytesTo(v.IVSize())
stream := crypto.NewChaCha20Stream(key, iv)
stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
return nil
}
func (v *ChaCha20) DecodePacket(key []byte, b *buf.Buffer) error {
if b.Len() <= v.IVSize() {
return newError("insufficient data: ", b.Len())
}
iv := b.BytesTo(v.IVSize())
stream := crypto.NewChaCha20Stream(key, iv)
stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
b.Advance(v.IVSize())
return nil
}
type NoneCipher struct{} type NoneCipher struct{}
func (NoneCipher) KeySize() int32 { return 0 } func (NoneCipher) KeySize() int32 { return 0 }
func (NoneCipher) IVSize() int32 { return 0 } func (NoneCipher) IVSize() int32 { return 0 }
func (NoneCipher) IsAEAD() bool { func (NoneCipher) IsAEAD() bool {
return true // to avoid OTA return false
} }
func (NoneCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) { func (NoneCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
@ -330,7 +223,7 @@ func passwordToCipherKey(password []byte, keySize int32) []byte {
return key return key
} }
func hkdfSHA1(secret, salt, outkey []byte) { func hkdfSHA1(secret, salt, outKey []byte) {
r := hkdf.New(sha1.New, secret, salt, []byte("ss-subkey")) r := hkdf.New(sha1.New, secret, salt, []byte("ss-subkey"))
common.Must2(io.ReadFull(r, outkey)) common.Must2(io.ReadFull(r, outKey))
} }

View File

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.25.0
// protoc v3.14.0 // protoc v3.15.8
// source: proxy/shadowsocks/config.proto // source: proxy/shadowsocks/config.proto
package shadowsocks package shadowsocks
@ -31,39 +31,27 @@ type CipherType int32
const ( const (
CipherType_UNKNOWN CipherType = 0 CipherType_UNKNOWN CipherType = 0
CipherType_AES_128_CFB CipherType = 1 CipherType_AES_128_GCM CipherType = 1
CipherType_AES_256_CFB CipherType = 2 CipherType_AES_256_GCM CipherType = 2
CipherType_CHACHA20 CipherType = 3 CipherType_CHACHA20_POLY1305 CipherType = 3
CipherType_CHACHA20_IETF CipherType = 4 CipherType_NONE CipherType = 4
CipherType_AES_128_GCM CipherType = 5
CipherType_AES_256_GCM CipherType = 6
CipherType_CHACHA20_POLY1305 CipherType = 7
CipherType_NONE CipherType = 8
) )
// Enum value maps for CipherType. // Enum value maps for CipherType.
var ( var (
CipherType_name = map[int32]string{ CipherType_name = map[int32]string{
0: "UNKNOWN", 0: "UNKNOWN",
1: "AES_128_CFB", 1: "AES_128_GCM",
2: "AES_256_CFB", 2: "AES_256_GCM",
3: "CHACHA20", 3: "CHACHA20_POLY1305",
4: "CHACHA20_IETF", 4: "NONE",
5: "AES_128_GCM",
6: "AES_256_GCM",
7: "CHACHA20_POLY1305",
8: "NONE",
} }
CipherType_value = map[string]int32{ CipherType_value = map[string]int32{
"UNKNOWN": 0, "UNKNOWN": 0,
"AES_128_CFB": 1, "AES_128_GCM": 1,
"AES_256_CFB": 2, "AES_256_GCM": 2,
"CHACHA20": 3, "CHACHA20_POLY1305": 3,
"CHACHA20_IETF": 4, "NONE": 4,
"AES_128_GCM": 5,
"AES_256_GCM": 6,
"CHACHA20_POLY1305": 7,
"NONE": 8,
} }
) )
@ -282,24 +270,19 @@ var file_proxy_shadowsocks_config_proto_rawDesc = []byte{
0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65,
0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2a, 0x9f, 0x01, 0x0a, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x72, 0x2a, 0x5c, 0x0a, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12,
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b,
0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x43, 0x46, 0x42, 0x10, 0x01, 0x12, 0x0f, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x10, 0x01, 0x12, 0x0f, 0x0a,
0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x43, 0x46, 0x42, 0x10, 0x02, 0x12, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47, 0x43, 0x4d, 0x10, 0x02, 0x12, 0x15,
0x0c, 0x0a, 0x08, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31,
0x0d, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x49, 0x45, 0x54, 0x46, 0x10, 0x04, 0x33, 0x30, 0x35, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x04, 0x42,
0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x10, 0x64, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47, 0x43, 0x4d, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x01, 0x5a,
0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73,
0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x07, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x45, 0x10, 0x08, 0x42, 0x64, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0xaa, 0x02, 0x16, 0x58,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77,
0x73, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73,
0xaa, 0x02, 0x16, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68,
0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
} }
var ( var (

View File

@ -17,14 +17,10 @@ message Account {
enum CipherType { enum CipherType {
UNKNOWN = 0; UNKNOWN = 0;
AES_128_CFB = 1; AES_128_GCM = 1;
AES_256_CFB = 2; AES_256_GCM = 2;
CHACHA20 = 3; CHACHA20_POLY1305 = 3;
CHACHA20_IETF = 4; NONE = 4;
AES_128_GCM = 5;
AES_256_GCM = 6;
CHACHA20_POLY1305 = 7;
NONE = 8;
} }
message ServerConfig { message ServerConfig {

View File

@ -18,6 +18,12 @@ func toAccount(a *Account) protocol.Account {
return account return account
} }
func equalRequestHeader(x, y *protocol.RequestHeader) bool {
return cmp.Equal(x, y, cmp.Comparer(func(x, y protocol.RequestHeader) bool {
return x == y
}))
}
func TestUDPEncoding(t *testing.T) { func TestUDPEncoding(t *testing.T) {
request := &protocol.RequestHeader{ request := &protocol.RequestHeader{
Version: Version, Version: Version,
@ -27,7 +33,7 @@ func TestUDPEncoding(t *testing.T) {
User: &protocol.MemoryUser{ User: &protocol.MemoryUser{
Email: "love@example.com", Email: "love@example.com",
Account: toAccount(&Account{ Account: toAccount(&Account{
Password: "shadowsocks-password", Password: "password",
CipherType: CipherType_AES_128_GCM, CipherType: CipherType_AES_128_GCM,
}), }),
}, },
@ -47,8 +53,8 @@ func TestUDPEncoding(t *testing.T) {
t.Error("data: ", r) t.Error("data: ", r)
} }
if r := cmp.Diff(decodedRequest, request, cmp.Comparer(func(a1, a2 protocol.Account) bool { return a1.Equals(a2) })); r != "" { if equalRequestHeader(decodedRequest, request) == false {
t.Error("request: ", r) t.Error("different request")
} }
} }
@ -67,7 +73,7 @@ func TestTCPRequest(t *testing.T) {
Email: "love@example.com", Email: "love@example.com",
Account: toAccount(&Account{ Account: toAccount(&Account{
Password: "tcp-password", Password: "tcp-password",
CipherType: CipherType_CHACHA20_POLY1305, CipherType: CipherType_AES_128_GCM,
}), }),
}, },
}, },
@ -99,7 +105,7 @@ func TestTCPRequest(t *testing.T) {
Email: "love@example.com", Email: "love@example.com",
Account: toAccount(&Account{ Account: toAccount(&Account{
Password: "password", Password: "password",
CipherType: CipherType_AES_128_GCM, CipherType: CipherType_CHACHA20_POLY1305,
}), }),
}, },
}, },
@ -123,8 +129,8 @@ func TestTCPRequest(t *testing.T) {
validator.Add(request.User) validator.Add(request.User)
decodedRequest, reader, err := ReadTCPSession(validator, cache) decodedRequest, reader, err := ReadTCPSession(validator, cache)
common.Must(err) common.Must(err)
if r := cmp.Diff(decodedRequest, request, cmp.Comparer(func(a1, a2 protocol.Account) bool { return a1.Equals(a2) })); r != "" { if equalRequestHeader(decodedRequest, request) == false {
t.Error("request: ", r) t.Error("different request")
} }
decodedData, err := reader.ReadMultiBuffer() decodedData, err := reader.ReadMultiBuffer()

View File

@ -1,17 +1,14 @@
package scenarios package scenarios
import ( import (
"crypto/rand"
"testing" "testing"
"time" "time"
"github.com/google/go-cmp/cmp"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"github.com/xtls/xray-core/app/log" "github.com/xtls/xray-core/app/log"
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
clog "github.com/xtls/xray-core/common/log" clog "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
@ -24,330 +21,7 @@ import (
"github.com/xtls/xray-core/testing/servers/udp" "github.com/xtls/xray-core/testing/servers/udp"
) )
func TestShadowsocksAES256TCP(t *testing.T) { func TestShadowsocksChaCha20Poly1305TCP(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
account := serial.ToTypedMessage(&shadowsocks.Account{
Password: "shadowsocks-password",
CipherType: shadowsocks.CipherType_AES_256_CFB,
})
serverPort := tcp.PickPort()
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
Users: []*protocol.User{{
Account: account,
Level: 1,
}},
Network: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := tcp.PickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
NetworkList: &net.NetworkList{
Network: []net.Network{net.Network_TCP},
},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
Server: []*protocol.ServerEndpoint{
{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
User: []*protocol.User{
{
Account: account,
},
},
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
var errg errgroup.Group
for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))
}
if err := errg.Wait(); err != nil {
t.Fatal(err)
}
}
func TestShadowsocksAES128UDP(t *testing.T) {
udpServer := udp.Server{
MsgProcessor: xor,
}
dest, err := udpServer.Start()
common.Must(err)
defer udpServer.Close()
account := serial.ToTypedMessage(&shadowsocks.Account{
Password: "shadowsocks-password",
CipherType: shadowsocks.CipherType_AES_128_CFB,
})
serverPort := tcp.PickPort()
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
Users: []*protocol.User{{
Account: account,
Level: 1,
}},
Network: []net.Network{net.Network_UDP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := tcp.PickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
NetworkList: &net.NetworkList{
Network: []net.Network{net.Network_UDP},
},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
Server: []*protocol.ServerEndpoint{
{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
User: []*protocol.User{
{
Account: account,
},
},
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
var errg errgroup.Group
for i := 0; i < 10; i++ {
errg.Go(func() error {
conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: []byte{127, 0, 0, 1},
Port: int(clientPort),
})
if err != nil {
return err
}
defer conn.Close()
payload := make([]byte, 1024)
common.Must2(rand.Read(payload))
nBytes, err := conn.Write(payload)
if err != nil {
return err
}
if nBytes != len(payload) {
return errors.New("expect ", len(payload), " written, but actually ", nBytes)
}
response := readFrom(conn, time.Second*5, 1024)
if r := cmp.Diff(response, xor(payload)); r != "" {
return errors.New(r)
}
return nil
})
}
if err := errg.Wait(); err != nil {
t.Fatal(err)
}
}
func TestShadowsocksChacha20TCP(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
account := serial.ToTypedMessage(&shadowsocks.Account{
Password: "shadowsocks-password",
CipherType: shadowsocks.CipherType_CHACHA20_IETF,
})
serverPort := tcp.PickPort()
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
Users: []*protocol.User{{
Account: account,
Level: 1,
}},
Network: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := tcp.PickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
NetworkList: &net.NetworkList{
Network: []net.Network{net.Network_TCP},
},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
Server: []*protocol.ServerEndpoint{
{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
User: []*protocol.User{
{
Account: account,
},
},
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
var errg errgroup.Group
for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40))
}
if err := errg.Wait(); err != nil {
t.Error(err)
}
}
func TestShadowsocksChacha20Poly1305TCP(t *testing.T) {
tcpServer := tcp.Server{ tcpServer := tcp.Server{
MsgProcessor: xor, MsgProcessor: xor,
} }
@ -395,9 +69,7 @@ func TestShadowsocksChacha20Poly1305TCP(t *testing.T) {
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &net.NetworkList{ Networks: []net.Network{net.Network_TCP},
Network: []net.Network{net.Network_TCP},
},
}), }),
}, },
}, },
@ -424,11 +96,11 @@ func TestShadowsocksChacha20Poly1305TCP(t *testing.T) {
common.Must(err) common.Must(err)
defer CloseAllServers(servers) defer CloseAllServers(servers)
var errg errgroup.Group var errGroup errgroup.Group
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20)) errGroup.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))
} }
if err := errg.Wait(); err != nil { if err := errGroup.Wait(); err != nil {
t.Error(err) t.Error(err)
} }
} }
@ -493,9 +165,7 @@ func TestShadowsocksAES256GCMTCP(t *testing.T) {
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &net.NetworkList{ Networks: []net.Network{net.Network_TCP},
Network: []net.Network{net.Network_TCP},
},
}), }),
}, },
}, },
@ -522,12 +192,12 @@ func TestShadowsocksAES256GCMTCP(t *testing.T) {
common.Must(err) common.Must(err)
defer CloseAllServers(servers) defer CloseAllServers(servers)
var errg errgroup.Group var errGroup errgroup.Group
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20)) errGroup.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))
} }
if err := errg.Wait(); err != nil { if err := errGroup.Wait(); err != nil {
t.Error(err) t.Error(err)
} }
} }
@ -592,9 +262,7 @@ func TestShadowsocksAES128GCMUDP(t *testing.T) {
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &net.NetworkList{ Networks: []net.Network{net.Network_UDP},
Network: []net.Network{net.Network_UDP},
},
}), }),
}, },
}, },
@ -621,11 +289,11 @@ func TestShadowsocksAES128GCMUDP(t *testing.T) {
common.Must(err) common.Must(err)
defer CloseAllServers(servers) defer CloseAllServers(servers)
var errg errgroup.Group var errGroup errgroup.Group
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
errg.Go(testUDPConn(clientPort, 1024, time.Second*5)) errGroup.Go(testUDPConn(clientPort, 1024, time.Second*5))
} }
if err := errg.Wait(); err != nil { if err := errGroup.Wait(); err != nil {
t.Error(err) t.Error(err)
} }
} }
@ -690,9 +358,7 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &net.NetworkList{ Networks: []net.Network{net.Network_UDP},
Network: []net.Network{net.Network_UDP},
},
}), }),
}, },
}, },
@ -725,11 +391,11 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
common.Must(err) common.Must(err)
defer CloseAllServers(servers) defer CloseAllServers(servers)
var errg errgroup.Group var errGroup errgroup.Group
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
errg.Go(testUDPConn(clientPort, 1024, time.Second*5)) errGroup.Go(testUDPConn(clientPort, 1024, time.Second*5))
} }
if err := errg.Wait(); err != nil { if err := errGroup.Wait(); err != nil {
t.Error(err) t.Error(err)
} }
} }
@ -783,9 +449,7 @@ func TestShadowsocksNone(t *testing.T) {
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &net.NetworkList{ Networks: []net.Network{net.Network_TCP},
Network: []net.Network{net.Network_TCP},
},
}), }),
}, },
}, },
@ -813,12 +477,12 @@ func TestShadowsocksNone(t *testing.T) {
defer CloseAllServers(servers) defer CloseAllServers(servers)
var errg errgroup.Group var errGroup errgroup.Group
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20)) errGroup.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))
} }
if err := errg.Wait(); err != nil { if err := errGroup.Wait(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }