Skip closing an initializing connection

Without this change, if a cert is updated (e.g. to add CNs) while the
listener is in the middle of Accept()ing a new connection, the
connection gets dropped, we'll see a message like this in the server
logs:

  http: TLS handshake error from 127.0.0.1:51232: write tcp 127.0.7.1:8443->127.0.0.1:51232: use of closed network connection

and the client (like a browser) won't necessarily reconnect. This change
modifies the GetCertificate routine in the listener's tls.Config to
keep track of the state of the incoming connections and only close
connections that have completed GetCertificate and therefore are
finished with their TLS handshake, so that only old established
connections are closed.
This commit is contained in:
Colleen Murphy 2021-10-22 15:54:20 -07:00
parent 94e22490cf
commit c7dd355394

View File

@ -275,8 +275,9 @@ func (l *listener) wrap(conn net.Conn) net.Conn {
type closeWrapper struct {
net.Conn
id int
l *listener
id int
l *listener
ready bool
}
func (c *closeWrapper) close() error {
@ -291,13 +292,14 @@ func (c *closeWrapper) Close() error {
}
func (l *listener) getCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
newConn := hello.Conn
if hello.ServerName != "" {
if err := l.updateCert(hello.ServerName); err != nil {
return nil, err
}
}
return l.loadCert()
return l.loadCert(newConn.(*closeWrapper))
}
func (l *listener) updateCert(cn ...string) error {
@ -339,7 +341,7 @@ func (l *listener) updateCert(cn ...string) error {
return nil
}
func (l *listener) loadCert() (*tls.Certificate, error) {
func (l *listener) loadCert(currentConn *closeWrapper) (*tls.Certificate, error) {
l.RLock()
defer l.RUnlock()
@ -373,8 +375,13 @@ func (l *listener) loadCert() (*tls.Certificate, error) {
if l.conns != nil && l.cert != nil {
l.connLock.Lock()
for _, conn := range l.conns {
// Don't close a connection that's in the middle of completing a TLS handshake
if !conn.ready {
continue
}
_ = conn.close()
}
l.conns[currentConn.id].ready = true
l.connLock.Unlock()
}