diff --git a/lib/peer.py b/lib/peer.py index 5f94e03..d011300 100644 --- a/lib/peer.py +++ b/lib/peer.py @@ -94,12 +94,14 @@ class Peer(object): return tuple(int(part) for part in vstr.split('.')) def matches(self, peers): - '''Return peers whose host matches the given peer's host or IP - address. This results in our favouring host names over IP - addresses. + '''Return peers whose host matches our hostname or IP address. + Additionally include all peers whose IP address matches our + hostname if that is an IP address. ''' candidates = (self.host.lower(), self.ip_addr) - return [peer for peer in peers if peer.host.lower() in candidates] + return [peer for peer in peers + if peer.host.lower() in candidates + or peer.ip_addr == self.host] def __str__(self): return self.host @@ -111,9 +113,13 @@ class Peer(object): except Exception: pass else: - self.features = tmp.features + self.update_features_from_peer(tmp) + + def update_features_from_peer(self, peer): + if peer != self: + self.features = peer.features for feature in self.FEATURES: - setattr(self, feature, getattr(tmp, feature)) + setattr(self, feature, getattr(peer, feature)) def connection_port_pairs(self): '''Return a list of (kind, port) pairs to try when making a diff --git a/server/peers.py b/server/peers.py index db19f32..8fb01a8 100644 --- a/server/peers.py +++ b/server/peers.py @@ -555,15 +555,20 @@ class PeerManager(util.LoggedClass): how = 'via {} at {}'.format(kind, peer.ip_addr) status = 'verified' if good else 'failed to verify' elapsed = time.time() - peer.last_try - self.log_info('{} {} in {:.1f}s'.format(status, how, elapsed)) + self.log_info('{} {} {} in {:.1f}s'.format(status, peer, how, elapsed)) if good: peer.try_count = 0 peer.source = 'peer' - # Remove matching IP addresses - for match in peer.matches(self.peers): - if match != peer and peer.host == peer.ip_addr: - self.peers.remove(match) + # At most 2 matches if we're a host name, potentially several if + # we're an IP address (several instances can share a NAT). + matches = peer.matches(self.peers) + for match in matches: + if match.ip_address: + if len(matches) > 1: + self.peers.remove(match) + elif peer.host in match.features['hosts']: + match.update_features_from_peer(peer) else: self.maybe_forget_peer(peer)