update path, add python unrar
This commit is contained in:
parent
642ba49f68
commit
00165d302e
862 changed files with 804 additions and 6 deletions
186
Shared/lib/python3.7/site-packages/stem/interpreter/__init__.py
Normal file
186
Shared/lib/python3.7/site-packages/stem/interpreter/__init__.py
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
# Copyright 2015-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
Interactive interpreter for interacting with Tor directly. This adds usability
|
||||
features such as tab completion, history, and IRC-style functions (like /help).
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import stem
|
||||
import stem.connection
|
||||
import stem.prereq
|
||||
import stem.process
|
||||
import stem.util.conf
|
||||
import stem.util.system
|
||||
import stem.util.term
|
||||
|
||||
from stem.util.term import Attr, Color, format
|
||||
|
||||
__all__ = [
|
||||
'arguments',
|
||||
'autocomplete',
|
||||
'commands',
|
||||
'help',
|
||||
]
|
||||
|
||||
PROMPT = format('>>> ', Color.GREEN, Attr.BOLD, Attr.READLINE_ESCAPE)
|
||||
|
||||
STANDARD_OUTPUT = (Color.BLUE, Attr.LINES)
|
||||
BOLD_OUTPUT = (Color.BLUE, Attr.BOLD, Attr.LINES)
|
||||
HEADER_OUTPUT = (Color.GREEN, Attr.LINES)
|
||||
HEADER_BOLD_OUTPUT = (Color.GREEN, Attr.BOLD, Attr.LINES)
|
||||
ERROR_OUTPUT = (Attr.BOLD, Color.RED, Attr.LINES)
|
||||
|
||||
settings_path = os.path.join(os.path.dirname(__file__), 'settings.cfg')
|
||||
uses_settings = stem.util.conf.uses_settings('stem_interpreter', settings_path)
|
||||
|
||||
|
||||
@uses_settings
|
||||
def msg(message, config, **attr):
|
||||
return config.get(message).format(**attr)
|
||||
|
||||
|
||||
def main():
|
||||
import readline
|
||||
|
||||
import stem.interpreter.arguments
|
||||
import stem.interpreter.autocomplete
|
||||
import stem.interpreter.commands
|
||||
|
||||
try:
|
||||
args = stem.interpreter.arguments.parse(sys.argv[1:])
|
||||
except ValueError as exc:
|
||||
print(exc)
|
||||
sys.exit(1)
|
||||
|
||||
if args.print_help:
|
||||
print(stem.interpreter.arguments.get_help())
|
||||
sys.exit()
|
||||
|
||||
if args.disable_color or not sys.stdout.isatty():
|
||||
global PROMPT
|
||||
stem.util.term.DISABLE_COLOR_SUPPORT = True
|
||||
PROMPT = '>>> '
|
||||
|
||||
# If the user isn't connecting to something in particular then offer to start
|
||||
# tor if it isn't running.
|
||||
|
||||
if not (args.user_provided_port or args.user_provided_socket):
|
||||
is_tor_running = stem.util.system.is_running('tor') or stem.util.system.is_running('tor.real')
|
||||
|
||||
if not is_tor_running:
|
||||
if args.tor_path == 'tor' and not stem.util.system.is_available('tor'):
|
||||
print(format(msg('msg.tor_unavailable'), *ERROR_OUTPUT))
|
||||
sys.exit(1)
|
||||
else:
|
||||
if not args.run_cmd and not args.run_path:
|
||||
print(format(msg('msg.starting_tor'), *HEADER_OUTPUT))
|
||||
|
||||
control_port = '9051' if args.control_port == 'default' else str(args.control_port)
|
||||
|
||||
try:
|
||||
stem.process.launch_tor_with_config(
|
||||
config = {
|
||||
'SocksPort': '0',
|
||||
'ControlPort': control_port,
|
||||
'CookieAuthentication': '1',
|
||||
'ExitPolicy': 'reject *:*',
|
||||
},
|
||||
tor_cmd = args.tor_path,
|
||||
completion_percent = 5,
|
||||
take_ownership = True,
|
||||
)
|
||||
except OSError as exc:
|
||||
print(format(msg('msg.unable_to_start_tor', error = exc), *ERROR_OUTPUT))
|
||||
sys.exit(1)
|
||||
|
||||
control_port = (args.control_address, args.control_port)
|
||||
control_socket = args.control_socket
|
||||
|
||||
# If the user explicitely specified an endpoint then just try to connect to
|
||||
# that.
|
||||
|
||||
if args.user_provided_socket and not args.user_provided_port:
|
||||
control_port = None
|
||||
elif args.user_provided_port and not args.user_provided_socket:
|
||||
control_socket = None
|
||||
|
||||
controller = stem.connection.connect(
|
||||
control_port = control_port,
|
||||
control_socket = control_socket,
|
||||
password_prompt = True,
|
||||
)
|
||||
|
||||
if controller is None:
|
||||
sys.exit(1)
|
||||
|
||||
with controller:
|
||||
autocompleter = stem.interpreter.autocomplete.Autocompleter(controller)
|
||||
readline.parse_and_bind('tab: complete')
|
||||
readline.set_completer(autocompleter.complete)
|
||||
readline.set_completer_delims('\n')
|
||||
|
||||
interpreter = stem.interpreter.commands.ControlInterpreter(controller)
|
||||
showed_close_confirmation = False
|
||||
|
||||
if args.run_cmd:
|
||||
if args.run_cmd.upper().startswith('SETEVENTS '):
|
||||
# TODO: we can use a lambda here when dropping python 2.x support, but
|
||||
# until then print's status as a keyword prevents it from being used in
|
||||
# lambdas
|
||||
|
||||
def handle_event(event_message):
|
||||
print(format(str(event_message), *STANDARD_OUTPUT))
|
||||
|
||||
controller._handle_event = handle_event
|
||||
|
||||
if sys.stdout.isatty():
|
||||
events = args.run_cmd.upper().split(' ', 1)[1]
|
||||
print(format('Listening to %s events. Press any key to quit.\n' % events, *HEADER_BOLD_OUTPUT))
|
||||
|
||||
controller.msg(args.run_cmd)
|
||||
|
||||
try:
|
||||
raw_input()
|
||||
except (KeyboardInterrupt, stem.SocketClosed):
|
||||
pass
|
||||
else:
|
||||
interpreter.run_command(args.run_cmd, print_response = True)
|
||||
elif args.run_path:
|
||||
try:
|
||||
for line in open(args.run_path).readlines():
|
||||
interpreter.run_command(line.strip(), print_response = True)
|
||||
except IOError as exc:
|
||||
print(format(msg('msg.unable_to_read_file', path = args.run_path, error = exc), *ERROR_OUTPUT))
|
||||
sys.exit(1)
|
||||
|
||||
else:
|
||||
for line in msg('msg.startup_banner').splitlines():
|
||||
line_format = HEADER_BOLD_OUTPUT if line.startswith(' ') else HEADER_OUTPUT
|
||||
print(format(line, *line_format))
|
||||
|
||||
print('')
|
||||
|
||||
while True:
|
||||
try:
|
||||
prompt = '... ' if interpreter.is_multiline_context else PROMPT
|
||||
user_input = input(prompt) if stem.prereq.is_python_3() else raw_input(prompt)
|
||||
interpreter.run_command(user_input, print_response = True)
|
||||
except stem.SocketClosed:
|
||||
if showed_close_confirmation:
|
||||
print(format('Unable to run tor commands. The control connection has been closed.', *ERROR_OUTPUT))
|
||||
else:
|
||||
prompt = format("Tor's control port has closed. Do you want to continue this interpreter? (y/n) ", *HEADER_BOLD_OUTPUT)
|
||||
user_input = input(prompt) if stem.prereq.is_python_3() else raw_input(prompt)
|
||||
print('') # blank line
|
||||
|
||||
if user_input.lower() in ('y', 'yes'):
|
||||
showed_close_confirmation = True
|
||||
else:
|
||||
break
|
||||
except (KeyboardInterrupt, EOFError, stem.SocketClosed):
|
||||
print('') # move cursor to the following line
|
||||
break
|
||||
105
Shared/lib/python3.7/site-packages/stem/interpreter/arguments.py
Normal file
105
Shared/lib/python3.7/site-packages/stem/interpreter/arguments.py
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# Copyright 2015-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
Commandline argument parsing for our interpreter prompt.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import getopt
|
||||
import os
|
||||
|
||||
import stem.interpreter
|
||||
import stem.util.connection
|
||||
|
||||
DEFAULT_ARGS = {
|
||||
'control_address': '127.0.0.1',
|
||||
'control_port': 'default',
|
||||
'user_provided_port': False,
|
||||
'control_socket': '/var/run/tor/control',
|
||||
'user_provided_socket': False,
|
||||
'tor_path': 'tor',
|
||||
'run_cmd': None,
|
||||
'run_path': None,
|
||||
'disable_color': False,
|
||||
'print_help': False,
|
||||
}
|
||||
|
||||
OPT = 'i:s:h'
|
||||
OPT_EXPANDED = ['interface=', 'socket=', 'tor=', 'run=', 'no-color', 'help']
|
||||
|
||||
|
||||
def parse(argv):
|
||||
"""
|
||||
Parses our arguments, providing a named tuple with their values.
|
||||
|
||||
:param list argv: input arguments to be parsed
|
||||
|
||||
:returns: a **named tuple** with our parsed arguments
|
||||
|
||||
:raises: **ValueError** if we got an invalid argument
|
||||
"""
|
||||
|
||||
args = dict(DEFAULT_ARGS)
|
||||
|
||||
try:
|
||||
recognized_args, unrecognized_args = getopt.getopt(argv, OPT, OPT_EXPANDED)
|
||||
|
||||
if unrecognized_args:
|
||||
error_msg = "aren't recognized arguments" if len(unrecognized_args) > 1 else "isn't a recognized argument"
|
||||
raise getopt.GetoptError("'%s' %s" % ("', '".join(unrecognized_args), error_msg))
|
||||
except Exception as exc:
|
||||
raise ValueError('%s (for usage provide --help)' % exc)
|
||||
|
||||
for opt, arg in recognized_args:
|
||||
if opt in ('-i', '--interface'):
|
||||
if ':' in arg:
|
||||
address, port = arg.rsplit(':', 1)
|
||||
else:
|
||||
address, port = None, arg
|
||||
|
||||
if address is not None:
|
||||
if not stem.util.connection.is_valid_ipv4_address(address):
|
||||
raise ValueError("'%s' isn't a valid IPv4 address" % address)
|
||||
|
||||
args['control_address'] = address
|
||||
|
||||
if not stem.util.connection.is_valid_port(port):
|
||||
raise ValueError("'%s' isn't a valid port number" % port)
|
||||
|
||||
args['control_port'] = int(port)
|
||||
args['user_provided_port'] = True
|
||||
elif opt in ('-s', '--socket'):
|
||||
args['control_socket'] = arg
|
||||
args['user_provided_socket'] = True
|
||||
elif opt in ('--tor'):
|
||||
args['tor_path'] = arg
|
||||
elif opt in ('--run'):
|
||||
if os.path.exists(arg):
|
||||
args['run_path'] = arg
|
||||
else:
|
||||
args['run_cmd'] = arg
|
||||
elif opt == '--no-color':
|
||||
args['disable_color'] = True
|
||||
elif opt in ('-h', '--help'):
|
||||
args['print_help'] = True
|
||||
|
||||
# translates our args dict into a named tuple
|
||||
|
||||
Args = collections.namedtuple('Args', args.keys())
|
||||
return Args(**args)
|
||||
|
||||
|
||||
def get_help():
|
||||
"""
|
||||
Provides our --help usage information.
|
||||
|
||||
:returns: **str** with our usage information
|
||||
"""
|
||||
|
||||
return stem.interpreter.msg(
|
||||
'msg.help',
|
||||
address = DEFAULT_ARGS['control_address'],
|
||||
port = DEFAULT_ARGS['control_port'],
|
||||
socket = DEFAULT_ARGS['control_socket'],
|
||||
)
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
# Copyright 2014-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
Tab completion for our interpreter prompt.
|
||||
"""
|
||||
|
||||
import stem.prereq
|
||||
|
||||
from stem.interpreter import uses_settings
|
||||
|
||||
if stem.prereq._is_lru_cache_available():
|
||||
from functools import lru_cache
|
||||
else:
|
||||
from stem.util.lru_cache import lru_cache
|
||||
|
||||
|
||||
@uses_settings
|
||||
def _get_commands(controller, config):
|
||||
"""
|
||||
Provides commands recognized by tor.
|
||||
"""
|
||||
|
||||
commands = config.get('autocomplete', [])
|
||||
|
||||
if controller is None:
|
||||
return commands
|
||||
|
||||
# GETINFO commands. Lines are of the form '[option] -- [description]'. This
|
||||
# strips '*' from options that accept values.
|
||||
|
||||
results = controller.get_info('info/names', None)
|
||||
|
||||
if results:
|
||||
for line in results.splitlines():
|
||||
option = line.split(' ', 1)[0].rstrip('*')
|
||||
commands.append('GETINFO %s' % option)
|
||||
else:
|
||||
commands.append('GETINFO ')
|
||||
|
||||
# GETCONF, SETCONF, and RESETCONF commands. Lines are of the form
|
||||
# '[option] [type]'.
|
||||
|
||||
results = controller.get_info('config/names', None)
|
||||
|
||||
if results:
|
||||
for line in results.splitlines():
|
||||
option = line.split(' ', 1)[0]
|
||||
|
||||
commands.append('GETCONF %s' % option)
|
||||
commands.append('SETCONF %s' % option)
|
||||
commands.append('RESETCONF %s' % option)
|
||||
else:
|
||||
commands += ['GETCONF ', 'SETCONF ', 'RESETCONF ']
|
||||
|
||||
# SETEVENT, USEFEATURE, and SIGNAL commands. For each of these the GETINFO
|
||||
# results are simply a space separated lists of the values they can have.
|
||||
|
||||
options = (
|
||||
('SETEVENTS ', 'events/names'),
|
||||
('USEFEATURE ', 'features/names'),
|
||||
('SIGNAL ', 'signal/names'),
|
||||
)
|
||||
|
||||
for prefix, getinfo_cmd in options:
|
||||
results = controller.get_info(getinfo_cmd, None)
|
||||
|
||||
if results:
|
||||
commands += [prefix + value for value in results.split()]
|
||||
else:
|
||||
commands.append(prefix)
|
||||
|
||||
# Adds /help commands.
|
||||
|
||||
usage_info = config.get('help.usage', {})
|
||||
|
||||
for cmd in usage_info.keys():
|
||||
commands.append('/help ' + cmd)
|
||||
|
||||
return commands
|
||||
|
||||
|
||||
class Autocompleter(object):
|
||||
def __init__(self, controller):
|
||||
self._commands = _get_commands(controller)
|
||||
|
||||
@lru_cache()
|
||||
def matches(self, text):
|
||||
"""
|
||||
Provides autocompletion matches for the given text.
|
||||
|
||||
:param str text: text to check for autocompletion matches with
|
||||
|
||||
:returns: **list** with possible matches
|
||||
"""
|
||||
|
||||
lowercase_text = text.lower()
|
||||
return [cmd for cmd in self._commands if cmd.lower().startswith(lowercase_text)]
|
||||
|
||||
def complete(self, text, state):
|
||||
"""
|
||||
Provides case insensetive autocompletion options, acting as a functor for
|
||||
the readlines set_completer function.
|
||||
|
||||
:param str text: text to check for autocompletion matches with
|
||||
:param int state: index of result to be provided, readline fetches matches
|
||||
until this function provides None
|
||||
|
||||
:returns: **str** with the autocompletion match, **None** if eithe none
|
||||
exists or state is higher than our number of matches
|
||||
"""
|
||||
|
||||
try:
|
||||
return self.matches(text)[state]
|
||||
except IndexError:
|
||||
return None
|
||||
383
Shared/lib/python3.7/site-packages/stem/interpreter/commands.py
Normal file
383
Shared/lib/python3.7/site-packages/stem/interpreter/commands.py
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
# Copyright 2014-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
Handles making requests and formatting the responses.
|
||||
"""
|
||||
|
||||
import code
|
||||
import contextlib
|
||||
import socket
|
||||
import sys
|
||||
|
||||
import stem
|
||||
import stem.control
|
||||
import stem.descriptor.remote
|
||||
import stem.interpreter.help
|
||||
import stem.util.connection
|
||||
import stem.util.str_tools
|
||||
import stem.util.tor_tools
|
||||
|
||||
from stem.interpreter import STANDARD_OUTPUT, BOLD_OUTPUT, ERROR_OUTPUT, uses_settings, msg
|
||||
from stem.util.term import format
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
|
||||
MAX_EVENTS = 100
|
||||
|
||||
|
||||
def _get_fingerprint(arg, controller):
|
||||
"""
|
||||
Resolves user input into a relay fingerprint. This accepts...
|
||||
|
||||
* Fingerprints
|
||||
* Nicknames
|
||||
* IPv4 addresses, either with or without an ORPort
|
||||
* Empty input, which is resolved to ourselves if we're a relay
|
||||
|
||||
:param str arg: input to be resolved to a relay fingerprint
|
||||
:param stem.control.Controller controller: tor control connection
|
||||
|
||||
:returns: **str** for the relay fingerprint
|
||||
|
||||
:raises: **ValueError** if we're unable to resolve the input to a relay
|
||||
"""
|
||||
|
||||
if not arg:
|
||||
try:
|
||||
return controller.get_info('fingerprint')
|
||||
except:
|
||||
raise ValueError("We aren't a relay, no information to provide")
|
||||
elif stem.util.tor_tools.is_valid_fingerprint(arg):
|
||||
return arg
|
||||
elif stem.util.tor_tools.is_valid_nickname(arg):
|
||||
try:
|
||||
return controller.get_network_status(arg).fingerprint
|
||||
except:
|
||||
raise ValueError("Unable to find a relay with the nickname of '%s'" % arg)
|
||||
elif ':' in arg or stem.util.connection.is_valid_ipv4_address(arg):
|
||||
if ':' in arg:
|
||||
address, port = arg.rsplit(':', 1)
|
||||
|
||||
if not stem.util.connection.is_valid_ipv4_address(address):
|
||||
raise ValueError("'%s' isn't a valid IPv4 address" % address)
|
||||
elif port and not stem.util.connection.is_valid_port(port):
|
||||
raise ValueError("'%s' isn't a valid port" % port)
|
||||
|
||||
port = int(port)
|
||||
else:
|
||||
address, port = arg, None
|
||||
|
||||
matches = {}
|
||||
|
||||
for desc in controller.get_network_statuses():
|
||||
if desc.address == address:
|
||||
if not port or desc.or_port == port:
|
||||
matches[desc.or_port] = desc.fingerprint
|
||||
|
||||
if len(matches) == 0:
|
||||
raise ValueError('No relays found at %s' % arg)
|
||||
elif len(matches) == 1:
|
||||
return list(matches.values())[0]
|
||||
else:
|
||||
response = "There's multiple relays at %s, include a port to specify which.\n\n" % arg
|
||||
|
||||
for i, or_port in enumerate(matches):
|
||||
response += ' %i. %s:%s, fingerprint: %s\n' % (i + 1, address, or_port, matches[or_port])
|
||||
|
||||
raise ValueError(response)
|
||||
else:
|
||||
raise ValueError("'%s' isn't a fingerprint, nickname, or IP address" % arg)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def redirect(stdout, stderr):
|
||||
original = sys.stdout, sys.stderr
|
||||
sys.stdout, sys.stderr = stdout, stderr
|
||||
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
sys.stdout, sys.stderr = original
|
||||
|
||||
|
||||
class ControlInterpreter(code.InteractiveConsole):
|
||||
"""
|
||||
Handles issuing requests and providing nicely formed responses, with support
|
||||
for special irc style subcommands.
|
||||
"""
|
||||
|
||||
def __init__(self, controller):
|
||||
self._received_events = []
|
||||
|
||||
code.InteractiveConsole.__init__(self, {
|
||||
'stem': stem,
|
||||
'stem.control': stem.control,
|
||||
'controller': controller,
|
||||
'events': self.get_events,
|
||||
})
|
||||
|
||||
self._controller = controller
|
||||
self._run_python_commands = True
|
||||
|
||||
# Indicates if we're processing a multiline command, such as conditional
|
||||
# block or loop.
|
||||
|
||||
self.is_multiline_context = False
|
||||
|
||||
# Intercept events our controller hears about at a pretty low level since
|
||||
# the user will likely be requesting them by direct 'SETEVENTS' calls.
|
||||
|
||||
handle_event_real = self._controller._handle_event
|
||||
|
||||
def handle_event_wrapper(event_message):
|
||||
handle_event_real(event_message)
|
||||
self._received_events.insert(0, event_message)
|
||||
|
||||
if len(self._received_events) > MAX_EVENTS:
|
||||
self._received_events.pop()
|
||||
|
||||
self._controller._handle_event = handle_event_wrapper
|
||||
|
||||
def get_events(self, *event_types):
|
||||
events = list(self._received_events)
|
||||
event_types = list(map(str.upper, event_types)) # make filtering case insensitive
|
||||
|
||||
if event_types:
|
||||
events = [e for e in events if e.type in event_types]
|
||||
|
||||
return events
|
||||
|
||||
def do_help(self, arg):
|
||||
"""
|
||||
Performs the '/help' operation, giving usage information for the given
|
||||
argument or a general summary if there wasn't one.
|
||||
"""
|
||||
|
||||
return stem.interpreter.help.response(self._controller, arg)
|
||||
|
||||
def do_events(self, arg):
|
||||
"""
|
||||
Performs the '/events' operation, dumping the events that we've received
|
||||
belonging to the given types. If no types are specified then this provides
|
||||
all buffered events.
|
||||
|
||||
If the user runs '/events clear' then this clears the list of events we've
|
||||
received.
|
||||
"""
|
||||
|
||||
event_types = arg.upper().split()
|
||||
|
||||
if 'CLEAR' in event_types:
|
||||
del self._received_events[:]
|
||||
return format('cleared event backlog', *STANDARD_OUTPUT)
|
||||
|
||||
return '\n'.join([format(str(e), *STANDARD_OUTPUT) for e in self.get_events(*event_types)])
|
||||
|
||||
def do_info(self, arg):
|
||||
"""
|
||||
Performs the '/info' operation, looking up a relay by fingerprint, IP
|
||||
address, or nickname and printing its descriptor and consensus entries in a
|
||||
pretty fashion.
|
||||
"""
|
||||
|
||||
try:
|
||||
fingerprint = _get_fingerprint(arg, self._controller)
|
||||
except ValueError as exc:
|
||||
return format(str(exc), *ERROR_OUTPUT)
|
||||
|
||||
ns_desc = self._controller.get_network_status(fingerprint, None)
|
||||
server_desc = self._controller.get_server_descriptor(fingerprint, None)
|
||||
extrainfo_desc = None
|
||||
micro_desc = self._controller.get_microdescriptor(fingerprint, None)
|
||||
|
||||
# We'll mostly rely on the router status entry. Either the server
|
||||
# descriptor or microdescriptor will be missing, so we'll treat them as
|
||||
# being optional.
|
||||
|
||||
if not ns_desc:
|
||||
return format('Unable to find consensus information for %s' % fingerprint, *ERROR_OUTPUT)
|
||||
|
||||
# More likely than not we'll have the microdescriptor but not server and
|
||||
# extrainfo descriptors. If so then fetching them.
|
||||
|
||||
downloader = stem.descriptor.remote.DescriptorDownloader(timeout = 5)
|
||||
server_desc_query = downloader.get_server_descriptors(fingerprint)
|
||||
extrainfo_desc_query = downloader.get_extrainfo_descriptors(fingerprint)
|
||||
|
||||
for desc in server_desc_query:
|
||||
server_desc = desc
|
||||
|
||||
for desc in extrainfo_desc_query:
|
||||
extrainfo_desc = desc
|
||||
|
||||
address_extrainfo = []
|
||||
|
||||
try:
|
||||
address_extrainfo.append(socket.gethostbyaddr(ns_desc.address)[0])
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
address_extrainfo.append(self._controller.get_info('ip-to-country/%s' % ns_desc.address))
|
||||
except:
|
||||
pass
|
||||
|
||||
address_extrainfo_label = ' (%s)' % ', '.join(address_extrainfo) if address_extrainfo else ''
|
||||
|
||||
if server_desc:
|
||||
exit_policy_label = str(server_desc.exit_policy)
|
||||
elif micro_desc:
|
||||
exit_policy_label = str(micro_desc.exit_policy)
|
||||
else:
|
||||
exit_policy_label = 'Unknown'
|
||||
|
||||
lines = [
|
||||
'%s (%s)' % (ns_desc.nickname, fingerprint),
|
||||
format('address: ', *BOLD_OUTPUT) + '%s:%s%s' % (ns_desc.address, ns_desc.or_port, address_extrainfo_label),
|
||||
]
|
||||
|
||||
if server_desc:
|
||||
lines.append(format('tor version: ', *BOLD_OUTPUT) + str(server_desc.tor_version))
|
||||
|
||||
lines.append(format('flags: ', *BOLD_OUTPUT) + ', '.join(ns_desc.flags))
|
||||
lines.append(format('exit policy: ', *BOLD_OUTPUT) + exit_policy_label)
|
||||
|
||||
if server_desc and server_desc.contact:
|
||||
contact = stem.util.str_tools._to_unicode(server_desc.contact)
|
||||
|
||||
# clears up some highly common obscuring
|
||||
|
||||
for alias in (' at ', ' AT '):
|
||||
contact = contact.replace(alias, '@')
|
||||
|
||||
for alias in (' dot ', ' DOT '):
|
||||
contact = contact.replace(alias, '.')
|
||||
|
||||
lines.append(format('contact: ', *BOLD_OUTPUT) + contact)
|
||||
|
||||
descriptor_section = [
|
||||
('Server Descriptor:', server_desc),
|
||||
('Extrainfo Descriptor:', extrainfo_desc),
|
||||
('Microdescriptor:', micro_desc),
|
||||
('Router Status Entry:', ns_desc),
|
||||
]
|
||||
|
||||
div = format('-' * 80, *STANDARD_OUTPUT)
|
||||
|
||||
for label, desc in descriptor_section:
|
||||
if desc:
|
||||
lines += ['', div, format(label, *BOLD_OUTPUT), div, '']
|
||||
lines += [format(l, *STANDARD_OUTPUT) for l in str(desc).splitlines()]
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
def do_python(self, arg):
|
||||
"""
|
||||
Performs the '/python' operation, toggling if we accept python commands or
|
||||
not.
|
||||
"""
|
||||
|
||||
if not arg:
|
||||
status = 'enabled' if self._run_python_commands else 'disabled'
|
||||
return format('Python support is currently %s.' % status, *STANDARD_OUTPUT)
|
||||
elif arg.lower() == 'enable':
|
||||
self._run_python_commands = True
|
||||
elif arg.lower() == 'disable':
|
||||
self._run_python_commands = False
|
||||
else:
|
||||
return format("'%s' is not recognized. Please run either '/python enable' or '/python disable'." % arg, *ERROR_OUTPUT)
|
||||
|
||||
if self._run_python_commands:
|
||||
response = "Python support enabled, we'll now run non-interpreter commands as python."
|
||||
else:
|
||||
response = "Python support disabled, we'll now pass along all commands to tor."
|
||||
|
||||
return format(response, *STANDARD_OUTPUT)
|
||||
|
||||
@uses_settings
|
||||
def run_command(self, command, config, print_response = False):
|
||||
"""
|
||||
Runs the given command. Requests starting with a '/' are special commands
|
||||
to the interpreter, and anything else is sent to the control port.
|
||||
|
||||
:param stem.control.Controller controller: tor control connection
|
||||
:param str command: command to be processed
|
||||
:param bool print_response: prints the response to stdout if true
|
||||
|
||||
:returns: **list** out output lines, each line being a list of
|
||||
(msg, format) tuples
|
||||
|
||||
:raises: **stem.SocketClosed** if the control connection has been severed
|
||||
"""
|
||||
|
||||
# Commands fall into three categories:
|
||||
#
|
||||
# * Interpreter commands. These start with a '/'.
|
||||
#
|
||||
# * Controller commands stem knows how to handle. We use our Controller's
|
||||
# methods for these to take advantage of caching and present nicer
|
||||
# output.
|
||||
#
|
||||
# * Other tor commands. We pass these directly on to the control port.
|
||||
|
||||
cmd, arg = command.strip(), ''
|
||||
|
||||
if ' ' in cmd:
|
||||
cmd, arg = cmd.split(' ', 1)
|
||||
|
||||
output = ''
|
||||
|
||||
if cmd.startswith('/'):
|
||||
cmd = cmd.lower()
|
||||
|
||||
if cmd == '/quit':
|
||||
raise stem.SocketClosed()
|
||||
elif cmd == '/events':
|
||||
output = self.do_events(arg)
|
||||
elif cmd == '/info':
|
||||
output = self.do_info(arg)
|
||||
elif cmd == '/python':
|
||||
output = self.do_python(arg)
|
||||
elif cmd == '/help':
|
||||
output = self.do_help(arg)
|
||||
else:
|
||||
output = format("'%s' isn't a recognized command" % command, *ERROR_OUTPUT)
|
||||
else:
|
||||
cmd = cmd.upper() # makes commands uppercase to match the spec
|
||||
|
||||
if cmd.replace('+', '') in ('LOADCONF', 'POSTDESCRIPTOR'):
|
||||
# provides a notice that multi-line controller input isn't yet implemented
|
||||
output = format(msg('msg.multiline_unimplemented_notice'), *ERROR_OUTPUT)
|
||||
elif cmd == 'QUIT':
|
||||
self._controller.msg(command)
|
||||
raise stem.SocketClosed()
|
||||
else:
|
||||
is_tor_command = cmd in config.get('help.usage', {}) and cmd.lower() != 'events'
|
||||
|
||||
if self._run_python_commands and not is_tor_command:
|
||||
console_output = StringIO()
|
||||
|
||||
with redirect(console_output, console_output):
|
||||
self.is_multiline_context = code.InteractiveConsole.push(self, command)
|
||||
|
||||
output = console_output.getvalue().strip()
|
||||
else:
|
||||
try:
|
||||
output = format(self._controller.msg(command).raw_content().strip(), *STANDARD_OUTPUT)
|
||||
except stem.ControllerError as exc:
|
||||
if isinstance(exc, stem.SocketClosed):
|
||||
raise
|
||||
else:
|
||||
output = format(str(exc), *ERROR_OUTPUT)
|
||||
|
||||
if output:
|
||||
output += '\n' # give ourselves an extra line before the next prompt
|
||||
|
||||
if print_response:
|
||||
print(output)
|
||||
|
||||
return output
|
||||
146
Shared/lib/python3.7/site-packages/stem/interpreter/help.py
Normal file
146
Shared/lib/python3.7/site-packages/stem/interpreter/help.py
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
# Copyright 2014-2018, Damian Johnson and The Tor Project
|
||||
# See LICENSE for licensing information
|
||||
|
||||
"""
|
||||
Provides our /help responses.
|
||||
"""
|
||||
|
||||
import stem.prereq
|
||||
|
||||
from stem.interpreter import (
|
||||
STANDARD_OUTPUT,
|
||||
BOLD_OUTPUT,
|
||||
ERROR_OUTPUT,
|
||||
msg,
|
||||
uses_settings,
|
||||
)
|
||||
|
||||
from stem.util.term import format
|
||||
|
||||
if stem.prereq._is_lru_cache_available():
|
||||
from functools import lru_cache
|
||||
else:
|
||||
from stem.util.lru_cache import lru_cache
|
||||
|
||||
|
||||
def response(controller, arg):
|
||||
"""
|
||||
Provides our /help response.
|
||||
|
||||
:param stem.control.Controller controller: tor control connection
|
||||
:param str arg: controller or interpreter command to provide help output for
|
||||
|
||||
:returns: **str** with our help response
|
||||
"""
|
||||
|
||||
# Normalizing inputs first so we can better cache responses.
|
||||
|
||||
return _response(controller, _normalize(arg))
|
||||
|
||||
|
||||
def _normalize(arg):
|
||||
arg = arg.upper()
|
||||
|
||||
# If there's multiple arguments then just take the first. This is
|
||||
# particularly likely if they're trying to query a full command (for
|
||||
# instance "/help GETINFO version")
|
||||
|
||||
arg = arg.split(' ')[0]
|
||||
|
||||
# strip slash if someone enters an interpreter command (ex. "/help /help")
|
||||
|
||||
if arg.startswith('/'):
|
||||
arg = arg[1:]
|
||||
|
||||
return arg
|
||||
|
||||
|
||||
@lru_cache()
|
||||
@uses_settings
|
||||
def _response(controller, arg, config):
|
||||
if not arg:
|
||||
return _general_help()
|
||||
|
||||
usage_info = config.get('help.usage', {})
|
||||
|
||||
if arg not in usage_info:
|
||||
return format("No help information available for '%s'..." % arg, *ERROR_OUTPUT)
|
||||
|
||||
output = format(usage_info[arg] + '\n', *BOLD_OUTPUT)
|
||||
|
||||
description = config.get('help.description.%s' % arg.lower(), '')
|
||||
|
||||
for line in description.splitlines():
|
||||
output += format(' ' + line, *STANDARD_OUTPUT) + '\n'
|
||||
|
||||
output += '\n'
|
||||
|
||||
if arg == 'GETINFO':
|
||||
results = controller.get_info('info/names', None)
|
||||
|
||||
if results:
|
||||
for line in results.splitlines():
|
||||
if ' -- ' in line:
|
||||
opt, summary = line.split(' -- ', 1)
|
||||
|
||||
output += format('%-33s' % opt, *BOLD_OUTPUT)
|
||||
output += format(' - %s' % summary, *STANDARD_OUTPUT) + '\n'
|
||||
elif arg == 'GETCONF':
|
||||
results = controller.get_info('config/names', None)
|
||||
|
||||
if results:
|
||||
options = [opt.split(' ', 1)[0] for opt in results.splitlines()]
|
||||
|
||||
for i in range(0, len(options), 2):
|
||||
line = ''
|
||||
|
||||
for entry in options[i:i + 2]:
|
||||
line += '%-42s' % entry
|
||||
|
||||
output += format(line.rstrip(), *STANDARD_OUTPUT) + '\n'
|
||||
elif arg == 'SIGNAL':
|
||||
signal_options = config.get('help.signal.options', {})
|
||||
|
||||
for signal, summary in signal_options.items():
|
||||
output += format('%-15s' % signal, *BOLD_OUTPUT)
|
||||
output += format(' - %s' % summary, *STANDARD_OUTPUT) + '\n'
|
||||
elif arg == 'SETEVENTS':
|
||||
results = controller.get_info('events/names', None)
|
||||
|
||||
if results:
|
||||
entries = results.split()
|
||||
|
||||
# displays four columns of 20 characters
|
||||
|
||||
for i in range(0, len(entries), 4):
|
||||
line = ''
|
||||
|
||||
for entry in entries[i:i + 4]:
|
||||
line += '%-20s' % entry
|
||||
|
||||
output += format(line.rstrip(), *STANDARD_OUTPUT) + '\n'
|
||||
elif arg == 'USEFEATURE':
|
||||
results = controller.get_info('features/names', None)
|
||||
|
||||
if results:
|
||||
output += format(results, *STANDARD_OUTPUT) + '\n'
|
||||
elif arg in ('LOADCONF', 'POSTDESCRIPTOR'):
|
||||
# gives a warning that this option isn't yet implemented
|
||||
output += format(msg('msg.multiline_unimplemented_notice'), *ERROR_OUTPUT) + '\n'
|
||||
|
||||
return output.rstrip()
|
||||
|
||||
|
||||
def _general_help():
|
||||
lines = []
|
||||
|
||||
for line in msg('help.general').splitlines():
|
||||
div = line.find(' - ')
|
||||
|
||||
if div != -1:
|
||||
cmd, description = line[:div], line[div:]
|
||||
lines.append(format(cmd, *BOLD_OUTPUT) + format(description, *STANDARD_OUTPUT))
|
||||
else:
|
||||
lines.append(format(line, *BOLD_OUTPUT))
|
||||
|
||||
return '\n'.join(lines)
|
||||
332
Shared/lib/python3.7/site-packages/stem/interpreter/settings.cfg
Normal file
332
Shared/lib/python3.7/site-packages/stem/interpreter/settings.cfg
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
################################################################################
|
||||
#
|
||||
# Configuration data used by Stem's interpreter prompt.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
##################
|
||||
# GENERAL MESSAGES #
|
||||
##################
|
||||
|
||||
msg.multiline_unimplemented_notice Multi-line control options like this are not yet implemented.
|
||||
|
||||
msg.help
|
||||
|Interactive interpreter for Tor. This provides you with direct access
|
||||
|to Tor's control interface via either python or direct requests.
|
||||
|
|
||||
| -i, --interface [ADDRESS:]PORT change control interface from {address}:{port}
|
||||
| -s, --socket SOCKET_PATH attach using unix domain socket if present,
|
||||
| SOCKET_PATH defaults to: {socket}
|
||||
| --tor PATH tor binary if tor isn't already running
|
||||
| --run executes the given command or file of commands
|
||||
| --no-color disables colorized output
|
||||
| -h, --help presents this help
|
||||
|
|
||||
|
||||
msg.startup_banner
|
||||
|Welcome to Stem's interpreter prompt. This provides you with direct access to
|
||||
|Tor's control interface.
|
||||
|
|
||||
|This acts like a standard python interpreter with a Tor connection available
|
||||
|via your 'controller' variable...
|
||||
|
|
||||
| >>> controller.get_info('version')
|
||||
| '0.2.5.1-alpha-dev (git-245ecfff36c0cecc)'
|
||||
|
|
||||
|You can also issue requests directly to Tor...
|
||||
|
|
||||
| >>> GETINFO version
|
||||
| 250-version=0.2.5.1-alpha-dev (git-245ecfff36c0cecc)
|
||||
| 250 OK
|
||||
|
|
||||
|For more information run '/help'.
|
||||
|
|
||||
|
||||
msg.tor_unavailable Tor isn't running and the command currently isn't in your PATH.
|
||||
msg.unable_to_start_tor Unable to start tor: {error}
|
||||
msg.unable_to_read_file Unable to read {path}: {error}
|
||||
|
||||
msg.starting_tor
|
||||
|Tor isn't running. Starting a temporary Tor instance for our interpreter to
|
||||
|interact with. This will have a minimal non-relaying configuration, and be
|
||||
|shut down when you're done.
|
||||
|
|
||||
|--------------------------------------------------------------------------------
|
||||
|
|
||||
|
||||
#################
|
||||
# OUTPUT OF /HELP #
|
||||
#################
|
||||
|
||||
# Response for the '/help' command without any arguments.
|
||||
|
||||
help.general
|
||||
|Interpreter commands include:
|
||||
| /help - provides information for interpreter and tor commands
|
||||
| /events - prints events that we've received
|
||||
| /info - general information for a relay
|
||||
| /python - enable or disable support for running python commands
|
||||
| /quit - shuts down the interpreter
|
||||
|
|
||||
|Tor commands include:
|
||||
| GETINFO - queries information from tor
|
||||
| GETCONF, SETCONF, RESETCONF - show or edit a configuration option
|
||||
| SIGNAL - issues control signal to the process (for resetting, stopping, etc)
|
||||
| SETEVENTS - configures the events tor will notify us of
|
||||
|
|
||||
| USEFEATURE - enables custom behavior for the controller
|
||||
| SAVECONF - writes tor's current configuration to our torrc
|
||||
| LOADCONF - loads the given input like it was part of our torrc
|
||||
| MAPADDRESS - replaces requests for one address with another
|
||||
| POSTDESCRIPTOR - adds a relay descriptor to our cache
|
||||
| EXTENDCIRCUIT - create or extend a tor circuit
|
||||
| SETCIRCUITPURPOSE - configures the purpose associated with a circuit
|
||||
| CLOSECIRCUIT - closes the given circuit
|
||||
| ATTACHSTREAM - associates an application's stream with a tor circuit
|
||||
| REDIRECTSTREAM - sets a stream's destination
|
||||
| CLOSESTREAM - closes the given stream
|
||||
| ADD_ONION - create a new hidden service
|
||||
| DEL_ONION - delete a hidden service that was created with ADD_ONION
|
||||
| HSFETCH - retrieve a hidden service descriptor, providing it in a HS_DESC_CONTENT event
|
||||
| HSPOST - uploads a hidden service descriptor
|
||||
| RESOLVE - issues an asynchronous dns or rdns request over tor
|
||||
| TAKEOWNERSHIP - instructs tor to quit when this control connection is closed
|
||||
| PROTOCOLINFO - queries version and controller authentication information
|
||||
| QUIT - disconnect the control connection
|
||||
|
|
||||
|For more information use '/help [OPTION]'.
|
||||
|
||||
# Usage of tor and interpreter commands.
|
||||
|
||||
help.usage HELP => /help [OPTION]
|
||||
help.usage EVENTS => /events [types]
|
||||
help.usage INFO => /info [relay fingerprint, nickname, or IP address]
|
||||
help.usage PYTHON => /python [enable,disable]
|
||||
help.usage QUIT => /quit
|
||||
help.usage GETINFO => GETINFO OPTION
|
||||
help.usage GETCONF => GETCONF OPTION
|
||||
help.usage SETCONF => SETCONF PARAM[=VALUE]
|
||||
help.usage RESETCONF => RESETCONF PARAM[=VALUE]
|
||||
help.usage SIGNAL => SIGNAL SIG
|
||||
help.usage SETEVENTS => SETEVENTS [EXTENDED] [EVENTS]
|
||||
help.usage USEFEATURE => USEFEATURE OPTION
|
||||
help.usage SAVECONF => SAVECONF
|
||||
help.usage LOADCONF => LOADCONF...
|
||||
help.usage MAPADDRESS => MAPADDRESS SOURCE_ADDR=DESTINATION_ADDR
|
||||
help.usage POSTDESCRIPTOR => POSTDESCRIPTOR [purpose=general/controller/bridge] [cache=yes/no]...
|
||||
help.usage EXTENDCIRCUIT => EXTENDCIRCUIT CircuitID [PATH] [purpose=general/controller]
|
||||
help.usage SETCIRCUITPURPOSE => SETCIRCUITPURPOSE CircuitID purpose=general/controller
|
||||
help.usage CLOSECIRCUIT => CLOSECIRCUIT CircuitID [IfUnused]
|
||||
help.usage ATTACHSTREAM => ATTACHSTREAM StreamID CircuitID [HOP=HopNum]
|
||||
help.usage REDIRECTSTREAM => REDIRECTSTREAM StreamID Address [Port]
|
||||
help.usage CLOSESTREAM => CLOSESTREAM StreamID Reason [Flag]
|
||||
help.usage ADD_ONION => KeyType:KeyBlob [Flags=Flag] (Port=Port [,Target])...
|
||||
help.usage DEL_ONION => ServiceID
|
||||
help.usage HSFETCH => HSFETCH (HSAddress/v2-DescId) [SERVER=Server]...
|
||||
help.usage HSPOST => [SERVER=Server] DESCRIPTOR
|
||||
help.usage RESOLVE => RESOLVE [mode=reverse] address
|
||||
help.usage TAKEOWNERSHIP => TAKEOWNERSHIP
|
||||
help.usage PROTOCOLINFO => PROTOCOLINFO [ProtocolVersion]
|
||||
|
||||
# Longer description of what tor and interpreter commands do.
|
||||
|
||||
help.description.help
|
||||
|Provides usage information for the given interpreter, tor command, or tor
|
||||
|configuration option.
|
||||
|
|
||||
|Example:
|
||||
| /help info # provides a description of the '/info' option
|
||||
| /help GETINFO # usage information for tor's GETINFO controller option
|
||||
|
||||
help.description.events
|
||||
|Provides events that we've received belonging to the given event types. If
|
||||
|no types are specified then this provides all the messages that we've
|
||||
|received.
|
||||
|
|
||||
|You can also run '/events clear' to clear the backlog of events we've
|
||||
|received.
|
||||
|
||||
help.description.info
|
||||
|Provides information for a relay that's currently in the consensus. If no
|
||||
|relay is specified then this provides information on ourselves.
|
||||
|
||||
help.description.python
|
||||
|Enables or disables support for running python commands. This determines how
|
||||
|we treat commands this interpreter doesn't recognize...
|
||||
|
|
||||
|* If enabled then unrecognized commands are executed as python.
|
||||
|* If disabled then unrecognized commands are passed along to tor.
|
||||
|
||||
help.description.quit
|
||||
|Terminates the interpreter.
|
||||
|
||||
help.description.getinfo
|
||||
|Queries the tor process for information. Options are...
|
||||
|
|
||||
|
||||
help.description.getconf
|
||||
|Provides the current value for a given configuration value. Options include...
|
||||
|
|
||||
|
||||
help.description.setconf
|
||||
|Sets the given configuration parameters. Values can be quoted or non-quoted
|
||||
|strings, and reverts the option to 0 or NULL if not provided.
|
||||
|
|
||||
|Examples:
|
||||
| * Sets a contact address and resets our family to NULL
|
||||
| SETCONF MyFamily ContactInfo=foo@bar.com
|
||||
|
|
||||
| * Sets an exit policy that only includes port 80/443
|
||||
| SETCONF ExitPolicy=\"accept *:80, accept *:443, reject *:*\"\
|
||||
|
||||
help.description.resetconf
|
||||
|Reverts the given configuration options to their default values. If a value
|
||||
|is provided then this behaves in the same way as SETCONF.
|
||||
|
|
||||
|Examples:
|
||||
| * Returns both of our accounting parameters to their defaults
|
||||
| RESETCONF AccountingMax AccountingStart
|
||||
|
|
||||
| * Uses the default exit policy and sets our nickname to be 'Goomba'
|
||||
| RESETCONF ExitPolicy Nickname=Goomba
|
||||
|
||||
help.description.signal
|
||||
|Issues a signal that tells the tor process to reload its torrc, dump its
|
||||
|stats, halt, etc.
|
||||
|
||||
help.description.setevents
|
||||
|Sets the events that we will receive. This turns off any events that aren't
|
||||
|listed so sending 'SETEVENTS' without any values will turn off all event reporting.
|
||||
|
|
||||
|For Tor versions between 0.1.1.9 and 0.2.2.1 adding 'EXTENDED' causes some
|
||||
|events to give us additional information. After version 0.2.2.1 this is
|
||||
|always on.
|
||||
|
|
||||
|Events include...
|
||||
|
|
||||
|
||||
help.description.usefeature
|
||||
|Customizes the behavior of the control port. Options include...
|
||||
|
|
||||
|
||||
help.description.saveconf
|
||||
|Writes Tor's current configuration to its torrc.
|
||||
|
||||
help.description.loadconf
|
||||
|Reads the given text like it belonged to our torrc.
|
||||
|
|
||||
|Example:
|
||||
| +LOADCONF
|
||||
| # sets our exit policy to just accept ports 80 and 443
|
||||
| ExitPolicy accept *:80
|
||||
| ExitPolicy accept *:443
|
||||
| ExitPolicy reject *:*
|
||||
| .
|
||||
|
||||
help.description.mapaddress
|
||||
|Replaces future requests for one address with another.
|
||||
|
|
||||
|Example:
|
||||
| MAPADDRESS 0.0.0.0=torproject.org 1.2.3.4=tor.freehaven.net
|
||||
|
||||
help.description.postdescriptor
|
||||
|Simulates getting a new relay descriptor.
|
||||
|
||||
help.description.extendcircuit
|
||||
|Extends the given circuit or create a new one if the CircuitID is zero. The
|
||||
|PATH is a comma separated list of fingerprints. If it isn't set then this
|
||||
|uses Tor's normal path selection.
|
||||
|
||||
help.description.setcircuitpurpose
|
||||
|Sets the purpose attribute for a circuit.
|
||||
|
||||
help.description.closecircuit
|
||||
|Closes the given circuit. If "IfUnused" is included then this only closes
|
||||
|the circuit if it isn't currently being used.
|
||||
|
||||
help.description.attachstream
|
||||
|Attaches a stream with the given built circuit (tor picks one on its own if
|
||||
|CircuitID is zero). If HopNum is given then this hop is used to exit the
|
||||
|circuit, otherwise the last relay is used.
|
||||
|
||||
help.description.redirectstream
|
||||
|Sets the destination for a given stream. This can only be done after a
|
||||
|stream is created but before it's attached to a circuit.
|
||||
|
||||
help.description.closestream
|
||||
|Closes the given stream, the reason being an integer matching a reason as
|
||||
|per section 6.3 of the tor-spec.
|
||||
|
||||
help.description.add_onion
|
||||
|Creates a new hidden service. Unlike 'SETCONF HiddenServiceDir...' this
|
||||
|doesn't persist the service to disk.
|
||||
|
||||
help.description.del_onion
|
||||
|Delete a hidden service that was created with ADD_ONION.
|
||||
|
||||
help.description.hsfetch
|
||||
|Retrieves the descriptor for a hidden service. This is an asynchronous
|
||||
|request, with the descriptor provided by a HS_DESC_CONTENT event.
|
||||
|
||||
help.description.hspost
|
||||
|Uploads a descriptor to a hidden service directory.
|
||||
|
||||
help.description.resolve
|
||||
|Performs IPv4 DNS resolution over tor, doing a reverse lookup instead if
|
||||
|"mode=reverse" is included. This request is processed in the background and
|
||||
|results in a ADDRMAP event with the response.
|
||||
|
||||
help.description.takeownership
|
||||
|Instructs Tor to gracefully shut down when this control connection is closed.
|
||||
|
||||
help.description.protocolinfo
|
||||
|Provides bootstrapping information that a controller might need when first
|
||||
|starting, like Tor's version and controller authentication. This can be done
|
||||
|before authenticating to the control port.
|
||||
|
||||
help.signal.options RELOAD / HUP => reload our torrc
|
||||
help.signal.options SHUTDOWN / INT => gracefully shut down, waiting 30 seconds if we're a relay
|
||||
help.signal.options DUMP / USR1 => logs information about open connections and circuits
|
||||
help.signal.options DEBUG / USR2 => makes us log at the DEBUG runlevel
|
||||
help.signal.options HALT / TERM => immediately shut down
|
||||
help.signal.options CLEARDNSCACHE => clears any cached DNS results
|
||||
help.signal.options NEWNYM => clears the DNS cache and uses new circuits for future connections
|
||||
|
||||
################
|
||||
# TAB COMPLETION #
|
||||
################
|
||||
|
||||
# Commands we'll autocomplete when the user hits tab. This is just the start of
|
||||
# our autocompletion list - more are determined dynamically by checking what
|
||||
# tor supports.
|
||||
|
||||
autocomplete /help
|
||||
autocomplete /events
|
||||
autocomplete /info
|
||||
autocomplete /quit
|
||||
autocomplete SAVECONF
|
||||
autocomplete MAPADDRESS
|
||||
autocomplete EXTENDCIRCUIT
|
||||
autocomplete SETCIRCUITPURPOSE
|
||||
autocomplete SETROUTERPURPOSE
|
||||
autocomplete ATTACHSTREAM
|
||||
#autocomplete +POSTDESCRIPTOR # TODO: needs multi-line support
|
||||
autocomplete REDIRECTSTREAM
|
||||
autocomplete CLOSESTREAM
|
||||
autocomplete CLOSECIRCUIT
|
||||
autocomplete QUIT
|
||||
autocomplete RESOLVE
|
||||
autocomplete PROTOCOLINFO
|
||||
#autocomplete +LOADCONF # TODO: needs multi-line support
|
||||
autocomplete TAKEOWNERSHIP
|
||||
autocomplete AUTHCHALLENGE
|
||||
autocomplete DROPGUARDS
|
||||
autocomplete ADD_ONION NEW:BEST
|
||||
autocomplete ADD_ONION NEW:RSA1024
|
||||
autocomplete ADD_ONION NEW:ED25519-V3
|
||||
autocomplete ADD_ONION RSA1024:
|
||||
autocomplete ADD_ONION ED25519-V3:
|
||||
autocomplete DEL_ONION
|
||||
autocomplete HSFETCH
|
||||
autocomplete HSPOST
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue