• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/brontide/listener.go
1
package brontide
2

3
import (
4
        "errors"
5
        "fmt"
6
        "io"
7
        "net"
8
        "time"
9

10
        "github.com/lightningnetwork/lnd/keychain"
11
)
12

13
// defaultHandshakes is the maximum number of handshakes that can be done in
14
// parallel.
15
const defaultHandshakes = 1000
16

17
// Listener is an implementation of a net.Conn which executes an authenticated
18
// key exchange and message encryption protocol dubbed "Machine" after
19
// initial connection acceptance. See the Machine struct for additional
20
// details w.r.t the handshake and encryption scheme used within the
21
// connection.
22
type Listener struct {
23
        localStatic keychain.SingleKeyECDH
24

25
        tcp *net.TCPListener
26

27
        handshakeSema chan struct{}
28
        conns         chan maybeConn
29
        quit          chan struct{}
30
}
31

32
// A compile-time assertion to ensure that Conn meets the net.Listener interface.
33
var _ net.Listener = (*Listener)(nil)
34

35
// NewListener returns a new net.Listener which enforces the Brontide scheme
36
// during both initial connection establishment and data transfer.
37
func NewListener(localStatic keychain.SingleKeyECDH,
38
        listenAddr string) (*Listener, error) {
3✔
39

3✔
40
        addr, err := net.ResolveTCPAddr("tcp", listenAddr)
3✔
41
        if err != nil {
3✔
42
                return nil, err
×
43
        }
×
44

45
        l, err := net.ListenTCP("tcp", addr)
3✔
46
        if err != nil {
3✔
47
                return nil, err
×
48
        }
×
49

50
        brontideListener := &Listener{
3✔
51
                localStatic:   localStatic,
3✔
52
                tcp:           l,
3✔
53
                handshakeSema: make(chan struct{}, defaultHandshakes),
3✔
54
                conns:         make(chan maybeConn),
3✔
55
                quit:          make(chan struct{}),
3✔
56
        }
3✔
57

3✔
58
        for i := 0; i < defaultHandshakes; i++ {
3,003✔
59
                brontideListener.handshakeSema <- struct{}{}
3,000✔
60
        }
3,000✔
61

62
        go brontideListener.listen()
3✔
63

3✔
64
        return brontideListener, nil
3✔
65
}
66

67
// listen accepts connection from the underlying tcp conn, then performs
68
// the brontinde handshake procedure asynchronously. A maximum of
69
// defaultHandshakes will be active at any given time.
70
//
71
// NOTE: This method must be run as a goroutine.
72
func (l *Listener) listen() {
3✔
73
        for {
22✔
74
                select {
19✔
75
                case <-l.handshakeSema:
16✔
76
                case <-l.quit:
3✔
77
                        return
3✔
78
                }
79

80
                conn, err := l.tcp.Accept()
16✔
81
                if err != nil {
24✔
82
                        l.rejectConn(err)
8✔
83
                        l.handshakeSema <- struct{}{}
8✔
84
                        continue
8✔
85
                }
86

87
                go l.doHandshake(conn)
8✔
88
        }
89
}
90

91
// rejectedConnErr is a helper function that prepends the remote address of the
92
// failed connection attempt to the original error message.
93
func rejectedConnErr(err error, remoteAddr string) error {
5✔
94
        return fmt.Errorf("unable to accept connection from %v: %w", remoteAddr,
5✔
95
                err)
5✔
96
}
5✔
97

98
// doHandshake asynchronously performs the brontide handshake, so that it does
99
// not block the main accept loop. This prevents peers that delay writing to the
100
// connection from block other connection attempts.
101
func (l *Listener) doHandshake(conn net.Conn) {
8✔
102
        defer func() { l.handshakeSema <- struct{}{} }()
16✔
103

104
        select {
8✔
105
        case <-l.quit:
×
106
                return
×
107
        default:
8✔
108
        }
109

110
        remoteAddr := conn.RemoteAddr().String()
8✔
111

8✔
112
        brontideConn := &Conn{
8✔
113
                conn:  conn,
8✔
114
                noise: NewBrontideMachine(false, l.localStatic, nil),
8✔
115
        }
8✔
116

8✔
117
        // We'll ensure that we get ActOne from the remote peer in a timely
8✔
118
        // manner. If they don't respond within handshakeReadTimeout, then
8✔
119
        // we'll kill the connection.
8✔
120
        err := conn.SetReadDeadline(time.Now().Add(handshakeReadTimeout))
8✔
121
        if err != nil {
8✔
122
                brontideConn.conn.Close()
×
123
                l.rejectConn(rejectedConnErr(err, remoteAddr))
×
124
                return
×
125
        }
×
126

127
        // Attempt to carry out the first act of the handshake protocol. If the
128
        // connecting node doesn't know our long-term static public key, then
129
        // this portion will fail with a non-nil error.
130
        var actOne [ActOneSize]byte
8✔
131
        if _, err := io.ReadFull(conn, actOne[:]); err != nil {
13✔
132
                brontideConn.conn.Close()
5✔
133
                l.rejectConn(rejectedConnErr(err, remoteAddr))
5✔
134
                return
5✔
135
        }
5✔
136
        if err := brontideConn.noise.RecvActOne(actOne); err != nil {
3✔
137
                brontideConn.conn.Close()
×
138
                l.rejectConn(rejectedConnErr(err, remoteAddr))
×
139
                return
×
140
        }
×
141

142
        // Next, progress the handshake processes by sending over our ephemeral
143
        // key for the session along with an authenticating tag.
144
        actTwo, err := brontideConn.noise.GenActTwo()
3✔
145
        if err != nil {
3✔
146
                brontideConn.conn.Close()
×
147
                l.rejectConn(rejectedConnErr(err, remoteAddr))
×
148
                return
×
149
        }
×
150
        if _, err := conn.Write(actTwo[:]); err != nil {
3✔
151
                brontideConn.conn.Close()
×
152
                l.rejectConn(rejectedConnErr(err, remoteAddr))
×
153
                return
×
154
        }
×
155

156
        select {
3✔
157
        case <-l.quit:
×
158
                return
×
159
        default:
3✔
160
        }
161

162
        // We'll ensure that we get ActTwo from the remote peer in a timely
163
        // manner. If they don't respond within handshakeReadTimeout, then
164
        // we'll kill the connection.
165
        err = conn.SetReadDeadline(time.Now().Add(handshakeReadTimeout))
3✔
166
        if err != nil {
3✔
167
                brontideConn.conn.Close()
×
168
                l.rejectConn(rejectedConnErr(err, remoteAddr))
×
169
                return
×
170
        }
×
171

172
        // Finally, finish the handshake processes by reading and decrypting
173
        // the connection peer's static public key. If this succeeds then both
174
        // sides have mutually authenticated each other.
175
        var actThree [ActThreeSize]byte
3✔
176
        if _, err := io.ReadFull(conn, actThree[:]); err != nil {
3✔
UNCOV
177
                brontideConn.conn.Close()
×
UNCOV
178
                l.rejectConn(rejectedConnErr(err, remoteAddr))
×
UNCOV
179
                return
×
UNCOV
180
        }
×
181
        if err := brontideConn.noise.RecvActThree(actThree); err != nil {
3✔
182
                brontideConn.conn.Close()
×
183
                l.rejectConn(rejectedConnErr(err, remoteAddr))
×
184
                return
×
185
        }
×
186

187
        // We'll reset the deadline as it's no longer critical beyond the
188
        // initial handshake.
189
        err = conn.SetReadDeadline(time.Time{})
3✔
190
        if err != nil {
3✔
191
                brontideConn.conn.Close()
×
192
                l.rejectConn(rejectedConnErr(err, remoteAddr))
×
193
                return
×
194
        }
×
195

196
        l.acceptConn(brontideConn)
3✔
197
}
198

199
// maybeConn holds either a brontide connection or an error returned from the
200
// handshake.
201
type maybeConn struct {
202
        conn *Conn
203
        err  error
204
}
205

206
// acceptConn returns a connection that successfully performed a handshake.
207
func (l *Listener) acceptConn(conn *Conn) {
3✔
208
        select {
3✔
209
        case l.conns <- maybeConn{conn: conn}:
3✔
210
        case <-l.quit:
×
211
        }
212
}
213

214
// rejectConn returns any errors encountered during connection or handshake.
215
func (l *Listener) rejectConn(err error) {
13✔
216
        select {
13✔
UNCOV
217
        case l.conns <- maybeConn{err: err}:
×
218
        case <-l.quit:
13✔
219
        }
220
}
221

222
// Accept waits for and returns the next connection to the listener. All
223
// incoming connections are authenticated via the three act Brontide
224
// key-exchange scheme. This function will fail with a non-nil error in the
225
// case that either the handshake breaks down, or the remote peer doesn't know
226
// our static public key.
227
//
228
// Part of the net.Listener interface.
229
func (l *Listener) Accept() (net.Conn, error) {
3✔
230
        select {
3✔
231
        case result := <-l.conns:
3✔
232
                return result.conn, result.err
3✔
UNCOV
233
        case <-l.quit:
×
UNCOV
234
                return nil, errors.New("brontide connection closed")
×
235
        }
236
}
237

238
// Close closes the listener.  Any blocked Accept operations will be unblocked
239
// and return errors.
240
//
241
// Part of the net.Listener interface.
242
func (l *Listener) Close() error {
3✔
243
        select {
3✔
244
        case <-l.quit:
×
245
        default:
3✔
246
                close(l.quit)
3✔
247
        }
248

249
        return l.tcp.Close()
3✔
250
}
251

252
// Addr returns the listener's network address.
253
//
254
// Part of the net.Listener interface.
255
func (l *Listener) Addr() net.Addr {
8✔
256
        return l.tcp.Addr()
8✔
257
}
8✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc