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

@ -151,7 +151,7 @@ type Options struct {
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

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(),