-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
factor out dial policy
- Loading branch information
Showing
7 changed files
with
242 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package autonat | ||
|
||
import ( | ||
"net" | ||
|
||
"github.com/libp2p/go-libp2p-core/host" | ||
ma "github.com/multiformats/go-multiaddr" | ||
manet "github.com/multiformats/go-multiaddr-net" | ||
) | ||
|
||
type dialPolicy struct { | ||
allowSelfDials bool | ||
host host.Host | ||
} | ||
|
||
// skipDial indicates that a multiaddress isn't worth attempted dialing. | ||
// The same logic is used when the autonat client is considering if | ||
// a remote peer is worth using as a server, and when the server is | ||
// considering if a requested client is worth dialing back. | ||
func (d *dialPolicy) skipDial(addr ma.Multiaddr) bool { | ||
// skip relay addresses | ||
_, err := addr.ValueForProtocol(ma.P_CIRCUIT) | ||
if err == nil { | ||
return true | ||
} | ||
|
||
if d.allowSelfDials { | ||
return false | ||
} | ||
|
||
// skip private network (unroutable) addresses | ||
if !manet.IsPublicAddr(addr) { | ||
return true | ||
} | ||
candidateIP, err := manet.ToIP(addr) | ||
if err != nil { | ||
return true | ||
} | ||
|
||
// Skip dialing addresses we believe are the local node's | ||
for _, localAddr := range d.host.Addrs() { | ||
localIP, err := manet.ToIP(localAddr) | ||
if err != nil { | ||
continue | ||
} | ||
if localIP.Equal(candidateIP) { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
// skipPeer indicates that the collection of multiaddresses representing a peer | ||
// isn't worth attempted dialing. Addresses are dialed individually, and while | ||
// individual addresses for a peer may be worth considering, there are some | ||
// factors, like the presence of the same public address as the local host, | ||
// that may make the peer undesirable to dial as a whole. | ||
func (d *dialPolicy) skipPeer(addrs []ma.Multiaddr) bool { | ||
localAddrs := d.host.Addrs() | ||
localHosts := make([]net.IP, 0) | ||
for _, lAddr := range localAddrs { | ||
if _, err := lAddr.ValueForProtocol(ma.P_CIRCUIT); err != nil && manet.IsPublicAddr(lAddr) { | ||
lIP, err := manet.ToIP(lAddr) | ||
if err != nil { | ||
continue | ||
} | ||
localHosts = append(localHosts, lIP) | ||
} | ||
} | ||
|
||
// if a public IP of the peer is one of ours: skip the peer. | ||
goodPublic := false | ||
for _, addr := range addrs { | ||
if _, err := addr.ValueForProtocol(ma.P_CIRCUIT); err != nil && manet.IsPublicAddr(addr) { | ||
aIP, err := manet.ToIP(addr) | ||
if err != nil { | ||
continue | ||
} | ||
|
||
for _, lIP := range localHosts { | ||
if lIP.Equal(aIP) { | ||
return true | ||
} | ||
} | ||
goodPublic = true | ||
} | ||
} | ||
|
||
if d.allowSelfDials { | ||
return false | ||
} | ||
|
||
return !goodPublic | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package autonat | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"net" | ||
"testing" | ||
|
||
blankhost "github.com/libp2p/go-libp2p-blankhost" | ||
"github.com/libp2p/go-libp2p-core/peer" | ||
"github.com/libp2p/go-libp2p-core/transport" | ||
swarmt "github.com/libp2p/go-libp2p-swarm/testing" | ||
"github.com/multiformats/go-multiaddr" | ||
) | ||
|
||
func makeMA(a string) multiaddr.Multiaddr { | ||
addr, err := multiaddr.NewMultiaddr(a) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return addr | ||
} | ||
|
||
type mockT struct { | ||
ctx context.Context | ||
addr multiaddr.Multiaddr | ||
} | ||
|
||
func (m *mockT) Dial(ctx context.Context, a multiaddr.Multiaddr, p peer.ID) (transport.CapableConn, error) { | ||
return nil, nil | ||
} | ||
func (m *mockT) CanDial(_ multiaddr.Multiaddr) bool { return true } | ||
func (m *mockT) Listen(a multiaddr.Multiaddr) (transport.Listener, error) { | ||
return &mockL{m.ctx, m.addr}, nil | ||
} | ||
func (m *mockT) Protocols() []int { return []int{multiaddr.P_IP4} } | ||
func (m *mockT) Proxy() bool { return false } | ||
func (m *mockT) String() string { return "mock-tcp-ipv4" } | ||
|
||
type mockL struct { | ||
ctx context.Context | ||
addr multiaddr.Multiaddr | ||
} | ||
|
||
func (l *mockL) Accept() (transport.CapableConn, error) { | ||
select { | ||
case <-l.ctx.Done(): | ||
} | ||
return nil, errors.New("expected in mocked test") | ||
} | ||
func (l *mockL) Close() error { return nil } | ||
func (l *mockL) Addr() net.Addr { return nil } | ||
func (l *mockL) Multiaddr() multiaddr.Multiaddr { return l.addr } | ||
|
||
func TestSkipDial(t *testing.T) { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
s := swarmt.GenSwarm(t, ctx) | ||
d := dialPolicy{host: blankhost.NewBlankHost(s)} | ||
if d.skipDial(makeMA("/ip4/8.8.8.8")) != false { | ||
t.Fatal("failed dialing a valid public addr") | ||
} | ||
|
||
if d.skipDial(makeMA("/ip6/2607:f8b0:400a::1")) != false { | ||
t.Fatal("failed dialing a valid public addr") | ||
} | ||
|
||
if d.skipDial(makeMA("/ip4/192.168.0.1")) != true { | ||
t.Fatal("didn't skip dialing an internal addr") | ||
} | ||
|
||
s.AddTransport(&mockT{ctx, makeMA("/ip4/8.8.8.8")}) | ||
err := s.AddListenAddr(makeMA("/ip4/8.8.8.8")) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if d.skipDial(makeMA("/ip4/8.8.8.8")) != true { | ||
t.Fatal("failed dialing a valid host address") | ||
} | ||
} | ||
|
||
func TestSkipPeer(t *testing.T) { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
s := swarmt.GenSwarm(t, ctx) | ||
d := dialPolicy{host: blankhost.NewBlankHost(s)} | ||
if d.skipPeer([]multiaddr.Multiaddr{makeMA("/ip4/8.8.8.8")}) != false { | ||
t.Fatal("failed dialing a valid public addr") | ||
} | ||
if d.skipPeer([]multiaddr.Multiaddr{makeMA("/ip4/8.8.8.8"), makeMA("/ip4/192.168.0.1")}) != false { | ||
t.Fatal("failed dialing a valid public addr") | ||
} | ||
if d.skipPeer([]multiaddr.Multiaddr{makeMA("/ip4/192.168.0.1")}) != true { | ||
t.Fatal("succeeded with no public addr") | ||
} | ||
|
||
s.AddTransport(&mockT{ctx, makeMA("/ip4/8.8.8.8")}) | ||
err := s.AddListenAddr(makeMA("/ip4/8.8.8.8")) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if d.skipPeer([]multiaddr.Multiaddr{makeMA("/ip4/8.8.8.8"), makeMA("/ip4/192.168.0.1")}) != true { | ||
t.Fatal("succeeded dialing host address") | ||
} | ||
if d.skipPeer([]multiaddr.Multiaddr{makeMA("/ip4/8.8.8.8"), makeMA("/ip4/9.9.9.9")}) != true { | ||
t.Fatal("succeeded dialing host address when other public") | ||
} | ||
if d.skipPeer([]multiaddr.Multiaddr{makeMA("/ip4/9.9.9.9")}) != false { | ||
t.Fatal("succeeded dialing host address when other public") | ||
} | ||
} | ||
|
||
func TestSkipLocalPeer(t *testing.T) { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
s := swarmt.GenSwarm(t, ctx) | ||
d := dialPolicy{host: blankhost.NewBlankHost(s)} | ||
s.AddTransport(&mockT{ctx, makeMA("/ip4/192.168.0.1")}) | ||
err := s.AddListenAddr(makeMA("/ip4/192.168.0.1")) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if d.skipPeer([]multiaddr.Multiaddr{makeMA("/ip4/8.8.8.8")}) != false { | ||
t.Fatal("failed dialing a valid public addr") | ||
} | ||
if d.skipPeer([]multiaddr.Multiaddr{makeMA("/ip4/8.8.8.8"), makeMA("/ip4/192.168.0.1")}) != false { | ||
t.Fatal("failed dialing a valid public addr") | ||
} | ||
if d.skipPeer([]multiaddr.Multiaddr{makeMA("/ip4/192.168.0.1")}) != true { | ||
t.Fatal("succeeded with no public addr") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters