Esempio n. 1
0
    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()
Esempio n. 2
0
    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()
Esempio n. 3
0
    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])
Esempio n. 4
0
    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
Esempio n. 5
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)
Esempio n. 6
0
 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)
Esempio n. 7
0
    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)
Esempio n. 8
0
    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
Esempio n. 9
0
    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')
Esempio n. 10
0
    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
Esempio n. 11
0
    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
Esempio n. 12
0
    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
Esempio n. 13
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')])