Browse Source

remove deprecate ciphers in shadowsocks (#566)

* remove deprecate ciphers in shadowsocks
Kslr 4 years ago
parent
commit
42f0f5dfec

+ 0 - 8
infra/conf/shadowsocks.go

@@ -12,14 +12,6 @@ import (
 
 func cipherFromString(c string) shadowsocks.CipherType {
 	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":
 		return shadowsocks.CipherType_AES_128_GCM
 	case "aes-256-gcm", "aead_aes_256_gcm":

+ 2 - 2
infra/conf/shadowsocks_test.go

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

+ 10 - 109
proxy/shadowsocks/config.go

@@ -39,22 +39,14 @@ func createAesGcm(key []byte) cipher.AEAD {
 	return gcm
 }
 
-func createChacha20Poly1305(key []byte) cipher.AEAD {
-	chacha20, err := chacha20poly1305.New(key)
+func createChaCha20Poly1305(key []byte) cipher.AEAD {
+	ChaChaPoly1305, err := chacha20poly1305.New(key)
 	common.Must(err)
-	return chacha20
+	return ChaChaPoly1305
 }
 
 func (a *Account) getCipher() (Cipher, error) {
 	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:
 		return &AEADCipher{
 			KeyBytes:        16,
@@ -71,7 +63,7 @@ func (a *Account) getCipher() (Cipher, error) {
 		return &AEADCipher{
 			KeyBytes:        32,
 			IVBytes:         32,
-			AEADAuthCreator: createChacha20Poly1305,
+			AEADAuthCreator: createChaCha20Poly1305,
 		}, nil
 	case CipherType_NONE:
 		return NoneCipher{}, nil
@@ -82,13 +74,13 @@ func (a *Account) getCipher() (Cipher, error) {
 
 // AsAccount implements protocol.AsAccount.
 func (a *Account) AsAccount() (protocol.Account, error) {
-	cipher, err := a.getCipher()
+	Cipher, err := a.getCipher()
 	if err != nil {
 		return nil, newError("failed to get cipher").Base(err)
 	}
 	return &MemoryAccount{
-		Cipher: cipher,
-		Key:    passwordToCipherKey([]byte(a.Password), cipher.KeySize()),
+		Cipher: Cipher,
+		Key:    passwordToCipherKey([]byte(a.Password), Cipher.KeySize()),
 	}, nil
 }
 
@@ -103,53 +95,6 @@ type Cipher interface {
 	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 {
 	KeyBytes        int32
 	IVBytes         int32
@@ -218,56 +163,12 @@ func (c *AEADCipher) DecodePacket(key []byte, b *buf.Buffer) error {
 	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{}
 
 func (NoneCipher) KeySize() int32 { return 0 }
 func (NoneCipher) IVSize() int32  { return 0 }
 func (NoneCipher) IsAEAD() bool {
-	return true // to avoid OTA
+	return false
 }
 
 func (NoneCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
@@ -303,7 +204,7 @@ func passwordToCipherKey(password []byte, keySize int32) []byte {
 	return key
 }
 
-func hkdfSHA1(secret, salt, outkey []byte) {
+func hkdfSHA1(secret, salt, outKey []byte) {
 	r := hkdf.New(sha1.New, secret, salt, []byte("ss-subkey"))
-	common.Must2(io.ReadFull(r, outkey))
+	common.Must2(io.ReadFull(r, outKey))
 }

+ 26 - 43
proxy/shadowsocks/config.pb.go

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

+ 4 - 8
proxy/shadowsocks/config.proto

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

+ 22 - 16
proxy/shadowsocks/protocol_test.go

@@ -18,6 +18,12 @@ func toAccount(a *Account) protocol.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) {
 	request := &protocol.RequestHeader{
 		Version: Version,
@@ -25,10 +31,10 @@ func TestUDPEncoding(t *testing.T) {
 		Address: net.LocalHostIP,
 		Port:    1234,
 		User: &protocol.MemoryUser{
-			Email: "love@v2ray.com",
+			Email: "love@v2fly.org",
 			Account: toAccount(&Account{
-				Password:   "shadowsocks-password",
-				CipherType: CipherType_AES_128_CFB,
+				Password:   "password",
+				CipherType: CipherType_AES_128_GCM,
 			}),
 		},
 	}
@@ -45,8 +51,8 @@ func TestUDPEncoding(t *testing.T) {
 		t.Error("data: ", r)
 	}
 
-	if r := cmp.Diff(decodedRequest, request); r != "" {
-		t.Error("request: ", r)
+	if equalRequestHeader(decodedRequest, request) == false {
+		t.Error("different request")
 	}
 }
 
@@ -62,10 +68,10 @@ func TestTCPRequest(t *testing.T) {
 				Address: net.LocalHostIP,
 				Port:    1234,
 				User: &protocol.MemoryUser{
-					Email: "love@v2ray.com",
+					Email: "love@v2fly.org",
 					Account: toAccount(&Account{
 						Password:   "tcp-password",
-						CipherType: CipherType_CHACHA20,
+						CipherType: CipherType_AES_128_GCM,
 					}),
 				},
 			},
@@ -78,10 +84,10 @@ func TestTCPRequest(t *testing.T) {
 				Address: net.LocalHostIPv6,
 				Port:    1234,
 				User: &protocol.MemoryUser{
-					Email: "love@v2ray.com",
+					Email: "love@v2fly.org",
 					Account: toAccount(&Account{
 						Password:   "password",
-						CipherType: CipherType_AES_256_CFB,
+						CipherType: CipherType_AES_256_GCM,
 					}),
 				},
 			},
@@ -91,13 +97,13 @@ func TestTCPRequest(t *testing.T) {
 			request: &protocol.RequestHeader{
 				Version: Version,
 				Command: protocol.RequestCommandTCP,
-				Address: net.DomainAddress("v2ray.com"),
+				Address: net.DomainAddress("v2fly.org"),
 				Port:    1234,
 				User: &protocol.MemoryUser{
-					Email: "love@v2ray.com",
+					Email: "love@v2fly.org",
 					Account: toAccount(&Account{
 						Password:   "password",
-						CipherType: CipherType_CHACHA20_IETF,
+						CipherType: CipherType_CHACHA20_POLY1305,
 					}),
 				},
 			},
@@ -119,8 +125,8 @@ func TestTCPRequest(t *testing.T) {
 
 		decodedRequest, reader, err := ReadTCPSession(request.User, cache)
 		common.Must(err)
-		if r := cmp.Diff(decodedRequest, request); r != "" {
-			t.Error("request: ", r)
+		if equalRequestHeader(decodedRequest, request) == false {
+			t.Error("different request")
 		}
 
 		decodedData, err := reader.ReadMultiBuffer()
@@ -139,7 +145,7 @@ func TestUDPReaderWriter(t *testing.T) {
 	user := &protocol.MemoryUser{
 		Account: toAccount(&Account{
 			Password:   "test-password",
-			CipherType: CipherType_CHACHA20_IETF,
+			CipherType: CipherType_CHACHA20_POLY1305,
 		}),
 	}
 	cache := buf.New()
@@ -149,7 +155,7 @@ func TestUDPReaderWriter(t *testing.T) {
 		Writer: cache,
 		Request: &protocol.RequestHeader{
 			Version: Version,
-			Address: net.DomainAddress("v2ray.com"),
+			Address: net.DomainAddress("v2fly.org"),
 			Port:    123,
 			User:    user,
 		},

+ 21 - 357
testing/scenarios/shadowsocks_test.go

@@ -1,18 +1,15 @@
 package scenarios
 
 import (
-	"crypto/rand"
 	"testing"
 	"time"
 
-	"github.com/google/go-cmp/cmp"
 	"golang.org/x/sync/errgroup"
 
 	"v2ray.com/core"
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/app/proxyman"
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/errors"
 	clog "v2ray.com/core/common/log"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
@@ -24,330 +21,7 @@ import (
 	"v2ray.com/core/testing/servers/udp"
 )
 
-func TestShadowsocksAES256TCP(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{
-					User: &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{
-					User: &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{
-					User: &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) {
+func TestShadowsocksChaCha20Poly1305TCP(t *testing.T) {
 	tcpServer := tcp.Server{
 		MsgProcessor: xor,
 	}
@@ -395,9 +69,7 @@ func TestShadowsocksChacha20Poly1305TCP(t *testing.T) {
 				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
 					Address: net.NewIPOrDomain(dest.Address),
 					Port:    uint32(dest.Port),
-					NetworkList: &net.NetworkList{
-						Network: []net.Network{net.Network_TCP},
-					},
+					Networks: []net.Network{net.Network_TCP},
 				}),
 			},
 		},
@@ -424,11 +96,11 @@ func TestShadowsocksChacha20Poly1305TCP(t *testing.T) {
 	common.Must(err)
 	defer CloseAllServers(servers)
 
-	var errg errgroup.Group
+	var errGroup errgroup.Group
 	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)
 	}
 }
@@ -493,9 +165,7 @@ func TestShadowsocksAES256GCMTCP(t *testing.T) {
 				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
 					Address: net.NewIPOrDomain(dest.Address),
 					Port:    uint32(dest.Port),
-					NetworkList: &net.NetworkList{
-						Network: []net.Network{net.Network_TCP},
-					},
+					Networks: []net.Network{net.Network_TCP},
 				}),
 			},
 		},
@@ -522,12 +192,12 @@ func TestShadowsocksAES256GCMTCP(t *testing.T) {
 	common.Must(err)
 	defer CloseAllServers(servers)
 
-	var errg errgroup.Group
+	var errGroup errgroup.Group
 	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)
 	}
 }
@@ -592,9 +262,7 @@ func TestShadowsocksAES128GCMUDP(t *testing.T) {
 				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
 					Address: net.NewIPOrDomain(dest.Address),
 					Port:    uint32(dest.Port),
-					NetworkList: &net.NetworkList{
-						Network: []net.Network{net.Network_UDP},
-					},
+					Networks: []net.Network{net.Network_UDP},
 				}),
 			},
 		},
@@ -621,11 +289,11 @@ func TestShadowsocksAES128GCMUDP(t *testing.T) {
 	common.Must(err)
 	defer CloseAllServers(servers)
 
-	var errg errgroup.Group
+	var errGroup errgroup.Group
 	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)
 	}
 }
@@ -690,9 +358,7 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
 				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
 					Address: net.NewIPOrDomain(dest.Address),
 					Port:    uint32(dest.Port),
-					NetworkList: &net.NetworkList{
-						Network: []net.Network{net.Network_UDP},
-					},
+					Networks: []net.Network{net.Network_UDP},
 				}),
 			},
 		},
@@ -725,11 +391,11 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
 	common.Must(err)
 	defer CloseAllServers(servers)
 
-	var errg errgroup.Group
+	var errGroup errgroup.Group
 	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)
 	}
 }
@@ -783,9 +449,7 @@ func TestShadowsocksNone(t *testing.T) {
 				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
 					Address: net.NewIPOrDomain(dest.Address),
 					Port:    uint32(dest.Port),
-					NetworkList: &net.NetworkList{
-						Network: []net.Network{net.Network_TCP},
-					},
+					Networks: []net.Network{net.Network_TCP},
 				}),
 			},
 		},
@@ -813,12 +477,12 @@ func TestShadowsocksNone(t *testing.T) {
 
 	defer CloseAllServers(servers)
 
-	var errg errgroup.Group
+	var errGroup errgroup.Group
 	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)
 	}
 }