package tcp import ( "crypto/tls" "errors" "fmt" "net" "os" "testing" "time" "github.com/rqlite/rqlite/v8/rtls" "github.com/rqlite/rqlite/v8/testdata/x509" ) func Test_NewDialer(t *testing.T) { d := NewDialer(1, nil) if d == nil { t.Fatal("failed to create a dialer") } } func Test_DialerNoConnect(t *testing.T) { d := NewDialer(87, nil) _, err := d.Dial("127.0.0.1:0", 5*time.Second) if err == nil { t.Fatalf("no error connecting to bad address") } } func Test_DialerHeader(t *testing.T) { s := mustNewEchoServer() defer s.Close() go s.Start(t) d := NewDialer(64, nil) conn, err := d.Dial(s.Addr(), 10*time.Second) if err != nil { t.Fatalf("failed to dial echo server: %s", err.Error()) } buf := make([]byte, 1) conn.SetReadDeadline(time.Now().Add(5 * time.Second)) _, err = conn.Read(buf) if err != nil { t.Fatalf("failed to read from echo server: %s", err.Error()) } if exp, got := buf[0], byte(64); exp != got { t.Fatalf("got wrong response from echo server, exp %d, got %d", exp, got) } } func Test_DialerHeaderTLS(t *testing.T) { s, cert, key := mustNewEchoServerTLS_ExampleDotCom() defer s.Close() defer os.Remove(cert) defer os.Remove(key) go s.Start(t) tlsConfig, err := rtls.CreateClientConfig("", "", rtls.NoCACert, rtls.NoServerName, true) if err != nil { t.Fatalf("failed to create TLS config: %s", err.Error()) } d := NewDialer(23, tlsConfig) conn, err := d.Dial(s.Addr(), 5*time.Second) if err != nil { t.Fatalf("failed to dial TLS echo server: %s", err.Error()) } buf := make([]byte, 1) conn.SetReadDeadline(time.Now().Add(5 * time.Second)) _, err = conn.Read(buf) if err != nil { t.Fatalf("failed to read from TLS echo server: %s", err.Error()) } if exp, got := buf[0], byte(23); exp != got { t.Fatalf("got wrong response from TLS echo server, exp %d, got %d", exp, got) } } func Test_DialerHeaderTLS_ExampleDotCom(t *testing.T) { s, cert, key := mustNewEchoServerTLS_ExampleDotCom() defer s.Close() defer os.Remove(cert) defer os.Remove(key) go s.Start(t) // Set server name to wrong value, dialing should fail. tlsConfig, err := rtls.CreateClientConfig("", "", cert, "wrong.com", false) if err != nil { t.Fatalf("failed to create TLS config: %s", err.Error()) } d := NewDialer(23, tlsConfig) _, err = d.Dial(s.Addr(), 5*time.Second) if err == nil { t.Fatalf("dialing TLS echo server should have failed") } // Set server name to example.com, so dialing should succeed. tlsConfig, err = rtls.CreateClientConfig("", "", cert, "example.com", false) if err != nil { t.Fatalf("failed to create TLS config: %s", err.Error()) } d = NewDialer(23, tlsConfig) _, err = d.Dial(s.Addr(), 5*time.Second) if err != nil { t.Fatalf("failed to dial TLS echo server: %s", err.Error()) } } func Test_DialerHeaderTLSBadConnect(t *testing.T) { s, cert, key := mustNewEchoServerTLS_ExampleDotCom() defer s.Close() defer os.Remove(cert) defer os.Remove(key) go s.Start(t) // Connect to a TLS server with an unencrypted client, to make sure // code can handle that misconfig. d := NewDialer(56, nil) conn, err := d.Dial(s.Addr(), 5*time.Second) if err != nil { t.Fatalf("failed to dial TLS echo server: %s", err.Error()) } buf := make([]byte, 1) conn.SetReadDeadline(time.Now().Add(2 * time.Second)) _, err = conn.Read(buf) if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { t.Fatalf("unexpected error from TLS echo server: %s", err.Error()) } } type echoServer struct { ln net.Listener } // Addr returns the address of the echo server. func (e *echoServer) Addr() string { return e.ln.Addr().String() } // Start starts the echo server. func (e *echoServer) Start(t *testing.T) { for { conn, err := e.ln.Accept() if err != nil { if errors.Is(err, net.ErrClosed) { // Successful testing can cause this. return } t.Logf("failed to accept a connection: %s", err.Error()) } go func(c net.Conn) { buf := make([]byte, 1) _, err := c.Read(buf) if err != nil { return } _, err = c.Write(buf) if err != nil { t.Logf("failed to write byte: %s", err.Error()) } c.Close() }(conn) } } // Close closes the echo server. func (e *echoServer) Close() { e.ln.Close() } func mustNewEchoServer() *echoServer { return &echoServer{ ln: mustTCPListener("127.0.0.1:0"), } } func mustNewEchoServerTLS_ExampleDotCom() (*echoServer, string, string) { ln := mustTCPListener("127.0.0.1:0") cert := x509.CertExampleDotComFile("") key := x509.KeyExampleDotComFile("") tlsConfig, err := rtls.CreateServerConfig(cert, key, rtls.NoCACert, rtls.MTLSStateDisabled) if err != nil { panic(fmt.Sprintf("failed to create TLS config: %s", err.Error())) } return &echoServer{ ln: tls.NewListener(ln, tlsConfig), }, cert, key }