Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions chanbackup/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ func TestFetchStaticChanBackups(t *testing.T) {
chanSource.addAddrsForNode(randomChan2.IdentityPub, []net.Addr{addr2})
chanSource.addAddrsForNode(randomChan2.IdentityPub, []net.Addr{addr3})
chanSource.addAddrsForNode(randomChan2.IdentityPub, []net.Addr{addr4})
chanSource.addAddrsForNode(randomChan2.IdentityPub, []net.Addr{addr5})

// With the channel source populated, we'll now attempt to create a set
// of backups for all the channels. This should succeed, as all items
Expand Down
2 changes: 1 addition & 1 deletion chanbackup/multi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestMultiPackUnpack(t *testing.T) {
}

single := NewSingle(
channel, []net.Addr{addr1, addr2, addr3, addr4},
channel, []net.Addr{addr1, addr2, addr3, addr4, addr5},
)

originalSingles = append(originalSingles, single)
Expand Down
10 changes: 7 additions & 3 deletions chanbackup/single_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ var (
OnionService: "3g2upl4pq6kufc4m.onion",
Port: 9735,
}
addr4 = &lnwire.OpaqueAddrs{
addr4 = &lnwire.DNSAddress{
Hostname: "example.com",
Port: 8080,
}
addr5 = &lnwire.OpaqueAddrs{
// The first byte must be an address type we are not yet aware
// of for it to be a valid OpaqueAddrs.
Payload: []byte{math.MaxUint8, 1, 2, 3, 4},
Expand Down Expand Up @@ -320,7 +324,7 @@ func TestSinglePackUnpack(t *testing.T) {
require.NoError(t, err, "unable to gen open channel")

singleChanBackup := NewSingle(
channel, []net.Addr{addr1, addr2, addr3, addr4},
channel, []net.Addr{addr1, addr2, addr3, addr4, addr5},
)

keyRing := &lnencrypt.MockKeyRing{}
Expand Down Expand Up @@ -647,7 +651,7 @@ func TestSingleUnconfirmedChannel(t *testing.T) {
channel.FundingBroadcastHeight = fundingBroadcastHeight

singleChanBackup := NewSingle(
channel, []net.Addr{addr1, addr2, addr3, addr4},
channel, []net.Addr{addr1, addr2, addr3, addr4, addr5},
)
keyRing := &lnencrypt.MockKeyRing{}

Expand Down
30 changes: 26 additions & 4 deletions discovery/chan_series.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,13 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash,
return nil, err
}

if err := netann.ValidateNodeAnnFields(nodeUpdate); err != nil {
log.Debugf("Skipping forwarding invalid node "+
"announcement %x: %v", nodeAnn.PubKeyBytes, err)

continue
}

updates = append(updates, nodeUpdate)
}

Expand Down Expand Up @@ -282,6 +289,7 @@ func (c *ChanSeries) FilterChannelRange(_ chainhash.Hash, startHeight,
// to reply to a QueryShortChanIDs message sent by a remote peer. The response
// will contain a unique set of ChannelAnnouncements, the latest ChannelUpdate
// for each of the announcements, and a unique set of NodeAnnouncements.
// Invalid node announcements are skipped and logged for debugging purposes.
//
// NOTE: This is part of the ChannelGraphTimeSeries interface.
func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash,
Expand Down Expand Up @@ -335,8 +343,15 @@ func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash,
return nil, err
}

chanAnns = append(chanAnns, nodeAnn)
nodePubsSent[nodePub] = struct{}{}
err = netann.ValidateNodeAnnFields(nodeAnn)
if err != nil {
log.Debugf("Skipping forwarding "+
"invalid node announcement "+
"%x: %v", nodeAnn.NodeID, err)
} else {
chanAnns = append(chanAnns, nodeAnn)
nodePubsSent[nodePub] = struct{}{}
}
Comment thread
ellemouton marked this conversation as resolved.
}
}
if edge2 != nil {
Expand All @@ -354,8 +369,15 @@ func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash,
return nil, err
}

chanAnns = append(chanAnns, nodeAnn)
nodePubsSent[nodePub] = struct{}{}
err = netann.ValidateNodeAnnFields(nodeAnn)
if err != nil {
log.Debugf("Skipping forwarding "+
"invalid node announcement "+
"%x: %v", nodeAnn.NodeID, err)
} else {
chanAnns = append(chanAnns, nodeAnn)
nodePubsSent[nodePub] = struct{}{}
}
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions discovery/gossiper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2229,7 +2229,9 @@ func (d *AuthenticatedGossiper) processZombieUpdate(_ context.Context,
}

// fetchNodeAnn fetches the latest signed node announcement from our point of
// view for the node with the given public key.
// view for the node with the given public key. It also validates the node
// announcement fields and returns an error if they are invalid to prevent
// forwarding invalid node announcements to our peers.
func (d *AuthenticatedGossiper) fetchNodeAnn(ctx context.Context,
pubKey [33]byte) (*lnwire.NodeAnnouncement, error) {

Expand All @@ -2238,7 +2240,12 @@ func (d *AuthenticatedGossiper) fetchNodeAnn(ctx context.Context,
return nil, err
}

return node.NodeAnnouncement(true)
nodeAnn, err := node.NodeAnnouncement(true)
Comment thread
moawnallah marked this conversation as resolved.
if err != nil {
return nil, err
}

return nodeAnn, netann.ValidateNodeAnnFields(nodeAnn)
}

// isMsgStale determines whether a message retrieved from the backing
Expand Down
5 changes: 5 additions & 0 deletions docs/release-notes/release-notes-0.20.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ reader of a payment request.
* [Require invoices to include a payment address or blinded paths](https://github.com/lightningnetwork/lnd/pull/9752)
to comply with updated BOLT 11 specifications before sending payments.

* [LND can now recgonize DNS address type in node
announcement msg](https://github.com/lightningnetwork/lnd/pull/9455). This
allows users to forward node announcement with valid DNS address types. The
validity aligns with Bolt 07 DNS constraints.

## Testing

* Previously, automatic peer bootstrapping was disabled for simnet, signet and
Expand Down
54 changes: 54 additions & 0 deletions graph/db/addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,36 @@ const (
// opaqueAddrs denotes an address (or a set of addresses) that LND was
// not able to parse since LND is not yet aware of the address type.
opaqueAddrs addressType = 4
Comment thread
ellemouton marked this conversation as resolved.

// dnsAddr denotes a DNS address type.
dnsAddr addressType = 5
)

// encodeDNSAddr encodes a DNS address.
func encodeDNSAddr(w io.Writer, addr *lnwire.DNSAddress) error {
if _, err := w.Write([]byte{byte(dnsAddr)}); err != nil {
return err
}

// Write the length of the hostname.
hostLen := len(addr.Hostname)
if _, err := w.Write([]byte{byte(hostLen)}); err != nil {
return err
}

if _, err := w.Write([]byte(addr.Hostname)); err != nil {
return err
}

var port [2]byte
byteOrder.PutUint16(port[:], addr.Port)
if _, err := w.Write(port[:]); err != nil {
return err
}

return nil
}

// encodeTCPAddr serializes a TCP address into its compact raw bytes
// representation.
func encodeTCPAddr(w io.Writer, addr *net.TCPAddr) error {
Expand Down Expand Up @@ -230,6 +258,30 @@ func DeserializeAddr(r io.Reader) (net.Addr, error) {
Port: port,
}

case dnsAddr:
// Read the length of the hostname.
var hostLen [1]byte
if _, err := r.Read(hostLen[:]); err != nil {
return nil, err
}

// Read the hostname.
hostname := make([]byte, hostLen[0])
if _, err := r.Read(hostname); err != nil {
return nil, err
}

// Read the port.
var port [2]byte
if _, err := r.Read(port[:]); err != nil {
return nil, err
}

address = &lnwire.DNSAddress{
Hostname: string(hostname),
Port: binary.BigEndian.Uint16(port[:]),
}

case opaqueAddrs:
// Read the length of the payload.
var l [2]byte
Expand Down Expand Up @@ -264,6 +316,8 @@ func SerializeAddr(w io.Writer, address net.Addr) error {
return encodeOnionAddr(w, addr)
case *lnwire.OpaqueAddrs:
return encodeOpaqueAddrs(w, addr)
case *lnwire.DNSAddress:
return encodeDNSAddr(w, addr)
default:
return ErrUnknownAddressType
}
Expand Down
19 changes: 19 additions & 0 deletions graph/db/addr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"
"testing"

"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tor"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -38,6 +39,18 @@ var (
OnionService: "vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd.onion", //nolint:ll
Port: 80,
}

testOpaqueAddr = &lnwire.OpaqueAddrs{
// NOTE: the first byte is a protocol level address type. So
// for we set it to 0xff to guarantee that we do not know this
// type yet.
Payload: []byte{0xff, 0x02, 0x03, 0x04, 0x05, 0x06},
}

testDNSAddr = &lnwire.DNSAddress{
Hostname: "example.com",
Port: 8080,
}
)

var addrTests = []struct {
Expand All @@ -57,6 +70,12 @@ var addrTests = []struct {
{
expAddr: testOnionV3Addr,
},
{
expAddr: testOpaqueAddr,
},
{
expAddr: testDNSAddr,
},

// Invalid addresses.
{
Expand Down
7 changes: 3 additions & 4 deletions graph/db/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@ var (
Port: 9000}
anotherAddr, _ = net.ResolveTCPAddr("tcp",
"[2001:db8:85a3:0:0:8a2e:370:7334]:80")
testAddrs = []net.Addr{testAddr, anotherAddr}
testOpaqueAddr = &lnwire.OpaqueAddrs{
Payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
}
testAddrs = []net.Addr{testAddr, anotherAddr}

testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571319d18" +
"e949ddfa2965fb6caa1bf0314f882d7")
Expand Down Expand Up @@ -208,6 +205,8 @@ func TestNodeInsertionAndDeletion(t *testing.T) {
// Add one v2 and one v3 onion address.
testOnionV2Addr,
testOnionV3Addr,
// Add a DNS host address.
testDNSAddr,
// Make sure to also test the opaque address type.
testOpaqueAddr,
}
Expand Down
22 changes: 22 additions & 0 deletions graph/db/sql_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -3530,6 +3530,7 @@ const (
addressTypeIPv6 dbAddressType = 2
addressTypeTorV2 dbAddressType = 3
addressTypeTorV3 dbAddressType = 4
addressTypeDNS dbAddressType = 5
Comment thread
moawnallah marked this conversation as resolved.
addressTypeOpaque dbAddressType = math.MaxInt8
)

Expand All @@ -3545,6 +3546,7 @@ func collectAddressRecords(addresses []net.Addr) (map[dbAddressType][]string,
addressTypeIPv6: {},
addressTypeTorV2: {},
addressTypeTorV3: {},
addressTypeDNS: {},
addressTypeOpaque: {},
}
addAddr := func(t dbAddressType, addr net.Addr) {
Expand Down Expand Up @@ -3574,6 +3576,9 @@ func collectAddressRecords(addresses []net.Addr) (map[dbAddressType][]string,
"a tor address")
}

case *lnwire.DNSAddress:
addAddr(addressTypeDNS, addr)

case *lnwire.OpaqueAddrs:
addAddr(addressTypeOpaque, addr)

Expand Down Expand Up @@ -4663,6 +4668,23 @@ func parseAddress(addrType dbAddressType, address string) (net.Addr, error) {
Port: port,
}, nil

case addressTypeDNS:
hostname, portStr, err := net.SplitHostPort(address)
if err != nil {
return nil, fmt.Errorf("unable to split DNS "+
"address: %v", address)
}

port, err := strconv.Atoi(portStr)
if err != nil {
return nil, err
}

return &lnwire.DNSAddress{
Hostname: hostname,
Port: uint16(port),
}, nil

case addressTypeOpaque:
opaque, err := hex.DecodeString(address)
if err != nil {
Expand Down
Loading
Loading