From 11d904754886a771ad502ff3c56a74c92bf2281e Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Thu, 17 Jan 2019 23:34:13 -0600 Subject: [PATCH] added tor check and fixed fd exhaustion --- onionr/api.py | 2 ++ onionr/communicator2.py | 3 +++ onionr/netcontroller.py | 9 +++++++++ onionr/onionr.py | 10 +++++++++- onionr/onionrutils.py | 10 +++++----- onionr/static-data/default_config.json | 1 + 6 files changed, 29 insertions(+), 6 deletions(-) diff --git a/onionr/api.py b/onionr/api.py index cec7288a..e24e21a6 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -99,6 +99,7 @@ class PublicAPI: resp.headers['X-Frame-Options'] = 'deny' resp.headers['X-Content-Type-Options'] = "nosniff" resp.headers['X-API'] = onionr.API_VERSION + resp.headers['Connection'] = "close" return resp @app.route('/') @@ -288,6 +289,7 @@ class API: resp.headers['X-API'] = onionr.API_VERSION resp.headers['Server'] = '' resp.headers['Date'] = 'Thu, 1 Jan 1970 00:00:00 GMT' # Clock info is probably useful to attackers. Set to unix epoch. + resp.headers['Connection'] = "close" return resp @app.route('/board/', endpoint='board') diff --git a/onionr/communicator2.py b/onionr/communicator2.py index c3540e61..e258c8c8 100755 --- a/onionr/communicator2.py +++ b/onionr/communicator2.py @@ -140,6 +140,9 @@ class OnionrCommunicatorDaemon: break i.processTimer() time.sleep(self.delay) + # Debug to print out used FDs (regular and net) + #proc = psutil.Process() + #print(proc.open_files(), len(psutil.net_connections())) except KeyboardInterrupt: self.shutdown = True pass diff --git a/onionr/netcontroller.py b/onionr/netcontroller.py index c87b5e46..c415c1a9 100644 --- a/onionr/netcontroller.py +++ b/onionr/netcontroller.py @@ -22,6 +22,7 @@ import subprocess, os, random, sys, logger, time, signal, config, base64, socket from stem.control import Controller from onionrblockapi import Block from dependencies import secrets +from shutil import which def getOpenPort(): # taken from (but modified) https://stackoverflow.com/a/2838309 @@ -31,6 +32,14 @@ def getOpenPort(): port = s.getsockname()[1] s.close() return port + +def torBinary(): + '''Return tor binary path or none if not exists''' + torPath = './tor' + if not os.path.exists(torPath): + torPath = which('tor') + return torPath + class NetController: ''' This class handles hidden service setup on Tor and I2P diff --git a/onionr/onionr.py b/onionr/onionr.py index e54e90bb..6ec90725 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -68,6 +68,10 @@ class Onionr: # Load global configuration data data_exists = Onionr.setupConfig(self.dataDir, self = self) + if netcontroller.torBinary() is None: + logger.error('Tor is not installed') + sys.exit(1) + self.onionrCore = core.Core() #self.deleteRunFiles() self.onionrUtils = onionrutils.OnionrUtils(self.onionrCore) @@ -292,7 +296,8 @@ class Onionr: newID = self.onionrCore._crypto.keyManager.addKey()[0] else: logger.warn('Deterministic keys require random and long passphrases.') - logger.warn('If a good password is not used, your key can be easily stolen.') + logger.warn('If a good passphrase is not used, your key can be easily stolen.') + logger.warn('You should use a series of hard to guess words, see this for reference: https://www.xkcd.com/936/') pass1 = getpass.getpass(prompt='Enter at least %s characters: ' % (self.onionrCore._crypto.deterministicRequirement,)) pass2 = getpass.getpass(prompt='Confirm entry: ') if self.onionrCore._crypto.safeCompare(pass1, pass2): @@ -760,6 +765,9 @@ class Onionr: try: while True: time.sleep(3) + # Debug to print out used FDs (regular and net) + #proc = psutil.Process() + #print('api-files:',proc.open_files(), len(psutil.net_connections())) # Break if communicator process ends, so we don't have left over processes if communicatorProc.poll() is not None: break diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index 4f936d93..3260a42b 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -184,9 +184,9 @@ class OnionrUtils: payload = 'http://%s/%s%s' % (hostname, command, data) try: if post: - retData = requests.post(payload, data=postData, headers={'token': config.get('client.webpassword')}, timeout=(maxWait, 30)).text + retData = requests.post(payload, data=postData, headers={'token': config.get('client.webpassword'), 'Connection':'close'}, timeout=(maxWait, 30)).text else: - retData = requests.get(payload, headers={'token': config.get('client.webpassword')}, timeout=(maxWait, 30)).text + retData = requests.get(payload, headers={'token': config.get('client.webpassword'), 'Connection':'close'}, timeout=(maxWait, 30)).text except Exception as error: if not silent: logger.error('Failed to make local request (command: %s):%s' % (command, error)) @@ -624,7 +624,7 @@ class OnionrUtils: proxies = {'http': 'http://127.0.0.1:4444'} else: return - headers = {'user-agent': 'PyOnionr'} + headers = {'user-agent': 'PyOnionr', 'Connection':'close'} try: proxies = {'http': 'socks4a://127.0.0.1:' + str(port), 'https': 'socks4a://127.0.0.1:' + str(port)} r = requests.post(url, data=data, headers=headers, proxies=proxies, allow_redirects=False, timeout=(15, 30)) @@ -649,11 +649,11 @@ class OnionrUtils: proxies = {'http': 'http://127.0.0.1:4444'} else: return - headers = {'user-agent': 'PyOnionr'} + headers = {'user-agent': 'PyOnionr', 'Connection':'close'} response_headers = dict() try: proxies = {'http': 'socks4a://127.0.0.1:' + str(port), 'https': 'socks4a://127.0.0.1:' + str(port)} - r = requests.get(url, headers=headers, proxies=proxies, allow_redirects=False, timeout=(15, 30)) + r = requests.get(url, headers=headers, proxies=proxies, allow_redirects=False, timeout=(15, 30), ) # Check server is using same API version as us if not ignoreAPI: try: diff --git a/onionr/static-data/default_config.json b/onionr/static-data/default_config.json index 2ef339bc..93f3a49a 100644 --- a/onionr/static-data/default_config.json +++ b/onionr/static-data/default_config.json @@ -7,6 +7,7 @@ "socket_servers": false, "security_level": 0, "max_block_age": 2678400, + "bypass_tor_check": false, "public_key": "" },