From c64811a5f3853e6a4f60e8bed2d9fba46807f2fa Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 4 Oct 2017 14:56:31 -0700 Subject: [PATCH] brontide: set read deadlines on socket during initial handshake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- brontide/conn.go | 9 +++++++++ brontide/listener.go | 15 +++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/brontide/conn.go b/brontide/conn.go index 7cda1a0a..da87c9c1 100644 --- a/brontide/conn.go +++ b/brontide/conn.go @@ -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 } diff --git a/brontide/listener.go b/brontide/listener.go index 9a2ca498..1cc171f6 100644 --- a/brontide/listener.go +++ b/brontide/listener.go @@ -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 }