Skip to content

Commit

Permalink
Filter Interface Addresses (#936)
Browse files Browse the repository at this point in the history
* Filter Host Addresses
  • Loading branch information
aarshkshah1992 committed May 29, 2020
1 parent 294ba3d commit 3a1d20b
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 12 deletions.
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/ipfs/go-log v1.0.4
github.com/jbenet/go-cienv v0.1.0
github.com/jbenet/goprocess v0.1.4
github.com/libp2p/go-addr-util v0.0.2
github.com/libp2p/go-conn-security-multistream v0.2.0
github.com/libp2p/go-eventbus v0.1.0
github.com/libp2p/go-libp2p-autonat v0.2.3
Expand All @@ -29,7 +30,8 @@ require (
github.com/libp2p/go-libp2p-tls v0.1.3
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0
github.com/libp2p/go-libp2p-yamux v0.2.7
github.com/libp2p/go-sockaddr v0.1.0 // indirect
github.com/libp2p/go-netroute v0.1.2
github.com/libp2p/go-sockaddr v0.1.0
github.com/libp2p/go-stream-muxer-multistream v0.3.0
github.com/libp2p/go-tcp-transport v0.2.0
github.com/libp2p/go-ws-transport v0.3.1
Expand Down
83 changes: 72 additions & 11 deletions p2p/host/basic/basic_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import (
"github.com/libp2p/go-libp2p-core/protocol"
"github.com/libp2p/go-libp2p-core/record"

addrutil "github.com/libp2p/go-addr-util"
"github.com/libp2p/go-eventbus"
inat "github.com/libp2p/go-libp2p-nat"
"github.com/libp2p/go-libp2p/p2p/protocol/identify"
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
"github.com/libp2p/go-netroute"

logging "github.com/ipfs/go-log"

Expand Down Expand Up @@ -101,6 +103,10 @@ type BasicHost struct {

addrChangeChan chan struct{}

lipMu sync.RWMutex
localIPv4Addr ma.Multiaddr
localIPv6Addr ma.Multiaddr

disableSignedPeerRecord bool
signKey crypto.PrivKey
caBook peerstore.CertifiedAddrBook
Expand Down Expand Up @@ -145,11 +151,11 @@ type HostOpts struct {
}

// NewHost constructs a new *BasicHost and activates it by attaching its stream and connection handlers to the given inet.Network.
func NewHost(ctx context.Context, net network.Network, opts *HostOpts) (*BasicHost, error) {
func NewHost(ctx context.Context, n network.Network, opts *HostOpts) (*BasicHost, error) {
hostCtx, cancel := context.WithCancel(ctx)

h := &BasicHost{
network: net,
network: n,
mux: msmux.NewMultistreamMuxer(),
negtimeout: DefaultNegotiationTimeout,
AddrsFactory: DefaultAddrsFactory,
Expand All @@ -161,6 +167,8 @@ func NewHost(ctx context.Context, net network.Network, opts *HostOpts) (*BasicHo
disableSignedPeerRecord: opts.DisableSignedPeerRecord,
}

h.updateLocalIpAddr()

var err error
if h.emitters.evtLocalProtocolsUpdated, err = h.eventbus.Emitter(&event.EvtLocalProtocolsUpdated{}); err != nil {
return nil, err
Expand All @@ -170,7 +178,7 @@ func NewHost(ctx context.Context, net network.Network, opts *HostOpts) (*BasicHo
}

if !h.disableSignedPeerRecord {
cab, ok := peerstore.GetCertifiedAddrBook(net.Peerstore())
cab, ok := peerstore.GetCertifiedAddrBook(n.Peerstore())
if !ok {
return nil, errors.New("peerstore should also be a certified address book")
}
Expand Down Expand Up @@ -212,7 +220,7 @@ func NewHost(ctx context.Context, net network.Network, opts *HostOpts) (*BasicHo
}

if opts.NATManager != nil {
h.natmgr = opts.NATManager(net)
h.natmgr = opts.NATManager(n)
}

if opts.MultiaddrResolver != nil {
Expand All @@ -223,14 +231,14 @@ func NewHost(ctx context.Context, net network.Network, opts *HostOpts) (*BasicHo
h.cmgr = &connmgr.NullConnMgr{}
} else {
h.cmgr = opts.ConnManager
net.Notify(h.cmgr.Notifee())
n.Notify(h.cmgr.Notifee())
}

if opts.EnablePing {
h.pings = ping.NewPingService(h)
}

net.SetStreamHandler(h.newStreamHandler)
n.SetStreamHandler(h.newStreamHandler)

// register to be notified when the network's listen addrs change,
// so we can update our address set and push events if needed
Expand All @@ -245,6 +253,33 @@ func NewHost(ctx context.Context, net network.Network, opts *HostOpts) (*BasicHo
return h, nil
}

func (h *BasicHost) updateLocalIpAddr() {
h.lipMu.Lock()
defer h.lipMu.Unlock()

if r, err := netroute.New(); err != nil {
log.Debugw("failed to build Router for kernel's routing table", "err", err)
} else {
if _, _, localIPv4, err := r.Route(net.IPv4zero); err != nil {
log.Debugw("failed to fetch local IPv4 address", "err", err)
} else {
maddr, err := manet.FromIP(localIPv4)
if err == nil {
h.localIPv4Addr = maddr
}
}

if _, _, localIpv6, err := r.Route(net.IPv6unspecified); err != nil {
log.Debugw("failed to fetch local IPv6 address", "err", err)
} else {
maddr, err := manet.FromIP(localIpv6)
if err == nil {
h.localIPv6Addr = maddr
}
}
}
}

// New constructs and sets up a new *BasicHost with given Network and options.
// The following options can be passed:
// * NATPortMap
Expand Down Expand Up @@ -433,6 +468,7 @@ func (h *BasicHost) background() {
defer ticker.Stop()

for {
h.updateLocalIpAddr()
curr := h.Addrs()
emitAddrChange(curr, lastAddrs)
lastAddrs = curr
Expand Down Expand Up @@ -711,10 +747,37 @@ func dedupAddrs(addrs []ma.Multiaddr) (uniqueAddrs []ma.Multiaddr) {
// AllAddrs returns all the addresses of BasicHost at this moment in time.
// It's ok to not include addresses if they're not available to be used now.
func (h *BasicHost) AllAddrs() []ma.Multiaddr {
listenAddrs, err := h.Network().InterfaceListenAddresses()
if err != nil {
log.Debug("error retrieving network interface addrs")
h.lipMu.RLock()
localIPv4Addr := h.localIPv4Addr
localIPv6Addr := h.localIPv6Addr
h.lipMu.RUnlock()

var finalAddrs []ma.Multiaddr
listenAddrs := h.Network().ListenAddresses()
for _, addr := range listenAddrs {
if !manet.IsIPUnspecified(addr) {
finalAddrs = append(finalAddrs, addr)
continue
}

ifaceAddrs := []ma.Multiaddr{manet.IP4Loopback, manet.IP6Loopback}
if localIPv4Addr != nil {
ifaceAddrs = append(ifaceAddrs, localIPv4Addr)
}
if localIPv6Addr != nil {
ifaceAddrs = append(ifaceAddrs, localIPv6Addr)
}

resolved, err := addrutil.ResolveUnspecifiedAddress(addr, ifaceAddrs)
if err == nil {
for _, r := range resolved {
finalAddrs = append(finalAddrs, r)
}
}
}

finalAddrs = dedupAddrs(finalAddrs)

var natMappings []inat.Mapping

// natmgr is nil if we do not use nat option;
Expand All @@ -723,9 +786,7 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr {
natMappings = h.natmgr.NAT().Mappings()
}

finalAddrs := listenAddrs
if len(natMappings) > 0 {

// We have successfully mapped ports on our NAT. Use those
// instead of observed addresses (mostly).

Expand Down
53 changes: 53 additions & 0 deletions p2p/host/basic/basic_host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
manet "github.com/multiformats/go-multiaddr-net"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -201,6 +202,58 @@ func TestHostAddrsFactory(t *testing.T) {
}
}

func TestLocalIPChangesWhenListenAddrChanges(t *testing.T) {
ctx := context.Background()

// no listen addrs
h := New(swarmt.GenSwarm(t, ctx, swarmt.OptDialOnly))
defer h.Close()

h.lipMu.Lock()
h.localIPv4Addr = nil
h.lipMu.Unlock()

// change listen addrs and veify local IP addr is not nil again
require.NoError(t, h.Network().Listen(ma.StringCast("/ip4/0.0.0.0/tcp/0")))
h.SignalAddressChange()
time.Sleep(1 * time.Second)

h.lipMu.RLock()
h.lipMu.RUnlock()
require.NotNil(t, h.localIPv4Addr)
}

func TestAllAddrs(t *testing.T) {
ctx := context.Background()

// no listen addrs
h := New(swarmt.GenSwarm(t, ctx, swarmt.OptDialOnly))
defer h.Close()
require.Nil(t, h.AllAddrs())

h.lipMu.RLock()
localIPv4Addr := h.localIPv4Addr
h.lipMu.RUnlock()

// listen on private IP address and see it's available on the address
laddr := localIPv4Addr.Encapsulate(ma.StringCast("/tcp/0"))
require.NoError(t, h.Network().Listen(laddr))
require.Len(t, h.AllAddrs(), 1)
addr := ma.Split(h.AllAddrs()[0])
require.Equal(t, localIPv4Addr.String(), addr[0].String())

// listen on IPv4 0.0.0.0
require.NoError(t, h.Network().Listen(ma.StringCast("/ip4/0.0.0.0/tcp/0")))
// should contain localhost and private local addr along with previous listen address
require.Len(t, h.AllAddrs(), 3)
ipmap := make(map[string]struct{})
for _, a := range h.AllAddrs() {
ipmap[ma.Split(a)[0].String()] = struct{}{}
}
require.Contains(t, ipmap, localIPv4Addr.String())
require.Contains(t, ipmap, manet.IP4Loopback.String())
}

func getHostPair(ctx context.Context, t *testing.T) (host.Host, host.Host) {
t.Helper()

Expand Down

0 comments on commit 3a1d20b

Please sign in to comment.