diff --git a/lnwire/announcement_signatures_test.go b/lnwire/announcement_signatures_test.go index 39fa0646..3b1ac4da 100644 --- a/lnwire/announcement_signatures_test.go +++ b/lnwire/announcement_signatures_test.go @@ -8,7 +8,7 @@ import ( func TestAnnounceSignatureEncodeDecode(t *testing.T) { ac := &AnnounceSignatures{ - ChannelID: *outpoint1, + ChannelID: ChannelID(revHash), ShortChannelID: NewShortChanIDFromInt(1), NodeSignature: someSig, BitcoinSignature: someSig, diff --git a/lnwire/close_request_test.go b/lnwire/close_request_test.go index ff92307a..a7184afc 100644 --- a/lnwire/close_request_test.go +++ b/lnwire/close_request_test.go @@ -10,7 +10,7 @@ import ( func TestCloseRequestEncodeDecode(t *testing.T) { cr := &CloseRequest{ - ChannelPoint: *outpoint1, + ChanID: ChannelID(revHash), RequesterCloseSig: commitSig, Fee: btcutil.Amount(10000), } diff --git a/lnwire/lnwire.go b/lnwire/lnwire.go index 21f7d82c..f25163de 100644 --- a/lnwire/lnwire.go +++ b/lnwire/lnwire.go @@ -174,6 +174,26 @@ func writeElement(w io.Writer, element interface{}) error { if _, err := w.Write(b[:]); err != nil { return err } + case PingPayload: + var l [2]byte + binary.BigEndian.PutUint16(l[:], uint16(len(e))) + if _, err := w.Write(l[:]); err != nil { + return err + } + + if _, err := w.Write(e[:]); err != nil { + return err + } + case PongPayload: + var l [2]byte + binary.BigEndian.PutUint16(l[:], uint16(len(e))) + if _, err := w.Write(l[:]); err != nil { + return err + } + + if _, err := w.Write(e[:]); err != nil { + return err + } case ErrorData: var l [2]byte binary.BigEndian.PutUint16(l[:], uint16(len(e))) @@ -535,6 +555,28 @@ func readElement(r io.Reader, element interface{}) error { if _, err := io.ReadFull(r, *e); err != nil { return err } + case *PingPayload: + var l [2]byte + if _, err := io.ReadFull(r, l[:]); err != nil { + return err + } + pingLen := binary.BigEndian.Uint16(l[:]) + + *e = PingPayload(make([]byte, pingLen)) + if _, err := io.ReadFull(r, *e); err != nil { + return err + } + case *PongPayload: + var l [2]byte + if _, err := io.ReadFull(r, l[:]); err != nil { + return err + } + pongLen := binary.BigEndian.Uint16(l[:]) + + *e = PongPayload(make([]byte, pongLen)) + if _, err := io.ReadFull(r, *e); err != nil { + return err + } case *[6]byte: if _, err := io.ReadFull(r, e[:]); err != nil { return err diff --git a/lnwire/ping.go b/lnwire/ping.go index 2cf2be9b..d951e15a 100644 --- a/lnwire/ping.go +++ b/lnwire/ping.go @@ -2,19 +2,28 @@ package lnwire import "io" +// PingPayload is a set of opaque bytes used to pad out a ping message. +type PingPayload []byte + // Ping defines a message which is sent by peers periodically to determine if -// the connection is still valid. Each ping message should carry a unique nonce -// which is to be echoed back within the Pong response. +// the connection is still valid. Each ping message carries the number of bytes +// to pad the pong response with, and also a number of bytes to be ignored at +// the end of the ping message (which is padding). type Ping struct { - // Nonce is a unique value associated with this ping message. The pong - // message that responds to this ping should reference the same value. - Nonce uint64 + // NumPongBytes is the number of bytes the pong response to this + // message should carry. + NumPongBytes uint16 + + // PaddingBytes is a set of opaque bytes used to pad out this ping + // message. Using this field in conjunction to the one above, it's + // possible for node to generate fake cover traffic. + PaddingBytes PingPayload } -// NewPing returns a new Ping message binded to the specified nonce. -func NewPing(nonce uint64) *Ping { +// NewPing returns a new Ping message. +func NewPing(numBytes uint16) *Ping { return &Ping{ - Nonce: nonce, + NumPongBytes: numBytes, } } @@ -27,8 +36,8 @@ var _ Message = (*Ping)(nil) // This is part of the lnwire.Message interface. func (p *Ping) Decode(r io.Reader, pver uint32) error { return readElements(r, - &p.Nonce, - ) + &p.NumPongBytes, + &p.PaddingBytes) } // Encode serializes the target Ping into the passed io.Writer observing the @@ -37,8 +46,8 @@ func (p *Ping) Decode(r io.Reader, pver uint32) error { // This is part of the lnwire.Message interface. func (p *Ping) Encode(w io.Writer, pver uint32) error { return writeElements(w, - p.Nonce, - ) + p.NumPongBytes, + p.PaddingBytes) } // Command returns the integer uniquely identifying this message type on the @@ -54,7 +63,7 @@ func (p *Ping) Command() uint32 { // // This is part of the lnwire.Message interface. func (p Ping) MaxPayloadLength(uint32) uint32 { - return 8 + return 65532 } // Validate performs any necessary sanity checks to ensure all fields present diff --git a/lnwire/ping_test.go b/lnwire/ping_test.go index c0b5a2f1..547a9b94 100644 --- a/lnwire/ping_test.go +++ b/lnwire/ping_test.go @@ -6,26 +6,27 @@ import ( "testing" ) -func TestPongEncodeDecode(t *testing.T) { - pong := &Pong{ - Nonce: 9, +func TestPingEncodeDecode(t *testing.T) { + ping := &Ping{ + NumPongBytes: 10, + PaddingBytes: bytes.Repeat([]byte("A"), 100), } - // Next encode the pong message into an empty bytes buffer. + // Next encode the ping message into an empty bytes buffer. var b bytes.Buffer - if err := pong.Encode(&b, 0); err != nil { - t.Fatalf("unable to encode pong: %v", err) + if err := ping.Encode(&b, 0); err != nil { + t.Fatalf("unable to encode ping: %v", err) } - // Deserialize the encoded pong message into a new empty struct. - pong2 := &Pong{} - if err := pong2.Decode(&b, 0); err != nil { + // Deserialize the encoded ping message into a new empty struct. + ping2 := &Ping{} + if err := ping2.Decode(&b, 0); err != nil { t.Fatalf("unable to decode ping: %v", err) } // Assert equality of the two instances. - if !reflect.DeepEqual(pong, pong2) { - t.Fatalf("encode/decode pong messages don't match %#v vs %#v", - pong, pong2) + if !reflect.DeepEqual(ping, ping2) { + t.Fatalf("encode/decode ping messages don't match %#v vs %#v", + ping, ping2) } } diff --git a/lnwire/pong.go b/lnwire/pong.go index fd75d32e..26011e12 100644 --- a/lnwire/pong.go +++ b/lnwire/pong.go @@ -2,20 +2,24 @@ package lnwire import "io" +// PingPayload is a set of opaque bytes sent in response to a ping message. +type PongPayload []byte + // Pong defines a message which is the direct response to a received Ping // message. A Pong reply indicates that a connection is still active. The Pong // reply to a Ping message should contain the nonce carried in the original // Pong message. type Pong struct { - // Nonce is the unique nonce that was associated with the Ping message - // that this Pong is replying to. - Nonce uint64 + // PongBytes is a set of opaque bytes that corresponds to the + // NumPongBytes defined in the ping message that this this pong is + // replying to. + PongBytes PongPayload } -// NewPong returns a new Pong message binded to the specified nonce. -func NewPong(nonce uint64) *Pong { +// NewPong returns a new Pong message. +func NewPong(pongBytes []byte) *Pong { return &Pong{ - Nonce: nonce, + PongBytes: pongBytes, } } @@ -28,7 +32,7 @@ var _ Message = (*Pong)(nil) // This is part of the lnwire.Message interface. func (p *Pong) Decode(r io.Reader, pver uint32) error { return readElements(r, - &p.Nonce, + &p.PongBytes, ) } @@ -38,7 +42,7 @@ func (p *Pong) Decode(r io.Reader, pver uint32) error { // This is part of the lnwire.Message interface. func (p *Pong) Encode(w io.Writer, pver uint32) error { return writeElements(w, - p.Nonce, + p.PongBytes, ) } @@ -55,7 +59,7 @@ func (p *Pong) Command() uint32 { // // This is part of the lnwire.Message interface. func (p *Pong) MaxPayloadLength(uint32) uint32 { - return 8 + return 65532 } // Validate performs any necessary sanity checks to ensure all fields present diff --git a/lnwire/pong_test.go b/lnwire/pong_test.go index 896a543d..8a415fcd 100644 --- a/lnwire/pong_test.go +++ b/lnwire/pong_test.go @@ -6,26 +6,26 @@ import ( "testing" ) -func TestPingEncodeDecode(t *testing.T) { - ping := &Ping{ - Nonce: 9, +func TestPongEncodeDecode(t *testing.T) { + pong := &Pong{ + PongBytes: bytes.Repeat([]byte("A"), 100), } - // Next encode the ping message into an empty bytes buffer. + // Next encode the pong message into an empty bytes buffer. var b bytes.Buffer - if err := ping.Encode(&b, 0); err != nil { - t.Fatalf("unable to encode ping: %v", err) + if err := pong.Encode(&b, 0); err != nil { + t.Fatalf("unable to encode pong: %v", err) } - // Deserialize the encoded ping message into a new empty struct. - ping2 := &Ping{} - if err := ping2.Decode(&b, 0); err != nil { + // Deserialize the encoded pong message into a new empty struct. + pong2 := &Pong{} + if err := pong2.Decode(&b, 0); err != nil { t.Fatalf("unable to decode ping: %v", err) } // Assert equality of the two instances. - if !reflect.DeepEqual(ping, ping2) { - t.Fatalf("encode/decode ping messages don't match %#v vs %#v", - ping, ping2) + if !reflect.DeepEqual(pong, pong2) { + t.Fatalf("encode/decode pong messages don't match %#v vs %#v", + pong, pong2) } } diff --git a/peer.go b/peer.go index 4fa3600c..27985dfb 100644 --- a/peer.go +++ b/peer.go @@ -3,9 +3,7 @@ package main import ( "bytes" "container/list" - "crypto/rand" "crypto/sha256" - "encoding/binary" "fmt" "net" "sync" @@ -436,7 +434,8 @@ out: atomic.StoreInt64(&p.pingTime, delay) case *lnwire.Ping: - p.queueMsg(lnwire.NewPong(msg.Nonce), nil) + pongBytes := make([]byte, msg.NumPongBytes) + p.queueMsg(lnwire.NewPong(pongBytes), nil) case *lnwire.SingleFundingRequest: p.server.fundingMgr.processFundingRequest(msg, p.addr) @@ -694,25 +693,14 @@ func (p *peer) pingHandler() { pingTicker := time.NewTicker(pingInterval) defer pingTicker.Stop() - var pingBuf [8]byte + // TODO(roasbeef): make dynamic in order to create fake cover traffic + const numPingBytes = 16 out: for { select { case <-pingTicker.C: - // Fill the ping buffer with fresh randomness. If we're - // unable to read enough bytes, then we simply defer - // sending the ping to the next interval. - if _, err := rand.Read(pingBuf[:]); err != nil { - peerLog.Errorf("unable to send ping to %v: %v", p, - err) - continue - } - - // Convert the bytes read into a uint64, and queue the - // message for sending. - nonce := binary.BigEndian.Uint64(pingBuf[:]) - p.queueMsg(lnwire.NewPing(nonce), nil) + p.queueMsg(lnwire.NewPing(numPingBytes), nil) case <-p.quit: break out }