diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index f2ad49602fb..88861055c5a 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -497,15 +497,29 @@ func printSwarmAddrs(node *core.IpfsNode) { fmt.Println("Swarm not listening, running in offline mode.") return } + + var lisAddrs []string + ifaceAddrs, err := node.PeerHost.Network().InterfaceListenAddresses() + if err != nil { + log.Errorf("failed to read listening addresses: %s", err) + } + for _, addr := range ifaceAddrs { + lisAddrs = append(lisAddrs, addr.String()) + } + sort.Sort(sort.StringSlice(lisAddrs)) + for _, addr := range lisAddrs { + fmt.Printf("Swarm listening on %s\n", addr) + } + var addrs []string for _, addr := range node.PeerHost.Addrs() { addrs = append(addrs, addr.String()) } sort.Sort(sort.StringSlice(addrs)) - for _, addr := range addrs { - fmt.Printf("Swarm listening on %s\n", addr) + fmt.Printf("Swarm announcing %s\n", addr) } + } // serveHTTPGateway collects options, creates listener, prints status message and starts serving requests diff --git a/core/core.go b/core/core.go index 367ec6d322c..1758a8b3d74 100644 --- a/core/core.go +++ b/core/core.go @@ -45,6 +45,7 @@ import ( pnet "gx/ipfs/QmNMCAuxnQFHLGWcvay3DmVFrKuY6Y2nsc9vzsf4gVouJV/go-libp2p-pnet" pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" routing "gx/ipfs/QmPjTrrSfE6TzLv6ya6VWhGcCgPrUAdcgrDcQyRDX2VyW1/go-libp2p-routing" + mafilter "gx/ipfs/QmQBB2dQLmQHJgs2gqZ3iqL2XiuCtUCvXzWt5kMXDf5Zcr/go-maddr-filter" ipnet "gx/ipfs/QmQq9YzmdFdWNTDdArueGyD7L5yyiRQigrRHJnTGkxcEjT/go-libp2p-interface-pnet" dht "gx/ipfs/QmRKEzkaiwud2LnwJ9CgBrKw122ddKPTMtLizV3DNimVRD/go-libp2p-kad-dht" p2phost "gx/ipfs/QmRNyPNJGNCaZyYonJj7owciWTsMd9gRfEKmZY3o6xwN3h/go-libp2p-host" @@ -212,8 +213,17 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption Routin }() } + addrsFactory, err := makeAddrsFactory(cfg.Addresses) + if err != nil { + return err + } + + hostopts := &ConstructPeerHostOpts{ + AddrsFactory: addrsFactory, + DisableNatPortMap: cfg.Swarm.DisableNatPortMap, + } peerhost, err := hostOption(ctx, n.Identity, n.Peerstore, n.Reporter, - addrfilter, tpt, protec, &ConstructPeerHostOpts{DisableNatPortMap: cfg.Swarm.DisableNatPortMap}) + addrfilter, tpt, protec, hostopts) if err != nil { return err } @@ -263,6 +273,52 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption Routin return n.Bootstrap(DefaultBootstrapConfig) } +func makeAddrsFactory(cfg config.Addresses) (p2pbhost.AddrsFactory, error) { + var annAddrs []ma.Multiaddr + for _, addr := range cfg.Announce { + maddr, err := ma.NewMultiaddr(addr) + if err != nil { + return nil, err + } + annAddrs = append(annAddrs, maddr) + } + + filters := mafilter.NewFilters() + noAnnAddrs := map[string]bool{} + for _, addr := range cfg.NoAnnounce { + f, err := mamask.NewMask(addr) + if err == nil { + filters.AddDialFilter(f) + continue + } + maddr, err := ma.NewMultiaddr(addr) + if err != nil { + return nil, err + } + noAnnAddrs[maddr.String()] = true + } + + return func(allAddrs []ma.Multiaddr) []ma.Multiaddr { + var addrs []ma.Multiaddr + if len(annAddrs) > 0 { + addrs = annAddrs + } else { + addrs = allAddrs + } + + var out []ma.Multiaddr + for _, maddr := range addrs { + // check for exact matches + ok, _ := noAnnAddrs[maddr.String()] + // check for /ipcidr matches + if !ok && !filters.AddrBlocked(maddr) { + out = append(out, maddr) + } + } + return out + }, nil +} + func makeSmuxTransport(mplexExp bool) smux.Transport { mstpt := mssmux.NewBlankTransport() @@ -705,6 +761,7 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) { type ConstructPeerHostOpts struct { DisableNatPortMap bool + AddrsFactory p2pbhost.AddrsFactory } type HostOption func(ctx context.Context, id peer.ID, ps pstore.Peerstore, bwr metrics.Reporter, fs []*net.IPNet, tpt smux.Transport, protc ipnet.Protector, opts *ConstructPeerHostOpts) (p2phost.Host, error) @@ -730,6 +787,9 @@ func constructPeerHost(ctx context.Context, id peer.ID, ps pstore.Peerstore, bwr if !opts.DisableNatPortMap { hostOpts = append(hostOpts, p2pbhost.NATPortMap) } + if opts.AddrsFactory != nil { + hostOpts = append(hostOpts, opts.AddrsFactory) + } host := p2pbhost.New(network, hostOpts...) diff --git a/package.json b/package.json index 50928884a6a..5c71bc26ea0 100644 --- a/package.json +++ b/package.json @@ -446,6 +446,11 @@ "hash": "Qma7Kuwun7w8SZphjEPDVxvGfetBkqdNGmigDA13sJdLex", "name": "go-ipld-git", "version": "0.1.3" + }, + { + "hash": "QmQBB2dQLmQHJgs2gqZ3iqL2XiuCtUCvXzWt5kMXDf5Zcr", + "name": "go-maddr-filter", + "version": "1.1.4" } ], "gxVersion": "0.10.0", diff --git a/repo/config/addresses.go b/repo/config/addresses.go index ba891526196..22c530655b2 100644 --- a/repo/config/addresses.go +++ b/repo/config/addresses.go @@ -2,7 +2,9 @@ package config // Addresses stores the (string) multiaddr addresses for the node. type Addresses struct { - Swarm []string // addresses for the swarm network - API string // address for the local API (RPC) - Gateway string // address to listen on for IPFS HTTP object gateway + Swarm []string // addresses for the swarm to listen on + Announce []string // swarm addresses to announce to the network + NoAnnounce []string // swarm addresses not to announce to the network + API string // address for the local API (RPC) + Gateway string // address to listen on for IPFS HTTP object gateway } diff --git a/repo/config/init.go b/repo/config/init.go index 1f8ee434be1..aa129d97e12 100644 --- a/repo/config/init.go +++ b/repo/config/init.go @@ -36,8 +36,10 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { // "/ip4/0.0.0.0/udp/4002/utp", // disabled for now. "/ip6/::/tcp/4001", }, - API: "/ip4/127.0.0.1/tcp/5001", - Gateway: "/ip4/127.0.0.1/tcp/8080", + Announce: []string{}, + NoAnnounce: []string{}, + API: "/ip4/127.0.0.1/tcp/5001", + Gateway: "/ip4/127.0.0.1/tcp/8080", }, Datastore: datastore, diff --git a/test/sharness/t0060-daemon.sh b/test/sharness/t0060-daemon.sh index 8f033876e09..ccc0fbdac43 100755 --- a/test/sharness/t0060-daemon.sh +++ b/test/sharness/t0060-daemon.sh @@ -39,6 +39,7 @@ test_expect_success "ipfs daemon output looks good" ' STARTFILE="ipfs cat /ipfs/$HASH_WELCOME_DOCS/readme" && echo "Initializing daemon..." >expected_daemon && sed "s/^/Swarm listening on /" local_addrs >>expected_daemon && + sed "s/^/Swarm announcing /" local_addrs >>expected_daemon && echo "API server listening on '$API_MADDR'" >>expected_daemon && echo "Gateway (readonly) server listening on '$GWAY_MADDR'" >>expected_daemon && echo "Daemon is ready" >>expected_daemon && diff --git a/test/sharness/t0140-swarm.sh b/test/sharness/t0140-swarm.sh index 3312148dc42..f7a9d886ef5 100755 --- a/test/sharness/t0140-swarm.sh +++ b/test/sharness/t0140-swarm.sh @@ -49,4 +49,52 @@ test_expect_success "cant trigger a dial backoff with swarm connect" ' test_kill_ipfs_daemon +announceCfg='["/ip4/127.0.0.1/tcp/4001", "/ip4/1.2.3.4/tcp/1234"]' +test_expect_success "test_config_set succeeds" " + ipfs config --json Addresses.Announce '$announceCfg' +" + +test_launch_ipfs_daemon + +test_expect_success 'Addresses.Announce affects addresses' ' + ipfs swarm addrs local >actual && + grep "/ip4/1.2.3.4/tcp/1234" actual && + ipfs id -f"" | xargs -n1 echo >actual && + grep "/ip4/1.2.3.4/tcp/1234" actual +' + +test_kill_ipfs_daemon + +noAnnounceCfg='["/ip4/1.2.3.4/tcp/1234"]' +test_expect_success "test_config_set succeeds" " + ipfs config --json Addresses.NoAnnounce '$noAnnounceCfg' +" + +test_launch_ipfs_daemon + +test_expect_success "Addresses.NoAnnounce affects addresses" ' + ipfs swarm addrs local >actual && + grep -v "/ip4/1.2.3.4/tcp/1234" actual && + ipfs id -f"" | xargs -n1 echo >actual && + grep -v "/ip4/1.2.3.4/tcp/1234" actual +' + +test_kill_ipfs_daemon + +noAnnounceCfg='["/ip4/1.2.3.4/ipcidr/16"]' +test_expect_success "test_config_set succeeds" " + ipfs config --json Addresses.NoAnnounce '$noAnnounceCfg' +" + +test_launch_ipfs_daemon + +test_expect_success "Addresses.NoAnnounce with /ipcidr affects addresses" ' + ipfs swarm addrs local >actual && + grep -v "/ip4/1.2.3.4/tcp/1234" actual && + ipfs id -f"" | xargs -n1 echo >actual && + grep -v "/ip4/1.2.3.4/tcp/1234" actual +' + +test_kill_ipfs_daemon + test_done