brontide: set read deadlines on socket during initial handshake

This commit fixes a lingering issue within lnd, which can cause a
server to freeze up, and not handle any incoming connections properly,
or cause clients to freeze and not return in a timely manner from a
failed connection attempt.

To avoid this, each time we need to read from the socket during the
initial brontide handshake, we add a 15 second read deadline. If we
don’t successfully read from the buffer during that time frame, then
the Read method will return a timeout error.

With this in place, we ensure that the main listener goroutine will
never be blocked waiting on a remote party to write ActOne.
This commit is contained in:
Olaoluwa Osuntokun 2017-10-04 14:56:31 -07:00
parent c8226b1393
commit c64811a5f3
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
2 changed files with 24 additions and 0 deletions

@ -55,6 +55,11 @@ func Dial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress) (*Conn, error
return nil, err
}
// We'll ensure that we get ActTwo from the remote peer in a timely
// manner. If they don't respond within 15 seconds, then we'll kill the
// connection.
conn.SetReadDeadline(time.Now().Add(time.Second * 15))
// If the first act was successful (we know that address is actually
// remotePub), then read the second act after which we'll be able to
// send our static public key to the remote peer with strong forward
@ -81,6 +86,10 @@ func Dial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress) (*Conn, error
return nil, err
}
// We'll reset the deadline as it's no longer critical beyond the
// initial handshake.
conn.SetReadDeadline(time.Time{})
return b, nil
}

@ -3,6 +3,7 @@ package brontide
import (
"io"
"net"
"time"
"github.com/roasbeef/btcd/btcec"
)
@ -59,6 +60,11 @@ func (l *Listener) Accept() (net.Conn, error) {
noise: NewBrontideMachine(false, l.localStatic, nil),
}
// We'll ensure that we get ActOne from the remote peer in a timely
// manner. If they don't respond within 15 seconds, then we'll kill the
// connection.
conn.SetReadDeadline(time.Now().Add(time.Second * 15))
// Attempt to carry out the first act of the handshake protocol. If the
// connecting node doesn't know our long-term static public key, then
// this portion will fail with a non-nil error.
@ -84,6 +90,11 @@ func (l *Listener) Accept() (net.Conn, error) {
return nil, err
}
// We'll ensure that we get ActTwo from the remote peer in a timely
// manner. If they don't respond within 15 seconds, then we'll kill the
// connection.
conn.SetReadDeadline(time.Now().Add(time.Second * 15))
// Finally, finish the handshake processes by reading and decrypting
// the connection peer's static public key. If this succeeds then both
// sides have mutually authenticated each other.
@ -97,6 +108,10 @@ func (l *Listener) Accept() (net.Conn, error) {
return nil, err
}
// We'll reset the deadline as it's no longer critical beyond the
// initial handshake.
conn.SetReadDeadline(time.Time{})
return brontideConn, nil
}