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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 hits per line

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

53.28
/brontide/conn.go
1
package brontide
2

3
import (
4
        "bytes"
5
        "io"
6
        "math"
7
        "net"
8
        "time"
9

10
        "github.com/btcsuite/btcd/btcec/v2"
11
        "github.com/lightningnetwork/lnd/keychain"
12
        "github.com/lightningnetwork/lnd/lnwire"
13
        "github.com/lightningnetwork/lnd/tor"
14
)
15

16
// Conn is an implementation of net.Conn which enforces an authenticated key
17
// exchange and message encryption protocol dubbed "Brontide" after initial TCP
18
// connection establishment. In the case of a successful handshake, all
19
// messages sent via the .Write() method are encrypted with an AEAD cipher
20
// along with an encrypted length-prefix. See the Machine struct for
21
// additional details w.r.t to the handshake and encryption scheme.
22
type Conn struct {
23
        conn net.Conn
24

25
        noise *Machine
26

27
        readBuf bytes.Buffer
28
}
29

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

33
// Dial attempts to establish an encrypted+authenticated connection with the
34
// remote peer located at address which has remotePub as its long-term static
35
// public key. In the case of a handshake failure, the connection is closed and
36
// a non-nil error is returned.
37
func Dial(local keychain.SingleKeyECDH, netAddr *lnwire.NetAddress,
38
        timeout time.Duration, dialer tor.DialFunc) (*Conn, error) {
3✔
39

3✔
40
        ipAddr := netAddr.Address.String()
3✔
41
        var conn net.Conn
3✔
42
        var err error
3✔
43
        conn, err = dialer("tcp", ipAddr, timeout)
3✔
44
        if err != nil {
6✔
45
                return nil, err
3✔
46
        }
3✔
47

48
        b := &Conn{
3✔
49
                conn:  conn,
3✔
50
                noise: NewBrontideMachine(true, local, netAddr.IdentityKey),
3✔
51
        }
3✔
52

3✔
53
        // Initiate the handshake by sending the first act to the receiver.
3✔
54
        actOne, err := b.noise.GenActOne()
3✔
55
        if err != nil {
3✔
56
                b.conn.Close()
×
57
                return nil, err
×
58
        }
×
59
        if _, err := conn.Write(actOne[:]); err != nil {
3✔
60
                b.conn.Close()
×
61
                return nil, err
×
62
        }
×
63

64
        // We'll ensure that we get ActTwo from the remote peer in a timely
65
        // manner. If they don't respond within handshakeReadTimeout, then
66
        // we'll kill the connection.
67
        err = conn.SetReadDeadline(time.Now().Add(handshakeReadTimeout))
3✔
68
        if err != nil {
3✔
69
                b.conn.Close()
×
70
                return nil, err
×
71
        }
×
72

73
        // If the first act was successful (we know that address is actually
74
        // remotePub), then read the second act after which we'll be able to
75
        // send our static public key to the remote peer with strong forward
76
        // secrecy.
77
        var actTwo [ActTwoSize]byte
3✔
78
        if _, err := io.ReadFull(conn, actTwo[:]); err != nil {
6✔
79
                b.conn.Close()
3✔
80
                return nil, err
3✔
81
        }
3✔
82
        if err := b.noise.RecvActTwo(actTwo); err != nil {
3✔
83
                b.conn.Close()
×
84
                return nil, err
×
85
        }
×
86

87
        // Finally, complete the handshake by sending over our encrypted static
88
        // key and execute the final ECDH operation.
89
        actThree, err := b.noise.GenActThree()
3✔
90
        if err != nil {
3✔
91
                b.conn.Close()
×
92
                return nil, err
×
93
        }
×
94
        if _, err := conn.Write(actThree[:]); err != nil {
3✔
95
                b.conn.Close()
×
96
                return nil, err
×
97
        }
×
98

99
        // We'll reset the deadline as it's no longer critical beyond the
100
        // initial handshake.
101
        err = conn.SetReadDeadline(time.Time{})
3✔
102
        if err != nil {
3✔
103
                b.conn.Close()
×
104
                return nil, err
×
105
        }
×
106

107
        return b, nil
3✔
108
}
109

110
// ReadNextMessage uses the connection in a message-oriented manner, instructing
111
// it to read the next _full_ message with the brontide stream. This function
112
// will block until the read of the header and body succeeds.
113
//
114
// NOTE: This method SHOULD NOT be used in the case that the connection may be
115
// adversarial and induce long delays. If the caller needs to set read deadlines
116
// appropriately, it is preferred that they use the split ReadNextHeader and
117
// ReadNextBody methods so that the deadlines can be set appropriately on each.
118
func (c *Conn) ReadNextMessage() ([]byte, error) {
3✔
119
        return c.noise.ReadMessage(c.conn)
3✔
120
}
3✔
121

122
// ReadNextHeader uses the connection to read the next header from the brontide
123
// stream. This function will block until the read of the header succeeds and
124
// return the packet length (including MAC overhead) that is expected from the
125
// subsequent call to ReadNextBody.
126
func (c *Conn) ReadNextHeader() (uint32, error) {
3✔
127
        return c.noise.ReadHeader(c.conn)
3✔
128
}
3✔
129

130
// ReadNextBody uses the connection to read the next message body from the
131
// brontide stream. This function will block until the read of the body succeeds
132
// and return the decrypted payload. The provided buffer MUST be the packet
133
// length returned by the preceding call to ReadNextHeader.
134
func (c *Conn) ReadNextBody(buf []byte) ([]byte, error) {
3✔
135
        return c.noise.ReadBody(c.conn, buf)
3✔
136
}
3✔
137

138
// Read reads data from the connection.  Read can be made to time out and
139
// return an Error with Timeout() == true after a fixed time limit; see
140
// SetDeadline and SetReadDeadline.
141
//
142
// Part of the net.Conn interface.
UNCOV
143
func (c *Conn) Read(b []byte) (n int, err error) {
×
UNCOV
144
        // In order to reconcile the differences between the record abstraction
×
UNCOV
145
        // of our AEAD connection, and the stream abstraction of TCP, we
×
UNCOV
146
        // maintain an intermediate read buffer. If this buffer becomes
×
UNCOV
147
        // depleted, then we read the next record, and feed it into the
×
UNCOV
148
        // buffer. Otherwise, we read directly from the buffer.
×
UNCOV
149
        if c.readBuf.Len() == 0 {
×
UNCOV
150
                plaintext, err := c.noise.ReadMessage(c.conn)
×
UNCOV
151
                if err != nil {
×
152
                        return 0, err
×
153
                }
×
154

UNCOV
155
                if _, err := c.readBuf.Write(plaintext); err != nil {
×
156
                        return 0, err
×
157
                }
×
158
        }
159

UNCOV
160
        return c.readBuf.Read(b)
×
161
}
162

163
// Write writes data to the connection.  Write can be made to time out and
164
// return an Error with Timeout() == true after a fixed time limit; see
165
// SetDeadline and SetWriteDeadline.
166
//
167
// Part of the net.Conn interface.
168
func (c *Conn) Write(b []byte) (n int, err error) {
3✔
169
        // If the message doesn't require any chunking, then we can go ahead
3✔
170
        // with a single write.
3✔
171
        if len(b) <= math.MaxUint16 {
6✔
172
                err = c.noise.WriteMessage(b)
3✔
173
                if err != nil {
3✔
174
                        return 0, err
×
175
                }
×
176
                return c.noise.Flush(c.conn)
3✔
177
        }
178

179
        // If we need to split the message into fragments, then we'll write
180
        // chunks which maximize usage of the available payload.
UNCOV
181
        chunkSize := math.MaxUint16
×
UNCOV
182

×
UNCOV
183
        bytesToWrite := len(b)
×
UNCOV
184
        bytesWritten := 0
×
UNCOV
185
        for bytesWritten < bytesToWrite {
×
UNCOV
186
                // If we're on the last chunk, then truncate the chunk size as
×
UNCOV
187
                // necessary to avoid an out-of-bounds array memory access.
×
UNCOV
188
                if bytesWritten+chunkSize > len(b) {
×
189
                        chunkSize = len(b) - bytesWritten
×
190
                }
×
191

192
                // Slice off the next chunk to be written based on our running
193
                // counter and next chunk size.
UNCOV
194
                chunk := b[bytesWritten : bytesWritten+chunkSize]
×
UNCOV
195
                if err := c.noise.WriteMessage(chunk); err != nil {
×
196
                        return bytesWritten, err
×
197
                }
×
198

UNCOV
199
                n, err := c.noise.Flush(c.conn)
×
UNCOV
200
                bytesWritten += n
×
UNCOV
201
                if err != nil {
×
202
                        return bytesWritten, err
×
203
                }
×
204
        }
205

UNCOV
206
        return bytesWritten, nil
×
207
}
208

209
// WriteMessage encrypts and buffers the next message p for the connection. The
210
// ciphertext of the message is prepended with an encrypt+auth'd length which
211
// must be used as the AD to the AEAD construction when being decrypted by the
212
// other side.
213
//
214
// NOTE: This DOES NOT write the message to the wire, it should be followed by a
215
// call to Flush to ensure the message is written.
216
func (c *Conn) WriteMessage(b []byte) error {
3✔
217
        return c.noise.WriteMessage(b)
3✔
218
}
3✔
219

220
// Flush attempts to write a message buffered using WriteMessage to the
221
// underlying connection. If no buffered message exists, this will result in a
222
// NOP. Otherwise, it will continue to write the remaining bytes, picking up
223
// where the byte stream left off in the event of a partial write. The number of
224
// bytes returned reflects the number of plaintext bytes in the payload, and
225
// does not account for the overhead of the header or MACs.
226
//
227
// NOTE: It is safe to call this method again iff a timeout error is returned.
228
func (c *Conn) Flush() (int, error) {
3✔
229
        return c.noise.Flush(c.conn)
3✔
230
}
3✔
231

232
// Close closes the connection. Any blocked Read or Write operations will be
233
// unblocked and return errors.
234
//
235
// Part of the net.Conn interface.
236
func (c *Conn) Close() error {
3✔
237
        // TODO(roasbeef): reset brontide state?
3✔
238
        return c.conn.Close()
3✔
239
}
3✔
240

241
// LocalAddr returns the local network address.
242
//
243
// Part of the net.Conn interface.
244
func (c *Conn) LocalAddr() net.Addr {
3✔
245
        return c.conn.LocalAddr()
3✔
246
}
3✔
247

248
// RemoteAddr returns the remote network address.
249
//
250
// Part of the net.Conn interface.
251
func (c *Conn) RemoteAddr() net.Addr {
3✔
252
        return c.conn.RemoteAddr()
3✔
253
}
3✔
254

255
// SetDeadline sets the read and write deadlines associated with the
256
// connection. It is equivalent to calling both SetReadDeadline and
257
// SetWriteDeadline.
258
//
259
// Part of the net.Conn interface.
260
func (c *Conn) SetDeadline(t time.Time) error {
×
261
        return c.conn.SetDeadline(t)
×
262
}
×
263

264
// SetReadDeadline sets the deadline for future Read calls. A zero value for t
265
// means Read will not time out.
266
//
267
// Part of the net.Conn interface.
268
func (c *Conn) SetReadDeadline(t time.Time) error {
3✔
269
        return c.conn.SetReadDeadline(t)
3✔
270
}
3✔
271

272
// SetWriteDeadline sets the deadline for future Write calls. Even if write
273
// times out, it may return n > 0, indicating that some of the data was
274
// successfully written. A zero value for t means Write will not time out.
275
//
276
// Part of the net.Conn interface.
277
func (c *Conn) SetWriteDeadline(t time.Time) error {
3✔
278
        return c.conn.SetWriteDeadline(t)
3✔
279
}
3✔
280

281
// RemotePub returns the remote peer's static public key.
282
func (c *Conn) RemotePub() *btcec.PublicKey {
3✔
283
        return c.noise.remoteStatic
3✔
284
}
3✔
285

286
// LocalPub returns the local peer's static public key.
287
func (c *Conn) LocalPub() *btcec.PublicKey {
×
288
        return c.noise.localStatic.PubKey()
×
289
}
×
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