Skip to content
Draft
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 @@ -161,6 +161,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
55 changes: 35 additions & 20 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,26 +336,28 @@ type Config struct {
// loadConfig function. We need to expose the 'raw' strings so the
// command line library can access them.
// Only the parsed net.Addrs should be used!
RawRPCListeners []string `long:"rpclisten" description:"Add an interface/port/socket to listen for RPC connections"`
RawRESTListeners []string `long:"restlisten" description:"Add an interface/port/socket to listen for REST connections"`
RawListeners []string `long:"listen" description:"Add an interface/port to listen for peer connections"`
RawExternalIPs []string `long:"externalip" description:"Add an ip:port to the list of local addresses we claim to listen on to peers. If a port is not specified, the default (9735) will be used regardless of other parameters"`
ExternalHosts []string `long:"externalhosts" description:"Add a hostname:port that should be periodically resolved to announce IPs for. If a port is not specified, the default (9735) will be used."`
RPCListeners []net.Addr
RESTListeners []net.Addr
RestCORS []string `long:"restcors" description:"Add an ip:port/hostname to allow cross origin access from. To allow all origins, set as \"*\"."`
Listeners []net.Addr
ExternalIPs []net.Addr
DisableListen bool `long:"nolisten" description:"Disable listening for incoming peer connections"`
DisableRest bool `long:"norest" description:"Disable REST API"`
DisableRestTLS bool `long:"no-rest-tls" description:"Disable TLS for REST connections"`
WSPingInterval time.Duration `long:"ws-ping-interval" description:"The ping interval for REST based WebSocket connections, set to 0 to disable sending ping messages from the server side"`
WSPongWait time.Duration `long:"ws-pong-wait" description:"The time we wait for a pong response message on REST based WebSocket connections before the connection is closed as inactive"`
NAT bool `long:"nat" description:"Toggle NAT traversal support (using either UPnP or NAT-PMP) to automatically advertise your external IP address to the network -- NOTE this does not support devices behind multiple NATs"`
AddPeers []string `long:"addpeer" description:"Specify peers to connect to first"`
MinBackoff time.Duration `long:"minbackoff" description:"Shortest backoff when reconnecting to persistent peers. Valid time units are {s, m, h}."`
MaxBackoff time.Duration `long:"maxbackoff" description:"Longest backoff when reconnecting to persistent peers. Valid time units are {s, m, h}."`
ConnectionTimeout time.Duration `long:"connectiontimeout" description:"The timeout value for network connections. Valid time units are {ms, s, m, h}."`
RawRPCListeners []string `long:"rpclisten" description:"Add an interface/port/socket to listen for RPC connections"`
RawRESTListeners []string `long:"restlisten" description:"Add an interface/port/socket to listen for REST connections"`
RawListeners []string `long:"listen" description:"Add an interface/port to listen for peer connections"`
RawExternalIPs []string `long:"externalip" description:"Add an ip:port to the list of local addresses we claim to listen on to peers. If a port is not specified, the default (9735) will be used regardless of other parameters"`
RawExternalDNSAddress string `long:"external-dns-address" description:"Specify a DNS hostname for the node's external address. If no port is provided, the default (9735) is used."`
ExternalHosts []string `long:"externalhosts" description:"Add a hostname:port that should be periodically resolved to announce IPs for. If a port is not specified, the default (9735) will be used."`
RPCListeners []net.Addr
RESTListeners []net.Addr
RestCORS []string `long:"restcors" description:"Add an ip:port/hostname to allow cross origin access from. To allow all origins, set as \"*\"."`
Listeners []net.Addr
ExternalIPs []net.Addr
ExternalDNSAddress *lnwire.DNSAddress
DisableListen bool `long:"nolisten" description:"Disable listening for incoming peer connections"`
DisableRest bool `long:"norest" description:"Disable REST API"`
DisableRestTLS bool `long:"no-rest-tls" description:"Disable TLS for REST connections"`
WSPingInterval time.Duration `long:"ws-ping-interval" description:"The ping interval for REST based WebSocket connections, set to 0 to disable sending ping messages from the server side"`
WSPongWait time.Duration `long:"ws-pong-wait" description:"The time we wait for a pong response message on REST based WebSocket connections before the connection is closed as inactive"`
NAT bool `long:"nat" description:"Toggle NAT traversal support (using either UPnP or NAT-PMP) to automatically advertise your external IP address to the network -- NOTE this does not support devices behind multiple NATs"`
AddPeers []string `long:"addpeer" description:"Specify peers to connect to first"`
MinBackoff time.Duration `long:"minbackoff" description:"Shortest backoff when reconnecting to persistent peers. Valid time units are {s, m, h}."`
MaxBackoff time.Duration `long:"maxbackoff" description:"Longest backoff when reconnecting to persistent peers. Valid time units are {s, m, h}."`
ConnectionTimeout time.Duration `long:"connectiontimeout" description:"The timeout value for network connections. Valid time units are {ms, s, m, h}."`

DebugLevel string `short:"d" long:"debuglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <global-level>,<subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"`

Expand Down Expand Up @@ -1592,6 +1594,7 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser,
ltndLog.Infof("Listening on the p2p interface is disabled!")
cfg.Listeners = nil
cfg.ExternalIPs = nil
cfg.ExternalDNSAddress = nil
} else {

// Add default port to all listener addresses if needed and remove
Expand All @@ -1615,6 +1618,18 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser,
return nil, err
}

// Parse the external DNS address if provided.
if cfg.RawExternalDNSAddress != "" {
addr, err := parseDNSAddr(
cfg.RawExternalDNSAddress, cfg.net,
)
if err != nil {
return nil, err
}

cfg.ExternalDNSAddress = addr
}

// For the p2p port it makes no sense to listen to an Unix socket.
// Also, we would need to refactor the brontide listener to support
// that.
Expand Down
30 changes: 26 additions & 4 deletions discovery/chan_series.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,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 @@ -243,6 +250,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 @@ -296,8 +304,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{}{}
}
}
}
if edge2 != nil {
Expand All @@ -315,8 +330,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 @@ -2220,7 +2220,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 @@ -2229,7 +2231,12 @@ func (d *AuthenticatedGossiper) fetchNodeAnn(ctx context.Context,
return nil, err
}

return node.NodeAnnouncement(true)
nodeAnn, err := node.NodeAnnouncement(true)
if err != nil {
return nil, err
}

return nodeAnn, netann.ValidateNodeAnnFields(nodeAnn)
}

// isMsgStale determines whether a message retrieved from the backing
Expand Down
8 changes: 8 additions & 0 deletions docs/release-notes/release-notes-0.20.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,14 @@ 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.

* [Support DNS address in
node announcement msg](https://github.com/lightningnetwork/lnd/pull/10159):
This update allows users to announce their LND node using a DNS address in
the node announcement message, by configuring `external-dns-address` field in
the LND config file.
**Note:** According to BOLT 07, only one DNS address may be announced per
node.

## 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

// 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
Loading
Loading