p2p/net/swarm: fix connect self problems
This adds two checks after a successful conn.Dial * if the remote peer is not who we wanted, close conn * if the remove peer is outselves, close conn (the second is redundant, but the codebase may evolve to end up disabling the first check, so keeping the second in place helps) note: Loopback addresses are actually sent out (they _have to be_, in cases where there are >1 node in the same machine), so many times when trying connections, nodes end up dialing themselves.
Juan Batiz-Benet committed
Jan 12, 2015 at 20:17 UTC
ddd5c4faee3ab1c4fc680a576acff5fc5679f8e5
1 file changed
+36
-14
p2p/net/swarm/swarm_dial.go
+36
-14
@@ -10,6 +10,7 @@ import (
10
lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"
11
12
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
13
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
14
)
15
16
// Dial connects to a peer.
@@ -56,23 +57,11 @@ func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) {
57
PrivateKey: sk,
58
}
59
59
- // try to connect to one of the peer's known addresses.
60
- // for simplicity, we do this sequentially.
61
- // A future commit will do this asynchronously.
62
- var connC conn.Conn
63
- var err error
64
- for _, addr := range remoteAddrs {
65
- connC, err = d.Dial(ctx, addr, p)
66
- if err == nil {
67
- break
68
- }
69
- }
60
+ // try to get a connection to any addr
61
+ connC, err := s.dialAddrs(ctx, d, p, remoteAddrs)
62
if err != nil {
63
return nil, err
64
}
73
- if connC == nil {
74
- err = fmt.Errorf("failed to dial %s", p)
75
- }
65
66
// ok try to setup the new connection.
67
swarmC, err := dialConnSetup(ctx, s, connC)
@@ -87,6 +76,39 @@ func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) {
76
return swarmC, nil
77
}
78
79
+func (s *Swarm) dialAddrs(ctx context.Context, d *conn.Dialer, p peer.ID, remoteAddrs []ma.Multiaddr) (conn.Conn, error) {
80
+
81
+ // try to connect to one of the peer's known addresses.
82
+ // for simplicity, we do this sequentially.
83
+ // A future commit will do this asynchronously.
84
+ for _, addr := range remoteAddrs {
85
+ connC, err := d.Dial(ctx, addr, p)
86
+ if err != nil {
87
+ continue
88
+ }
89
+
90
+ // if the connection is not to whom we thought it would be...
91
+ if connC.RemotePeer() != p {
92
+ log.Infof("misdial to %s through %s (got %s)", p, addr, connC.RemoteMultiaddr())
93
+ connC.Close()
94
+ continue
95
+ }
96
+
97
+ // if the connection is to ourselves...
98
+ // this can happen TONS when Loopback addrs are advertized.
99
+ // (this should be caught by two checks above, but let's just make sure.)
100
+ if connC.RemotePeer() == s.local {
101
+ log.Infof("misdial to %s through %s", p, addr)
102
+ connC.Close()
103
+ continue
104
+ }
105
+
106
+ // success! we got one!
107
+ return connC, nil
108
+ }
109
+ return nil, fmt.Errorf("failed to dial %s", p)
110
+}
111
+
112
// dialConnSetup is the setup logic for a connection from the dial side. it
113
// needs to add the Conn to the StreamSwarm, then run newConnSetup
114
func dialConnSetup(ctx context.Context, s *Swarm, connC conn.Conn) (*Conn, error) {