Skip to content

Commit 796b95b

Browse files
authored
Merge pull request #576 from libp2p/feat/filter-rt
fix: use the routing table filter
2 parents 6c82b40 + 6400d24 commit 796b95b

File tree

5 files changed

+107
-4
lines changed

5 files changed

+107
-4
lines changed

dht_filters.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ package dht
33
import (
44
"bytes"
55
"net"
6+
"sync"
7+
"time"
68

79
"github.com/libp2p/go-libp2p-core/network"
810
"github.com/libp2p/go-libp2p-core/peer"
11+
12+
"github.com/google/gopacket/routing"
913
netroute "github.com/libp2p/go-netroute"
1014

1115
ma "github.com/multiformats/go-multiaddr"
@@ -64,10 +68,42 @@ func PrivateQueryFilter(dht *IpfsDHT, ai peer.AddrInfo) bool {
6468

6569
var _ QueryFilterFunc = PrivateQueryFilter
6670

71+
// We call this very frequently but routes can technically change at runtime.
72+
// Cache it for two minutes.
73+
const routerCacheTime = 2 * time.Minute
74+
75+
var routerCache struct {
76+
sync.RWMutex
77+
router routing.Router
78+
expires time.Time
79+
}
80+
81+
func getCachedRouter() routing.Router {
82+
routerCache.RLock()
83+
router := routerCache.router
84+
expires := routerCache.expires
85+
routerCache.RUnlock()
86+
87+
if time.Now().Before(expires) {
88+
return router
89+
}
90+
91+
routerCache.Lock()
92+
defer routerCache.Unlock()
93+
94+
now := time.Now()
95+
if now.Before(routerCache.expires) {
96+
return router
97+
}
98+
routerCache.router, _ = netroute.New()
99+
routerCache.expires = now.Add(routerCacheTime)
100+
return router
101+
}
102+
67103
// PrivateRoutingTableFilter allows a peer to be added to the routing table if the connections to that peer indicate
68104
// that it is on a private network
69105
func PrivateRoutingTableFilter(dht *IpfsDHT, conns []network.Conn) bool {
70-
router, _ := netroute.New()
106+
router := getCachedRouter()
71107
myAdvertisedIPs := make([]net.IP, 0)
72108
for _, a := range dht.Host().Addrs() {
73109
if manet.IsPublicAddr(a) && !isRelayAddr(a) {

dht_filters_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
package dht
22

33
import (
4+
"context"
5+
"net"
46
"testing"
57

8+
ic "github.com/libp2p/go-libp2p-core/crypto"
9+
"github.com/libp2p/go-libp2p-core/network"
10+
"github.com/libp2p/go-libp2p-core/peer"
611
"github.com/multiformats/go-multiaddr"
12+
ma "github.com/multiformats/go-multiaddr"
13+
manet "github.com/multiformats/go-multiaddr-net"
714
)
815

916
func TestIsRelay(t *testing.T) {
@@ -21,3 +28,39 @@ func TestIsRelay(t *testing.T) {
2128
}
2229

2330
}
31+
32+
type mockConn struct {
33+
local peer.AddrInfo
34+
remote peer.AddrInfo
35+
}
36+
37+
func (m *mockConn) Close() error { return nil }
38+
func (m *mockConn) NewStream() (network.Stream, error) { return nil, nil }
39+
func (m *mockConn) GetStreams() []network.Stream { return []network.Stream{} }
40+
func (m *mockConn) Stat() network.Stat { return network.Stat{Direction: network.DirOutbound} }
41+
func (m *mockConn) LocalMultiaddr() ma.Multiaddr { return m.local.Addrs[0] }
42+
func (m *mockConn) RemoteMultiaddr() ma.Multiaddr { return m.remote.Addrs[0] }
43+
func (m *mockConn) LocalPeer() peer.ID { return m.local.ID }
44+
func (m *mockConn) LocalPrivateKey() ic.PrivKey { return nil }
45+
func (m *mockConn) RemotePeer() peer.ID { return m.remote.ID }
46+
func (m *mockConn) RemotePublicKey() ic.PubKey { return nil }
47+
48+
func TestFilterCaching(t *testing.T) {
49+
ctx, cancel := context.WithCancel(context.Background())
50+
defer cancel()
51+
d := setupDHT(ctx, t, true)
52+
53+
remote, _ := manet.FromIP(net.IPv4(8, 8, 8, 8))
54+
if PrivateRoutingTableFilter(d, []network.Conn{&mockConn{
55+
local: d.Host().Peerstore().PeerInfo(d.Host().ID()),
56+
remote: peer.AddrInfo{ID: "", Addrs: []ma.Multiaddr{remote}},
57+
}}) {
58+
t.Fatal("filter should prevent public remote peers.")
59+
}
60+
61+
r1 := getCachedRouter()
62+
r2 := getCachedRouter()
63+
if r1 != r2 {
64+
t.Fatal("router should be returned multiple times.")
65+
}
66+
}

dht_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,3 +1958,27 @@ func TestInvalidKeys(t *testing.T) {
19581958
t.Fatal("expected to have failed")
19591959
}
19601960
}
1961+
1962+
func TestRoutingFilter(t *testing.T) {
1963+
ctx, cancel := context.WithCancel(context.Background())
1964+
defer cancel()
1965+
1966+
nDHTs := 2
1967+
dhts := setupDHTS(t, ctx, nDHTs)
1968+
defer func() {
1969+
for i := 0; i < nDHTs; i++ {
1970+
dhts[i].Close()
1971+
defer dhts[i].host.Close()
1972+
}
1973+
}()
1974+
dhts[0].routingTablePeerFilter = PublicRoutingTableFilter
1975+
1976+
connectNoSync(t, ctx, dhts[0], dhts[1])
1977+
wait(t, ctx, dhts[1], dhts[0])
1978+
1979+
select {
1980+
case <-ctx.Done():
1981+
t.Fatal(ctx.Err())
1982+
case <-time.After(time.Millisecond * 200):
1983+
}
1984+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.14
44

55
require (
66
github.com/gogo/protobuf v1.3.1
7+
github.com/google/gopacket v1.1.17
78
github.com/google/uuid v1.1.1
89
github.com/hashicorp/go-multierror v1.1.0
910
github.com/hashicorp/golang-lru v0.5.4
@@ -24,7 +25,6 @@ require (
2425
github.com/libp2p/go-libp2p-testing v0.1.1
2526
github.com/libp2p/go-msgio v0.0.4
2627
github.com/libp2p/go-netroute v0.1.2
27-
github.com/mr-tron/base58 v1.1.3
2828
github.com/multiformats/go-base32 v0.0.3
2929
github.com/multiformats/go-multiaddr v0.2.1
3030
github.com/multiformats/go-multiaddr-dns v0.2.0

subscriber_notifee.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,11 @@ func handleLocalReachabilityChangedEvent(dht *IpfsDHT, e event.EvtLocalReachabil
172172
// routing table
173173
func (dht *IpfsDHT) validRTPeer(p peer.ID) (bool, error) {
174174
protos, err := dht.peerstore.SupportsProtocols(p, protocol.ConvertToStrings(dht.protocols)...)
175-
if err != nil {
175+
if len(protos) == 0 || err != nil {
176176
return false, err
177177
}
178178

179-
return len(protos) > 0, nil
179+
return dht.routingTablePeerFilter == nil || dht.routingTablePeerFilter(dht, dht.Host().Network().ConnsToPeer(p)), nil
180180
}
181181

182182
func (nn *subscriberNotifee) Disconnected(n network.Network, v network.Conn) {

0 commit comments

Comments
 (0)