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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 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