import re import stem.util.proc import stem.util.system from stem.util import conf, enum, log # Connection resolution is risky to log about since it's highly likely to # contain sensitive information. That said, it's also difficult to get right in # a platform independent fashion. To opt into the logging requried to # troubleshoot connection resolution set the following... LOG_CONNECTION_RESOLUTION = False Resolver = enum.Enum(('PROC', 'proc'), ('NETSTAT', 'netstat'), ('SS', 'ss'), ('LSOF', 'lsof'), ('SOCKSTAT', 'sockstat'), ('BSD_SOCKSTAT', 'sockstat (bsd)'), ('BSD_PROCSTAT', 'procstat (bsd)')) Connection = collections.namedtuple('Connection', [ 'local_address', 'local_port', 'remote_address', 'remote_port', 'protocol', ]) FULL_IPv4_MASK = '255.255.255.255' FULL_IPv6_MASK = 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF' CRYPTOVARIABLE_EQUALITY_COMPARISON_NONCE = os.urandom(32)
'port_usage_rate': 5, }) UNABLE_TO_USE_ANY_RESOLVER_MSG = """ We were unable to use any of your system's resolvers to get tor's connections. This is fine, but means that the connections page will be empty. This is usually permissions related so if you would like to fix this then run nyx with the same user as tor (ie, "sudo -u <tor user> nyx"). """.strip() CONNECTION_TRACKER = None RESOURCE_TRACKER = None PORT_USAGE_TRACKER = None CONSENSUS_TRACKER = None CustomResolver = enum.Enum(('INFERENCE', 'by inference'), ) # Extending stem's Connection tuple with attributes for the uptime of the # connection. Connection = collections.namedtuple( 'Connection', [ 'start_time', 'is_legacy', # boolean to indicate if the connection predated us ] + list(stem.util.connection.Connection._fields)) Resources = collections.namedtuple('Resources', [ 'cpu_sample', 'cpu_average', 'cpu_total',
def general_conf_handler(config, key): value = config.get(key) if key.startswith("config.summary."): # we'll look for summary keys with a lowercase config name CONFIG[key.lower()] = value elif key.startswith("torrc.label.") and value: # all the torrc.label.* values are comma separated lists return [entry.strip() for entry in value[0].split(",")] conf.get_config("arm").add_listener(general_conf_handler, backfill=True) # enums and values for numeric torrc entries ValueType = enum.Enum("UNRECOGNIZED", "SIZE", "TIME") SIZE_MULT = { "b": 1, "kb": 1024, "mb": 1048576, "gb": 1073741824, "tb": 1099511627776 } TIME_MULT = {"sec": 1, "min": 60, "hour": 3600, "day": 86400, "week": 604800} # enums for issues found during torrc validation: # DUPLICATE - entry is ignored due to being a duplicate # MISMATCH - the value doesn't match tor's current state # MISSING - value differs from its default but is missing from the torrc # IS_DEFAULT - the configuration option matches tor's default ValidationError = enum.Enum("DUPLICATE", "MISMATCH", "MISSING", "IS_DEFAULT")
LAST_RETRIEVED_CIRCUITS = None ENTRY_CACHE = {} ENTRY_CACHE_REFERENCED = {} # Connection Categories: # Inbound Relay connection, coming to us. # Outbound Relay connection, leaving us. # Exit Outbound relay connection leaving the Tor network. # Hidden Connections to a hidden service we're providing. # Socks Socks connections for applications using Tor. # Circuit Circuits our tor client has created. # Directory Fetching tor consensus information. # Control Tor controller (nyx, vidalia, etc). Category = enum.Enum('INBOUND', 'OUTBOUND', 'EXIT', 'HIDDEN', 'SOCKS', 'CIRCUIT', 'DIRECTORY', 'CONTROL') SortAttr = enum.Enum('CATEGORY', 'UPTIME', 'IP_ADDRESS', 'PORT', 'FINGERPRINT', 'NICKNAME', 'COUNTRY') LineType = enum.Enum('CONNECTION', 'CIRCUIT_HEADER', 'CIRCUIT') Line = collections.namedtuple('Line', [ 'entry', 'line_type', 'connection', 'circuit', 'fingerprint', 'nickname', 'locale', ])
"startup.events": "N3", "startup.dataDirectory": "~/.arm", "startup.blindModeEnabled": False, "features.panels.show.graph": True, "features.panels.show.log": True, "features.panels.show.connection": True, "features.panels.show.config": True, "features.panels.show.torrc": True, "features.redrawRate": 5, "features.refreshRate": 5, "features.confirmQuit": True, "features.graph.type": 1, "features.graph.bw.prepopulate": True, }, conf_handler) GraphStat = enum.Enum("BANDWIDTH", "CONNECTIONS", "SYSTEM_RESOURCES") # maps 'features.graph.type' config values to the initial types GRAPH_INIT_STATS = { 1: GraphStat.BANDWIDTH, 2: GraphStat.CONNECTIONS, 3: GraphStat.SYSTEM_RESOURCES } def getController(): """ Provides the arm controller instance. """ return ARM_CONTROLLER
import curses import threading import cli.controller import popups from util import panel, sysTools, torConfig, torTools, uiTools import stem.control from stem.util import conf, enum, str_tools # TODO: The arm use cases are incomplete since they currently can't be # modified, have their descriptions fetched, or even get a complete listing # of what's available. State = enum.Enum("TOR", "ARM") # state to be presented # mappings of option categories to the color for their entries CATEGORY_COLOR = {torConfig.Category.GENERAL: "green", torConfig.Category.CLIENT: "blue", torConfig.Category.RELAY: "yellow", torConfig.Category.DIRECTORY: "magenta", torConfig.Category.AUTHORITY: "red", torConfig.Category.HIDDEN_SERVICE: "cyan", torConfig.Category.TESTING: "white", torConfig.Category.UNKNOWN: "white"} # attributes of a ConfigEntry Field = enum.Enum("CATEGORY", "OPTION", "VALUE", "TYPE", "ARG_USAGE", "SUMMARY", "DESCRIPTION", "MAN_ENTRY", "IS_DEFAULT")
import os import nyx.controller import nyx.curses import nyx.panel import nyx.popups import stem.control import stem.manual from nyx.curses import WHITE, NORMAL, BOLD, HIGHLIGHT from nyx import DATA_DIR, tor_controller from stem.util import conf, enum, log, str_tools SortAttr = enum.Enum('NAME', 'VALUE', 'VALUE_TYPE', 'CATEGORY', 'USAGE', 'SUMMARY', 'DESCRIPTION', 'MAN_PAGE_ENTRY', 'IS_SET') DETAILS_HEIGHT = 8 NAME_WIDTH = 25 VALUE_WIDTH = 15 def conf_handler(key, value): if key == 'features.config.order': return conf.parse_enum_csv(key, value[0], SortAttr, 3) CONFIG = conf.config_dict( 'nyx', { 'attr.config.category_color': {}, 'attr.config.sort_color': {},
import curses import threading import cli.popups from cli.connections import countPopup, descriptorPopup, entries, connEntry, circEntry from util import connections, panel, torTools, uiTools from stem.control import State from stem.util import conf, enum # height of the detail panel content, not counting top and bottom border DETAILS_HEIGHT = 7 # listing types Listing = enum.Enum(("IP_ADDRESS", "IP Address"), "HOSTNAME", "FINGERPRINT", "NICKNAME") def conf_handler(key, value): if key == "features.connection.listingType": return conf.parse_enum(key, value, Listing) elif key == "features.connection.refreshRate": return max(1, value) elif key == "features.connection.order": return conf.parse_enum_csv(key, value[0], entries.SortAttr, 3) CONFIG = conf.config_dict( "arm", { "features.connection.resolveApps": True,
import functools import threading import time import nyx.curses import nyx.panel import nyx.popups import nyx.tracker from nyx import nyx_interface, tor_controller, join, show_message from nyx.curses import RED, GREEN, CYAN, BOLD, HIGHLIGHT from nyx.menu import MenuItem, Submenu, RadioMenuItem, RadioGroup from stem.control import EventType, Listener from stem.util import conf, enum, log, str_tools, system GraphStat = enum.Enum(('BANDWIDTH', 'bandwidth'), ('CONNECTIONS', 'connections'), ('SYSTEM_RESOURCES', 'resources')) Interval = enum.Enum(('EACH_SECOND', 'each second'), ('FIVE_SECONDS', '5 seconds'), ('THIRTY_SECONDS', '30 seconds'), ('MINUTELY', 'minutely'), ('FIFTEEN_MINUTE', '15 minute'), ('THIRTY_MINUTE', '30 minute'), ('HOURLY', 'hourly'), ('DAILY', 'daily')) Bounds = enum.Enum(('GLOBAL_MAX', 'global_max'), ('LOCAL_MAX', 'local_max'), ('TIGHT', 'tight')) INTERVAL_SECONDS = { Interval.EACH_SECOND: 1, Interval.FIVE_SECONDS: 5, Interval.THIRTY_SECONDS: 30, Interval.MINUTELY: 60, Interval.FIFTEEN_MINUTE: 900, Interval.THIRTY_MINUTE: 1800, Interval.HOURLY: 3600, Interval.DAILY: 86400, } PRIMARY_COLOR, SECONDARY_COLOR = GREEN, CYAN
"blue": curses.COLOR_BLUE, "cyan": curses.COLOR_CYAN, "magenta": curses.COLOR_MAGENTA, "black": curses.COLOR_BLACK, "white": curses.COLOR_WHITE } # boolean for if we have color support enabled, None not yet determined COLOR_IS_SUPPORTED = None # mappings for getColor() - this uses the default terminal color scheme if # color support is unavailable COLOR_ATTR_INITIALIZED = False COLOR_ATTR = dict([(color, 0) for color in COLOR_LIST]) Ending = enum.Enum("ELLIPSE", "HYPHEN") SCROLL_KEYS = (curses.KEY_UP, curses.KEY_DOWN, curses.KEY_PPAGE, curses.KEY_NPAGE, curses.KEY_HOME, curses.KEY_END) def conf_handler(key, value): if key == "features.colorOverride" and value != "none": try: setColorOverride(value) except ValueError, exc: log.notice(exc) CONFIG = conf.config_dict( "arm", { "features.colorOverride": "none",
- sockstat sockstat -4c | grep '<process> *<pid>' - procstat procstat -f <pid> | grep TCP | grep -v 0.0.0.0:0 """ import re import os import time import threading from stem.util import conf, enum, log, proc, system # enums for connection resolution utilities Resolver = enum.Enum(("PROC", "proc"), ("NETSTAT", "netstat"), ("SS", "ss"), ("LSOF", "lsof"), ("SOCKSTAT", "sockstat"), ("BSD_SOCKSTAT", "sockstat (bsd)"), ("BSD_PROCSTAT", "procstat (bsd)")) # If true this provides new instantiations for resolvers if the old one has # been stopped. This can make it difficult ensure all threads are terminated # when accessed concurrently. RECREATE_HALTED_RESOLVERS = False # formatted strings for the commands to be executed with the various resolvers # options are: # n = prevents dns lookups, p = include process # output: # tcp 0 0 127.0.0.1:9051 127.0.0.1:53308 ESTABLISHED 9912/tor # *note: bsd uses a different variant ('-t' => '-p tcp', but worse an
def conf_handler(key, value): if key == "features.config.file.maxLinesPerEntry": return max(1, value) CONFIG = conf.config_dict( "arm", { "features.config.file.showScrollbars": True, "features.config.file.maxLinesPerEntry": 8, }, conf_handler) # TODO: The armrc use case is incomplete. There should be equivilant reloading # and validation capabilities to the torrc. Config = enum.Enum("TORRC", "ARMRC") # configuration file types that can be displayed class TorrcPanel(panel.Panel): """ Renders the current torrc or armrc with syntax highlighting in a scrollable area. """ def __init__(self, stdscr, configType): panel.Panel.__init__(self, stdscr, "torrc", 0) self.valsLock = threading.RLock() self.configType = configType self.scroll = 0 self.showLineNum = True # shows left aligned line numbers self.stripComments = False # drops comments and extra whitespace
""" Interface for entries in the connection panel. These consist of two parts: the entry itself (ie, Tor connection, client circuit, etc) and the lines it consists of in the listing. """ from stem.util import enum # attributes we can list entries by ListingType = enum.Enum(("IP_ADDRESS", "IP Address"), "HOSTNAME", "FINGERPRINT", "NICKNAME") SortAttr = enum.Enum("CATEGORY", "UPTIME", "LISTING", "IP_ADDRESS", "PORT", "HOSTNAME", "FINGERPRINT", "NICKNAME", "COUNTRY") SORT_COLORS = { SortAttr.CATEGORY: "red", SortAttr.UPTIME: "yellow", SortAttr.LISTING: "green", SortAttr.IP_ADDRESS: "blue", SortAttr.PORT: "blue", SortAttr.HOSTNAME: "magenta", SortAttr.FINGERPRINT: "cyan", SortAttr.NICKNAME: "cyan", SortAttr.COUNTRY: "blue" } # maximum number of ports a system can have PORT_COUNT = 65536
from stem.util import conf, enum, str_tools # time intervals at which graphs can be updated UPDATE_INTERVALS = [("each second", 1), ("5 seconds", 5), ("30 seconds", 30), ("minutely", 60), ("15 minute", 900), ("30 minute", 1800), ("hourly", 3600), ("daily", 86400)] DEFAULT_CONTENT_HEIGHT = 4 # space needed for labeling above and below the graph DEFAULT_COLOR_PRIMARY, DEFAULT_COLOR_SECONDARY = "green", "cyan" MIN_GRAPH_HEIGHT = 1 # enums for graph bounds: # Bounds.GLOBAL_MAX - global maximum (highest value ever seen) # Bounds.LOCAL_MAX - local maximum (highest value currently on the graph) # Bounds.TIGHT - local maximum and minimum Bounds = enum.Enum("GLOBAL_MAX", "LOCAL_MAX", "TIGHT") WIDE_LABELING_GRAPH_COL = 50 # minimum graph columns to use wide spacing for x-axis labels def conf_handler(key, value): if key == "features.graph.height": return max(MIN_GRAPH_HEIGHT, value) elif key == "features.graph.maxWidth": return max(1, value) elif key == "features.graph.interval": return max(0, min(len(UPDATE_INTERVALS) - 1, value)) elif key == "features.graph.bound": return max(0, min(2, value)) # used for setting defaults when initializing GraphStats and GraphPanel instances CONFIG = conf.config_dict("arm", {
from util import connections, torTools, uiTools from cli.connections import entries from stem.util import conf, enum, str_tools # Connection Categories: # Inbound Relay connection, coming to us. # Outbound Relay connection, leaving us. # Exit Outbound relay connection leaving the Tor network. # Hidden Connections to a hidden service we're providing. # Socks Socks connections for applications using Tor. # Circuit Circuits our tor client has created. # Directory Fetching tor consensus information. # Control Tor controller (arm, vidalia, etc). Category = enum.Enum("INBOUND", "OUTBOUND", "EXIT", "HIDDEN", "SOCKS", "CIRCUIT", "DIRECTORY", "CONTROL") CATEGORY_COLOR = { Category.INBOUND: "green", Category.OUTBOUND: "blue", Category.EXIT: "red", Category.HIDDEN: "magenta", Category.SOCKS: "yellow", Category.CIRCUIT: "cyan", Category.DIRECTORY: "magenta", Category.CONTROL: "red" } # static data for listing format # <src> --> <dst> <etc><padding> LABEL_FORMAT = "%s --> %s %s%s" LABEL_MIN_PADDING = 2 # min space between listing label and following data
""" Provides a dialog with client locale or exiting port counts. """ import curses import operator import cli.controller import cli.popups from util import connections, uiTools from stem.util import enum, log CountType = enum.Enum("CLIENT_LOCALE", "EXIT_PORT") EXIT_USAGE_WIDTH = 15 def showCountDialog(countType, counts): """ Provides a dialog with bar graphs and percentages for the given set of counts. Pressing any key closes the dialog. Arguments: countType - type of counts being presented counts - mapping of labels to counts """ isNoStats = not counts noStatsMsg = "Usage stats aren't available yet, press any key..."