diff --git a/chanbackup/backup_test.go b/chanbackup/backup_test.go index 2c324caa7..05a24090c 100644 --- a/chanbackup/backup_test.go +++ b/chanbackup/backup_test.go @@ -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 diff --git a/chanbackup/multi_test.go b/chanbackup/multi_test.go index 3350c773c..d84ca2f11 100644 --- a/chanbackup/multi_test.go +++ b/chanbackup/multi_test.go @@ -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) diff --git a/chanbackup/single_test.go b/chanbackup/single_test.go index b3c7471a3..f1f805c14 100644 --- a/chanbackup/single_test.go +++ b/chanbackup/single_test.go @@ -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}, @@ -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{} @@ -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{} diff --git a/graph/db/addr.go b/graph/db/addr.go index c68039a26..836d516b0 100644 --- a/graph/db/addr.go +++ b/graph/db/addr.go @@ -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 + + // 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 { @@ -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 @@ -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 } diff --git a/graph/db/addr_test.go b/graph/db/addr_test.go index b3dbea8cb..d3c3700a3 100644 --- a/graph/db/addr_test.go +++ b/graph/db/addr_test.go @@ -6,6 +6,7 @@ import ( "strings" "testing" + "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/tor" "github.com/stretchr/testify/require" ) @@ -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 { @@ -57,6 +70,12 @@ var addrTests = []struct { { expAddr: testOnionV3Addr, }, + { + expAddr: testOpaqueAddr, + }, + { + expAddr: testDNSAddr, + }, // Invalid addresses. { diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go index ac0872e27..0d55ef625 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -37,13 +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{ - // 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}, - } + testAddrs = []net.Addr{testAddr, anotherAddr} testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571319d18" + "e949ddfa2965fb6caa1bf0314f882d7") @@ -211,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, } diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go index 1789c70c4..c53a0fe5c 100644 --- a/graph/db/sql_store.go +++ b/graph/db/sql_store.go @@ -3530,6 +3530,7 @@ const ( addressTypeIPv6 dbAddressType = 2 addressTypeTorV2 dbAddressType = 3 addressTypeTorV3 dbAddressType = 4 + addressTypeDNS dbAddressType = 5 addressTypeOpaque dbAddressType = math.MaxInt8 ) @@ -3545,6 +3546,7 @@ func collectAddressRecords(addresses []net.Addr) (map[dbAddressType][]string, addressTypeIPv6: {}, addressTypeTorV2: {}, addressTypeTorV3: {}, + addressTypeDNS: {}, addressTypeOpaque: {}, } addAddr := func(t dbAddressType, addr net.Addr) { @@ -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) @@ -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 {