def on_peers_subscribe(self, request): '''Handle the response to the peers.subcribe message.''' if not self.is_good(request, list): return # Check the peers list we got from a remote peer. # Each is expected to be of the form: # [ip_addr, hostname, ['v1.0', 't51001', 's51002']] # Call add_peer if the remote doesn't appear to know about us. raw_peers = request.result() try: real_names = [' '.join([u[1]] + u[2]) for u in raw_peers] peers = [ Peer.from_real_name(real_name, str(self.peer)) for real_name in real_names ] except Exception: self.bad('bad server.peers.subscribe response') return features = self.peer_mgr.features_to_register(self.peer, peers) if features: self.logger.info(f'registering ourself with "server.add_peer"') self.send_request('server.add_peer', [features], self.on_add_peer, timeout=self.timeout) else: self.maybe_close()
def __init__(self, env, db): self.logger = class_logger(__name__, self.__class__.__name__) # Initialise the Peer class Peer.DEFAULT_PORTS = env.coin.PEER_DEFAULT_PORTS self.env = env self.db = db # Our reported clearnet and Tor Peers, if any sclass = env.coin.SESSIONCLS self.myselves = [ Peer(str(service.host), sclass.server_features(env), 'env') for service in env.report_services ] self.server_version_args = sclass.server_version_args() # Peers have one entry per hostname. Once connected, the # ip_addr property is either None, an onion peer, or the # IP address that was connected to. Adding a peer will evict # any other peers with the same host name or IP address. self.peers = set() self.permit_onion_peer_time = time.time() self.proxy = None self.group = TaskGroup() self.recent_peer_adds = {} # refreshed self.blacklist = set()
async def _send_peers_subscribe(self, session, peer): message = 'server.peers.subscribe' raw_peers = await session.send_request(message) assert_good(message, raw_peers, list) # Check the peers list we got from a remote peer. # Each is expected to be of the form: # [ip_addr, hostname, ['v1.0', 't51001', 's51002']] # Call add_peer if the remote doesn't appear to know about us. try: real_names = [' '.join([u[1]] + u[2]) for u in raw_peers] peers = [ Peer.from_real_name(real_name, str(peer)) for real_name in real_names ] except Exception: raise BadPeerError('bad server.peers.subscribe response') await self._note_peers(peers) features = self._features_to_register(peer, peers) if not features: return self.logger.info(f'registering ourself with {peer}') # We only care to wait for the response await session.send_request('server.add_peer', [features])
def __init__(self, env, tasks, chain_state): self.logger = class_logger(__name__, self.__class__.__name__) # Initialise the Peer class Peer.DEFAULT_PORTS = env.coin.PEER_DEFAULT_PORTS self.env = env self.tasks = tasks self.chain_state = chain_state self.loop = tasks.loop # Our clearnet and Tor Peers, if any sclass = env.coin.SESSIONCLS self.myselves = [ Peer(ident.host, sclass.server_features(env), 'env') for ident in env.identities ] self.server_version_args = sclass.server_version_args() self.retry_event = asyncio.Event() # Peers have one entry per hostname. Once connected, the # ip_addr property is either None, an onion peer, or the # IP address that was connected to. Adding a peer will evict # any other peers with the same host name or IP address. self.peers = set() self.permit_onion_peer_time = time.time() self.proxy = None self.last_proxy_try = 0
def rpc_add_peer(self, real_name): '''Add a peer. real_name: a real name, as would appear on IRC ''' peer = Peer.from_real_name(real_name, 'RPC') self.controller.peer_mgr.add_peers([peer]) return "peer '{}' added".format(real_name)
async def _import_peers(self): '''Import hard-coded peers from a file or the coin defaults.''' imported_peers = self.myselves.copy() # Add the hard-coded ones unless only reporting ourself if self.env.peer_discovery != self.env.PD_SELF: imported_peers.extend(Peer.from_real_name(real_name, 'coins.py') for real_name in self.env.coin.PEERS) await self._note_peers(imported_peers, limit=None)
def import_peers(self): '''Import hard-coded peers from a file or the coin defaults.''' self.add_peers(self.myselves) # Add the hard-coded ones unless only returning self if self.env.peer_discovery != self.env.PD_SELF: coin_peers = self.env.coin.PEERS peers = [Peer.from_real_name(real_name, 'coins.py') for real_name in coin_peers] self.add_peers(peers, limit=None)
async def on_add_peer(self, features, source_addr): '''Add a peer (but only if the peer resolves to the source).''' if self.env.peer_discovery != self.env.PD_ON: return False if not source_addr: self.logger.info('ignored add_peer request: no source info') return False source = str(source_addr.host) peers = Peer.peers_from_features(features, source) if not peers: self.logger.info('ignored add_peer request: no peers given') return False # Just look at the first peer, require it peer = peers[0] host = peer.host now = time.time() # Rate limit peer adds by domain to one every 10 minutes if peer.ip_address is not None: bucket = 'ip_addr' else: bucket = '.'.join(host.lower().split('.')[-2:]) last = self.recent_peer_adds.get(bucket, 0) self.recent_peer_adds[bucket] = now if last + PEER_ADD_PAUSE >= now: return False if peer.is_tor: permit = self._permit_new_onion_peer(now) reason = 'rate limiting' else: getaddrinfo = asyncio.get_event_loop().getaddrinfo try: infos = await getaddrinfo(host, 80, type=socket.SOCK_STREAM) except socket.gaierror: permit = False reason = 'address resolution failure' else: permit = any(source == info[-1][0] for info in infos) reason = 'source-destination mismatch' if permit: self.logger.info( f'accepted add_peer request from {source} for {host}') await self._note_peers([peer], check_ports=True) else: self.logger.warning(f'rejected add_peer request from {source} ' f'for {host} ({reason})') return permit
async def _send_peers_subscribe(self, session, peer): message = 'server.peers.subscribe' raw_peers = await session.send_request(message) assert_good(message, raw_peers, list) # Check the peers list we got from a remote peer. # Each is expected to be of the form: # [ip_addr, hostname, ['v1.0', 't51001', 's51002']] # Call add_peer if the remote doesn't appear to know about us. try: real_names = [' '.join([u[1]] + u[2]) for u in raw_peers] return [Peer.from_real_name(real_name, str(peer)) for real_name in real_names] except Exception: raise BadPeerError('bad server.peers.subscribe response')
async def on_add_peer(self, features, source_info): '''Add a peer (but only if the peer resolves to the source).''' if not source_info: self.logger.info('ignored add_peer request: no source info') return False source = source_info[0] peers = Peer.peers_from_features(features, source) if not peers: self.logger.info('ignored add_peer request: no peers given') return False # Just look at the first peer, require it peer = peers[0] host = peer.host if peer.is_tor: permit, reason = self._permit_new_onion_peer() # check if peer_discovery_tor is enabled and also if sufficient time has passed since we added tor peers (we rate limit tor even if discovery is enabled) else: getaddrinfo = asyncio.get_event_loop().getaddrinfo try: infos = await getaddrinfo(host, 80, type=socket.SOCK_STREAM) except socket.gaierror: permit = False reason = 'address resolution failure' else: permit = any(source == info[-1][0] for info in infos) reason = 'source-destination mismatch' if permit: permit = not any(ip_address(info[-1][0]) in self.session_mgr.banned_ips for info in infos) reason = 'banned IP' if permit: permit = not any(self._dupes_for_peer(info[-1][0]) for info in infos) reason = 'dupe peer' if permit: notok = self.session_mgr.does_peer_match_hostname_ban(peer) if notok: permit = False reason = f'banned hostname suffix: {notok}' if permit: self.logger.info(f'accepted add_peer request from {source} ' f'for {host}') await self._note_peers([peer], check_ports=True) else: self.logger.warning(f'rejected add_peer request from {source} ' f'for {host} ({reason})') return permit
async def on_add_peer(self, features, source_info): '''Add a peer (but only if the peer resolves to the source).''' if not source_info: self.logger.info('ignored add_peer request: no source info') return False source = source_info[0] peers = Peer.peers_from_features(features, source) if not peers: self.logger.info('ignored add_peer request: no peers given') return False # Just look at the first peer, require it peer = peers[0] host = peer.host if peer.is_tor: permit = self.permit_new_onion_peer() reason = 'rate limiting' else: try: infos = await self.loop.getaddrinfo(host, 80, type=socket.SOCK_STREAM) except socket.gaierror: permit = False reason = 'address resolution failure' else: permit = any(source == info[-1][0] for info in infos) reason = 'source-destination mismatch' if permit: self.logger.info('accepted add_peer request from {} for {}'.format( source, host)) self.add_peers([peer], check_ports=True) else: self.logger.warning( 'rejected add_peer request from {} for {} ({})'.format( source, host, reason)) return permit
def __init__(self, env, controller): self.logger = logging.getLogger(__name__)\ .getChild(self.__class__.__name__) # Initialise the Peer class Peer.DEFAULT_PORTS = env.coin.PEER_DEFAULT_PORTS self.env = env self.controller = controller self.loop = controller.loop # Our clearnet and Tor Peers, if any self.myselves = [ Peer(ident.host, controller.server_features(), 'env') for ident in env.identities ] self.retry_event = asyncio.Event() # Peers have one entry per hostname. Once connected, the # ip_addr property is either None, an onion peer, or the # IP address that was connected to. Adding a peer will evict # any other peers with the same host name or IP address. self.peers = set() self.permit_onion_peer_time = time.time() self.proxy = None self.last_proxy_try = 0
async def add_localRPC_peer(self, real_name): '''Add a peer passed by the admin over LocalRPC.''' await self._note_peers([Peer.from_real_name(real_name, 'RPC')])