• 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

45.99
/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 {
3✔
UNCOV
45
                return nil, err
×
UNCOV
46
        }
×
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 {
3✔
UNCOV
79
                b.conn.Close()
×
UNCOV
80
                return nil, err
×
UNCOV
81
        }
×
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✔
UNCOV
91
                b.conn.Close()
×
UNCOV
92
                return nil, err
×
UNCOV
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.
UNCOV
118
func (c *Conn) ReadNextMessage() ([]byte, error) {
×
UNCOV
119
        return c.noise.ReadMessage(c.conn)
×
UNCOV
120
}
×
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.
UNCOV
126
func (c *Conn) ReadNextHeader() (uint32, error) {
×
UNCOV
127
        return c.noise.ReadHeader(c.conn)
×
UNCOV
128
}
×
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.
UNCOV
134
func (c *Conn) ReadNextBody(buf []byte) ([]byte, error) {
×
UNCOV
135
        return c.noise.ReadBody(c.conn, buf)
×
UNCOV
136
}
×
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.
143
func (c *Conn) Read(b []byte) (n int, err error) {
21✔
144
        // In order to reconcile the differences between the record abstraction
21✔
145
        // of our AEAD connection, and the stream abstraction of TCP, we
21✔
146
        // maintain an intermediate read buffer. If this buffer becomes
21✔
147
        // depleted, then we read the next record, and feed it into the
21✔
148
        // buffer. Otherwise, we read directly from the buffer.
21✔
149
        if c.readBuf.Len() == 0 {
41✔
150
                plaintext, err := c.noise.ReadMessage(c.conn)
20✔
151
                if err != nil {
20✔
152
                        return 0, err
×
153
                }
×
154

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

160
        return c.readBuf.Read(b)
21✔
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) {
12✔
169
        // If the message doesn't require any chunking, then we can go ahead
12✔
170
        // with a single write.
12✔
171
        if len(b) <= math.MaxUint16 {
23✔
172
                err = c.noise.WriteMessage(b)
11✔
173
                if err != nil {
11✔
174
                        return 0, err
×
175
                }
×
176
                return c.noise.Flush(c.conn)
11✔
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.
181
        chunkSize := math.MaxUint16
1✔
182

1✔
183
        bytesToWrite := len(b)
1✔
184
        bytesWritten := 0
1✔
185
        for bytesWritten < bytesToWrite {
10✔
186
                // If we're on the last chunk, then truncate the chunk size as
9✔
187
                // necessary to avoid an out-of-bounds array memory access.
9✔
188
                if bytesWritten+chunkSize > len(b) {
9✔
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.
194
                chunk := b[bytesWritten : bytesWritten+chunkSize]
9✔
195
                if err := c.noise.WriteMessage(chunk); err != nil {
9✔
196
                        return bytesWritten, err
×
197
                }
×
198

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

206
        return bytesWritten, nil
1✔
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.
UNCOV
216
func (c *Conn) WriteMessage(b []byte) error {
×
UNCOV
217
        return c.noise.WriteMessage(b)
×
UNCOV
218
}
×
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.
UNCOV
228
func (c *Conn) Flush() (int, error) {
×
UNCOV
229
        return c.noise.Flush(c.conn)
×
UNCOV
230
}
×
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 {
6✔
237
        // TODO(roasbeef): reset brontide state?
6✔
238
        return c.conn.Close()
6✔
239
}
6✔
240

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

248
// RemoteAddr returns the remote network address.
249
//
250
// Part of the net.Conn interface.
UNCOV
251
func (c *Conn) RemoteAddr() net.Addr {
×
UNCOV
252
        return c.conn.RemoteAddr()
×
UNCOV
253
}
×
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.
UNCOV
268
func (c *Conn) SetReadDeadline(t time.Time) error {
×
UNCOV
269
        return c.conn.SetReadDeadline(t)
×
UNCOV
270
}
×
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.
UNCOV
277
func (c *Conn) SetWriteDeadline(t time.Time) error {
×
UNCOV
278
        return c.conn.SetWriteDeadline(t)
×
UNCOV
279
}
×
280

281
// RemotePub returns the remote peer's static public key.
UNCOV
282
func (c *Conn) RemotePub() *btcec.PublicKey {
×
UNCOV
283
        return c.noise.remoteStatic
×
UNCOV
284
}
×
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