/ src / network / connectionchooser.py
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