lnwire: extract addr descriptor reading logic

cause we will need to be able to deserialise any persisted OpaqueAddrs
which will have a Payload that we should be able to decode with this
lnwire method to extract any new addresses that we now support.

Co-authored-by: Elle Mouton <elle.mouton@gmail.com>
This commit is contained in:
Elle Mouton
2025-08-14 13:28:03 +00:00
committed by Mohamed Awnallah
parent 5844bb0477
commit 0a064d531c

View File

@@ -719,174 +719,9 @@ 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 addresses, err := ReadAddresses(r)
// used to encode the set of addresses. if err != nil {
var numAddrsBytes [2]byte return fmt.Errorf("unable to read addresses: %w", err)
if _, err = io.ReadFull(r, numAddrsBytes[:]); err != nil {
return err
}
addrsLen := binary.BigEndian.Uint16(numAddrsBytes[:])
// With the number of addresses, read, we'll now pull in the
// 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)
// 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
if _, err = io.ReadFull(addrBuf, descriptor[:]); err != nil {
return err
}
addrBytesRead++
var address net.Addr
switch aType := addressType(descriptor[0]); aType {
case noAddr:
continue
case tcp4Addr:
var ip [4]byte
if _, err := io.ReadFull(addrBuf, ip[:]); err != nil {
return err
}
var port [2]byte
if _, err := io.ReadFull(addrBuf, port[:]); err != nil {
return err
}
address = &net.TCPAddr{
IP: net.IP(ip[:]),
Port: int(binary.BigEndian.Uint16(port[:])),
}
addrBytesRead += tcp4AddrLen
case tcp6Addr:
var ip [16]byte
if _, err := io.ReadFull(addrBuf, ip[:]); err != nil {
return err
}
var port [2]byte
if _, err := io.ReadFull(addrBuf, port[:]); err != nil {
return err
}
address = &net.TCPAddr{
IP: net.IP(ip[:]),
Port: int(binary.BigEndian.Uint16(port[:])),
}
addrBytesRead += tcp6AddrLen
case v2OnionAddr:
var h [tor.V2DecodedLen]byte
if _, err := io.ReadFull(addrBuf, h[:]); err != nil {
return err
}
var p [2]byte
if _, err := io.ReadFull(addrBuf, p[:]); err != nil {
return err
}
onionService := tor.Base32Encoding.EncodeToString(h[:])
onionService += tor.OnionSuffix
port := int(binary.BigEndian.Uint16(p[:]))
address = &tor.OnionAddr{
OnionService: onionService,
Port: port,
}
addrBytesRead += v2OnionAddrLen
case v3OnionAddr:
var h [tor.V3DecodedLen]byte
if _, err := io.ReadFull(addrBuf, h[:]); err != nil {
return err
}
var p [2]byte
if _, err := io.ReadFull(addrBuf, p[:]); err != nil {
return err
}
onionService := tor.Base32Encoding.EncodeToString(h[:])
onionService += tor.OnionSuffix
port := int(binary.BigEndian.Uint16(p[:]))
address = &tor.OnionAddr{
OnionService: onionService,
Port: port,
}
addrBytesRead += v3OnionAddrLen
case dnsAddr:
var hostnameLen [1]byte
_, err := io.ReadFull(addrBuf, hostnameLen[:])
if err != nil {
return err
}
hostname := make([]byte, hostnameLen[0])
_, err = io.ReadFull(addrBuf, hostname)
if err != nil {
return err
}
var port [2]byte
_, err = io.ReadFull(addrBuf, port[:])
if err != nil {
return err
}
address = &DNSAddress{
Hostname: string(hostname),
Port: binary.BigEndian.Uint16(
port[:],
),
}
addrBytesRead += dnsAddrOverhead +
uint16(len(hostname))
default:
// If we don't understand this address type,
// we just store it along with the remaining
// address bytes as type OpaqueAddrs. We need
// to hold onto the bytes so that we can still
// write them back to the wire when we
// propagate this message.
payloadLen := 1 + addrsLen - addrBytesRead
payload := make([]byte, payloadLen)
// First write a byte for the address type that
// we already read.
payload[0] = byte(aType)
// Now append the rest of the address bytes.
_, err := io.ReadFull(addrBuf, payload[1:])
if err != nil {
return err
}
address = &OpaqueAddrs{
Payload: payload,
}
addrBytesRead = addrsLen
}
addresses = append(addresses, address)
} }
*e = addresses *e = addresses
@@ -949,3 +784,180 @@ func ReadElements(r io.Reader, elements ...interface{}) error {
} }
return nil return nil
} }
// ReadAddresses reads encoded network addresses.
//
//nolint:funlen
func ReadAddresses(r io.Reader) ([]net.Addr, error) {
// First, we'll read the number of total bytes that have been
// used to encode the set of addresses.
var numAddrsBytes [2]byte
if _, err := io.ReadFull(r, numAddrsBytes[:]); err != nil {
return nil, err
}
addrsLen := binary.BigEndian.Uint16(numAddrsBytes[:])
// With the number of addresses, read, we'll now pull in the
// buffer of the encoded addresses into memory.
addrs := make([]byte, addrsLen)
if _, err := io.ReadFull(r, addrs); err != nil {
return nil, err
}
addrBuf := bytes.NewReader(addrs)
// 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
if _, err := io.ReadFull(addrBuf, descriptor[:]); err != nil {
return nil, err
}
addrBytesRead++
var address net.Addr
switch aType := addressType(descriptor[0]); aType {
case noAddr:
continue
case tcp4Addr:
var ip [4]byte
if _, err := io.ReadFull(addrBuf, ip[:]); err != nil {
return nil, err
}
var port [2]byte
if _, err := io.ReadFull(addrBuf, port[:]); err != nil {
return nil, err
}
address = &net.TCPAddr{
IP: net.IP(ip[:]),
Port: int(binary.BigEndian.Uint16(port[:])),
}
addrBytesRead += tcp4AddrLen
case tcp6Addr:
var ip [16]byte
if _, err := io.ReadFull(addrBuf, ip[:]); err != nil {
return nil, err
}
var port [2]byte
if _, err := io.ReadFull(addrBuf, port[:]); err != nil {
return nil, err
}
address = &net.TCPAddr{
IP: net.IP(ip[:]),
Port: int(binary.BigEndian.Uint16(port[:])),
}
addrBytesRead += tcp6AddrLen
case v2OnionAddr:
var h [tor.V2DecodedLen]byte
if _, err := io.ReadFull(addrBuf, h[:]); err != nil {
return nil, err
}
var p [2]byte
if _, err := io.ReadFull(addrBuf, p[:]); err != nil {
return nil, err
}
onionService := tor.Base32Encoding.EncodeToString(h[:])
onionService += tor.OnionSuffix
port := int(binary.BigEndian.Uint16(p[:]))
address = &tor.OnionAddr{
OnionService: onionService,
Port: port,
}
addrBytesRead += v2OnionAddrLen
case v3OnionAddr:
var h [tor.V3DecodedLen]byte
if _, err := io.ReadFull(addrBuf, h[:]); err != nil {
return nil, err
}
var p [2]byte
if _, err := io.ReadFull(addrBuf, p[:]); err != nil {
return nil, err
}
onionService := tor.Base32Encoding.EncodeToString(h[:])
onionService += tor.OnionSuffix
port := int(binary.BigEndian.Uint16(p[:]))
address = &tor.OnionAddr{
OnionService: onionService,
Port: port,
}
addrBytesRead += v3OnionAddrLen
case dnsAddr:
var hostnameLen [1]byte
_, err := io.ReadFull(addrBuf, hostnameLen[:])
if err != nil {
return nil, err
}
hostname := make([]byte, hostnameLen[0])
_, err = io.ReadFull(addrBuf, hostname)
if err != nil {
return nil, err
}
var port [2]byte
_, err = io.ReadFull(addrBuf, port[:])
if err != nil {
return nil, err
}
address = &DNSAddress{
Hostname: string(hostname),
Port: binary.BigEndian.Uint16(
port[:],
),
}
addrBytesRead += dnsAddrOverhead +
uint16(len(hostname))
default:
// If we don't understand this address type,
// we just store it along with the remaining
// address bytes as type OpaqueAddrs. We need
// to hold onto the bytes so that we can still
// write them back to the wire when we
// propagate this message.
payloadLen := 1 + addrsLen - addrBytesRead
payload := make([]byte, payloadLen)
// First write a byte for the address type that
// we already read.
payload[0] = byte(aType)
// Now append the rest of the address bytes.
_, err := io.ReadFull(addrBuf, payload[1:])
if err != nil {
return nil, err
}
address = &OpaqueAddrs{
Payload: payload,
}
addrBytesRead = addrsLen
}
addresses = append(addresses, address)
}
return addresses, nil
}