diff --git a/typha/fv-tests/server_test.go b/typha/fv-tests/server_test.go index bb9413b81c4..9de18b15dfe 100644 --- a/typha/fv-tests/server_test.go +++ b/typha/fv-tests/server_test.go @@ -20,6 +20,7 @@ import ( "encoding/gob" "errors" "fmt" + "io" "net" "os" "path/filepath" @@ -1611,6 +1612,19 @@ var _ = Describe("with server requiring TLS", func() { } } + testTcpHalfOpen := func() { + deadline := time.Now().Add(9 * time.Second) + serverAddr := fmt.Sprintf("127.0.0.1:%d", server.Port()) + tcpConn, err := net.Dial("tcp", serverAddr) + Expect(err).NotTo(HaveOccurred()) + err = tcpConn.SetDeadline(time.Now().Add(30 * time.Second)) + Expect(err).NotTo(HaveOccurred()) + received := make([]byte, 1024) + _, err = tcpConn.Read(received) + Expect(err).Should(Equal(io.EOF)) + Expect(time.Now().Unix()).Should(BeNumerically(">=", deadline.Unix())) + } + Describe("and CN or URI SAN", func() { BeforeEach(func() { requiredClientCN = clientCN @@ -1686,4 +1700,14 @@ var _ = Describe("with server requiring TLS", func() { It("TLS connection with good CN and URI should fail", testTLSGoodCNURI(false)) }) + + Describe("handshake", func() { + BeforeEach(func() { + requiredClientCN = clientCN + requiredClientURISAN = clientURISAN + serverCertName = "server" + }) + + It("should timeout after 10 seconds for TCP half open connections", testTcpHalfOpen) + }) }) diff --git a/typha/pkg/config/config_params.go b/typha/pkg/config/config_params.go index dbe574bd073..ef0ca9addaf 100644 --- a/typha/pkg/config/config_params.go +++ b/typha/pkg/config/config_params.go @@ -120,6 +120,7 @@ type Config struct { ServerMinBatchingAgeThresholdSecs time.Duration `config:"seconds;0.01"` ServerPingIntervalSecs time.Duration `config:"seconds;10"` ServerPongTimeoutSecs time.Duration `config:"seconds;60"` + ServerHandshakeTimeoutSecs time.Duration `config:"seconds;10"` ServerPort int `config:"port;0"` // Server-side TLS config for Typha's communication with Felix. If any of these are diff --git a/typha/pkg/daemon/daemon.go b/typha/pkg/daemon/daemon.go index 7c6c12649de..39ea5ba012f 100644 --- a/typha/pkg/daemon/daemon.go +++ b/typha/pkg/daemon/daemon.go @@ -394,6 +394,7 @@ func (t *TyphaDaemon) CreateServer() { NewClientFallBehindGracePeriod: t.ConfigParams.ServerNewClientFallBehindGracePeriod, PingInterval: t.ConfigParams.ServerPingIntervalSecs, PongTimeout: t.ConfigParams.ServerPongTimeoutSecs, + HandshakeTimeout: t.ConfigParams.ServerHandshakeTimeoutSecs, DropInterval: t.ConfigParams.ConnectionDropIntervalSecs, ShutdownTimeout: t.ConfigParams.ShutdownTimeoutSecs, ShutdownMaxDropInterval: t.ConfigParams.ShutdownConnectionDropIntervalMaxSecs, diff --git a/typha/pkg/syncserver/sync_server.go b/typha/pkg/syncserver/sync_server.go index 7fde7675292..f2f4489db68 100644 --- a/typha/pkg/syncserver/sync_server.go +++ b/typha/pkg/syncserver/sync_server.go @@ -101,6 +101,7 @@ const ( defaultBatchingAgeThreshold = 100 * time.Millisecond defaultPingInterval = 10 * time.Second defaultWriteTimeout = 120 * time.Second + defaultHandshakeTimeout = 10 * time.Second defaultDropInterval = 1 * time.Second defaultShutdownTimeout = 300 * time.Second defaultMaxConns = math.MaxInt32 @@ -140,6 +141,7 @@ type Config struct { MinBatchingAgeThreshold time.Duration PingInterval time.Duration PongTimeout time.Duration + HandshakeTimeout time.Duration WriteTimeout time.Duration DropInterval time.Duration ShutdownTimeout time.Duration @@ -217,6 +219,13 @@ func (c *Config) ApplyDefaults() { }).Info("PongTimeout < PingInterval * 2; Defaulting PongTimeout.") c.PongTimeout = defaultTimeout } + if c.HandshakeTimeout <= 0 { + log.WithFields(log.Fields{ + "value": c.HandshakeTimeout, + "default": defaultHandshakeTimeout, + }).Info("Defaulting HandshakeTimeout.") + c.HandshakeTimeout = defaultHandshakeTimeout + } if c.WriteTimeout <= 0 { log.WithField("default", defaultWriteTimeout).Info("Defaulting write timeout.") c.WriteTimeout = defaultWriteTimeout @@ -424,7 +433,11 @@ func (s *Server) serve(cxt context.Context) { // Doing TLS, we must do the handshake... tlsConn := conn.(*tls.Conn) logCxt.Debug("TLS connection") - err = tlsConn.Handshake() + err = func() error { + handshakeCxt, handshakeCancel := context.WithTimeout(cxt, s.config.HandshakeTimeout) + defer handshakeCancel() + return tlsConn.HandshakeContext(handshakeCxt) + }() if err != nil { logCxt.WithError(err).Error("TLS handshake error") err = conn.Close() diff --git a/typha/pkg/syncserver/syncserver_test.go b/typha/pkg/syncserver/syncserver_test.go index f57c19f8ff1..b3e990fc462 100644 --- a/typha/pkg/syncserver/syncserver_test.go +++ b/typha/pkg/syncserver/syncserver_test.go @@ -41,6 +41,7 @@ var _ = Describe("With zero config", func() { MinBatchingAgeThreshold: 100 * time.Millisecond, PingInterval: 10 * time.Second, PongTimeout: 60 * time.Second, + HandshakeTimeout: 10 * time.Second, DropInterval: time.Second, ShutdownTimeout: 300 * time.Second, ShutdownMaxDropInterval: time.Second,