connectionchooser.py
1 """ 2 Select which node to connect to 3 """ 4 # pylint: disable=too-many-branches 5 import logging 6 import random 7 8 from six.moves import queue 9 10 import knownnodes 11 import protocol 12 import state 13 14 from bmconfigparser import config 15 from network import portCheckerQueue 16 17 logger = logging.getLogger('default') 18 19 20 def getDiscoveredPeer(): 21 """Get a peer from the local peer discovery list""" 22 try: 23 peer = random.choice(list(state.discoveredPeers.keys())) # nosec B311 24 except (IndexError, KeyError): 25 raise ValueError 26 try: 27 del state.discoveredPeers[peer] 28 except KeyError: 29 pass 30 return peer 31 32 33 def chooseConnection(stream): 34 """Returns an appropriate connection""" 35 haveOnion = config.safeGet( 36 "bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS' 37 onionOnly = config.safeGetBoolean( 38 "bitmessagesettings", "onionservicesonly") 39 try: 40 retval = portCheckerQueue.get(False) 41 portCheckerQueue.task_done() 42 return retval 43 except queue.Empty: 44 pass 45 # with a probability of 0.5, connect to a discovered peer 46 if random.choice((False, True)) and not haveOnion: # nosec B311 47 # discovered peers are already filtered by allowed streams 48 return getDiscoveredPeer() 49 for _ in range(50): 50 peer = random.choice( # nosec B311 51 list(knownnodes.knownNodes[stream].keys())) 52 try: 53 peer_info = knownnodes.knownNodes[stream][peer] 54 if peer_info.get('self'): 55 continue 56 rating = peer_info["rating"] 57 except TypeError: 58 logger.warning('Error in %s', peer) 59 rating = 0 60 if haveOnion: 61 # do not connect to raw IP addresses 62 # --keep all traffic within Tor overlay 63 if onionOnly and not peer.host.endswith('.onion'): 64 continue 65 # onion addresses have a higher priority when SOCKS 66 if peer.host.endswith('.onion') and rating > 0: 67 rating = 1 68 # TODO: need better check 69 elif not peer.host.startswith('bootstrap'): 70 encodedAddr = protocol.encodeHost(peer.host) 71 # don't connect to local IPs when using SOCKS 72 if not protocol.checkIPAddress(encodedAddr, False): 73 continue 74 if rating > 1: 75 rating = 1 76 try: 77 if 0.05 / (1.0 - rating) > random.random(): # nosec B311 78 return peer 79 except ZeroDivisionError: 80 return peer 81 raise ValueError