feat: advertise custom multiaddresses

This replaces the flag `--advertise-address` with `--ext-multiaddr`
This commit is contained in:
Richard Ramos 2023-02-08 12:02:06 -04:00 committed by RichΛrd
parent 57d707ff50
commit eb9e727b1b
8 changed files with 59 additions and 98 deletions

View File

@ -147,11 +147,13 @@ var (
Destination: &options.NAT, // TODO: accept none,any,upnp,extaddr Destination: &options.NAT, // TODO: accept none,any,upnp,extaddr
EnvVars: []string{"WAKUNODE2_NAT"}, EnvVars: []string{"WAKUNODE2_NAT"},
}) })
AdvertiseAddress = altsrc.NewStringFlag(&cli.StringFlag{ AdvertiseAddress = cliutils.NewGenericFlagMultiValue(&cli.GenericFlag{
Name: "advertise-address", Name: "ext-multiaddr",
Usage: "External address to advertise to other nodes (overrides --address and --ws-address flags)", Usage: "External address to advertise to other nodes. Ooverrides --address and --ws-address flags. Option may be repeated",
Destination: &options.AdvertiseAddress, Value: &cliutils.MultiaddrSlice{
EnvVars: []string{"WAKUNODE2_ADVERTISE_ADDRESS"}, Values: &options.AdvertiseAddresses,
},
EnvVars: []string{"WAKUNODE2_EXT_MULTIADDR"},
}) })
ShowAddresses = altsrc.NewBoolFlag(&cli.BoolFlag{ ShowAddresses = altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "show-addresses", Name: "show-addresses",

View File

@ -56,26 +56,6 @@ func failOnErr(err error, msg string) {
} }
} }
func freePort() (int, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return 0, err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return 0, err
}
port := l.Addr().(*net.TCPAddr).Port
err = l.Close()
if err != nil {
return 0, err
}
return port, nil
}
const dialTimeout = 7 * time.Second const dialTimeout = 7 * time.Second
// Execute starts a go-waku node with settings determined by the Options parameter // Execute starts a go-waku node with settings determined by the Options parameter
@ -127,21 +107,8 @@ func Execute(options Options) {
node.WithKeepAlive(options.KeepAlive), node.WithKeepAlive(options.KeepAlive),
} }
if options.AdvertiseAddress != "" { if len(options.AdvertiseAddresses) != 0 {
advertiseAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", options.AdvertiseAddress, options.Port)) nodeOpts = append(nodeOpts, node.WithAdvertiseAddresses(options.AdvertiseAddresses...))
failOnErr(err, "Invalid advertise address")
if advertiseAddr.Port == 0 {
for {
p, err := freePort()
if err == nil {
advertiseAddr.Port = p
break
}
}
}
nodeOpts = append(nodeOpts, node.WithAdvertiseAddress(advertiseAddr))
} }
if options.Dns4DomainName != "" { if options.Dns4DomainName != "" {
@ -149,7 +116,7 @@ func Execute(options Options) {
} }
libp2pOpts := node.DefaultLibP2POptions libp2pOpts := node.DefaultLibP2POptions
if options.AdvertiseAddress == "" { if len(options.AdvertiseAddresses) == 0 {
libp2pOpts = append(libp2pOpts, libp2p.NATPortMap()) // Attempt to open ports using uPNP for NATed hosts.) libp2pOpts = append(libp2pOpts, libp2p.NATPortMap()) // Attempt to open ports using uPNP for NATed hosts.)
} }

View File

@ -141,25 +141,25 @@ type PeerExchangeOptions struct {
// Options contains all the available features and settings that can be // Options contains all the available features and settings that can be
// configured via flags when executing go-waku as a service. // configured via flags when executing go-waku as a service.
type Options struct { type Options struct {
Port int Port int
Address string Address string
Dns4DomainName string Dns4DomainName string
NodeKey *ecdsa.PrivateKey NodeKey *ecdsa.PrivateKey
KeyFile string KeyFile string
KeyPasswd string KeyPasswd string
GenerateKey bool GenerateKey bool
Overwrite bool Overwrite bool
StaticNodes []multiaddr.Multiaddr StaticNodes []multiaddr.Multiaddr
KeepAlive time.Duration KeepAlive time.Duration
AdvertiseAddress string AdvertiseAddresses []multiaddr.Multiaddr
ShowAddresses bool ShowAddresses bool
LogLevel string LogLevel string
LogEncoding string LogEncoding string
LogOutput string LogOutput string
NAT string NAT string
PersistPeers bool PersistPeers bool
UserAgent string UserAgent string
PProf bool PProf bool
PeerExchange PeerExchangeOptions PeerExchange PeerExchangeOptions
Websocket WSOptions Websocket WSOptions

View File

@ -11,6 +11,7 @@ import (
"github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
"github.com/waku-org/go-discover/discover" "github.com/waku-org/go-discover/discover"
"github.com/waku-org/go-waku/logging" "github.com/waku-org/go-waku/logging"
"github.com/waku-org/go-waku/waku/v2/utils" "github.com/waku-org/go-waku/waku/v2/utils"
@ -22,7 +23,6 @@ import (
var ErrNoDiscV5Listener = errors.New("no discv5 listener") var ErrNoDiscV5Listener = errors.New("no discv5 listener")
type DiscoveryV5 struct { type DiscoveryV5 struct {
sync.RWMutex sync.RWMutex
@ -46,7 +46,7 @@ type discV5Parameters struct {
autoUpdate bool autoUpdate bool
bootnodes []*enode.Node bootnodes []*enode.Node
udpPort uint udpPort uint
advertiseAddr *net.IP advertiseAddr []multiaddr.Multiaddr
} }
type DiscoveryV5Option func(*discV5Parameters) type DiscoveryV5Option func(*discV5Parameters)
@ -65,9 +65,9 @@ func WithBootnodes(bootnodes []*enode.Node) DiscoveryV5Option {
} }
} }
func WithAdvertiseAddr(addr net.IP) DiscoveryV5Option { func WithAdvertiseAddr(addr []multiaddr.Multiaddr) DiscoveryV5Option {
return func(params *discV5Parameters) { return func(params *discV5Parameters) {
params.advertiseAddr = &addr params.advertiseAddr = addr
} }
} }

View File

@ -53,7 +53,7 @@ func writeMultiaddressField(localnode *enode.LocalNode, addrAggr []ma.Multiaddr)
return nil return nil
} }
func (w *WakuNode) updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr, ipAddr *net.TCPAddr, udpPort uint, wakuFlags utils.WakuEnrBitfield, advertiseAddr *net.IP, shouldAutoUpdate bool, log *zap.Logger) error { func (w *WakuNode) updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr, ipAddr *net.TCPAddr, udpPort uint, wakuFlags utils.WakuEnrBitfield, advertiseAddr []ma.Multiaddr, shouldAutoUpdate bool, log *zap.Logger) error {
localnode.SetFallbackUDP(int(udpPort)) localnode.SetFallbackUDP(int(udpPort))
localnode.Set(enr.WithEntry(utils.WakuENRField, wakuFlags)) localnode.Set(enr.WithEntry(utils.WakuENRField, wakuFlags))
localnode.SetFallbackIP(net.IP{127, 0, 0, 1}) localnode.SetFallbackIP(net.IP{127, 0, 0, 1})
@ -65,13 +65,22 @@ func (w *WakuNode) updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.M
if advertiseAddr != nil { if advertiseAddr != nil {
// An advertised address disables libp2p address updates // An advertised address disables libp2p address updates
// and discv5 predictions // and discv5 predictions
localnode.SetStaticIP(*advertiseAddr)
ipAddr, err := selectMostExternalAddress(advertiseAddr)
if err != nil {
return err
}
localnode.SetStaticIP(ipAddr.IP)
localnode.Set(enr.TCP(uint16(ipAddr.Port))) // TODO: ipv6? localnode.Set(enr.TCP(uint16(ipAddr.Port))) // TODO: ipv6?
return writeMultiaddresses(localnode, multiaddrs)
} else if !shouldAutoUpdate { } else if !shouldAutoUpdate {
// We received a libp2p address update. Autoupdate is disabled // We received a libp2p address update. Autoupdate is disabled
// Using a static ip will disable endpoint prediction. // Using a static ip will disable endpoint prediction.
localnode.SetStaticIP(ipAddr.IP) localnode.SetStaticIP(ipAddr.IP)
localnode.Set(enr.TCP(uint16(ipAddr.Port))) // TODO: ipv6? localnode.Set(enr.TCP(uint16(ipAddr.Port))) // TODO: ipv6?
return writeMultiaddresses(localnode, multiaddrs)
} else { } else {
// We received a libp2p address update, but we should still // We received a libp2p address update, but we should still
// allow discv5 to update the enr record. We set the localnode // allow discv5 to update the enr record. We set the localnode
@ -94,8 +103,13 @@ func (w *WakuNode) updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.M
localnode.Delete(enr.IPv6{}) localnode.Delete(enr.IPv6{})
localnode.Delete(enr.TCP6(0)) localnode.Delete(enr.TCP6(0))
} }
return writeMultiaddresses(localnode, multiaddrs)
} }
}
func writeMultiaddresses(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr) error {
// Randomly shuffle multiaddresses // Randomly shuffle multiaddresses
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(multiaddrs), func(i, j int) { multiaddrs[i], multiaddrs[j] = multiaddrs[j], multiaddrs[i] }) rand.Shuffle(len(multiaddrs), func(i, j int) { multiaddrs[i], multiaddrs[j] = multiaddrs[j], multiaddrs[i] })
@ -203,7 +217,6 @@ func extractIPAddressForENR(addr ma.Multiaddr) (*net.TCPAddr, error) {
func selectMostExternalAddress(addresses []ma.Multiaddr) (*net.TCPAddr, error) { func selectMostExternalAddress(addresses []ma.Multiaddr) (*net.TCPAddr, error) {
var ipAddrs []*net.TCPAddr var ipAddrs []*net.TCPAddr
for _, addr := range addresses { for _, addr := range addresses {
ipAddr, err := extractIPAddressForENR(addr) ipAddr, err := extractIPAddressForENR(addr)
if err != nil { if err != nil {
@ -337,7 +350,7 @@ func (w *WakuNode) setupENR(ctx context.Context, addrs []ma.Multiaddr) error {
return err return err
} }
err = w.updateLocalNode(w.localNode, multiaddresses, ipAddr, w.opts.udpPort, w.wakuFlag, w.opts.advertiseAddr, w.opts.discV5autoUpdate, w.log) err = w.updateLocalNode(w.localNode, multiaddresses, ipAddr, w.opts.udpPort, w.wakuFlag, w.opts.advertiseAddrs, w.opts.discV5autoUpdate, w.log)
if err != nil { if err != nil {
w.log.Error("updating localnode ENR record", zap.Error(err)) w.log.Error("updating localnode ENR record", zap.Error(err))
return err return err

View File

@ -554,8 +554,8 @@ func (w *WakuNode) mountDiscV5() error {
discv5.WithAutoUpdate(w.opts.discV5autoUpdate), discv5.WithAutoUpdate(w.opts.discV5autoUpdate),
} }
if w.opts.advertiseAddr != nil { if w.opts.advertiseAddrs != nil {
discV5Options = append(discV5Options, discv5.WithAdvertiseAddr(*w.opts.advertiseAddr)) discV5Options = append(discV5Options, discv5.WithAdvertiseAddr(w.opts.advertiseAddrs))
} }
var err error var err error

View File

@ -23,6 +23,7 @@ import (
quic "github.com/libp2p/go-libp2p/p2p/transport/quic" quic "github.com/libp2p/go-libp2p/p2p/transport/quic"
"github.com/libp2p/go-libp2p/p2p/transport/tcp" "github.com/libp2p/go-libp2p/p2p/transport/tcp"
"github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net" manet "github.com/multiformats/go-multiaddr/net"
"github.com/waku-org/go-waku/waku/v2/protocol/filter" "github.com/waku-org/go-waku/waku/v2/protocol/filter"
"github.com/waku-org/go-waku/waku/v2/protocol/pb" "github.com/waku-org/go-waku/waku/v2/protocol/pb"
@ -42,7 +43,7 @@ const defaultMinRelayPeersToPublish = 0
type WakuNodeParameters struct { type WakuNodeParameters struct {
hostAddr *net.TCPAddr hostAddr *net.TCPAddr
dns4Domain string dns4Domain string
advertiseAddr *net.IP advertiseAddrs []multiaddr.Multiaddr
multiAddr []multiaddr.Multiaddr multiAddr []multiaddr.Multiaddr
addressFactory basichost.AddrsFactory addressFactory basichost.AddrsFactory
privKey *ecdsa.PrivateKey privKey *ecdsa.PrivateKey
@ -199,32 +200,12 @@ func WithHostAddress(hostAddr *net.TCPAddr) WakuNodeOption {
} }
} }
// WithAdvertiseAddress is a WakuNodeOption that allows overriding the address used in the waku node with custom value // WithAdvertiseAddresses is a WakuNodeOption that allows overriding the address used in the waku node with custom value
func WithAdvertiseAddress(address *net.TCPAddr) WakuNodeOption { func WithAdvertiseAddresses(advertiseAddrs ...ma.Multiaddr) WakuNodeOption {
return func(params *WakuNodeParameters) error { return func(params *WakuNodeParameters) error {
params.advertiseAddr = &address.IP params.advertiseAddrs = advertiseAddrs
advertiseAddress, err := manet.FromNetAddr(address)
if err != nil {
return err
}
params.addressFactory = func([]multiaddr.Multiaddr) (addresses []multiaddr.Multiaddr) { params.addressFactory = func([]multiaddr.Multiaddr) (addresses []multiaddr.Multiaddr) {
addresses = append(addresses, advertiseAddress) return advertiseAddrs
if params.enableWSS {
wsMa, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/wss", address.IP, params.wssPort))
if err != nil {
panic(err)
}
addresses = append(addresses, wsMa)
} else if params.enableWS {
wsMa, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/ws", address.IP, params.wsPort))
if err != nil {
panic(err)
}
addresses = append(addresses, wsMa)
}
return addresses
} }
return nil return nil
} }

View File

@ -27,15 +27,13 @@ func TestWakuOptions(t *testing.T) {
addr, err := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/4000/ws") addr, err := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/4000/ws")
require.NoError(t, err) require.NoError(t, err)
advertiseAddr, _ := net.ResolveTCPAddr("tcp", "0.0.0.0:0")
storeFactory := func(w *WakuNode) store.Store { storeFactory := func(w *WakuNode) store.Store {
return store.NewWakuStore(w.host, w.swap, w.opts.messageProvider, w.timesource, w.log) return store.NewWakuStore(w.host, w.swap, w.opts.messageProvider, w.timesource, w.log)
} }
options := []WakuNodeOption{ options := []WakuNodeOption{
WithHostAddress(hostAddr), WithHostAddress(hostAddr),
WithAdvertiseAddress(advertiseAddr), WithAdvertiseAddresses(addr),
WithMultiaddress([]multiaddr.Multiaddr{addr}), WithMultiaddress([]multiaddr.Multiaddr{addr}),
WithPrivateKey(prvKey), WithPrivateKey(prvKey),
WithLibP2POptions(), WithLibP2POptions(),