From ddd5c4faee3ab1c4fc680a576acff5fc5679f8e5 Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Mon, 12 Jan 2015 20:17:54 -0800 Subject: [PATCH] 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. --- p2p/net/swarm/swarm_dial.go | 50 ++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go index d17d31c8d..041e8a0db 100644 --- a/p2p/net/swarm/swarm_dial.go +++ b/p2p/net/swarm/swarm_dial.go @@ -10,6 +10,7 @@ import ( lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables" context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" ) // Dial connects to a peer. @@ -56,23 +57,11 @@ func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) { PrivateKey: sk, } - // try to connect to one of the peer's known addresses. - // for simplicity, we do this sequentially. - // A future commit will do this asynchronously. - var connC conn.Conn - var err error - for _, addr := range remoteAddrs { - connC, err = d.Dial(ctx, addr, p) - if err == nil { - break - } - } + // try to get a connection to any addr + connC, err := s.dialAddrs(ctx, d, p, remoteAddrs) if err != nil { return nil, err } - if connC == nil { - err = fmt.Errorf("failed to dial %s", p) - } // ok try to setup the new connection. swarmC, err := dialConnSetup(ctx, s, connC) @@ -87,6 +76,39 @@ func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) { return swarmC, nil } +func (s *Swarm) dialAddrs(ctx context.Context, d *conn.Dialer, p peer.ID, remoteAddrs []ma.Multiaddr) (conn.Conn, error) { + + // try to connect to one of the peer's known addresses. + // for simplicity, we do this sequentially. + // A future commit will do this asynchronously. + for _, addr := range remoteAddrs { + connC, err := d.Dial(ctx, addr, p) + if err != nil { + continue + } + + // if the connection is not to whom we thought it would be... + if connC.RemotePeer() != p { + log.Infof("misdial to %s through %s (got %s)", p, addr, connC.RemoteMultiaddr()) + connC.Close() + continue + } + + // if the connection is to ourselves... + // this can happen TONS when Loopback addrs are advertized. + // (this should be caught by two checks above, but let's just make sure.) + if connC.RemotePeer() == s.local { + log.Infof("misdial to %s through %s", p, addr) + connC.Close() + continue + } + + // success! we got one! + return connC, nil + } + return nil, fmt.Errorf("failed to dial %s", p) +} + // dialConnSetup is the setup logic for a connection from the dial side. it // needs to add the Conn to the StreamSwarm, then run newConnSetup func dialConnSetup(ctx context.Context, s *Swarm, connC conn.Conn) (*Conn, error) {