浏览代码

Merge branch 'master' of https://github.com/v2ray/v2ray-core

Darien Raymond 8 年之前
父节点
当前提交
a8abd68574

+ 23 - 25
common/crypto/auth.go

@@ -2,20 +2,16 @@ package crypto
 
 
 import (
 import (
 	"crypto/cipher"
 	"crypto/cipher"
-	"errors"
 	"io"
 	"io"
 
 
 	"v2ray.com/core/common"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/buf"
+	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/serial"
 	"v2ray.com/core/common/serial"
 )
 )
 
 
 var (
 var (
-	ErrAuthenticationFailed = errors.New("Authentication failed.")
-
 	errInsufficientBuffer = errors.New("Insufficient buffer.")
 	errInsufficientBuffer = errors.New("Insufficient buffer.")
-	errInvalidNonce       = errors.New("Invalid nonce.")
-	errInvalidLength      = errors.New("Invalid buffer size.")
 )
 )
 
 
 type BytesGenerator interface {
 type BytesGenerator interface {
@@ -54,7 +50,7 @@ type AEADAuthenticator struct {
 func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
 func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
 	iv := v.NonceGenerator.Next()
 	iv := v.NonceGenerator.Next()
 	if len(iv) != v.AEAD.NonceSize() {
 	if len(iv) != v.AEAD.NonceSize() {
-		return nil, errInvalidNonce
+		return nil, errors.New("Crypto:AEADAuthenticator: Invalid nonce size: ", len(iv))
 	}
 	}
 
 
 	additionalData := v.AdditionalDataGenerator.Next()
 	additionalData := v.AdditionalDataGenerator.Next()
@@ -64,7 +60,7 @@ func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
 func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {
 func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {
 	iv := v.NonceGenerator.Next()
 	iv := v.NonceGenerator.Next()
 	if len(iv) != v.AEAD.NonceSize() {
 	if len(iv) != v.AEAD.NonceSize() {
-		return nil, errInvalidNonce
+		return nil, errors.New("Crypto:AEADAuthenticator: Invalid nonce size: ", len(iv))
 	}
 	}
 
 
 	additionalData := v.AdditionalDataGenerator.Next()
 	additionalData := v.AdditionalDataGenerator.Next()
@@ -100,13 +96,13 @@ func (v *AuthenticationReader) NextChunk() error {
 		return errInsufficientBuffer
 		return errInsufficientBuffer
 	}
 	}
 	if size > readerBufferSize-2 {
 	if size > readerBufferSize-2 {
-		return errInvalidLength
+		return errors.New("Crypto:AuthenticationReader: Size too large: ", size)
 	}
 	}
 	if size == v.auth.Overhead() {
 	if size == v.auth.Overhead() {
 		return io.EOF
 		return io.EOF
 	}
 	}
 	if size < v.auth.Overhead() {
 	if size < v.auth.Overhead() {
-		return errors.New("AuthenticationReader: invalid packet size.")
+		return errors.New("AuthenticationReader: invalid packet size:", size)
 	}
 	}
 	cipherChunk := v.buffer.BytesRange(2, size+2)
 	cipherChunk := v.buffer.BytesRange(2, size+2)
 	plainChunk, err := v.auth.Open(cipherChunk[:0], cipherChunk)
 	plainChunk, err := v.auth.Open(cipherChunk[:0], cipherChunk)
@@ -132,26 +128,28 @@ func (v *AuthenticationReader) CopyChunk(b []byte) int {
 }
 }
 
 
 func (v *AuthenticationReader) EnsureChunk() error {
 func (v *AuthenticationReader) EnsureChunk() error {
+	atHead := false
+	if v.buffer.IsEmpty() {
+		v.buffer.Clear()
+		atHead = true
+	}
+
 	for {
 	for {
 		err := v.NextChunk()
 		err := v.NextChunk()
-		if err == nil {
-			return nil
+		if err != errInsufficientBuffer {
+			return err
 		}
 		}
-		if err == errInsufficientBuffer {
-			if v.buffer.IsEmpty() {
-				v.buffer.Clear()
-			} else {
-				leftover := v.buffer.Bytes()
-				common.Must(v.buffer.Reset(func(b []byte) (int, error) {
-					return copy(b, leftover), nil
-				}))
-			}
-			err = v.buffer.AppendSupplier(buf.ReadFrom(v.reader))
-			if err == nil {
-				continue
-			}
+
+		leftover := v.buffer.Bytes()
+		if !atHead && len(leftover) > 0 {
+			common.Must(v.buffer.Reset(func(b []byte) (int, error) {
+				return copy(b, leftover), nil
+			}))
+		}
+
+		if err := v.buffer.AppendSupplier(buf.ReadFrom(v.reader)); err != nil {
+			return err
 		}
 		}
-		return err
 	}
 	}
 }
 }
 
 

+ 24 - 2
common/crypto/auth_test.go

@@ -7,6 +7,8 @@ import (
 	"io"
 	"io"
 	"testing"
 	"testing"
 
 
+	"time"
+
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/buf"
 	. "v2ray.com/core/common/crypto"
 	. "v2ray.com/core/common/crypto"
 	"v2ray.com/core/testing/assert"
 	"v2ray.com/core/testing/assert"
@@ -77,10 +79,10 @@ func TestAuthenticationReaderWriterPartial(t *testing.T) {
 	payload := make([]byte, 8*1024)
 	payload := make([]byte, 8*1024)
 	rand.Read(payload)
 	rand.Read(payload)
 
 
-	cache := buf.NewLocal(16 * 1024)
 	iv := make([]byte, 12)
 	iv := make([]byte, 12)
 	rand.Read(iv)
 	rand.Read(iv)
 
 
+	cache := buf.NewLocal(16 * 1024)
 	writer := NewAuthenticationWriter(&AEADAuthenticator{
 	writer := NewAuthenticationWriter(&AEADAuthenticator{
 		AEAD: aead,
 		AEAD: aead,
 		NonceGenerator: &StaticBytesGenerator{
 		NonceGenerator: &StaticBytesGenerator{
@@ -89,6 +91,8 @@ func TestAuthenticationReaderWriterPartial(t *testing.T) {
 		AdditionalDataGenerator: &NoOpBytesGenerator{},
 		AdditionalDataGenerator: &NoOpBytesGenerator{},
 	}, cache)
 	}, cache)
 
 
+	writer.Write([]byte{'a', 'b', 'c', 'd'})
+
 	nBytes, err := writer.Write(payload)
 	nBytes, err := writer.Write(payload)
 	assert.Error(err).IsNil()
 	assert.Error(err).IsNil()
 	assert.Int(nBytes).Equals(len(payload))
 	assert.Int(nBytes).Equals(len(payload))
@@ -96,17 +100,35 @@ func TestAuthenticationReaderWriterPartial(t *testing.T) {
 	_, err = writer.Write([]byte{})
 	_, err = writer.Write([]byte{})
 	assert.Error(err).IsNil()
 	assert.Error(err).IsNil()
 
 
+	pr, pw := io.Pipe()
+	go func() {
+		pw.Write(cache.BytesTo(1024))
+		time.Sleep(time.Second * 2)
+		pw.Write(cache.BytesRange(1024, 2048))
+		time.Sleep(time.Second * 2)
+		pw.Write(cache.BytesRange(2048, 3072))
+		time.Sleep(time.Second * 2)
+		pw.Write(cache.BytesFrom(3072))
+		time.Sleep(time.Second * 2)
+		pw.Close()
+	}()
+
 	reader := NewAuthenticationReader(&AEADAuthenticator{
 	reader := NewAuthenticationReader(&AEADAuthenticator{
 		AEAD: aead,
 		AEAD: aead,
 		NonceGenerator: &StaticBytesGenerator{
 		NonceGenerator: &StaticBytesGenerator{
 			Content: iv,
 			Content: iv,
 		},
 		},
 		AdditionalDataGenerator: &NoOpBytesGenerator{},
 		AdditionalDataGenerator: &NoOpBytesGenerator{},
-	}, cache)
+	}, pr)
 
 
 	actualPayload := make([]byte, 7*1024)
 	actualPayload := make([]byte, 7*1024)
 	nBytes, err = reader.Read(actualPayload)
 	nBytes, err = reader.Read(actualPayload)
 	assert.Error(err).IsNil()
 	assert.Error(err).IsNil()
+	assert.Int(nBytes).Equals(4)
+	assert.Bytes(actualPayload[:nBytes]).Equals([]byte{'a', 'b', 'c', 'd'})
+
+	nBytes, err = reader.Read(actualPayload)
+	assert.Error(err).IsNil()
 	assert.Int(nBytes).Equals(len(actualPayload))
 	assert.Int(nBytes).Equals(len(actualPayload))
 	assert.Bytes(actualPayload[:nBytes]).Equals(payload[:nBytes])
 	assert.Bytes(actualPayload[:nBytes]).Equals(payload[:nBytes])
 
 

+ 2 - 2
proxy/vmess/encoding/auth.go

@@ -2,9 +2,9 @@ package encoding
 
 
 import (
 import (
 	"crypto/md5"
 	"crypto/md5"
+	"errors"
 	"hash/fnv"
 	"hash/fnv"
 
 
-	"v2ray.com/core/common/crypto"
 	"v2ray.com/core/common/serial"
 	"v2ray.com/core/common/serial"
 )
 )
 
 
@@ -58,7 +58,7 @@ func (v *FnvAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []
 // Open implements AEAD.Open().
 // Open implements AEAD.Open().
 func (v *FnvAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
 func (v *FnvAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
 	if serial.BytesToUint32(ciphertext[:4]) != Authenticate(ciphertext[4:]) {
 	if serial.BytesToUint32(ciphertext[:4]) != Authenticate(ciphertext[4:]) {
-		return dst, crypto.ErrAuthenticationFailed
+		return dst, errors.New("VMess|FNV: Invalid authentication.")
 	}
 	}
 	return append(dst, ciphertext[4:]...), nil
 	return append(dst, ciphertext[4:]...), nil
 }
 }

+ 1 - 1
testing/scenarios/common.go

@@ -29,7 +29,7 @@ func xor(b []byte) []byte {
 }
 }
 
 
 func readFrom(conn net.Conn, timeout time.Duration, length int) []byte {
 func readFrom(conn net.Conn, timeout time.Duration, length int) []byte {
-	b := make([]byte, 2048)
+	b := make([]byte, length)
 	deadline := time.Now().Add(timeout)
 	deadline := time.Now().Add(timeout)
 	conn.SetReadDeadline(deadline)
 	conn.SetReadDeadline(deadline)
 	n, _ := io.ReadFull(conn, b[:length])
 	n, _ := io.ReadFull(conn, b[:length])

+ 0 - 43
testing/scenarios/data/test_4_client.json

@@ -1,43 +0,0 @@
-{
-  "port": 50030,
-  "log": {
-    "loglevel": "debug"
-  },
-  "inbound": {
-    "listen": "127.0.0.1",
-    "protocol": "dokodemo-door",
-    "settings": {
-      "address": "127.0.0.1",
-      "port": 50032,
-      "network": "tcp",
-      "timeout": 0
-    }
-  },
-  "outbound": {
-    "protocol": "vmess",
-    "streamSettings": {
-      "network": "kcp"
-    },
-    "settings": {
-      "vnext": [
-        {
-          "address": "127.0.0.1",
-          "port": 50031,
-          "users": [
-            {
-              "id": "d17a1af7-efa5-42ca-b7e9-6a35282d737f",
-              "alterId": 10
-            }
-          ]
-        }
-      ]
-    }
-  },
-  "transport": {
-    "kcpSettings": {
-      "header": {
-        "type": "srtp"
-      }
-    }
-  }
-}

+ 0 - 53
testing/scenarios/data/test_4_server.json

@@ -1,53 +0,0 @@
-{
-  "port": 50031,
-  "log": {
-    "loglevel": "debug"
-  },
-  "inbound": {
-    "listen": "127.0.0.1",
-    "protocol": "vmess",
-    "streamSettings": {
-      "network": "kcp"
-    },
-    "settings": {
-      "clients": [
-        {
-          "id": "d17a1af7-efa5-42ca-b7e9-6a35282d737f",
-          "level": 1,
-          "alterId": 10
-        }
-      ],
-      "detour": {
-        "to": "detour"
-      }
-    }
-  },
-  "outbound": {
-    "protocol": "freedom",
-    "settings": {}
-  },
-  "inboundDetour": [
-    {
-      "protocol": "vmess",
-      "listen": "127.0.0.1",
-      "port": "50035-50039",
-      "tag": "detour",
-      "settings": {},
-      "streamSettings": {
-      "network": "kcp"
-    },
-      "allocate": {
-        "strategy": "random",
-        "concurrency": 2,
-        "refresh": 5
-      }
-    }
-  ],
-  "transport": {
-    "kcpSettings": {
-      "header": {
-        "type": "srtp"
-      }
-    }
-  }
-}

+ 0 - 51
testing/scenarios/dynamic_vmess_test.go

@@ -1,51 +0,0 @@
-package scenarios
-
-import (
-	"net"
-	"testing"
-	"time"
-
-	v2net "v2ray.com/core/common/net"
-	"v2ray.com/core/testing/assert"
-	"v2ray.com/core/testing/servers/tcp"
-)
-
-func TestDynamicVMess(t *testing.T) {
-	assert := assert.On(t)
-
-	tcpServer := &tcp.Server{
-		Port: v2net.Port(50032),
-		MsgProcessor: func(data []byte) []byte {
-			buffer := make([]byte, 0, 2048)
-			buffer = append(buffer, []byte("Processed: ")...)
-			buffer = append(buffer, data...)
-			return buffer
-		},
-	}
-	_, err := tcpServer.Start()
-	assert.Error(err).IsNil()
-	defer tcpServer.Close()
-
-	assert.Error(InitializeServerSetOnce("test_4")).IsNil()
-
-	for i := 0; i < 100; i++ {
-		conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
-			IP:   []byte{127, 0, 0, 1},
-			Port: 50030,
-		})
-		assert.Error(err).IsNil()
-
-		payload := "dokodemo request."
-		nBytes, err := conn.Write([]byte(payload))
-		assert.Error(err).IsNil()
-		assert.Int(nBytes).Equals(len(payload))
-
-		expectedResponse := "Processed: " + payload
-		response := readFrom(conn, time.Second, len(expectedResponse))
-		assert.String(string(response)).Equals(expectedResponse)
-
-		conn.Close()
-	}
-
-	CloseAllServers()
-}

+ 662 - 0
testing/scenarios/vmess_test.go

@@ -0,0 +1,662 @@
+package scenarios
+
+import (
+	"crypto/rand"
+	"net"
+	"testing"
+
+	"time"
+
+	"sync"
+
+	"v2ray.com/core"
+	"v2ray.com/core/app/log"
+	"v2ray.com/core/app/proxyman"
+	v2net "v2ray.com/core/common/net"
+	"v2ray.com/core/common/protocol"
+	"v2ray.com/core/common/serial"
+	"v2ray.com/core/common/uuid"
+	"v2ray.com/core/proxy/dokodemo"
+	"v2ray.com/core/proxy/freedom"
+	"v2ray.com/core/proxy/vmess"
+	"v2ray.com/core/proxy/vmess/inbound"
+	"v2ray.com/core/proxy/vmess/outbound"
+	"v2ray.com/core/testing/assert"
+	"v2ray.com/core/testing/servers/tcp"
+	"v2ray.com/core/transport/internet"
+)
+
+func TestVMessDynamicPort(t *testing.T) {
+	assert := assert.On(t)
+
+	tcpServer := tcp.Server{
+		MsgProcessor: xor,
+	}
+	dest, err := tcpServer.Start()
+	assert.Error(err).IsNil()
+	defer tcpServer.Close()
+
+	userID := protocol.NewID(uuid.New())
+	serverPort := pickPort()
+	serverConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(serverPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&inbound.Config{
+					User: []*protocol.User{
+						{
+							Account: serial.ToTypedMessage(&vmess.Account{
+								Id: userID.String(),
+							}),
+						},
+					},
+					Detour: &inbound.DetourConfig{
+						To: "detour",
+					},
+				}),
+			},
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: &v2net.PortRange{
+						From: uint32(serverPort + 1),
+						To:   uint32(serverPort + 100),
+					},
+					Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
+					AllocationStrategy: &proxyman.AllocationStrategy{
+						Type: proxyman.AllocationStrategy_Random,
+						Concurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
+							Value: 2,
+						},
+						Refresh: &proxyman.AllocationStrategy_AllocationStrategyRefresh{
+							Value: 5,
+						},
+					},
+				}),
+				ProxySettings: serial.ToTypedMessage(&inbound.Config{}),
+				Tag:           "detour",
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	clientPort := pickPort()
+	clientConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(clientPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
+					Address: v2net.NewIPOrDomain(dest.Address),
+					Port:    uint32(dest.Port),
+					NetworkList: &v2net.NetworkList{
+						Network: []v2net.Network{v2net.Network_TCP},
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&outbound.Config{
+					Receiver: []*protocol.ServerEndpoint{
+						{
+							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
+							Port:    uint32(serverPort),
+							User: []*protocol.User{
+								{
+									Account: serial.ToTypedMessage(&vmess.Account{
+										Id: userID.String(),
+									}),
+								},
+							},
+						},
+					},
+				}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
+	assert.Error(InitializeServerConfig(clientConfig)).IsNil()
+
+	for i := 0; i < 10; i++ {
+		conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
+			IP:   []byte{127, 0, 0, 1},
+			Port: int(clientPort),
+		})
+		assert.Error(err).IsNil()
+
+		payload := "dokodemo request."
+		nBytes, err := conn.Write([]byte(payload))
+		assert.Error(err).IsNil()
+		assert.Int(nBytes).Equals(len(payload))
+
+		response := make([]byte, 1024)
+		nBytes, err = conn.Read(response)
+		assert.Error(err).IsNil()
+		assert.Bytes(response[:nBytes]).Equals(xor([]byte(payload)))
+		assert.Error(conn.Close()).IsNil()
+	}
+
+	CloseAllServers()
+}
+
+func TestVMessGCM(t *testing.T) {
+	assert := assert.On(t)
+
+	tcpServer := tcp.Server{
+		MsgProcessor: xor,
+	}
+	dest, err := tcpServer.Start()
+	assert.Error(err).IsNil()
+	defer tcpServer.Close()
+
+	userID := protocol.NewID(uuid.New())
+	serverPort := pickPort()
+	serverConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(serverPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&inbound.Config{
+					User: []*protocol.User{
+						{
+							Account: serial.ToTypedMessage(&vmess.Account{
+								Id:      userID.String(),
+								AlterId: 64,
+							}),
+						},
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	clientPort := pickPort()
+	clientConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(clientPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
+					Address: v2net.NewIPOrDomain(dest.Address),
+					Port:    uint32(dest.Port),
+					NetworkList: &v2net.NetworkList{
+						Network: []v2net.Network{v2net.Network_TCP},
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&outbound.Config{
+					Receiver: []*protocol.ServerEndpoint{
+						{
+							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
+							Port:    uint32(serverPort),
+							User: []*protocol.User{
+								{
+									Account: serial.ToTypedMessage(&vmess.Account{
+										Id:      userID.String(),
+										AlterId: 64,
+										SecuritySettings: &protocol.SecurityConfig{
+											Type: protocol.SecurityType_AES128_GCM,
+										},
+									}),
+								},
+							},
+						},
+					},
+				}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
+	assert.Error(InitializeServerConfig(clientConfig)).IsNil()
+
+	var wg sync.WaitGroup
+	wg.Add(10)
+	for i := 0; i < 10; i++ {
+		go func() {
+			conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
+				IP:   []byte{127, 0, 0, 1},
+				Port: int(clientPort),
+			})
+			assert.Error(err).IsNil()
+
+			payload := make([]byte, 10240*1024)
+			rand.Read(payload)
+
+			nBytes, err := conn.Write([]byte(payload))
+			assert.Error(err).IsNil()
+			assert.Int(nBytes).Equals(len(payload))
+
+			response := readFrom(conn, time.Second*10, 10240*1024)
+			assert.Bytes(response).Equals(xor([]byte(payload)))
+			assert.Error(conn.Close()).IsNil()
+			wg.Done()
+		}()
+	}
+	wg.Wait()
+
+	CloseAllServers()
+}
+
+func TestVMessChacha20(t *testing.T) {
+	assert := assert.On(t)
+
+	tcpServer := tcp.Server{
+		MsgProcessor: xor,
+	}
+	dest, err := tcpServer.Start()
+	assert.Error(err).IsNil()
+	defer tcpServer.Close()
+
+	userID := protocol.NewID(uuid.New())
+	serverPort := pickPort()
+	serverConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(serverPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&inbound.Config{
+					User: []*protocol.User{
+						{
+							Account: serial.ToTypedMessage(&vmess.Account{
+								Id:      userID.String(),
+								AlterId: 64,
+							}),
+						},
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	clientPort := pickPort()
+	clientConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(clientPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
+					Address: v2net.NewIPOrDomain(dest.Address),
+					Port:    uint32(dest.Port),
+					NetworkList: &v2net.NetworkList{
+						Network: []v2net.Network{v2net.Network_TCP},
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&outbound.Config{
+					Receiver: []*protocol.ServerEndpoint{
+						{
+							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
+							Port:    uint32(serverPort),
+							User: []*protocol.User{
+								{
+									Account: serial.ToTypedMessage(&vmess.Account{
+										Id:      userID.String(),
+										AlterId: 64,
+										SecuritySettings: &protocol.SecurityConfig{
+											Type: protocol.SecurityType_CHACHA20_POLY1305,
+										},
+									}),
+								},
+							},
+						},
+					},
+				}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
+	assert.Error(InitializeServerConfig(clientConfig)).IsNil()
+
+	var wg sync.WaitGroup
+	wg.Add(10)
+	for i := 0; i < 10; i++ {
+		go func() {
+			conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
+				IP:   []byte{127, 0, 0, 1},
+				Port: int(clientPort),
+			})
+			assert.Error(err).IsNil()
+
+			payload := make([]byte, 10240*1024)
+			rand.Read(payload)
+
+			nBytes, err := conn.Write([]byte(payload))
+			assert.Error(err).IsNil()
+			assert.Int(nBytes).Equals(len(payload))
+
+			response := readFrom(conn, time.Second*10, 10240*1024)
+			assert.Bytes(response).Equals(xor([]byte(payload)))
+			assert.Error(conn.Close()).IsNil()
+			wg.Done()
+		}()
+	}
+	wg.Wait()
+
+	CloseAllServers()
+}
+
+func TestVMessNone(t *testing.T) {
+	assert := assert.On(t)
+
+	tcpServer := tcp.Server{
+		MsgProcessor: xor,
+	}
+	dest, err := tcpServer.Start()
+	assert.Error(err).IsNil()
+	defer tcpServer.Close()
+
+	userID := protocol.NewID(uuid.New())
+	serverPort := pickPort()
+	serverConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(serverPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&inbound.Config{
+					User: []*protocol.User{
+						{
+							Account: serial.ToTypedMessage(&vmess.Account{
+								Id:      userID.String(),
+								AlterId: 64,
+							}),
+						},
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	clientPort := pickPort()
+	clientConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(clientPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
+					Address: v2net.NewIPOrDomain(dest.Address),
+					Port:    uint32(dest.Port),
+					NetworkList: &v2net.NetworkList{
+						Network: []v2net.Network{v2net.Network_TCP},
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&outbound.Config{
+					Receiver: []*protocol.ServerEndpoint{
+						{
+							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
+							Port:    uint32(serverPort),
+							User: []*protocol.User{
+								{
+									Account: serial.ToTypedMessage(&vmess.Account{
+										Id:      userID.String(),
+										AlterId: 64,
+										SecuritySettings: &protocol.SecurityConfig{
+											Type: protocol.SecurityType_NONE,
+										},
+									}),
+								},
+							},
+						},
+					},
+				}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
+	assert.Error(InitializeServerConfig(clientConfig)).IsNil()
+
+	var wg sync.WaitGroup
+	wg.Add(10)
+	for i := 0; i < 10; i++ {
+		go func() {
+			conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
+				IP:   []byte{127, 0, 0, 1},
+				Port: int(clientPort),
+			})
+			assert.Error(err).IsNil()
+
+			payload := make([]byte, 10240*1024)
+			rand.Read(payload)
+
+			nBytes, err := conn.Write([]byte(payload))
+			assert.Error(err).IsNil()
+			assert.Int(nBytes).Equals(len(payload))
+
+			response := readFrom(conn, time.Second*10, 10240*1024)
+			assert.Bytes(response).Equals(xor([]byte(payload)))
+			assert.Error(conn.Close()).IsNil()
+			wg.Done()
+		}()
+	}
+	wg.Wait()
+
+	CloseAllServers()
+}
+
+func TestVMessKCP(t *testing.T) {
+	assert := assert.On(t)
+
+	tcpServer := tcp.Server{
+		MsgProcessor: xor,
+	}
+	dest, err := tcpServer.Start()
+	assert.Error(err).IsNil()
+	defer tcpServer.Close()
+
+	userID := protocol.NewID(uuid.New())
+	serverPort := pickPort()
+	serverConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(serverPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+					StreamSettings: &internet.StreamConfig{
+						Protocol: internet.TransportProtocol_MKCP,
+					},
+				}),
+				ProxySettings: serial.ToTypedMessage(&inbound.Config{
+					User: []*protocol.User{
+						{
+							Account: serial.ToTypedMessage(&vmess.Account{
+								Id:      userID.String(),
+								AlterId: 64,
+							}),
+						},
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	clientPort := pickPort()
+	clientConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: v2net.SinglePortRange(clientPort),
+					Listen:    v2net.NewIPOrDomain(v2net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
+					Address: v2net.NewIPOrDomain(dest.Address),
+					Port:    uint32(dest.Port),
+					NetworkList: &v2net.NetworkList{
+						Network: []v2net.Network{v2net.Network_TCP},
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&outbound.Config{
+					Receiver: []*protocol.ServerEndpoint{
+						{
+							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
+							Port:    uint32(serverPort),
+							User: []*protocol.User{
+								{
+									Account: serial.ToTypedMessage(&vmess.Account{
+										Id:      userID.String(),
+										AlterId: 64,
+										SecuritySettings: &protocol.SecurityConfig{
+											Type: protocol.SecurityType_AES128_GCM,
+										},
+									}),
+								},
+							},
+						},
+					},
+				}),
+				SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
+					StreamSettings: &internet.StreamConfig{
+						Protocol: internet.TransportProtocol_MKCP,
+					},
+				}),
+			},
+		},
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{
+				ErrorLogLevel: log.LogLevel_Debug,
+				ErrorLogType:  log.LogType_Console,
+			}),
+		},
+	}
+
+	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
+	assert.Error(InitializeServerConfig(clientConfig)).IsNil()
+
+	var wg sync.WaitGroup
+	wg.Add(10)
+	for i := 0; i < 10; i++ {
+		go func() {
+			conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
+				IP:   []byte{127, 0, 0, 1},
+				Port: int(clientPort),
+			})
+			assert.Error(err).IsNil()
+
+			payload := make([]byte, 10240*1024)
+			rand.Read(payload)
+
+			nBytes, err := conn.Write([]byte(payload))
+			assert.Error(err).IsNil()
+			assert.Int(nBytes).Equals(len(payload))
+
+			response := readFrom(conn, time.Second*10, 10240*1024)
+			assert.Bytes(response).Equals(xor([]byte(payload)))
+			assert.Error(conn.Close()).IsNil()
+			wg.Done()
+		}()
+	}
+	wg.Wait()
+
+	CloseAllServers()
+}

+ 3 - 3
transport/internet/kcp/crypt.go

@@ -2,9 +2,9 @@ package kcp
 
 
 import (
 import (
 	"crypto/cipher"
 	"crypto/cipher"
+	"errors"
 	"hash/fnv"
 	"hash/fnv"
 
 
-	"v2ray.com/core/common/crypto"
 	"v2ray.com/core/common/serial"
 	"v2ray.com/core/common/serial"
 )
 )
 
 
@@ -64,12 +64,12 @@ func (v *SimpleAuthenticator) Open(dst, nonce, cipherText, extra []byte) ([]byte
 	fnvHash := fnv.New32a()
 	fnvHash := fnv.New32a()
 	fnvHash.Write(dst[4:])
 	fnvHash.Write(dst[4:])
 	if serial.BytesToUint32(dst[:4]) != fnvHash.Sum32() {
 	if serial.BytesToUint32(dst[:4]) != fnvHash.Sum32() {
-		return nil, crypto.ErrAuthenticationFailed
+		return nil, errors.New("KCP:SimpleAuthenticator: Invalid auth.")
 	}
 	}
 
 
 	length := serial.BytesToUint16(dst[4:6])
 	length := serial.BytesToUint16(dst[4:6])
 	if len(dst)-6 != int(length) {
 	if len(dst)-6 != int(length) {
-		return nil, crypto.ErrAuthenticationFailed
+		return nil, errors.New("KCP:SimpleAuthenticator: Invalid auth.")
 	}
 	}
 
 
 	return dst[6:], nil
 	return dst[6:], nil