commit 49a58b9dff0f1cf53b743c400d18bd3dbbe70184 Author: Sambuddha Basu sambuddhabasu1@gmail.com Date: Sun Jun 19 21:27:36 2016 -0700
Added help options to interpreter panel --- nyx/panel/interpreter.py | 10 +- nyx/tor_interpreter.py | 286 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 263 insertions(+), 33 deletions(-)
diff --git a/nyx/panel/interpreter.py b/nyx/panel/interpreter.py index 2e3ec0d..0c5d8c6 100644 --- a/nyx/panel/interpreter.py +++ b/nyx/panel/interpreter.py @@ -7,8 +7,7 @@ import nyx.controller import nyx.curses
from nyx.curses import GREEN, CYAN, BOLD, HIGHLIGHT -from nyx.tor_interpreter import handle_query, InterpreterClosed -from nyx import panel +from nyx import panel, tor_interpreter
USAGE_INFO = "to use this panel press enter" @@ -25,6 +24,7 @@ class InterpreterPanel(panel.Panel): panel.Panel.__init__(self, 'interpreter')
self._is_input_mode = False + self.interpreter = tor_interpreter.ControlInterpreter()
def key_handlers(self): def _execute_command(): @@ -39,12 +39,12 @@ class InterpreterPanel(panel.Panel): is_done = True else: try: - input_entry, output_entry = handle_query(user_input) + input_entry, output_entry = self.interpreter.handle_query(user_input) input_entry.insert(0, (PROMPT, GREEN, BOLD)) PROMPT_LINE.insert(len(PROMPT_LINE) - 1, input_entry) for line in output_entry: - PROMPT_LINE.insert(len(PROMPT_LINE) - 1, [line]) - except InterpreterClosed: + PROMPT_LINE.insert(len(PROMPT_LINE) - 1, line) + except tor_interpreter.InterpreterClosed: is_done = True
if is_done: diff --git a/nyx/tor_interpreter.py b/nyx/tor_interpreter.py index bf94403..62986ec 100644 --- a/nyx/tor_interpreter.py +++ b/nyx/tor_interpreter.py @@ -1,43 +1,273 @@ -from nyx.curses import GREEN, CYAN, RED, MAGENTA, BOLD, HIGHLIGHT +from nyx.curses import GREEN, CYAN, RED, MAGENTA, BLUE, BOLD, HIGHLIGHT from nyx import tor_controller
-def handle_query(user_input): +# initial location /write will save to when no path is specified +DEFAULT_WRITE_PATH = "/tmp/torInterpretor_output" + +GENERAL_HELP = """Interpretor commands include: + /help - provides information for interpretor and tor commands/config options + /info - general information for a relay + /find - searches backlog for lines with the given regex + /events - prints events that we've received + /write - saves backlog to a given location + /quit - shuts down the interpretor + +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 + 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]'.""" + +HELP_HELP = """Provides usage information for the given interpretor, 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 ExitPolicy # description of tor's ExitPolicy configuration option""" + +HELP_WRITE = """Writes the interpretor's backlog to the given path. If no location is +specified then this saves to the last path specified (initially '%s').""" % DEFAULT_WRITE_PATH + +HELP_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.""" + +HELP_INFO = """Provides general information for a relay that's currently in the consensus. +If no relay is specified then this provides information on ourselves.""" + +HELP_FIND = """Searches the backlog for lines matching a given regular expression pattern. +Results are deduplicated and the matching portions bolded.""" + +HELP_QUIT = """Terminates the interpretor.""" + +HELP_GETINFO = """Queries the tor process for information. Options are... +""" + +HELP_GETCONF = """Provides the current value for a given configuration value. Options include... +""" + +HELP_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_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_SIGNAL = """Issues a signal that tells the tor process to reload its torrc, dump its +stats, halt, etc. +""" + +SIGNAL_DESCRIPTIONS = ( + ("RELOAD / HUP", "reload our torrc"), + ("SHUTDOWN / INT", "gracefully shut down, waiting 30 seconds if we're a relay"), + ("DUMP / USR1", "logs information about open connections and circuits"), + ("DEBUG / USR2", "makes us log at the DEBUG runlevel"), + ("HALT / TERM", "immediately shut down"), + ("CLEARDNSCACHE", "clears any cached DNS results"), + ("NEWNYM", "clears the DNS cache and uses new circuits for future connections") +) + +HELP_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_USEFEATURE = """Customizes the behavior of the control port. Options include... +""" + +HELP_SAVECONF = """Writes Tor's current configuration to its torrc.""" + +HELP_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_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_POSTDESCRIPTOR = """Simulates getting a new relay descriptor.""" + +HELP_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_SETCIRCUITPURPOSE = """Sets the purpose attribute for a circuit.""" + +HELP_CLOSECIRCUIT = """Closes the given circuit. If "IfUnused" is included then this only closes +the circuit if it isn't currently being used.""" + +HELP_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_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_CLOSESTREAM = """Closes the given stream, the reason being an integer matching a reason as +per section 6.3 of the tor-spec.""" + +HELP_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_TAKEOWNERSHIP = """Instructs Tor to gracefully shut down when this control connection is closed.""" + +HELP_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_OPTIONS = { + "HELP": ("/help [OPTION]", HELP_HELP), + "WRITE": ("/write [PATH]", HELP_WRITE), + "EVENTS": ("/events [types]", HELP_EVENTS), + "INFO": ("/info [relay fingerprint, nickname, or IP address]", HELP_INFO), + "FIND": ("/find PATTERN", HELP_FIND), + "QUIT": ("/quit", HELP_QUIT), + "GETINFO": ("GETINFO OPTION", HELP_GETINFO), + "GETCONF": ("GETCONF OPTION", HELP_GETCONF), + "SETCONF": ("SETCONF PARAM[=VALUE]", HELP_SETCONF), + "RESETCONF": ("RESETCONF PARAM[=VALUE]", HELP_RESETCONF), + "SIGNAL": ("SIGNAL SIG", HELP_SIGNAL), + "SETEVENTS": ("SETEVENTS [EXTENDED] [EVENTS]", HELP_SETEVENTS), + "USEFEATURE": ("USEFEATURE OPTION", HELP_USEFEATURE), + "SAVECONF": ("SAVECONF", HELP_SAVECONF), + "LOADCONF": ("LOADCONF...", HELP_LOADCONF), + "MAPADDRESS": ("MAPADDRESS SOURCE_ADDR=DESTINATION_ADDR", HELP_MAPADDRESS), + "POSTDESCRIPTOR": ("POSTDESCRIPTOR [purpose=general/controller/bridge] [cache=yes/no]...", HELP_POSTDESCRIPTOR), + "EXTENDCIRCUIT": ("EXTENDCIRCUIT CircuitID [PATH] [purpose=general/controller]", HELP_EXTENDCIRCUIT), + "SETCIRCUITPURPOSE": ("SETCIRCUITPURPOSE CircuitID purpose=general/controller", HELP_SETCIRCUITPURPOSE), + "CLOSECIRCUIT": ("CLOSECIRCUIT CircuitID [IfUnused]", HELP_CLOSECIRCUIT), + "ATTACHSTREAM": ("ATTACHSTREAM StreamID CircuitID [HOP=HopNum]", HELP_ATTACHSTREAM), + "REDIRECTSTREAM": ("REDIRECTSTREAM StreamID Address [Port]", HELP_REDIRECTSTREAM), + "CLOSESTREAM": ("CLOSESTREAM StreamID Reason [Flag]", HELP_CLOSESTREAM), + "RESOLVE": ("RESOLVE [mode=reverse] address", HELP_RESOLVE), + "TAKEOWNERSHIP": ("TAKEOWNERSHIP", HELP_TAKEOWNERSHIP), + "PROTOCOLINFO": ("PROTOCOLINFO [ProtocolVersion]", HELP_PROTOCOLINFO), +} + +class ControlInterpreter: """ - Processes the given input. Requests starting with a '/' are special - commands to the interpretor, and anything else is sent to the control port. - This returns an input/output tuple, each entry being a list of lines, each - line having a list of (msg, format) tuples for the content to be displayed. - This raises a InterpretorClosed if the interpretor should be shut down. - - Arguments: - user_input - user input to be processed + Interpretor that handles queries to the control port, providing usability + imporvements like irc style help optoins. This tracks input and responses. """
- user_input = user_input.strip() + def do_help(self, arg, output_entry): + """ + Performs the '/help' operation, giving usage information for the given + argument or a general summary if there wasn't one. + """
- input_entry, output_entry = [], [] + arg = arg.upper()
- if " " in user_input: cmd, arg = user_input.split(" ", 1) - else: cmd, arg = user_input, "" + # 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 interpretor command (ex. "/help /help") + if arg.startswith("/"): arg = arg[1:]
- if cmd.startswith("/"): - input_entry.append((cmd, MAGENTA, BOLD)) - if cmd == "/quit": raise InterpreterClosed() - else: - output_entry.append(("Not yet implemented...", RED, BOLD)) - else: - cmd = cmd.upper() - input_entry.append((cmd + " ", GREEN, BOLD)) if arg: - input_entry.append((arg, CYAN, BOLD)) + if arg in HELP_OPTIONS: + # Provides information for the tor or interpretor argument. This bolds + # the usage information and indents the description after it. + usage, description = HELP_OPTIONS[arg] + + output_entry.append([(usage, BLUE, BOLD)]) + + for line in description.split("\n"): + output_entry.append([(" " + line, BLUE, )]) + else: + # provides the GENERAL_HELP with everything bolded except descriptions + for line in GENERAL_HELP.split("\n"): + cmd_start = line.find(" - ") + if cmd_start != -1: + output_entry.append([(line[:cmd_start], BLUE, BOLD), (line[cmd_start:], BLUE, )]) + else: + output_entry.append([(line, BLUE, BOLD)]) + + def handle_query(self, user_input): + """ + Processes the given input. Requests starting with a '/' are special + commands to the interpretor, and anything else is sent to the control port. + This returns an input/output tuple, each entry being a list of lines, each + line having a list of (msg, format) tuples for the content to be displayed. + This raises a InterpretorClosed if the interpretor should be shut down. + + Arguments: + user_input - user input to be processed + """ + + user_input = user_input.strip() + + input_entry, output_entry = [], [] + + if " " in user_input: cmd, arg = user_input.split(" ", 1) + else: cmd, arg = user_input, "" + + if cmd.startswith("/"): + input_entry.append((cmd, MAGENTA, BOLD)) + if cmd == "/quit": raise InterpreterClosed() + elif cmd == "/help": self.do_help(arg, output_entry) + else: + output_entry.append([("Not yet implemented...", RED, BOLD)]) + else: + cmd = cmd.upper() + input_entry.append((cmd + " ", GREEN, BOLD)) + if arg: + input_entry.append((arg, CYAN, BOLD))
- if cmd == "GETINFO": - resp = tor_controller().get_info(arg) - for line in resp.split('\n'): - output_entry.append((line, CYAN,)) + if cmd == "GETINFO": + resp = tor_controller().get_info(arg) + for line in resp.split('\n'): + output_entry.append([(line, CYAN,)])
- return input_entry, output_entry + return input_entry, output_entry
class InterpreterClosed(Exception):