From 0a064d531c093f3fc57aff0a3dbaa304ef07764e Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 14 Aug 2025 13:28:03 +0000 Subject: [PATCH] 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 --- lnwire/lnwire.go | 348 ++++++++++++++++++++++++----------------------- 1 file changed, 180 insertions(+), 168 deletions(-) diff --git a/lnwire/lnwire.go b/lnwire/lnwire.go index 86f7caa61..e77bafaf3 100644 --- a/lnwire/lnwire.go +++ b/lnwire/lnwire.go @@ -719,174 +719,9 @@ func ReadElement(r io.Reader, element interface{}) error { } 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 - 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) + addresses, err := ReadAddresses(r) + if err != nil { + return fmt.Errorf("unable to read addresses: %w", err) } *e = addresses @@ -949,3 +784,180 @@ func ReadElements(r io.Reader, elements ...interface{}) error { } 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 +}