mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-15 01:09:20 +02:00
VMess AEAD based packet length
(cherry picked from commit 08221600082a79376bdc262f2ffec1a3129ae98d)
This commit is contained in:
parent
5bf2b31883
commit
778876df9e
|
@ -38,6 +38,8 @@ const (
|
||||||
RequestOptionChunkMasking bitmask.Byte = 0x04
|
RequestOptionChunkMasking bitmask.Byte = 0x04
|
||||||
|
|
||||||
RequestOptionGlobalPadding bitmask.Byte = 0x08
|
RequestOptionGlobalPadding bitmask.Byte = 0x08
|
||||||
|
|
||||||
|
RequestOptionAuthenticatedLength bitmask.Byte = 0x10
|
||||||
)
|
)
|
||||||
|
|
||||||
type RequestHeader struct {
|
type RequestHeader struct {
|
||||||
|
|
|
@ -18,6 +18,7 @@ type VMessAccount struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
AlterIds uint16 `json:"alterId"`
|
AlterIds uint16 `json:"alterId"`
|
||||||
Security string `json:"security"`
|
Security string `json:"security"`
|
||||||
|
Experiments string `json:"experiments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
|
@ -43,6 +44,7 @@ func (a *VMessAccount) Build() *vmess.Account {
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
Type: st,
|
Type: st,
|
||||||
},
|
},
|
||||||
|
TestsEnabled: a.Experiments,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package vmess
|
package vmess
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/dice"
|
"github.com/xtls/xray-core/common/dice"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
|
@ -14,6 +16,8 @@ type MemoryAccount struct {
|
||||||
AlterIDs []*protocol.ID
|
AlterIDs []*protocol.ID
|
||||||
// Security type of the account. Used for client connections.
|
// Security type of the account. Used for client connections.
|
||||||
Security protocol.SecurityType
|
Security protocol.SecurityType
|
||||||
|
|
||||||
|
AuthenticatedLengthExperiment bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnyValidID returns an ID that is either the main ID or one of the alternative IDs if any.
|
// AnyValidID returns an ID that is either the main ID or one of the alternative IDs if any.
|
||||||
|
@ -41,9 +45,14 @@ func (a *Account) AsAccount() (protocol.Account, error) {
|
||||||
return nil, newError("failed to parse ID").Base(err).AtError()
|
return nil, newError("failed to parse ID").Base(err).AtError()
|
||||||
}
|
}
|
||||||
protoID := protocol.NewID(id)
|
protoID := protocol.NewID(id)
|
||||||
|
var AuthenticatedLength bool
|
||||||
|
if strings.Contains(a.TestsEnabled, "AuthenticatedLength") {
|
||||||
|
AuthenticatedLength = true
|
||||||
|
}
|
||||||
return &MemoryAccount{
|
return &MemoryAccount{
|
||||||
ID: protoID,
|
ID: protoID,
|
||||||
AlterIDs: protocol.NewAlterIDs(protoID, uint16(a.AlterId)),
|
AlterIDs: protocol.NewAlterIDs(protoID, uint16(a.AlterId)),
|
||||||
Security: a.SecuritySettings.GetSecurityType(),
|
Security: a.SecuritySettings.GetSecurityType(),
|
||||||
|
AuthenticatedLengthExperiment: AuthenticatedLength,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/crypto"
|
||||||
|
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -116,3 +118,11 @@ func (s *ShakeSizeParser) NextPaddingLen() uint16 {
|
||||||
func (s *ShakeSizeParser) MaxPaddingLen() uint16 {
|
func (s *ShakeSizeParser) MaxPaddingLen() uint16 {
|
||||||
return 64
|
return 64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AEADSizeParser struct {
|
||||||
|
crypto.AEADChunkSizeParser
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAEADSizeParser(auth *crypto.AEADAuthenticator) *AEADSizeParser {
|
||||||
|
return &AEADSizeParser{crypto.AEADChunkSizeParser{Auth: auth}}
|
||||||
|
}
|
||||||
|
|
|
@ -171,6 +171,17 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
|
||||||
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
|
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
}
|
}
|
||||||
|
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
|
||||||
|
AuthenticatedLengthKey := vmessaead.KDF16(c.requestBodyKey[:], "auth_len")
|
||||||
|
AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey)
|
||||||
|
|
||||||
|
lengthAuth := &crypto.AEADAuthenticator{
|
||||||
|
AEAD: AuthenticatedLengthKeyAEAD,
|
||||||
|
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
|
}
|
||||||
|
sizeParser = NewAEADSizeParser(lengthAuth)
|
||||||
|
}
|
||||||
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
|
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
|
||||||
case protocol.SecurityType_CHACHA20_POLY1305:
|
case protocol.SecurityType_CHACHA20_POLY1305:
|
||||||
aead, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey[:]))
|
aead, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey[:]))
|
||||||
|
@ -181,6 +192,18 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
|
||||||
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
|
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
}
|
}
|
||||||
|
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
|
||||||
|
AuthenticatedLengthKey := vmessaead.KDF16(c.requestBodyKey[:], "auth_len")
|
||||||
|
AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey))
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
lengthAuth := &crypto.AEADAuthenticator{
|
||||||
|
AEAD: AuthenticatedLengthKeyAEAD,
|
||||||
|
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
|
}
|
||||||
|
sizeParser = NewAEADSizeParser(lengthAuth)
|
||||||
|
}
|
||||||
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
|
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
|
||||||
default:
|
default:
|
||||||
panic("Unknown security type.")
|
panic("Unknown security type.")
|
||||||
|
@ -312,6 +335,17 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
|
||||||
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
|
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
}
|
}
|
||||||
|
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
|
||||||
|
AuthenticatedLengthKey := vmessaead.KDF16(c.requestBodyKey[:], "auth_len")
|
||||||
|
AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey)
|
||||||
|
|
||||||
|
lengthAuth := &crypto.AEADAuthenticator{
|
||||||
|
AEAD: AuthenticatedLengthKeyAEAD,
|
||||||
|
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
|
}
|
||||||
|
sizeParser = NewAEADSizeParser(lengthAuth)
|
||||||
|
}
|
||||||
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
|
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
|
||||||
case protocol.SecurityType_CHACHA20_POLY1305:
|
case protocol.SecurityType_CHACHA20_POLY1305:
|
||||||
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.responseBodyKey[:]))
|
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.responseBodyKey[:]))
|
||||||
|
@ -321,6 +355,18 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
|
||||||
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
|
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
}
|
}
|
||||||
|
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
|
||||||
|
AuthenticatedLengthKey := vmessaead.KDF16(c.requestBodyKey[:], "auth_len")
|
||||||
|
AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey))
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
lengthAuth := &crypto.AEADAuthenticator{
|
||||||
|
AEAD: AuthenticatedLengthKeyAEAD,
|
||||||
|
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
|
}
|
||||||
|
sizeParser = NewAEADSizeParser(lengthAuth)
|
||||||
|
}
|
||||||
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
|
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
|
||||||
default:
|
default:
|
||||||
panic("Unknown security type.")
|
panic("Unknown security type.")
|
||||||
|
|
|
@ -362,6 +362,17 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
|
||||||
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
|
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
}
|
}
|
||||||
|
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
|
||||||
|
AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len")
|
||||||
|
AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey)
|
||||||
|
|
||||||
|
lengthAuth := &crypto.AEADAuthenticator{
|
||||||
|
AEAD: AuthenticatedLengthKeyAEAD,
|
||||||
|
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
|
}
|
||||||
|
sizeParser = NewAEADSizeParser(lengthAuth)
|
||||||
|
}
|
||||||
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
|
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
|
||||||
|
|
||||||
case protocol.SecurityType_CHACHA20_POLY1305:
|
case protocol.SecurityType_CHACHA20_POLY1305:
|
||||||
|
@ -372,6 +383,18 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
|
||||||
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
|
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
}
|
}
|
||||||
|
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
|
||||||
|
AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len")
|
||||||
|
AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey))
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
lengthAuth := &crypto.AEADAuthenticator{
|
||||||
|
AEAD: AuthenticatedLengthKeyAEAD,
|
||||||
|
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
|
}
|
||||||
|
sizeParser = NewAEADSizeParser(lengthAuth)
|
||||||
|
}
|
||||||
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
|
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -480,6 +503,17 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
|
||||||
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
|
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
}
|
}
|
||||||
|
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
|
||||||
|
AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len")
|
||||||
|
AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey)
|
||||||
|
|
||||||
|
lengthAuth := &crypto.AEADAuthenticator{
|
||||||
|
AEAD: AuthenticatedLengthKeyAEAD,
|
||||||
|
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
|
}
|
||||||
|
sizeParser = NewAEADSizeParser(lengthAuth)
|
||||||
|
}
|
||||||
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
|
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
|
||||||
|
|
||||||
case protocol.SecurityType_CHACHA20_POLY1305:
|
case protocol.SecurityType_CHACHA20_POLY1305:
|
||||||
|
@ -490,6 +524,18 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
|
||||||
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
|
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
}
|
}
|
||||||
|
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
|
||||||
|
AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len")
|
||||||
|
AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey))
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
lengthAuth := &crypto.AEADAuthenticator{
|
||||||
|
AEAD: AuthenticatedLengthKeyAEAD,
|
||||||
|
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
|
||||||
|
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
||||||
|
}
|
||||||
|
sizeParser = NewAEADSizeParser(lengthAuth)
|
||||||
|
}
|
||||||
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
|
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -119,6 +119,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||||
request.Option.Clear(protocol.RequestOptionChunkMasking)
|
request.Option.Clear(protocol.RequestOptionChunkMasking)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if account.AuthenticatedLengthExperiment {
|
||||||
|
request.Option.Set(protocol.RequestOptionAuthenticatedLength)
|
||||||
|
}
|
||||||
|
|
||||||
input := link.Reader
|
input := link.Reader
|
||||||
output := link.Writer
|
output := link.Writer
|
||||||
|
|
||||||
|
|
|
@ -1330,3 +1330,110 @@ func TestVMessZero(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVMessGCMLengthAuth(t *testing.T) {
|
||||||
|
tcpServer := tcp.Server{
|
||||||
|
MsgProcessor: xor,
|
||||||
|
}
|
||||||
|
dest, err := tcpServer.Start()
|
||||||
|
common.Must(err)
|
||||||
|
defer tcpServer.Close()
|
||||||
|
|
||||||
|
userID := protocol.NewID(uuid.New())
|
||||||
|
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(&inbound.Config{
|
||||||
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
AlterId: 64,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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(&outbound.Config{
|
||||||
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
|
{
|
||||||
|
Address: net.NewIPOrDomain(net.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,
|
||||||
|
},
|
||||||
|
TestsEnabled: "AuthenticatedLength",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Failed to initialize all servers: ", err.Error())
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue