From 57bb437802cabc25f5c915148d879405c418da5e Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 27 Dec 2020 20:27:04 +0000 Subject: [PATCH 1/8] Log timestamp --- cmd/ck-client/ck-client.go | 3 +++ cmd/ck-server/ck-server.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/cmd/ck-client/ck-client.go b/cmd/ck-client/ck-client.go index efe51c2..2c19cd3 100644 --- a/cmd/ck-client/ck-client.go +++ b/cmd/ck-client/ck-client.go @@ -73,6 +73,9 @@ func main() { log.Info("Starting standalone mode") } + log.SetFormatter(&log.TextFormatter{ + FullTimestamp: true, + }) lvl, err := log.ParseLevel(*verbosity) if err != nil { log.Fatal(err) diff --git a/cmd/ck-server/ck-server.go b/cmd/ck-server/ck-server.go index b646232..b83460c 100644 --- a/cmd/ck-server/ck-server.go +++ b/cmd/ck-server/ck-server.go @@ -72,6 +72,10 @@ func main() { var pluginMode bool + log.SetFormatter(&log.TextFormatter{ + FullTimestamp: true, + }) + if os.Getenv("SS_LOCAL_HOST") != "" && os.Getenv("SS_LOCAL_PORT") != "" { pluginMode = true config = os.Getenv("SS_PLUGIN_OPTIONS") From e0b97db7cc50f9324fa3d81e484a303c33485ff2 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 27 Dec 2020 21:40:59 +0000 Subject: [PATCH 2/8] Add unordered benchmark for RecvDataFromRemote --- internal/multiplex/session_test.go | 41 ++++++++++++++++++------------ 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/internal/multiplex/session_test.go b/internal/multiplex/session_test.go index ebd305e..b2eb76a 100644 --- a/internal/multiplex/session_test.go +++ b/internal/multiplex/session_test.go @@ -4,6 +4,7 @@ import ( "bytes" "github.com/cbeuw/connutil" "github.com/stretchr/testify/assert" + "io/ioutil" "math/rand" "strconv" "sync" @@ -415,7 +416,7 @@ func TestSession_timeoutAfter(t *testing.T) { } } -func BenchmarkRecvDataFromRemote_Ordered(b *testing.B) { +func BenchmarkRecvDataFromRemote(b *testing.B) { testPayload := make([]byte, testPayloadLen) rand.Read(testPayload) f := &Frame{ @@ -439,23 +440,31 @@ func BenchmarkRecvDataFromRemote_Ordered(b *testing.B) { for name, ep := range table { ep := ep b.Run(name, func(b *testing.B) { - seshConfig := seshConfigs["ordered"] - obfuscator, _ := MakeObfuscator(ep, sessionKey) - seshConfig.Obfuscator = obfuscator - sesh := MakeSession(0, seshConfig) + for seshType, seshConfig := range seshConfigs { + b.Run(seshType, func(b *testing.B) { + obfuscator, _ := MakeObfuscator(ep, sessionKey) + seshConfig.Obfuscator = obfuscator + sesh := MakeSession(0, seshConfig) - binaryFrames := [maxIter][]byte{} - for i := 0; i < maxIter; i++ { - obfsBuf := make([]byte, obfsBufLen) - n, _ := sesh.obfuscate(f, obfsBuf, 0) - binaryFrames[i] = obfsBuf[:n] - f.Seq++ - } + go func() { + stream, _ := sesh.Accept() + stream.(*Stream).WriteTo(ioutil.Discard) + }() - b.SetBytes(int64(len(f.Payload))) - b.ResetTimer() - for i := 0; i < b.N; i++ { - sesh.recvDataFromRemote(binaryFrames[i]) + binaryFrames := [maxIter][]byte{} + for i := 0; i < maxIter; i++ { + obfsBuf := make([]byte, obfsBufLen) + n, _ := sesh.obfuscate(f, obfsBuf, 0) + binaryFrames[i] = obfsBuf[:n] + f.Seq++ + } + + b.SetBytes(int64(len(f.Payload))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + sesh.recvDataFromRemote(binaryFrames[i]) + } + }) } }) } From 23b32b603f9fc2808e7abc71a400982ef92f6152 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 27 Dec 2020 22:01:41 +0000 Subject: [PATCH 3/8] Latency benchmark --- internal/multiplex/session_test.go | 98 +++++++++++++++++------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/internal/multiplex/session_test.go b/internal/multiplex/session_test.go index b2eb76a..049a00c 100644 --- a/internal/multiplex/session_test.go +++ b/internal/multiplex/session_test.go @@ -4,8 +4,10 @@ import ( "bytes" "github.com/cbeuw/connutil" "github.com/stretchr/testify/assert" + "io" "io/ioutil" "math/rand" + "net" "strconv" "sync" "sync/atomic" @@ -17,6 +19,12 @@ var seshConfigs = map[string]SessionConfig{ "ordered": {}, "unordered": {Unordered: true}, } +var encryptionMethods = map[string]byte{ + "plain": EncryptionMethodPlain, + "aes-256-gcm": EncryptionMethodAES256GCM, + "aes-128-gcm": EncryptionMethodAES128GCM, + "chacha20poly1305": EncryptionMethodChaha20Poly1305, +} const testPayloadLen = 1024 const obfsBufLen = testPayloadLen * 2 @@ -35,27 +43,17 @@ func TestRecvDataFromRemote(t *testing.T) { var sessionKey [32]byte rand.Read(sessionKey[:]) - MakeObfuscatorUnwrap := func(method byte, sessionKey [32]byte) Obfuscator { - ret, err := MakeObfuscator(method, sessionKey) - if err != nil { - t.Fatalf("failed to make an obfuscator: %v", err) - } - return ret - } - - encryptionMethods := map[string]Obfuscator{ - "plain": MakeObfuscatorUnwrap(EncryptionMethodPlain, sessionKey), - "aes-gcm": MakeObfuscatorUnwrap(EncryptionMethodAES256GCM, sessionKey), - "chacha20-poly1305": MakeObfuscatorUnwrap(EncryptionMethodChaha20Poly1305, sessionKey), - } - for seshType, seshConfig := range seshConfigs { seshConfig := seshConfig t.Run(seshType, func(t *testing.T) { - for method, obfuscator := range encryptionMethods { - obfuscator := obfuscator - t.Run(method, func(t *testing.T) { - seshConfig.Obfuscator = obfuscator + for methodName, method := range encryptionMethods { + method := method + t.Run(methodName, func(t *testing.T) { + var err error + seshConfig.Obfuscator, err = MakeObfuscator(method, sessionKey) + if err != nil { + t.Fatalf("failed to make obfuscator: %v", err) + } sesh := MakeSession(0, seshConfig) n, err := sesh.obfuscate(f, obfsBuf, 0) if err != nil { @@ -95,10 +93,9 @@ func TestRecvDataFromRemote_Closing_InOrder(t *testing.T) { var sessionKey [32]byte rand.Read(sessionKey[:]) - obfuscator, _ := MakeObfuscator(EncryptionMethodPlain, sessionKey) seshConfig := seshConfigs["ordered"] - seshConfig.Obfuscator = obfuscator + seshConfig.Obfuscator, _ = MakeObfuscator(EncryptionMethodPlain, sessionKey) sesh := MakeSession(0, seshConfig) f1 := &Frame{ @@ -234,10 +231,9 @@ func TestRecvDataFromRemote_Closing_OutOfOrder(t *testing.T) { var sessionKey [32]byte rand.Read(sessionKey[:]) - obfuscator, _ := MakeObfuscator(EncryptionMethodPlain, sessionKey) seshConfig := seshConfigs["ordered"] - seshConfig.Obfuscator = obfuscator + seshConfig.Obfuscator, _ = MakeObfuscator(EncryptionMethodPlain, sessionKey) sesh := MakeSession(0, seshConfig) // receive stream 1 closing first @@ -429,21 +425,13 @@ func BenchmarkRecvDataFromRemote(b *testing.B) { var sessionKey [32]byte rand.Read(sessionKey[:]) - table := map[string]byte{ - "plain": EncryptionMethodPlain, - "aes-256-gcm": EncryptionMethodAES256GCM, - "aes-128-gcm": EncryptionMethodAES128GCM, - "chacha20poly1305": EncryptionMethodChaha20Poly1305, - } - const maxIter = 100_000 // run with -benchtime 100000x to avoid index out of bounds panic - for name, ep := range table { + for name, ep := range encryptionMethods { ep := ep b.Run(name, func(b *testing.B) { for seshType, seshConfig := range seshConfigs { b.Run(seshType, func(b *testing.B) { - obfuscator, _ := MakeObfuscator(ep, sessionKey) - seshConfig.Obfuscator = obfuscator + seshConfig.Obfuscator, _ = MakeObfuscator(ep, sessionKey) sesh := MakeSession(0, seshConfig) go func() { @@ -474,22 +462,13 @@ func BenchmarkMultiStreamWrite(b *testing.B) { var sessionKey [32]byte rand.Read(sessionKey[:]) - table := map[string]byte{ - "plain": EncryptionMethodPlain, - "aes-256-gcm": EncryptionMethodAES256GCM, - "aes-128-gcm": EncryptionMethodAES128GCM, - "chacha20poly1305": EncryptionMethodChaha20Poly1305, - } - testPayload := make([]byte, testPayloadLen) - for name, ep := range table { + for name, ep := range encryptionMethods { b.Run(name, func(b *testing.B) { for seshType, seshConfig := range seshConfigs { - seshConfig := seshConfig b.Run(seshType, func(b *testing.B) { - obfuscator, _ := MakeObfuscator(ep, sessionKey) - seshConfig.Obfuscator = obfuscator + seshConfig.Obfuscator, _ = MakeObfuscator(ep, sessionKey) sesh := MakeSession(0, seshConfig) sesh.AddConnection(connutil.Discard()) b.ResetTimer() @@ -505,3 +484,36 @@ func BenchmarkMultiStreamWrite(b *testing.B) { }) } } + +func BenchmarkLatency(b *testing.B) { + var sessionKey [32]byte + rand.Read(sessionKey[:]) + + for name, ep := range encryptionMethods { + b.Run(name, func(b *testing.B) { + for seshType, seshConfig := range seshConfigs { + b.Run(seshType, func(b *testing.B) { + seshConfig.Obfuscator, _ = MakeObfuscator(ep, sessionKey) + clientSesh := MakeSession(0, seshConfig) + serverSesh := MakeSession(0, seshConfig) + + c, s := net.Pipe() + clientSesh.AddConnection(c) + serverSesh.AddConnection(s) + + buf := make([]byte, 64) + clientStream, _ := clientSesh.OpenStream() + clientStream.Write(buf) + serverStream, _ := serverSesh.Accept() + io.ReadFull(serverStream, buf) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + clientStream.Write(buf) + io.ReadFull(serverStream, buf) + } + }) + } + }) + } +} From 8fbb2dd8ccaa1f9440b74c9560b4a4a3ea6097fa Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 28 Dec 2020 00:29:56 +0000 Subject: [PATCH 4/8] Add more data reception tests --- internal/multiplex/session_test.go | 191 ++++++++++++++++++++++++----- 1 file changed, 157 insertions(+), 34 deletions(-) diff --git a/internal/multiplex/session_test.go b/internal/multiplex/session_test.go index 049a00c..210bce4 100644 --- a/internal/multiplex/session_test.go +++ b/internal/multiplex/session_test.go @@ -30,16 +30,6 @@ const testPayloadLen = 1024 const obfsBufLen = testPayloadLen * 2 func TestRecvDataFromRemote(t *testing.T) { - testPayload := make([]byte, testPayloadLen) - rand.Read(testPayload) - f := &Frame{ - 1, - 0, - 0, - testPayload, - } - obfsBuf := make([]byte, obfsBufLen) - var sessionKey [32]byte rand.Read(sessionKey[:]) @@ -54,31 +44,164 @@ func TestRecvDataFromRemote(t *testing.T) { if err != nil { t.Fatalf("failed to make obfuscator: %v", err) } - sesh := MakeSession(0, seshConfig) - n, err := sesh.obfuscate(f, obfsBuf, 0) - if err != nil { - t.Error(err) - return - } - err = sesh.recvDataFromRemote(obfsBuf[:n]) - if err != nil { - t.Error(err) - return - } - stream, err := sesh.Accept() - if err != nil { - t.Error(err) - return - } + t.Run("initial frame", func(t *testing.T) { + sesh := MakeSession(0, seshConfig) + obfsBuf := make([]byte, obfsBufLen) + f := Frame{ + 1, + 0, + 0, + make([]byte, testPayloadLen), + } + rand.Read(f.Payload) + n, err := sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + stream, err := sesh.Accept() + assert.NoError(t, err) - resultPayload := make([]byte, testPayloadLen) - _, err = stream.Read(resultPayload) - if err != nil { - t.Error(err) - return - } - if !bytes.Equal(testPayload, resultPayload) { - t.Errorf("Expecting %x, got %x", testPayload, resultPayload) + resultPayload := make([]byte, testPayloadLen) + _, err = stream.Read(resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + }) + + t.Run("two frames in order", func(t *testing.T) { + sesh := MakeSession(0, seshConfig) + obfsBuf := make([]byte, obfsBufLen) + f := Frame{ + 1, + 0, + 0, + make([]byte, testPayloadLen), + } + rand.Read(f.Payload) + n, err := sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + stream, err := sesh.Accept() + assert.NoError(t, err) + + resultPayload := make([]byte, testPayloadLen) + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + + f.Seq += 1 + rand.Read(f.Payload) + n, err = sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + }) + + t.Run("two frames in order", func(t *testing.T) { + sesh := MakeSession(0, seshConfig) + obfsBuf := make([]byte, obfsBufLen) + f := Frame{ + 1, + 0, + 0, + make([]byte, testPayloadLen), + } + rand.Read(f.Payload) + n, err := sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + stream, err := sesh.Accept() + assert.NoError(t, err) + + resultPayload := make([]byte, testPayloadLen) + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + + f.Seq += 1 + rand.Read(f.Payload) + n, err = sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + }) + + if seshType == "ordered" { + t.Run("frames out of order", func(t *testing.T) { + sesh := MakeSession(0, seshConfig) + obfsBuf := make([]byte, obfsBufLen) + f := Frame{ + 1, + 0, + 0, + nil, + } + + // First frame + seq0 := make([]byte, testPayloadLen) + rand.Read(seq0) + f.Seq = 0 + f.Payload = seq0 + n, err := sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + + // Third frame + seq2 := make([]byte, testPayloadLen) + rand.Read(seq2) + f.Seq = 2 + f.Payload = seq2 + n, err = sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + + // Second frame + seq1 := make([]byte, testPayloadLen) + rand.Read(seq1) + f.Seq = 1 + f.Payload = seq1 + n, err = sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + + // Expect things to receive in order + stream, err := sesh.Accept() + assert.NoError(t, err) + + resultPayload := make([]byte, testPayloadLen) + + // First + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + assert.EqualValues(t, seq0, resultPayload) + + // Second + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + assert.EqualValues(t, seq1, resultPayload) + + // Third + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + assert.EqualValues(t, seq2, resultPayload) + }) } }) } From f322f8b47f4754e6e43eb4a6d430a7ecd64765f3 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 28 Dec 2020 00:48:16 +0000 Subject: [PATCH 5/8] Randomise echo test data --- internal/multiplex/mux_test.go | 5 +++-- internal/test/integration_test.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/multiplex/mux_test.go b/internal/multiplex/mux_test.go index 86dec41..e492305 100644 --- a/internal/multiplex/mux_test.go +++ b/internal/multiplex/mux_test.go @@ -65,14 +65,15 @@ func makeSessionPair(numConn int) (*Session, *Session, []*connPair) { func runEchoTest(t *testing.T, conns []net.Conn, msgLen int) { var wg sync.WaitGroup - testData := make([]byte, msgLen) - rand.Read(testData) for _, conn := range conns { wg.Add(1) go func(conn net.Conn) { defer wg.Done() + testData := make([]byte, msgLen) + rand.Read(testData) + // we cannot call t.Fatalf in concurrent contexts n, err := conn.Write(testData) if n != msgLen { diff --git a/internal/test/integration_test.go b/internal/test/integration_test.go index 22935b2..e4072e0 100644 --- a/internal/test/integration_test.go +++ b/internal/test/integration_test.go @@ -222,14 +222,15 @@ func establishSession(lcc client.LocalConnConfig, rcc client.RemoteConnConfig, a func runEchoTest(t *testing.T, conns []net.Conn, msgLen int) { var wg sync.WaitGroup - testData := make([]byte, msgLen) - rand.Read(testData) for _, conn := range conns { wg.Add(1) go func(conn net.Conn) { defer wg.Done() + testData := make([]byte, msgLen) + rand.Read(testData) + // we cannot call t.Fatalf in concurrent contexts n, err := conn.Write(testData) if n != msgLen { From 661db9d0831ccbf6b084da4f785638486f4f90db Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 28 Dec 2020 00:48:41 +0000 Subject: [PATCH 6/8] Correctly copy frame payload in frame sorter --- internal/multiplex/streamBuffer.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/multiplex/streamBuffer.go b/internal/multiplex/streamBuffer.go index 13cc523..a9fd0fd 100644 --- a/internal/multiplex/streamBuffer.go +++ b/internal/multiplex/streamBuffer.go @@ -82,6 +82,8 @@ func (sb *streamBuffer) Write(f *Frame) (toBeClosed bool, err error) { } saved := *f + saved.Payload = make([]byte, len(f.Payload)) + copy(saved.Payload, f.Payload) heap.Push(&sb.sh, &saved) // Keep popping from the heap until empty or to the point that the wanted seq was not received for len(sb.sh) > 0 && sb.sh[0].Seq == sb.nextRecvSeq { From c60c6d8ddbd3b9f256c58cadbbf9b1c1b9ad5bd8 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 28 Dec 2020 01:25:22 +0000 Subject: [PATCH 7/8] Avoid assigning functions to variables in hot path --- internal/multiplex/obfs.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/internal/multiplex/obfs.go b/internal/multiplex/obfs.go index 8ec0d5b..91c9a76 100644 --- a/internal/multiplex/obfs.go +++ b/internal/multiplex/obfs.go @@ -11,11 +11,6 @@ import ( "golang.org/x/crypto/salsa20" ) -var u32 = binary.BigEndian.Uint32 -var u64 = binary.BigEndian.Uint64 -var putU32 = binary.BigEndian.PutUint32 -var putU64 = binary.BigEndian.PutUint64 - const frameHeaderLength = 14 const salsa20NonceSize = 8 @@ -98,8 +93,8 @@ func (o *Obfuscator) obfuscate(f *Frame, buf []byte, payloadOffsetInBuf int) (in } header := buf[:frameHeaderLength] - putU32(header[0:4], f.StreamID) - putU64(header[4:12], f.Seq) + binary.BigEndian.PutUint32(header[0:4], f.StreamID) + binary.BigEndian.PutUint64(header[4:12], f.Seq) header[12] = f.Closing header[13] = byte(extraLen) @@ -130,8 +125,8 @@ func (o *Obfuscator) deobfuscate(f *Frame, in []byte) error { nonce := in[len(in)-salsa20NonceSize:] salsa20.XORKeyStream(header, header, nonce, &o.SessionKey) - streamID := u32(header[0:4]) - seq := u64(header[4:12]) + streamID := binary.BigEndian.Uint32(header[0:4]) + seq := binary.BigEndian.Uint64(header[4:12]) closing := header[12] extraLen := header[13] From fd695db044ae2e73ddca9313727baa6c044cea87 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 28 Dec 2020 01:27:40 +0000 Subject: [PATCH 8/8] Reduce unnecessary test bloat --- internal/multiplex/session_test.go | 312 ++++++++++++++--------------- 1 file changed, 154 insertions(+), 158 deletions(-) diff --git a/internal/multiplex/session_test.go b/internal/multiplex/session_test.go index 210bce4..dfa3dbb 100644 --- a/internal/multiplex/session_test.go +++ b/internal/multiplex/session_test.go @@ -36,175 +36,171 @@ func TestRecvDataFromRemote(t *testing.T) { for seshType, seshConfig := range seshConfigs { seshConfig := seshConfig t.Run(seshType, func(t *testing.T) { - for methodName, method := range encryptionMethods { - method := method - t.Run(methodName, func(t *testing.T) { - var err error - seshConfig.Obfuscator, err = MakeObfuscator(method, sessionKey) - if err != nil { - t.Fatalf("failed to make obfuscator: %v", err) + var err error + seshConfig.Obfuscator, err = MakeObfuscator(EncryptionMethodPlain, sessionKey) + if err != nil { + t.Fatalf("failed to make obfuscator: %v", err) + } + t.Run("initial frame", func(t *testing.T) { + sesh := MakeSession(0, seshConfig) + obfsBuf := make([]byte, obfsBufLen) + f := Frame{ + 1, + 0, + 0, + make([]byte, testPayloadLen), + } + rand.Read(f.Payload) + n, err := sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + stream, err := sesh.Accept() + assert.NoError(t, err) + + resultPayload := make([]byte, testPayloadLen) + _, err = stream.Read(resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + }) + + t.Run("two frames in order", func(t *testing.T) { + sesh := MakeSession(0, seshConfig) + obfsBuf := make([]byte, obfsBufLen) + f := Frame{ + 1, + 0, + 0, + make([]byte, testPayloadLen), + } + rand.Read(f.Payload) + n, err := sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + stream, err := sesh.Accept() + assert.NoError(t, err) + + resultPayload := make([]byte, testPayloadLen) + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + + f.Seq += 1 + rand.Read(f.Payload) + n, err = sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + }) + + t.Run("two frames in order", func(t *testing.T) { + sesh := MakeSession(0, seshConfig) + obfsBuf := make([]byte, obfsBufLen) + f := Frame{ + 1, + 0, + 0, + make([]byte, testPayloadLen), + } + rand.Read(f.Payload) + n, err := sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + stream, err := sesh.Accept() + assert.NoError(t, err) + + resultPayload := make([]byte, testPayloadLen) + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + + f.Seq += 1 + rand.Read(f.Payload) + n, err = sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) + + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + + assert.EqualValues(t, f.Payload, resultPayload) + }) + + if seshType == "ordered" { + t.Run("frames out of order", func(t *testing.T) { + sesh := MakeSession(0, seshConfig) + obfsBuf := make([]byte, obfsBufLen) + f := Frame{ + 1, + 0, + 0, + nil, } - t.Run("initial frame", func(t *testing.T) { - sesh := MakeSession(0, seshConfig) - obfsBuf := make([]byte, obfsBufLen) - f := Frame{ - 1, - 0, - 0, - make([]byte, testPayloadLen), - } - rand.Read(f.Payload) - n, err := sesh.obfuscate(&f, obfsBuf, 0) - assert.NoError(t, err) - err = sesh.recvDataFromRemote(obfsBuf[:n]) - assert.NoError(t, err) - stream, err := sesh.Accept() - assert.NoError(t, err) - resultPayload := make([]byte, testPayloadLen) - _, err = stream.Read(resultPayload) - assert.NoError(t, err) + // First frame + seq0 := make([]byte, testPayloadLen) + rand.Read(seq0) + f.Seq = 0 + f.Payload = seq0 + n, err := sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) - assert.EqualValues(t, f.Payload, resultPayload) - }) + // Third frame + seq2 := make([]byte, testPayloadLen) + rand.Read(seq2) + f.Seq = 2 + f.Payload = seq2 + n, err = sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) - t.Run("two frames in order", func(t *testing.T) { - sesh := MakeSession(0, seshConfig) - obfsBuf := make([]byte, obfsBufLen) - f := Frame{ - 1, - 0, - 0, - make([]byte, testPayloadLen), - } - rand.Read(f.Payload) - n, err := sesh.obfuscate(&f, obfsBuf, 0) - assert.NoError(t, err) - err = sesh.recvDataFromRemote(obfsBuf[:n]) - assert.NoError(t, err) - stream, err := sesh.Accept() - assert.NoError(t, err) + // Second frame + seq1 := make([]byte, testPayloadLen) + rand.Read(seq1) + f.Seq = 1 + f.Payload = seq1 + n, err = sesh.obfuscate(&f, obfsBuf, 0) + assert.NoError(t, err) + err = sesh.recvDataFromRemote(obfsBuf[:n]) + assert.NoError(t, err) - resultPayload := make([]byte, testPayloadLen) - _, err = io.ReadFull(stream, resultPayload) - assert.NoError(t, err) + // Expect things to receive in order + stream, err := sesh.Accept() + assert.NoError(t, err) - assert.EqualValues(t, f.Payload, resultPayload) + resultPayload := make([]byte, testPayloadLen) - f.Seq += 1 - rand.Read(f.Payload) - n, err = sesh.obfuscate(&f, obfsBuf, 0) - assert.NoError(t, err) - err = sesh.recvDataFromRemote(obfsBuf[:n]) - assert.NoError(t, err) + // First + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + assert.EqualValues(t, seq0, resultPayload) - _, err = io.ReadFull(stream, resultPayload) - assert.NoError(t, err) + // Second + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + assert.EqualValues(t, seq1, resultPayload) - assert.EqualValues(t, f.Payload, resultPayload) - }) - - t.Run("two frames in order", func(t *testing.T) { - sesh := MakeSession(0, seshConfig) - obfsBuf := make([]byte, obfsBufLen) - f := Frame{ - 1, - 0, - 0, - make([]byte, testPayloadLen), - } - rand.Read(f.Payload) - n, err := sesh.obfuscate(&f, obfsBuf, 0) - assert.NoError(t, err) - err = sesh.recvDataFromRemote(obfsBuf[:n]) - assert.NoError(t, err) - stream, err := sesh.Accept() - assert.NoError(t, err) - - resultPayload := make([]byte, testPayloadLen) - _, err = io.ReadFull(stream, resultPayload) - assert.NoError(t, err) - - assert.EqualValues(t, f.Payload, resultPayload) - - f.Seq += 1 - rand.Read(f.Payload) - n, err = sesh.obfuscate(&f, obfsBuf, 0) - assert.NoError(t, err) - err = sesh.recvDataFromRemote(obfsBuf[:n]) - assert.NoError(t, err) - - _, err = io.ReadFull(stream, resultPayload) - assert.NoError(t, err) - - assert.EqualValues(t, f.Payload, resultPayload) - }) - - if seshType == "ordered" { - t.Run("frames out of order", func(t *testing.T) { - sesh := MakeSession(0, seshConfig) - obfsBuf := make([]byte, obfsBufLen) - f := Frame{ - 1, - 0, - 0, - nil, - } - - // First frame - seq0 := make([]byte, testPayloadLen) - rand.Read(seq0) - f.Seq = 0 - f.Payload = seq0 - n, err := sesh.obfuscate(&f, obfsBuf, 0) - assert.NoError(t, err) - err = sesh.recvDataFromRemote(obfsBuf[:n]) - assert.NoError(t, err) - - // Third frame - seq2 := make([]byte, testPayloadLen) - rand.Read(seq2) - f.Seq = 2 - f.Payload = seq2 - n, err = sesh.obfuscate(&f, obfsBuf, 0) - assert.NoError(t, err) - err = sesh.recvDataFromRemote(obfsBuf[:n]) - assert.NoError(t, err) - - // Second frame - seq1 := make([]byte, testPayloadLen) - rand.Read(seq1) - f.Seq = 1 - f.Payload = seq1 - n, err = sesh.obfuscate(&f, obfsBuf, 0) - assert.NoError(t, err) - err = sesh.recvDataFromRemote(obfsBuf[:n]) - assert.NoError(t, err) - - // Expect things to receive in order - stream, err := sesh.Accept() - assert.NoError(t, err) - - resultPayload := make([]byte, testPayloadLen) - - // First - _, err = io.ReadFull(stream, resultPayload) - assert.NoError(t, err) - assert.EqualValues(t, seq0, resultPayload) - - // Second - _, err = io.ReadFull(stream, resultPayload) - assert.NoError(t, err) - assert.EqualValues(t, seq1, resultPayload) - - // Third - _, err = io.ReadFull(stream, resultPayload) - assert.NoError(t, err) - assert.EqualValues(t, seq2, resultPayload) - }) - } + // Third + _, err = io.ReadFull(stream, resultPayload) + assert.NoError(t, err) + assert.EqualValues(t, seq2, resultPayload) }) } + }) } }