123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- 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 = "Connected (via Stem)"
- except Exception as err:
- print("\n")
- traceback.print_exc()
- print("\n")
- self.controller = None
- self.status = "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 as err:
- self.status = "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 as err:
- self.status = "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 as err:
- self.status = "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 ""
|