lnwire: properly encode/decode addrs in NodeAnnouncement msg
This commit fixes an existing deviation in the way we encode+decode the addresses within the NodeAnnouncement message with that of the specification. Prior to this commit, we would encode the _number_ of addresses, rather than the number of bytes it takes to encode all the addresses. In this commit, we fix this mistake by properly writing out the total number of bytes, modifying our parsing to take account of this new encoding.
This commit is contained in:
parent
3e97aa3931
commit
6e7fcac1f5
154
lnwire/lnwire.go
154
lnwire/lnwire.go
@ -1,6 +1,7 @@
|
|||||||
package lnwire
|
package lnwire
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -28,11 +29,47 @@ type PkScript []byte
|
|||||||
type addressType uint8
|
type addressType uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tcp4Addr addressType = 1
|
// noAddr denotes a blank address. An address of this type indicates
|
||||||
tcp6Addr addressType = 2
|
// that a node doesn't have any advertise d addresses.
|
||||||
onionAddr addressType = 3
|
noAddr addressType = 0
|
||||||
|
|
||||||
|
// tcp4Addr denotes an IPv4 TCP address.
|
||||||
|
tcp4Addr addressType = 1
|
||||||
|
|
||||||
|
// tcp4Addr denotes an IPv6 TCP address.
|
||||||
|
tcp6Addr addressType = 2
|
||||||
|
|
||||||
|
// v2OnionAddr denotes a version 2 Tor onion service address.
|
||||||
|
v2OnionAddr addressType = 3
|
||||||
|
|
||||||
|
// v3OnionAddr denotes a version 3 Tor (prop224) onion service
|
||||||
|
// addresses
|
||||||
|
v3OnionAddr addressType = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AddrLen returns the number of bytes that it takes to encode the target
|
||||||
|
// address.
|
||||||
|
func (a addressType) AddrLen() uint16 {
|
||||||
|
switch a {
|
||||||
|
case noAddr:
|
||||||
|
return 0
|
||||||
|
case tcp4Addr:
|
||||||
|
return 6
|
||||||
|
|
||||||
|
case tcp6Addr:
|
||||||
|
return 18
|
||||||
|
|
||||||
|
case v2OnionAddr:
|
||||||
|
return 12
|
||||||
|
|
||||||
|
case v3OnionAddr:
|
||||||
|
return 37
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// writeElement is a one-stop shop to write the big endian representation of
|
// writeElement is a one-stop shop to write the big endian representation of
|
||||||
// any element which is to be serialized for the wire protocol. The passed
|
// any element which is to be serialized for the wire protocol. The passed
|
||||||
// io.Writer should be backed by an appropriately sized byte slice, or be able
|
// io.Writer should be backed by an appropriately sized byte slice, or be able
|
||||||
@ -93,7 +130,6 @@ func writeElement(w io.Writer, element interface{}) error {
|
|||||||
var b [33]byte
|
var b [33]byte
|
||||||
serializedPubkey := e.SerializeCompressed()
|
serializedPubkey := e.SerializeCompressed()
|
||||||
copy(b[:], serializedPubkey)
|
copy(b[:], serializedPubkey)
|
||||||
// TODO(roasbeef): use WriteVarBytes here?
|
|
||||||
if _, err := w.Write(b[:]); err != nil {
|
if _, err := w.Write(b[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -251,6 +287,7 @@ func writeElement(w io.Writer, element interface{}) error {
|
|||||||
return fmt.Errorf("cannot write nil TCPAddr")
|
return fmt.Errorf("cannot write nil TCPAddr")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(roasbeef): account for onion types too
|
||||||
if e.IP.To4() != nil {
|
if e.IP.To4() != nil {
|
||||||
var descriptor [1]byte
|
var descriptor [1]byte
|
||||||
descriptor[0] = uint8(tcp4Addr)
|
descriptor[0] = uint8(tcp4Addr)
|
||||||
@ -280,27 +317,37 @@ func writeElement(w io.Writer, element interface{}) error {
|
|||||||
if _, err := w.Write(port[:]); err != nil {
|
if _, err := w.Write(port[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
case []net.Addr:
|
case []net.Addr:
|
||||||
// Write out the number of addresses.
|
// First, we'll encode all the addresses into an intermediate
|
||||||
if err := writeElement(w, uint16(len(e))); err != nil {
|
// buffer. We need to do this in order to compute the total
|
||||||
|
// length of the addresses.
|
||||||
|
var addrBuf bytes.Buffer
|
||||||
|
for _, address := range e {
|
||||||
|
if err := writeElement(&addrBuf, address); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// With the addresses fully encoded, we can now write out the
|
||||||
|
// number of bytes needed to encode them.
|
||||||
|
addrLen := addrBuf.Len()
|
||||||
|
if err := writeElement(w, uint16(addrLen)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the actual addresses.
|
// Finally, we'll write out the raw addresses themselves, but
|
||||||
for _, address := range e {
|
// only if we have any bytes to write.
|
||||||
if err := writeElement(w, address); err != nil {
|
if addrLen > 0 {
|
||||||
|
if _, err := w.Write(addrBuf.Bytes()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case RGB:
|
case RGB:
|
||||||
err := writeElements(w,
|
if err := writeElements(w, e.red, e.green, e.blue); err != nil {
|
||||||
e.red,
|
|
||||||
e.green,
|
|
||||||
e.blue,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
case DeliveryAddress:
|
case DeliveryAddress:
|
||||||
var length [2]byte
|
var length [2]byte
|
||||||
binary.BigEndian.PutUint16(length[:], uint16(len(e)))
|
binary.BigEndian.PutUint16(length[:], uint16(len(e)))
|
||||||
@ -531,44 +578,91 @@ func readElement(r io.Reader, element interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *[]net.Addr:
|
case *[]net.Addr:
|
||||||
|
// First, we'll read the number of total bytes that have been
|
||||||
|
// used to encode the set of addresses.
|
||||||
var numAddrsBytes [2]byte
|
var numAddrsBytes [2]byte
|
||||||
if _, err = io.ReadFull(r, numAddrsBytes[:]); err != nil {
|
if _, err = io.ReadFull(r, numAddrsBytes[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
addrsLen := binary.BigEndian.Uint16(numAddrsBytes[:])
|
||||||
|
|
||||||
numAddrs := binary.BigEndian.Uint16(numAddrsBytes[:])
|
// With the number of addresses, read, we'll now pull in the
|
||||||
addresses := make([]net.Addr, 0, numAddrs)
|
// buffer of the encoded addresses into memory.
|
||||||
|
addrs := make([]byte, addrsLen)
|
||||||
|
if _, err := io.ReadFull(r, addrs[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
addrBuf := bytes.NewReader(addrs)
|
||||||
|
|
||||||
for i := 0; i < int(numAddrs); i++ {
|
// Finally, we'll parse the remaining address payload in
|
||||||
|
// series, using the first byte to denote how to decode the
|
||||||
|
// address itself.
|
||||||
|
var (
|
||||||
|
addresses []net.Addr
|
||||||
|
addrBytesRead uint16
|
||||||
|
)
|
||||||
|
for addrBytesRead < addrsLen {
|
||||||
var descriptor [1]byte
|
var descriptor [1]byte
|
||||||
if _, err = io.ReadFull(r, descriptor[:]); err != nil {
|
if _, err = io.ReadFull(addrBuf, descriptor[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addrBytesRead += 1
|
||||||
|
|
||||||
address := &net.TCPAddr{}
|
address := &net.TCPAddr{}
|
||||||
switch descriptor[0] {
|
aType := addressType(descriptor[0])
|
||||||
case 1:
|
switch aType {
|
||||||
|
|
||||||
|
case noAddr:
|
||||||
|
addrBytesRead += aType.AddrLen()
|
||||||
|
continue
|
||||||
|
|
||||||
|
case tcp4Addr:
|
||||||
var ip [4]byte
|
var ip [4]byte
|
||||||
if _, err = io.ReadFull(r, ip[:]); err != nil {
|
if _, err = io.ReadFull(addrBuf, ip[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
address.IP = (net.IP)(ip[:])
|
address.IP = (net.IP)(ip[:])
|
||||||
case 2:
|
|
||||||
|
var port [2]byte
|
||||||
|
if _, err = io.ReadFull(addrBuf, port[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
address.Port = int(binary.BigEndian.Uint16(port[:]))
|
||||||
|
|
||||||
|
addrBytesRead += aType.AddrLen()
|
||||||
|
|
||||||
|
case tcp6Addr:
|
||||||
var ip [16]byte
|
var ip [16]byte
|
||||||
if _, err = io.ReadFull(r, ip[:]); err != nil {
|
if _, err = io.ReadFull(addrBuf, ip[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
address.IP = (net.IP)(ip[:])
|
address.IP = (net.IP)(ip[:])
|
||||||
|
|
||||||
|
var port [2]byte
|
||||||
|
if _, err = io.ReadFull(addrBuf, port[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
address.Port = int(binary.BigEndian.Uint16(port[:]))
|
||||||
|
|
||||||
|
addrBytesRead += aType.AddrLen()
|
||||||
|
|
||||||
|
case v2OnionAddr:
|
||||||
|
addrBytesRead += aType.AddrLen()
|
||||||
|
continue
|
||||||
|
|
||||||
|
case v3OnionAddr:
|
||||||
|
addrBytesRead += aType.AddrLen()
|
||||||
|
continue
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown address type: %v", aType)
|
||||||
}
|
}
|
||||||
|
|
||||||
var port [2]byte
|
|
||||||
if _, err = io.ReadFull(r, port[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
address.Port = int(binary.BigEndian.Uint16(port[:]))
|
|
||||||
addresses = append(addresses, address)
|
addresses = append(addresses, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
*e = addresses
|
*e = addresses
|
||||||
case *RGB:
|
case *RGB:
|
||||||
err := readElements(r,
|
err := readElements(r,
|
||||||
|
@ -404,6 +404,7 @@ func TestLightningWireProtocol(t *testing.T) {
|
|||||||
green: uint8(r.Int31()),
|
green: uint8(r.Int31()),
|
||||||
blue: uint8(r.Int31()),
|
blue: uint8(r.Int31()),
|
||||||
},
|
},
|
||||||
|
// TODO(roasbeef): proper gen rand addrs
|
||||||
Addresses: testAddrs,
|
Addresses: testAddrs,
|
||||||
}
|
}
|
||||||
req.Features.featuresMap = nil
|
req.Features.featuresMap = nil
|
||||||
|
Loading…
Reference in New Issue
Block a user