Merge pull request #834 from MuxZeroNet/patch-13
[Open for more Tests] StemPort Plugin
This commit is contained in:
commit
409841a3cf
3 changed files with 170 additions and 9 deletions
135
plugins/disabled-StemPort/StemPortPlugin.py
Normal file
135
plugins/disabled-StemPort/StemPortPlugin.py
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import stem
|
||||||
|
from stem import Signal
|
||||||
|
from stem.control import Controller
|
||||||
|
from stem.socket import ControlPort
|
||||||
|
|
||||||
|
from Plugin import PluginManager
|
||||||
|
from Config import config
|
||||||
|
from Debug import Debug
|
||||||
|
|
||||||
|
if config.tor != "disable":
|
||||||
|
from gevent import monkey
|
||||||
|
monkey.patch_time()
|
||||||
|
monkey.patch_socket(dns=False)
|
||||||
|
monkey.patch_thread()
|
||||||
|
print "Stem Port Plugin: modules are patched."
|
||||||
|
else:
|
||||||
|
print "Stem Port Plugin: Tor mode disabled. Module patching skipped."
|
||||||
|
|
||||||
|
|
||||||
|
class PatchedControlPort(ControlPort):
|
||||||
|
def _make_socket(self):
|
||||||
|
try:
|
||||||
|
if "socket_noproxy" in dir(socket): # Socket proxy-patched, use non-proxy one
|
||||||
|
control_socket = socket.socket_noproxy(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
else:
|
||||||
|
control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
# TODO: repeated code - consider making a separate method
|
||||||
|
|
||||||
|
control_socket.connect((self._control_addr, self._control_port))
|
||||||
|
return control_socket
|
||||||
|
except socket.error as exc:
|
||||||
|
raise stem.SocketError(exc)
|
||||||
|
|
||||||
|
def from_port(address = '127.0.0.1', port = 'default'):
|
||||||
|
import stem.connection
|
||||||
|
|
||||||
|
if not stem.util.connection.is_valid_ipv4_address(address):
|
||||||
|
raise ValueError('Invalid IP address: %s' % address)
|
||||||
|
elif port != 'default' and not stem.util.connection.is_valid_port(port):
|
||||||
|
raise ValueError('Invalid port: %s' % port)
|
||||||
|
|
||||||
|
if port == 'default':
|
||||||
|
raise ValueError('Must specify a port')
|
||||||
|
else:
|
||||||
|
control_port = PatchedControlPort(address, port)
|
||||||
|
|
||||||
|
return Controller(control_port)
|
||||||
|
|
||||||
|
|
||||||
|
@PluginManager.registerTo("TorManager")
|
||||||
|
class TorManagerPlugin(object):
|
||||||
|
|
||||||
|
def connectController(self):
|
||||||
|
self.log.info("Authenticate using Stem... %s:%s" % (self.ip, self.port))
|
||||||
|
|
||||||
|
try:
|
||||||
|
with self.lock:
|
||||||
|
if config.tor_password:
|
||||||
|
controller = from_port(port=self.port, password=config.tor_password)
|
||||||
|
else:
|
||||||
|
controller = from_port(port=self.port)
|
||||||
|
controller.authenticate()
|
||||||
|
self.controller = controller
|
||||||
|
self.status = u"Connected (via Stem)"
|
||||||
|
except Exception, err:
|
||||||
|
print("\n")
|
||||||
|
traceback.print_exc()
|
||||||
|
print("\n")
|
||||||
|
|
||||||
|
self.controller = None
|
||||||
|
self.status = u"Error (%s)" % err
|
||||||
|
self.log.error("Tor stem connect error: %s" % Debug.formatException(err))
|
||||||
|
|
||||||
|
return self.controller
|
||||||
|
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
self.controller.close()
|
||||||
|
self.controller = None
|
||||||
|
|
||||||
|
|
||||||
|
def resetCircuits(self):
|
||||||
|
try:
|
||||||
|
self.controller.signal(Signal.NEWNYM)
|
||||||
|
except Exception, err:
|
||||||
|
self.status = u"Stem reset circuits error (%s)" % err
|
||||||
|
self.log.error("Stem reset circuits error: %s" % err)
|
||||||
|
|
||||||
|
|
||||||
|
def makeOnionAndKey(self):
|
||||||
|
try:
|
||||||
|
service = self.controller.create_ephemeral_hidden_service(
|
||||||
|
{self.fileserver_port: self.fileserver_port},
|
||||||
|
await_publication = False
|
||||||
|
)
|
||||||
|
if service.private_key_type != "RSA1024":
|
||||||
|
raise Exception("ZeroNet doesn't support crypto " + service.private_key_type)
|
||||||
|
|
||||||
|
self.log.debug("Stem created %s.onion (async descriptor publication)" % service.service_id)
|
||||||
|
|
||||||
|
return (service.service_id, service.private_key)
|
||||||
|
|
||||||
|
except Exception, err:
|
||||||
|
self.status = u"AddOnion error (Stem: %s)" % err
|
||||||
|
self.log.error("Failed to create hidden service with Stem: " + err)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def delOnion(self, address):
|
||||||
|
try:
|
||||||
|
self.controller.remove_ephemeral_hidden_service(address)
|
||||||
|
return True
|
||||||
|
except Exception, err:
|
||||||
|
self.status = u"DelOnion error (Stem: %s)" % err
|
||||||
|
self.log.error("Stem failed to delete %s.onion: %s" % (address, err))
|
||||||
|
self.disconnect() # Why?
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def request(self, cmd):
|
||||||
|
with self.lock:
|
||||||
|
if not self.enabled:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
self.log.error("[WARNING] StemPort self.request should not be called")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def send(self, cmd, conn=None):
|
||||||
|
self.log.error("[WARNING] StemPort self.send should not be called")
|
||||||
|
return ""
|
10
plugins/disabled-StemPort/__init__.py
Normal file
10
plugins/disabled-StemPort/__init__.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
try:
|
||||||
|
from stem.control import Controller
|
||||||
|
stem_found = True
|
||||||
|
except Exception, err:
|
||||||
|
print "STEM NOT FOUND! %s" % err
|
||||||
|
stem_found = False
|
||||||
|
|
||||||
|
if stem_found:
|
||||||
|
print "Starting Stem plugin..."
|
||||||
|
import StemPortPlugin
|
|
@ -20,9 +20,11 @@ except:
|
||||||
from gevent.lock import RLock
|
from gevent.lock import RLock
|
||||||
from util import helper
|
from util import helper
|
||||||
from Debug import Debug
|
from Debug import Debug
|
||||||
|
from Plugin import PluginManager
|
||||||
|
|
||||||
|
|
||||||
class TorManager:
|
@PluginManager.acceptPlugins
|
||||||
|
class TorManager(object):
|
||||||
def __init__(self, fileserver_ip=None, fileserver_port=None):
|
def __init__(self, fileserver_ip=None, fileserver_port=None):
|
||||||
self.privatekeys = {} # Onion: Privatekey
|
self.privatekeys = {} # Onion: Privatekey
|
||||||
self.site_onions = {} # Site address: Onion
|
self.site_onions = {} # Site address: Onion
|
||||||
|
@ -58,7 +60,7 @@ class TorManager:
|
||||||
assert self.connect(), "No connection"
|
assert self.connect(), "No connection"
|
||||||
self.log.debug("Tor proxy port %s check ok" % config.tor_proxy)
|
self.log.debug("Tor proxy port %s check ok" % config.tor_proxy)
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
self.log.debug("Tor proxy port %s check error: %s" % (config.tor_proxy, err))
|
self.log.info("Starting self-bundled Tor, due to Tor proxy port %s check error: %s" % (config.tor_proxy, err))
|
||||||
self.enabled = False
|
self.enabled = False
|
||||||
# Change to self-bundled Tor ports
|
# Change to self-bundled Tor ports
|
||||||
from lib.PySocks import socks
|
from lib.PySocks import socks
|
||||||
|
@ -148,12 +150,15 @@ class TorManager:
|
||||||
self.site_onions = {}
|
self.site_onions = {}
|
||||||
self.privatekeys = {}
|
self.privatekeys = {}
|
||||||
|
|
||||||
|
return self.connectController()
|
||||||
|
|
||||||
|
def connectController(self):
|
||||||
if "socket_noproxy" in dir(socket): # Socket proxy-patched, use non-proxy one
|
if "socket_noproxy" in dir(socket): # Socket proxy-patched, use non-proxy one
|
||||||
conn = socket.socket_noproxy(socket.AF_INET, socket.SOCK_STREAM)
|
conn = socket.socket_noproxy(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
else:
|
else:
|
||||||
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
self.log.debug("Connecting to %s:%s" % (self.ip, self.port))
|
self.log.info("Connecting to Tor Controller %s:%s" % (self.ip, self.port))
|
||||||
try:
|
try:
|
||||||
with self.lock:
|
with self.lock:
|
||||||
conn.connect((self.ip, self.port))
|
conn.connect((self.ip, self.port))
|
||||||
|
@ -203,19 +208,28 @@ class TorManager:
|
||||||
self.log.error("Tor reset circuits error: %s" % res)
|
self.log.error("Tor reset circuits error: %s" % res)
|
||||||
|
|
||||||
def addOnion(self):
|
def addOnion(self):
|
||||||
|
result = self.makeOnionAndKey()
|
||||||
|
if result:
|
||||||
|
onion_address, onion_privatekey = result
|
||||||
|
self.privatekeys[onion_address] = onion_privatekey
|
||||||
|
self.status = u"OK (%s onions running)" % len(self.privatekeys)
|
||||||
|
SiteManager.peer_blacklist.append((onion_address + ".onion", self.fileserver_port))
|
||||||
|
return onion_address
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def makeOnionAndKey(self):
|
||||||
res = self.request("ADD_ONION NEW:RSA1024 port=%s" % self.fileserver_port)
|
res = self.request("ADD_ONION NEW:RSA1024 port=%s" % self.fileserver_port)
|
||||||
match = re.search("ServiceID=([A-Za-z0-9]+).*PrivateKey=RSA1024:(.*?)[\r\n]", res, re.DOTALL)
|
match = re.search("ServiceID=([A-Za-z0-9]+).*PrivateKey=RSA1024:(.*?)[\r\n]", res, re.DOTALL)
|
||||||
if match:
|
if match:
|
||||||
onion_address, onion_privatekey = match.groups()
|
onion_address, onion_privatekey = match.groups()
|
||||||
self.privatekeys[onion_address] = onion_privatekey
|
return (onion_address, onion_privatekey)
|
||||||
self.status = u"OK (%s onion running)" % len(self.privatekeys)
|
|
||||||
SiteManager.peer_blacklist.append((onion_address + ".onion", self.fileserver_port))
|
|
||||||
return onion_address
|
|
||||||
else:
|
else:
|
||||||
self.status = u"AddOnion error (%s)" % res
|
self.status = u"AddOnion error (%s)" % res
|
||||||
self.log.error("Tor addOnion error: %s" % res)
|
self.log.error("Tor addOnion error: %s" % res)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def delOnion(self, address):
|
def delOnion(self, address):
|
||||||
res = self.request("DEL_ONION %s" % address)
|
res = self.request("DEL_ONION %s" % address)
|
||||||
if "250 OK" in res:
|
if "250 OK" in res:
|
||||||
|
@ -278,11 +292,13 @@ class TorManager:
|
||||||
self.log.debug("Created new hidden service for %s: %s" % (site_address, onion))
|
self.log.debug("Created new hidden service for %s: %s" % (site_address, onion))
|
||||||
return onion
|
return onion
|
||||||
|
|
||||||
|
# Creates and returns a
|
||||||
|
# socket that has connected to the Tor Network
|
||||||
def createSocket(self, onion, port):
|
def createSocket(self, onion, port):
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
return False
|
return False
|
||||||
self.log.debug("Creating new socket to %s:%s" % (onion, port))
|
self.log.debug("Creating new Tor socket to %s:%s" % (onion, port))
|
||||||
if config.tor == "always": # Every socket is proxied by default
|
if config.tor == "always": # Every socket is proxied by default, in this mode
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
sock.connect((onion, int(port)))
|
sock.connect((onion, int(port)))
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in a new issue