diff --git a/router/connection_maker.go b/router/connection_maker.go index bcf0f96215..50582d947d 100644 --- a/router/connection_maker.go +++ b/router/connection_maker.go @@ -19,7 +19,7 @@ type ConnectionMaker struct { peers *Peers normalisePeerAddr func(string) string targets map[string]*Target - cmdLinePeers map[string]string + cmdLinePeers map[string]*CmdLinePeer actionChan chan<- ConnectionMakerAction } @@ -31,6 +31,11 @@ type Target struct { tryInterval time.Duration // backoff time on next failure } +type CmdLinePeer struct { + address string // normalised and resolved address of peer to connect to + portSupplied bool // did the original address contain a port? +} + type ConnectionMakerAction func() bool func NewConnectionMaker(ourself *LocalPeer, peers *Peers, normalisePeerAddr func(string) string) *ConnectionMaker { @@ -38,7 +43,7 @@ func NewConnectionMaker(ourself *LocalPeer, peers *Peers, normalisePeerAddr func ourself: ourself, peers: peers, normalisePeerAddr: normalisePeerAddr, - cmdLinePeers: make(map[string]string), + cmdLinePeers: make(map[string]*CmdLinePeer), targets: make(map[string]*Target)} } @@ -49,14 +54,15 @@ func (cm *ConnectionMaker) Start() { } func (cm *ConnectionMaker) InitiateConnection(peer string) error { - addr, err := net.ResolveTCPAddr("tcp4", cm.normalisePeerAddr(peer)) + normalisedPeerAddr := cm.normalisePeerAddr(peer) + addr, err := net.ResolveTCPAddr("tcp4", normalisedPeerAddr) if err != nil { return err } address := addr.String() - + portSupplied := peer == normalisedPeerAddr cm.actionChan <- func() bool { - cm.cmdLinePeers[peer] = address + cm.cmdLinePeers[peer] = &CmdLinePeer{address: address, portSupplied: portSupplied} // curtail any existing reconnect interval if target, found := cm.targets[address]; found { target.tryAfter, target.tryInterval = tryImmediately() @@ -138,7 +144,7 @@ func (cm *ConnectionMaker) checkStateAndAttemptConnections() time.Duration { // Copy the set of things we are connected to, so we can access // them without locking. Also clear out any entries in cm.targets // for existing connections. - ourConnectedPeers, ourConnectedTargets := cm.ourConnections() + ourConnectedPeers, ourConnectedTargets, ourInboundIPs := cm.ourConnections() addTarget := func(address string) { if _, connected := ourConnectedTargets[address]; connected { @@ -154,9 +160,18 @@ func (cm *ConnectionMaker) checkStateAndAttemptConnections() time.Duration { } // Add command-line targets that are not connected - for _, address := range cm.cmdLinePeers { - addTarget(address) - cmdLineTarget[address] = void + for _, cmdLinePeer := range cm.cmdLinePeers { + cmdLineTarget[cmdLinePeer.address] = void + // if a peer was specified w/o a port, then do not connect to + // it if we have inbound connections from that IP. + if !cmdLinePeer.portSupplied { + if ip, _, err := net.SplitHostPort(cmdLinePeer.address); err == nil { // should always succeed + if _, connected := ourInboundIPs[ip]; connected { + continue + } + } + } + addTarget(cmdLinePeer.address) } // Add targets for peers that someone else is connected to, but we @@ -166,18 +181,25 @@ func (cm *ConnectionMaker) checkStateAndAttemptConnections() time.Duration { return cm.connectToTargets(validTarget, cmdLineTarget) } -func (cm *ConnectionMaker) ourConnections() (PeerNameSet, map[string]struct{}) { +func (cm *ConnectionMaker) ourConnections() (PeerNameSet, map[string]struct{}, map[string]struct{}) { var ( ourConnectedPeers = make(PeerNameSet) ourConnectedTargets = make(map[string]struct{}) + ourInboundIPs = make(map[string]struct{}) ) for conn := range cm.ourself.Connections() { address := conn.RemoteTCPAddr() + delete(cm.targets, address) ourConnectedPeers[conn.Remote().Name] = void ourConnectedTargets[address] = void - delete(cm.targets, address) + if conn.Outbound() { + continue + } + if ip, _, err := net.SplitHostPort(address); err == nil { // should always succeed + ourInboundIPs[ip] = void + } } - return ourConnectedPeers, ourConnectedTargets + return ourConnectedPeers, ourConnectedTargets, ourInboundIPs } func (cm *ConnectionMaker) addPeerTargets(ourConnectedPeers PeerNameSet, addTarget func(string)) {