From bc6e2bf2da7e8d2580381fa5bad5dac1a496dca3 Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Wed, 14 Aug 2024 16:45:00 -0700 Subject: [PATCH] test against tls.Conns, not pipes Specifically to debug hashicorp/nomad#23305 but tests should probably run against multiple net.Conn implementations as yamux is sensitive to net.Conn behaviors such as concurrent Read|Write|Close and what errors are returned. --- session_test.go | 77 ++++++++++++++++++++++++++++++++++++++-------- testdata/README.md | 7 +++++ testdata/cert.pem | 18 +++++++++++ testdata/key.pem | 28 +++++++++++++++++ 4 files changed, 118 insertions(+), 12 deletions(-) create mode 100644 testdata/README.md create mode 100644 testdata/cert.pem create mode 100644 testdata/key.pem diff --git a/session_test.go b/session_test.go index 46e9233..92986de 100644 --- a/session_test.go +++ b/session_test.go @@ -3,6 +3,7 @@ package yamux import ( "bytes" "context" + "crypto/tls" "errors" "fmt" "io" @@ -67,12 +68,58 @@ func (p *pipeConn) Close() error { return p.writer.Close() } -func testConn() (io.ReadWriteCloser, io.ReadWriteCloser) { - read1, write1 := io.Pipe() - read2, write2 := io.Pipe() - conn1 := &pipeConn{reader: read1, writer: write2} - conn2 := &pipeConn{reader: read2, writer: write1} - return conn1, conn2 +func testConn(t testing.TB) (io.ReadWriteCloser, io.ReadWriteCloser) { + /* + read1, write1 := io.Pipe() + read2, write2 := io.Pipe() + conn1 := &pipeConn{reader: read1, writer: write2} + conn2 := &pipeConn{reader: read2, writer: write1} + */ + + cert, err := tls.LoadX509KeyPair("testdata/cert.pem", "testdata/key.pem") + if err != nil { + t.Fatalf("error loading certificate: %v", err) + } + + l, err := net.ListenTCP("tcp", nil) + if err != nil { + t.Fatalf("error creating listener: %v", err) + } + t.Cleanup(func() { l.Close() }) + + var srv net.Conn + errCh := make(chan error, 1) + go func() { + defer close(errCh) + conn, err := l.Accept() + if err != nil { + errCh <- err + return + } + + srv = tls.Server(conn, &tls.Config{ + Certificates: []tls.Certificate{cert}, + }) + }() + + t.Logf("Connecting to %s: %s", l.Addr().Network(), l.Addr()) + client, err := net.DialTimeout(l.Addr().Network(), l.Addr().String(), 10*time.Second) + if err != nil { + t.Fatalf("error dialing tls listener: %v", err) + } + t.Cleanup(func() { client.Close() }) + + tlsClient := tls.Client(client, &tls.Config{ + // InsecureSkipVerify is safe to use here since this is only for tests. + InsecureSkipVerify: true, + }) + + if err := <-errCh; err != nil { + t.Fatalf("error creating tls server: %v", err) + } + t.Cleanup(func() { srv.Close() }) + + return srv, tlsClient } func testConf() *Config { @@ -101,7 +148,7 @@ func testClientServer(t testing.TB) (*Session, *Session) { } func testClientServerConfig(t testing.TB, serverConf, clientConf *Config) (*Session, *Session) { - conn1, conn2 := testConn() + conn1, conn2 := testConn(t) client, err := Client(conn1, clientConf) if err != nil { @@ -138,6 +185,7 @@ func TestPing(t *testing.T) { } func TestPing_Timeout(t *testing.T) { + t.Skip("FIXME: expects a pipe") conf := testConfNoKeepAlive() client, server := testClientServerConfig(t, conf.Clone(), conf.Clone()) @@ -434,11 +482,11 @@ func TestSendData_Small(t *testing.T) { drainErrorsUntil(t, errCh, 2, time.Second, "timeout") - if client.NumStreams() != 0 { - t.Fatalf("bad") + if n := client.NumStreams(); n != 0 { + t.Errorf("expected 0 client streams but found %d", n) } - if server.NumStreams() != 0 { - t.Fatalf("bad") + if n := server.NumStreams(); n != 0 { + t.Errorf("expected 0 server streams but found %d", n) } } @@ -1038,7 +1086,8 @@ func TestKeepAlive(t *testing.T) { } func TestKeepAlive_Timeout(t *testing.T) { - conn1, conn2 := testConn() + t.Skip("FIXME: expects a pipe") + conn1, conn2 := testConn(t) clientConf := testConf() clientConf.ConnectionWriteTimeout = time.Hour // We're testing keep alives, not connection writes @@ -1239,6 +1288,7 @@ func TestBacklogExceeded_Accept(t *testing.T) { } func TestSession_WindowUpdateWriteDuringRead(t *testing.T) { + t.Skip("FIXME: expects a pipe") conf := testConfNoKeepAlive() client, server := testClientServerConfig(t, conf, conf.Clone()) @@ -1360,6 +1410,7 @@ func TestSession_PartialReadWindowUpdate(t *testing.T) { } func TestSession_sendNoWait_Timeout(t *testing.T) { + t.Skip("FIXME: expects a pipe") conf := testConfNoKeepAlive() client, server := testClientServerConfig(t, conf, conf.Clone()) @@ -1410,6 +1461,7 @@ func TestSession_sendNoWait_Timeout(t *testing.T) { } func TestSession_PingOfDeath(t *testing.T) { + t.Skip("FIXME: expects a pipe") conf := testConfNoKeepAlive() client, server := testClientServerConfig(t, conf, conf.Clone()) @@ -1483,6 +1535,7 @@ func TestSession_PingOfDeath(t *testing.T) { } func TestSession_ConnectionWriteTimeout(t *testing.T) { + t.Skip("FIXME: expects a pipe") conf := testConfNoKeepAlive() client, server := testClientServerConfig(t, conf, conf.Clone()) diff --git a/testdata/README.md b/testdata/README.md new file mode 100644 index 0000000..91a8338 --- /dev/null +++ b/testdata/README.md @@ -0,0 +1,7 @@ +Test certificates generated with: + +``` +go run $(go env GOROOT)/src/crypto/tls/generate_cert.go --host example.com +``` + +Requires a bash-like shell and Go installed. diff --git a/testdata/cert.pem b/testdata/cert.pem new file mode 100644 index 0000000..77bbaab --- /dev/null +++ b/testdata/cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC/DCCAeSgAwIBAgIRAI8YOah8fp9JcV8YbON8488wDQYJKoZIhvcNAQELBQAw +EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0yNDA4MTQyMzE0MTJaFw0yNTA4MTQyMzE0 +MTJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQC5cvLaZRsKScA/JBgIlXTs3uJj7KLOLwGuRxk3sUQ7aREoqlC1bGR8 +wN5mYu9Yso6dEOWJBSXybtSpH60AtGnepAKAra4IDNfLbNmWi+13lyqD/BgIpWoP +Lww6MDHLxNP1+U4hQ2mcOw/hueaSMUahXhjTTTVHq+cLQ9eBxk7b/mcxzHLS6he+ +0zS2QsQ7p/R5RN5QTALZNoHTgXh7Wou/ynmCHNVzaAOdGIvDTSi6fBdqNgvWrY0w +WcZePVcTiZ2y/4TKEugXqu6RdO1C3rtAFEWCn9q+RyNl0MCcbxo+n3xljy9y3HTW +0qdpYg2wZJKuRBRlsr0D72pEg+OTd4gNAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIF +oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2C +C2V4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBvjm0Y6uS285qhh9Ae/4+f +/nc9KVECHCt0w4CAVmkoCULncOLPnfDRgfn0S2jveBeD/1916egnRljYdqHaE/1G +/DHo3b45uC77dCGZzCKl7GC50GOUdirHxNiS99xCPM2rWmoada+v5Oe3kcCBXlJ4 +KeDffE7EGo8ACzO5ziKMbR8oThaFrOXIPtUYUFInURbu9VKfRzkLzXNGBZ1WgVZ6 +i9McZImuKnKLZJ1e3SlX3PcZwoBYbumaIG1XFx0K4FCO+QsZNOtLPIzA+aVdtFii +f5nn4CxXJ/SGhwnjbJE4lS7vH0JlzVIX5rHEYB4jL8d7TApXVgJ0L/0wgFvQ0bCv +-----END CERTIFICATE----- diff --git a/testdata/key.pem b/testdata/key.pem new file mode 100644 index 0000000..579ae5f --- /dev/null +++ b/testdata/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5cvLaZRsKScA/ +JBgIlXTs3uJj7KLOLwGuRxk3sUQ7aREoqlC1bGR8wN5mYu9Yso6dEOWJBSXybtSp +H60AtGnepAKAra4IDNfLbNmWi+13lyqD/BgIpWoPLww6MDHLxNP1+U4hQ2mcOw/h +ueaSMUahXhjTTTVHq+cLQ9eBxk7b/mcxzHLS6he+0zS2QsQ7p/R5RN5QTALZNoHT +gXh7Wou/ynmCHNVzaAOdGIvDTSi6fBdqNgvWrY0wWcZePVcTiZ2y/4TKEugXqu6R +dO1C3rtAFEWCn9q+RyNl0MCcbxo+n3xljy9y3HTW0qdpYg2wZJKuRBRlsr0D72pE +g+OTd4gNAgMBAAECggEAdVXvppM2KqpDQzAZLMUzt/PGFidRU1eWnqhJol08qMJv +ouUwL7onUm/Nx8ZtXheL+IEKWkmxmtTZJTDvi3SbT81B8Bzz8g/+Ma3rdj+Ovo4c +zmmg40eV9Yl1GRQJTb55xjY5Yv5+QeV0xQOUiYc4Az3AQ2GkhnaTtyLzph7NIo+d +n4jiNJIlCP2wO3hyIaIVtQXyoGAwNWHTrJsShGaNi9C32SEqzSzuNF94lnGJ4U9M +7yLl1GD+uhz6V0q3eY8CHK6g8HOaj1ukMlIz+qZdsY252qpEgmY21kvoUJ9Awjjn +3dAtR7aX+YFtMdAD8rCPHS00lmSlGOEMcg8m07EHmQKBgQDEyHIKvls9RGRfbMbR ++GQ0HyQu2ACbHu6sc8baZZpr9h0pQJOObvPhVWkTcMpVZqlfJZ3X08WHhBBmTZkQ +F4K1nAs+Ps7U04cBDph3eGGfe+roQSVcVARmTq4is1SOQMtSpnKyRMS1HLFp9sR0 +03m9a43pmnkT45m/BxFp6kCMxwKBgQDxQV5yH0YBfT5i8T63vDs/f9nvxgRODC5d +0rdgJBd1R4VPTmI5Cbcfa3IY4H5nMgh90x9T7xu209ywp75TYS/Q119eElTcj5tX +xhDitw052F2ZA90nuCsyXQq+01zLeRuhMQQx3HbmgoVDNNJJBRfERakhM8z4FDVi +a5FDrDQoiwKBgBZg6T85iKy+A2Aqwa2NPvACfp3pKKB7cw8fl4Ssu1P9yDExy9YN +3iRJD0sLr6bopuhQIdQynCseJLNNrdN7qPy4QzsP73ualqbTHxmvEgMOF5fUGMiY +MWvlFL6TgFExIy5CCZcmZOxn1/FCA/N5PUYCXkArtgtB/fEQf7V402BvAoGBAN3g +oazRaD/cYLD8cBLo0ZCf0955veHNwCLXtYB9EPnycf8y9pDAh6Mk3QVWCcp8sGSP +82LtKA7oIDJzw03JtwEZ4oKQ120VwediqIrpkQdfHw2oCRALh+bEvSotF02mryt6 ++gGlYdCzvz3E6ZTwUyBWdKqtileptkMy7KFRUZLrAoGAVHMhb1CJWIHLOSNWBHU3 +U0Aq9kY3sK/iECKRa0e7qe8gK/hSm61q3RyyYsrrsp8nyPhuvvoJ61AyD9sf4bWn +4lQalf69PpfdM3Kr9wgu3B8UG15RYAgu9mEp4f5ys/lB0kdcoNhXHm/omuEI7xho +0TzPD2rJfUl/Jce1oLGoPL8= +-----END PRIVATE KEY-----