Add Tor hidden service support
- PyBitmessage can now run as a hidden service on Tor - three new variables in keys.dat: onionhostname, onionport, onionbindip - you need to manually add a hidden service to tor
This commit is contained in:
parent
33991f4598
commit
1a40c29d22
|
@ -50,7 +50,10 @@ class outgoingSynSender(threading.Thread, StoppableThread):
|
|||
if (random.random() <= priority):
|
||||
break
|
||||
time.sleep(0.01) # prevent CPU hogging if something is broken
|
||||
return peer
|
||||
try:
|
||||
return peer
|
||||
except NameError:
|
||||
return shared.Peer('127.0.0.1', 8444)
|
||||
|
||||
def stopThread(self):
|
||||
super(outgoingSynSender, self).stopThread()
|
||||
|
|
|
@ -601,10 +601,19 @@ class receiveDataThread(threading.Thread):
|
|||
# the right child stream.
|
||||
with shared.knownNodesLock:
|
||||
if len(shared.knownNodes[self.streamNumber]) > 0:
|
||||
ownPosition = random.randint(0, 499)
|
||||
sentOwn = False
|
||||
for i in range(500):
|
||||
peer, = random.sample(shared.knownNodes[self.streamNumber], 1)
|
||||
# if current connection is over a proxy, sent our own onion address at a random position
|
||||
if ownPosition == i and ".onion" in shared.config.get("bitmessagesettings", "onionhostname") and self.sock.getproxytype() != 0 and not sentOwn:
|
||||
peer = shared.Peer(shared.config.get("bitmessagesettings", "onionhostname"), shared.config.getint("bitmessagesettings", "onionport"))
|
||||
else:
|
||||
# still may contain own onion address, but we don't change it
|
||||
peer, = random.sample(shared.knownNodes[self.streamNumber], 1)
|
||||
if isHostInPrivateIPRange(peer.host):
|
||||
continue
|
||||
if shared.config.get("bitmessagesettings", "onionhostname") == peer.host:
|
||||
sentOwn = True
|
||||
addrsInMyStream[peer] = shared.knownNodes[
|
||||
self.streamNumber][peer]
|
||||
if len(shared.knownNodes[self.streamNumber * 2]) > 0:
|
||||
|
|
|
@ -27,6 +27,9 @@ class singleListener(threading.Thread, StoppableThread):
|
|||
|
||||
def _createListenSocket(self, family):
|
||||
HOST = '' # Symbolic name meaning all available interfaces
|
||||
# If not sockslisten, but onionhostname defined, only listen on localhost
|
||||
if not shared.safeConfigGetBoolean('bitmessagesettings', 'sockslisten') and ".onion" in shared.config.get('bitmessagesettings', 'onionhostname'):
|
||||
HOST = shared.config.get('bitmessagesettings', 'onionbindip')
|
||||
PORT = shared.config.getint('bitmessagesettings', 'port')
|
||||
sock = socket.socket(family, socket.SOCK_STREAM)
|
||||
if family == socket.AF_INET6:
|
||||
|
@ -43,12 +46,14 @@ class singleListener(threading.Thread, StoppableThread):
|
|||
def stopThread(self):
|
||||
super(singleListener, self).stopThread()
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.connect(('127.0.0.1', shared.config.getint('bitmessagesettings', 'port')))
|
||||
s.shutdown(socket.SHUT_RDWR)
|
||||
s.close()
|
||||
except:
|
||||
pass
|
||||
for ip in ('127.0.0.1', shared.config.get('bitmessagesettings', 'onionbindip')):
|
||||
try:
|
||||
s.connect((ip, shared.config.getint('bitmessagesettings', 'port')))
|
||||
s.shutdown(socket.SHUT_RDWR)
|
||||
s.close()
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
# If there is a trusted peer then we don't want to accept
|
||||
|
@ -62,8 +67,12 @@ class singleListener(threading.Thread, StoppableThread):
|
|||
# We typically don't want to accept incoming connections if the user is using a
|
||||
# SOCKS proxy, unless they have configured otherwise. If they eventually select
|
||||
# proxy 'none' or configure SOCKS listening then this will start listening for
|
||||
# connections.
|
||||
while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten') and shared.shutdown == 0:
|
||||
# connections. But if on SOCKS and have an onionhostname, listen
|
||||
# (socket is then only opened for localhost)
|
||||
while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \
|
||||
(not shared.config.getboolean('bitmessagesettings', 'sockslisten') and \
|
||||
".onion" not in shared.config.get('bitmessagesettings', 'onionhostname')) and \
|
||||
shared.shutdown == 0:
|
||||
self.stop.wait(5)
|
||||
|
||||
logger.info('Listening for incoming connections.')
|
||||
|
@ -77,6 +86,7 @@ class singleListener(threading.Thread, StoppableThread):
|
|||
if (isinstance(e.args, tuple) and
|
||||
e.args[0] in (errno.EAFNOSUPPORT,
|
||||
errno.EPFNOSUPPORT,
|
||||
errno.EADDRNOTAVAIL,
|
||||
errno.ENOPROTOOPT)):
|
||||
sock = self._createListenSocket(socket.AF_INET)
|
||||
else:
|
||||
|
@ -90,7 +100,7 @@ class singleListener(threading.Thread, StoppableThread):
|
|||
# SOCKS proxy, unless they have configured otherwise. If they eventually select
|
||||
# proxy 'none' or configure SOCKS listening then this will start listening for
|
||||
# connections.
|
||||
while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten') and shared.shutdown == 0:
|
||||
while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten') and ".onion" not in shared.config.get('bitmessagesettings', 'onionhostname') and shared.shutdown == 0:
|
||||
self.stop.wait(10)
|
||||
while len(shared.connectedHostsList) > 220 and shared.shutdown == 0:
|
||||
logger.info('We are connected to too many people. Not accepting further incoming connections for ten seconds.')
|
||||
|
@ -112,7 +122,9 @@ class singleListener(threading.Thread, StoppableThread):
|
|||
# is already connected because the two computers will
|
||||
# share the same external IP. This is here to prevent
|
||||
# connection flooding.
|
||||
if HOST in shared.connectedHostsList:
|
||||
# permit repeated connections from Tor
|
||||
# FIXME: sockshostname may be a hostname rather than IP, in such a case this will break
|
||||
if HOST in shared.connectedHostsList and (".onion" not in shared.config.get('bitmessagesettings', 'onionhostname') or HOST != shared.config.get('bitmessagesettings', 'sockshostname')):
|
||||
socketObject.close()
|
||||
logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.')
|
||||
else:
|
||||
|
|
|
@ -419,6 +419,13 @@ class sqlThread(threading.Thread):
|
|||
logger.debug('In messages.dat database, done adding address field to the pubkeys table and removing the hash field.')
|
||||
self.cur.execute('''update settings set value=10 WHERE key='version';''')
|
||||
|
||||
if not shared.config.has_option('bitmessagesettings', 'onionhostname'):
|
||||
shared.config.set('bitmessagesettings', 'onionhostname', '')
|
||||
if not shared.config.has_option('bitmessagesettings', 'onionport'):
|
||||
shared.config.set('bitmessagesettings', 'onionport', '8444')
|
||||
if not shared.config.has_option('bitmessagesettings', 'onionbindip'):
|
||||
shared.config.set('bitmessagesettings', 'onionbindip', '127.0.0.1')
|
||||
shared.writeKeysFile()
|
||||
|
||||
# Are you hoping to add a new option to the keys.dat file of existing
|
||||
# Bitmessage users or modify the SQLite database? Add it right above this line!
|
||||
|
|
|
@ -21,13 +21,16 @@ def knownNodes():
|
|||
shared.knownNodes[stream] = {}
|
||||
for node_tuple in nodes.items():
|
||||
try:
|
||||
host, (port, time) = node_tuple
|
||||
host, (port, lastseen) = node_tuple
|
||||
peer = shared.Peer(host, port)
|
||||
except:
|
||||
peer, time = node_tuple
|
||||
shared.knownNodes[stream][peer] = time
|
||||
peer, lastseen = node_tuple
|
||||
shared.knownNodes[stream][peer] = lastseen
|
||||
except:
|
||||
shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata)
|
||||
# your own onion address, if setup
|
||||
if shared.config.has_option('bitmessagesettings', 'onionhostname') and ".onion" in shared.config.get('bitmessagesettings', 'onionhostname'):
|
||||
shared.knownNodes[1][shared.Peer(shared.config.get('bitmessagesettings', 'onionhostname'), shared.config.getint('bitmessagesettings', 'onionport'))] = int(time.time())
|
||||
if shared.config.getint('bitmessagesettings', 'settingsversion') > 10:
|
||||
logger.error('Bitmessage cannot read future versions of the keys file (keys.dat). Run the newer version of Bitmessage.')
|
||||
raise SystemExit
|
||||
|
|
|
@ -299,6 +299,9 @@ class socksocket(socket.socket):
|
|||
"""
|
||||
return self.__proxypeername
|
||||
|
||||
def getproxytype(self):
|
||||
return self.__proxy[0]
|
||||
|
||||
def __negotiatesocks4(self,destaddr,destport):
|
||||
"""__negotiatesocks4(self,destaddr,destport)
|
||||
Negotiates a connection through a SOCKS4 server.
|
||||
|
@ -425,4 +428,4 @@ class socksocket(socket.socket):
|
|||
self.__negotiatesocks5()
|
||||
return self.__resolvesocks5(host)
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
|
Loading…
Reference in New Issue
Block a user