diff --git a/waku/node.go b/waku/node.go index 48d62816..4bccef71 100644 --- a/waku/node.go +++ b/waku/node.go @@ -17,11 +17,13 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" dssql "github.com/ipfs/go-ds-sql" + manet "github.com/multiformats/go-multiaddr/net" logging "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p" libp2pcrypto "github.com/libp2p/go-libp2p-core/crypto" libp2pdisc "github.com/libp2p/go-libp2p-core/discovery" + "github.com/libp2p/go-libp2p/config" "github.com/libp2p/go-libp2p-core/protocol" "github.com/libp2p/go-libp2p-peerstore/pstoreds" @@ -61,9 +63,8 @@ func Execute(options Options) { return } - hostAddr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", options.Address, options.Port)) - - var err error + hostAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", options.Address, options.Port)) + failOnErr(err, "invalid host address") prvKey, err := getPrivKey(options) failOnErr(err, "nodekey error") @@ -93,13 +94,19 @@ func Execute(options Options) { node.WithKeepAlive(time.Duration(options.KeepAlive) * time.Second), } + if options.AdvertiseAddress != "" { + advertiseAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", options.AdvertiseAddress, options.Port)) + failOnErr(err, "invalid advertise address") + nodeOpts = append(nodeOpts, node.WithAdvertiseAddress([]net.Addr{advertiseAddr}, options.EnableWS, options.WSPort)) + } + if options.EnableWS { wsMa, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/ws", options.WSAddress, options.WSPort)) nodeOpts = append(nodeOpts, node.WithMultiaddress([]multiaddr.Multiaddr{wsMa})) } if options.ShowAddresses { - printListeningAddresses(ctx, nodeOpts) + printListeningAddresses(ctx, nodeOpts, options) return } @@ -336,7 +343,7 @@ func getPrivKey(options Options) (*ecdsa.PrivateKey, error) { return prvKey, nil } -func printListeningAddresses(ctx context.Context, nodeOpts []node.WakuNodeOption) { +func printListeningAddresses(ctx context.Context, nodeOpts []node.WakuNodeOption, options Options) { ctx, cancel := context.WithCancel(ctx) defer cancel() params := new(node.WakuNodeParameters) @@ -346,12 +353,36 @@ func printListeningAddresses(ctx context.Context, nodeOpts []node.WakuNodeOption panic(err) } } - h, err := libp2p.New(ctx, libp2p.ListenAddrs(params.MultiAddresses()...)) + + var libp2pOpts []config.Option + + if options.AdvertiseAddress != "" { + advertiseAddress, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", options.AdvertiseAddress, options.Port)) + if err != nil { + panic(err) + } + libp2pOpts = append(libp2pOpts, libp2p.AddrsFactory(func([]multiaddr.Multiaddr) []multiaddr.Multiaddr { + addr, _ := manet.FromNetAddr(advertiseAddress) + var result []multiaddr.Multiaddr + result = append(result, addr) + + if options.EnableWS { + wsMa, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/ws", options.AdvertiseAddress, options.WSPort)) + result = append(result, wsMa) + } + + return result + })) + } + + libp2pOpts = append(libp2pOpts, libp2p.ListenAddrs(params.MultiAddresses()...)) + h, err := libp2p.New(ctx, libp2pOpts...) if err != nil { panic(err) } hostInfo, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/p2p/%s", h.ID().Pretty())) + for _, addr := range h.Addrs() { fmt.Println(addr.Encapsulate(hostInfo)) } diff --git a/waku/options.go b/waku/options.go index 74d45311..630c101a 100644 --- a/waku/options.go +++ b/waku/options.go @@ -60,21 +60,22 @@ type MetricsOptions struct { // Options contains all the available features and settings that can be // configured via flags when executing go-waku as a service. type Options struct { - Port int `short:"p" long:"port" description:"Libp2p TCP listening port (0 for random)" default:"9000"` - Address string `long:"address" description:"Listening address" default:"0.0.0.0"` - EnableWS bool `long:"ws" description:"Enable websockets support"` - WSPort int `long:"ws-port" description:"Libp2p TCP listening port for websocket connection (0 for random)" default:"9001"` - WSAddress string `long:"ws-address" description:"Listening address for websocket connections" default:"0.0.0.0"` - NodeKey string `long:"nodekey" description:"P2P node private key as hex. Can also be set with GOWAKU-NODEKEY env variable (default random)"` - KeyFile string `long:"key-file" description:"Path to a file containing the private key for the P2P node" default:"./nodekey"` - GenerateKey bool `long:"generate-key" description:"Generate private key file at path specified in --key-file"` - Overwrite bool `long:"overwrite" description:"When generating a keyfile, overwrite the nodekey file if it already exists"` - StaticNodes []string `long:"static-node" description:"Multiaddr of peer to directly connect with. Option may be repeated"` - KeepAlive int `long:"keep-alive" default:"20" description:"Interval in seconds for pinging peers to keep the connection alive."` - UseDB bool `long:"use-db" description:"Use SQLiteDB to persist information"` - DBPath string `long:"dbpath" default:"./store.db" description:"Path to DB file"` - ShowAddresses bool `long:"show-addresses" description:"Display listening addresses according to current configuration"` - LogLevel string `short:"l" long:"log-level" description:"Define the logging level, supported strings are: DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL, and their lower-case forms." default:"INFO"` + Port int `short:"p" long:"port" description:"Libp2p TCP listening port (0 for random)" default:"9000"` + Address string `long:"address" description:"Listening address" default:"0.0.0.0"` + EnableWS bool `long:"ws" description:"Enable websockets support"` + WSPort int `long:"ws-port" description:"Libp2p TCP listening port for websocket connection (0 for random)" default:"9001"` + WSAddress string `long:"ws-address" description:"Listening address for websocket connections" default:"0.0.0.0"` + NodeKey string `long:"nodekey" description:"P2P node private key as hex. Can also be set with GOWAKU-NODEKEY env variable (default random)"` + KeyFile string `long:"key-file" description:"Path to a file containing the private key for the P2P node" default:"./nodekey"` + GenerateKey bool `long:"generate-key" description:"Generate private key file at path specified in --key-file"` + Overwrite bool `long:"overwrite" description:"When generating a keyfile, overwrite the nodekey file if it already exists"` + StaticNodes []string `long:"static-node" description:"Multiaddr of peer to directly connect with. Option may be repeated"` + KeepAlive int `long:"keep-alive" default:"20" description:"Interval in seconds for pinging peers to keep the connection alive."` + UseDB bool `long:"use-db" description:"Use SQLiteDB to persist information"` + DBPath string `long:"dbpath" default:"./store.db" description:"Path to DB file"` + AdvertiseAddress string `long:"advertise-address" default:"" description:"External address to advertise to other nodes (overrides --address and --ws-address flags)"` + ShowAddresses bool `long:"show-addresses" description:"Display listening addresses according to current configuration"` + LogLevel string `short:"l" long:"log-level" description:"Define the logging level, supported strings are: DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL, and their lower-case forms." default:"INFO"` Relay RelayOptions `group:"Relay Options"` Store StoreOptions `group:"Store Options"` diff --git a/waku/v2/node/wakunode2.go b/waku/v2/node/wakunode2.go index 3fd4fdc8..3771f723 100644 --- a/waku/v2/node/wakunode2.go +++ b/waku/v2/node/wakunode2.go @@ -91,6 +91,10 @@ func New(ctx context.Context, opts ...WakuNodeOption) (*WakuNode, error) { params.libP2POpts = append(params.libP2POpts, libp2p.Identity(*params.privKey)) } + if params.addressFactory != nil { + params.libP2POpts = append(params.libP2POpts, libp2p.AddrsFactory(params.addressFactory)) + } + host, err := libp2p.New(ctx, params.libP2POpts...) if err != nil { cancel() diff --git a/waku/v2/node/wakuoptions.go b/waku/v2/node/wakuoptions.go index cbd5716a..1342af00 100644 --- a/waku/v2/node/wakuoptions.go +++ b/waku/v2/node/wakuoptions.go @@ -2,6 +2,7 @@ package node import ( "crypto/ecdsa" + "fmt" "net" "time" @@ -9,6 +10,8 @@ import ( connmgr "github.com/libp2p/go-libp2p-connmgr" "github.com/libp2p/go-libp2p-core/crypto" pubsub "github.com/libp2p/go-libp2p-pubsub" + basichost "github.com/libp2p/go-libp2p/p2p/host/basic" + "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" rendezvous "github.com/status-im/go-waku-rendezvous" @@ -19,9 +22,10 @@ import ( const clientId string = "Go Waku v2 node" type WakuNodeParameters struct { - multiAddr []ma.Multiaddr - privKey *crypto.PrivKey - libP2POpts []libp2p.Option + multiAddr []ma.Multiaddr + addressFactory basichost.AddrsFactory + privKey *crypto.PrivKey + libP2POpts []libp2p.Option enableRelay bool enableFilter bool @@ -31,7 +35,6 @@ type WakuNodeParameters struct { shouldResume bool storeMsgs bool store *store.WakuStore - // filter *filter.WakuFilter enableRendezvous bool enableRendezvousServer bool @@ -69,6 +72,25 @@ func WithHostAddress(hostAddr []net.Addr) WakuNodeOption { } } +// WithAdvertiseAddress is a WakuNodeOption that allows overriding the addresses used in the waku node with custom values +func WithAdvertiseAddress(addressesToAdvertise []net.Addr, enableWS bool, wsPort int) WakuNodeOption { + return func(params *WakuNodeParameters) error { + params.addressFactory = func([]ma.Multiaddr) []ma.Multiaddr { + var result []multiaddr.Multiaddr + for _, adv := range addressesToAdvertise { + addr, _ := manet.FromNetAddr(adv) + result = append(result, addr) + if enableWS { + wsMa, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/ws", adv, wsPort)) + result = append(result, wsMa) + } + } + return result + } + return nil + } +} + // WithMultiaddress is a WakuNodeOption that configures libp2p to listen on a list of multiaddresses func WithMultiaddress(addresses []ma.Multiaddr) WakuNodeOption { return func(params *WakuNodeParameters) error {