Merge pull request #834 from MuxZeroNet/patch-13

[Open for more Tests] StemPort Plugin
This commit is contained in:
ZeroNet 2017-04-08 22:20:06 +02:00 committed by GitHub
commit 409841a3cf
3 changed files with 170 additions and 9 deletions

View 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 ""

View 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

View file

@ -20,9 +20,11 @@ except:
from gevent.lock import RLock
from util import helper
from Debug import Debug
from Plugin import PluginManager
class TorManager:
@PluginManager.acceptPlugins
class TorManager(object):
def __init__(self, fileserver_ip=None, fileserver_port=None):
self.privatekeys = {} # Onion: Privatekey
self.site_onions = {} # Site address: Onion
@ -58,7 +60,7 @@ class TorManager:
assert self.connect(), "No connection"
self.log.debug("Tor proxy port %s check ok" % config.tor_proxy)
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
# Change to self-bundled Tor ports
from lib.PySocks import socks
@ -148,12 +150,15 @@ class TorManager:
self.site_onions = {}
self.privatekeys = {}
return self.connectController()
def connectController(self):
if "socket_noproxy" in dir(socket): # Socket proxy-patched, use non-proxy one
conn = socket.socket_noproxy(socket.AF_INET, socket.SOCK_STREAM)
else:
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:
with self.lock:
conn.connect((self.ip, self.port))
@ -203,19 +208,28 @@ class TorManager:
self.log.error("Tor reset circuits error: %s" % res)
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)
match = re.search("ServiceID=([A-Za-z0-9]+).*PrivateKey=RSA1024:(.*?)[\r\n]", res, re.DOTALL)
if match:
onion_address, onion_privatekey = match.groups()
self.privatekeys[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
return (onion_address, onion_privatekey)
else:
self.status = u"AddOnion error (%s)" % res
self.log.error("Tor addOnion error: %s" % res)
return False
def delOnion(self, address):
res = self.request("DEL_ONION %s" % address)
if "250 OK" in res:
@ -278,11 +292,13 @@ class TorManager:
self.log.debug("Created new hidden service for %s: %s" % (site_address, onion))
return onion
# Creates and returns a
# socket that has connected to the Tor Network
def createSocket(self, onion, port):
if not self.enabled:
return False
self.log.debug("Creating new socket to %s:%s" % (onion, port))
if config.tor == "always": # Every socket is proxied by default
self.log.debug("Creating new Tor socket to %s:%s" % (onion, port))
if config.tor == "always": # Every socket is proxied by default, in this mode
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((onion, int(port)))
else: