def __init__(self): """ Initializes parameters needed to present a graph. """ TorCtl.PostEventListener.__init__(self) # panel to be redrawn when updated (set when added to GraphPanel) self._graphPanel = None self.isSelected = False self.isPauseBuffer = False # tracked stats self.tick = 0 # number of processed events self.lastPrimary, self.lastSecondary = 0, 0 # most recent registered stats self.primaryTotal, self.secondaryTotal = 0, 0 # sum of all stats seen # timescale dependent stats self.maxCol = CONFIG["features.graph.maxWidth"] self.maxPrimary, self.maxSecondary = {}, {} self.primaryCounts, self.secondaryCounts = {}, {} for i in range(len(UPDATE_INTERVALS)): # recent rates for graph self.maxPrimary[i] = 0 self.maxSecondary[i] = 0 # historic stats for graph, first is accumulator # iterative insert needed to avoid making shallow copies (nasty, nasty gotcha) self.primaryCounts[i] = (self.maxCol + 1) * [0] self.secondaryCounts[i] = (self.maxCol + 1) * [0] # tracks BW events torTools.getConn().addEventListener(self)
def shutdownDaemons(): """ Stops and joins on worker threads. """ # prevents further worker threads from being spawned torTools.NO_SPAWN = True # stops panel daemons control = getController() for panelImpl in control.getDaemonPanels(): panelImpl.stop() for panelImpl in control.getDaemonPanels(): panelImpl.join() # joins on stem threads torTools.getConn().close() # joins on utility daemon threads - this might take a moment since the # internal threadpools being joined might be sleeping hostnames.stop() resourceTrackers = sysTools.RESOURCE_TRACKERS.values() resolver = connections.getResolver("tor") if connections.isResolverAlive("tor") else None for tracker in resourceTrackers: tracker.stop() if resolver: resolver.stop() # sets halt flag (returning immediately) for tracker in resourceTrackers: tracker.join() if resolver: resolver.join() # joins on halted resolver
def __init__(self): """ Initializes parameters needed to present a graph. """ # panel to be redrawn when updated (set when added to GraphPanel) self._graphPanel = None self.isSelected = False self.isPauseBuffer = False # tracked stats self.tick = 0 # number of processed events self.lastPrimary, self.lastSecondary = 0, 0 # most recent registered stats self.primaryTotal, self.secondaryTotal = 0, 0 # sum of all stats seen # timescale dependent stats self.maxCol = CONFIG["features.graph.maxWidth"] self.maxPrimary, self.maxSecondary = {}, {} self.primaryCounts, self.secondaryCounts = {}, {} for i in range(len(UPDATE_INTERVALS)): # recent rates for graph self.maxPrimary[i] = 0 self.maxSecondary[i] = 0 # historic stats for graph, first is accumulator # iterative insert needed to avoid making shallow copies (nasty, nasty gotcha) self.primaryCounts[i] = (self.maxCol + 1) * [0] self.secondaryCounts[i] = (self.maxCol + 1) * [0] # tracks BW events torTools.getConn().addEventListener(self.bandwidth_event, stem.control.EventType.BW)
def quit(self): """ Terminates arm after the input is processed. Optionally if we're connected to a arm generated tor instance then this may check if that should be shut down too. """ self._isDone = True # check if the torrc has a "ARM_SHUTDOWN" comment flag, if so then shut # down the instance isShutdownFlagPresent = False torrcContents = torConfig.getTorrc().getContents() if torrcContents: for line in torrcContents: if "# ARM_SHUTDOWN" in line: isShutdownFlagPresent = True break if isShutdownFlagPresent: try: torTools.getConn().shutdown() except IOError, exc: cli.popups.showMsg(str(exc), 3, curses.A_BOLD)
def shutdownDaemons(): """ Stops and joins on worker threads. """ # prevents further worker threads from being spawned torTools.NO_SPAWN = True # stops panel daemons control = getController() for panelImpl in control.getDaemonPanels(): panelImpl.stop() for panelImpl in control.getDaemonPanels(): panelImpl.join() # joins on TorCtl event thread torTools.getConn().close() # joins on utility daemon threads - this might take a moment since the # internal threadpools being joined might be sleeping hostnames.stop() resourceTrackers = sysTools.RESOURCE_TRACKERS.values() resolver = connections.getResolver("tor") if connections.isResolverAlive( "tor") else None for tracker in resourceTrackers: tracker.stop() if resolver: resolver.stop() # sets halt flag (returning immediately) for tracker in resourceTrackers: tracker.join() if resolver: resolver.join() # joins on halted resolver
def __init__(self): self.backlog = [] # prior requests the user has made self.contents = [] # (msg, format list) tuples for what's been displayed self.writePath = DEFAULT_WRITE_PATH # last location we've saved to self.eventBuffer = [] # unread event messages self.loggedEvents = [] # event types that we're listening for torTools.getConn().addEventListener(TorEventObserver(self.registerEvent))
def __init__(self): self.backlog = [] # prior requests the user has made self.contents = [ ] # (msg, format list) tuples for what's been displayed self.writePath = DEFAULT_WRITE_PATH # last location we've saved to self.eventBuffer = [] # unread event messages self.loggedEvents = [] # event types that we're listening for torTools.getConn().addEventListener( TorEventObserver(self.registerEvent))
def isExitsAllowed(self): """ True if exit connections are permissable, false otherwise. """ if not torTools.getConn().getOption("ORPort", None): return False # no ORPort policy = torTools.getConn().getExitPolicy() return policy and policy.is_exiting_allowed()
def sendNewnym(self): """ Requests a new identity and provides a visual queue. """ torTools.getConn().sendNewnym() # If we're wide then the newnym label in this panel will give an # indication that the signal was sent. Otherwise use a msg. isWide = self.getParent().getmaxyx()[1] >= MIN_DUAL_COL_WIDTH if not isWide: cli.popups.showMsg("Requesting a new identity", 1)
def resetOptions(self): self.familyResolutions = {} self.familyFingerprints = {} try: self.address = "" # fetched when needed if unset self.nickname = self.conn.get_option("Nickname")[0][1] if self.nickname == None: self.nickname = "Unnamed" self.orPort = self.conn.get_option("ORPort")[0][1] self.dirPort = self.conn.get_option("DirPort")[0][1] self.controlPort = self.conn.get_option("ControlPort")[0][1] # uses ports to identify type of connections (ORListenAddress port overwrites ORPort if set) listenAddr = self.conn.get_option("ORListenAddress")[0][1] if listenAddr and ":" in listenAddr: self.listenPort = listenAddr[listenAddr.find(":") + 1:] else: self.listenPort = self.orPort self.socksPort = torTools.getConn().getOption("SocksPort", "0") # entry is None if not set, otherwise of the format "$<fingerprint>,$<fingerprint>" familyEntry = self.conn.get_option("MyFamily")[0][1] if familyEntry: self.family = familyEntry.split(",") else: self.family = [] self.isBridge = self.conn.get_option("BridgeRelay")[0][1] == "1" policyEntries = torTools.getConn().getOption("ExitPolicy", multiple=True) if not policyEntries: policyEntries = [] # if ExitPolicy is undefined, policyEntries is None self.exitPolicy = ",".join(policyEntries) self.exitPolicy = self.exitPolicy.replace("\\t", " ").replace("\"", "") if self.exitPolicy: self.exitPolicy += "," + self.conn.get_info("exit-policy/default")["exit-policy/default"] else: self.exitPolicy = self.conn.get_info("exit-policy/default")["exit-policy/default"] self.exitRejectPrivate = self.conn.get_option("ExitPolicyRejectPrivate")[0][1] == "1" self._resolveFamilyEntries() except (socket.error, TorCtl.ErrorReply, TorCtl.TorCtlClosed): self.nickname = "" self.listenPort = None self.orPort = "0" self.dirPort = "0" self.controlPort = "0" self.socksPort = "0" self.family = [] self.isBridge = False self.exitPolicy = "" self.exitRejectPrivate = True
def isClientsAllowed(self): """ True if client connections are permissable, false otherwise. """ conn = torTools.getConn() return "Guard" in conn.getMyFlags([]) or conn.getOption("BridgeRelay") == "1"
def isExitsAllowed(self): """ True if exit connections are permissable, false otherwise. """ policy = torTools.getConn().getExitPolicy() return policy and policy.isExitingAllowed()
def isUnset(self): """ True if we have no value, false otherwise. """ confValue = torTools.getConn().getOption(self.get(Field.OPTION), [], True) return not bool(confValue)
def getMultilineParameters(): """ Provides parameters that can be defined multiple times in the torrc without overwriting the value. """ # fetches config options with the LINELIST (aka 'LineList'), LINELIST_S (aka # 'Dependent'), and LINELIST_V (aka 'Virtual') types global MULTILINE_PARAM if MULTILINE_PARAM == None: conn, multilineEntries = torTools.getConn(), [] configOptionQuery = conn.getInfo("config/names") if configOptionQuery: for line in configOptionQuery.strip().split("\n"): confOption, confType = line.strip().split(" ", 1) if confType in ("LineList", "Dependant", "Virtual"): multilineEntries.append(confOption) else: # unable to query tor connection, so not caching results return () MULTILINE_PARAM = multilineEntries return tuple(MULTILINE_PARAM)
def isPrivate(self): """ Returns true if the endpoint is private, possibly belonging to a client connection or exit traffic. """ if not CONFIG["features.connection.showIps"]: return True # This is used to scrub private information from the interface. Relaying # etiquette (and wiretapping laws) say these are bad things to look at so # DON'T CHANGE THIS UNLESS YOU HAVE A DAMN GOOD REASON! myType = self.getType() if myType == Category.INBOUND: # if we're a guard or bridge and the connection doesn't belong to a # known relay then it might be client traffic conn = torTools.getConn() if "Guard" in conn.getMyFlags([]) or conn.getOption("BridgeRelay", None) == "1": allMatches = conn.getRelayFingerprint(self.foreign.getIpAddr(), getAllMatches = True) return allMatches == [] elif myType == Category.EXIT: # DNS connections exiting us aren't private (since they're hitting our # resolvers). Everything else, however, is. # TODO: Ideally this would also double check that it's a UDP connection # (since DNS is the only UDP connections Tor will relay), however this # will take a bit more work to propagate the information up from the # connection resolver. return self.foreign.getPort() != "53" # for everything else this isn't a concern return False
def getCustomOptions(includeValue = False): """ Provides the torrc parameters that differ from their defaults. Arguments: includeValue - provides the current value with results if true, otherwise this just contains the options """ configText = torTools.getConn().getInfo("config-text", "").strip() configLines = configText.split("\n") # removes any duplicates configLines = list(set(configLines)) # The "GETINFO config-text" query only provides options that differ # from Tor's defaults with the exception of its Log and Nickname entries # which, even if undefined, returns "Log notice stdout" as per: # https://trac.torproject.org/projects/tor/ticket/2362 try: configLines.remove("Log notice stdout") except ValueError: pass try: configLines.remove("Nickname %s" % socket.gethostname()) except ValueError: pass if includeValue: return configLines else: return [line[:line.find(" ")] for line in configLines]
def __init__(self, stdscr, configType, config=None): panel.Panel.__init__(self, stdscr, "configuration", 0) self.sortOrdering = DEFAULT_SORT_ORDER self._config = dict(DEFAULT_CONFIG) if config: config.update( self._config, { "features.config.selectionDetails.height": 0, "features.config.state.colWidth.option": 5, "features.config.state.colWidth.value": 5 }) sortFields = Field.values() customOrdering = config.getIntCSV("features.config.order", None, 3, 0, len(sortFields)) if customOrdering: self.sortOrdering = [sortFields[i] for i in customOrdering] self.configType = configType self.confContents = [] self.confImportantContents = [] self.scroller = uiTools.Scroller(True) self.valsLock = threading.RLock() # shows all configuration options if true, otherwise only the ones with # the 'important' flag are shown self.showAll = False # initializes config contents if we're connected conn = torTools.getConn() conn.addStatusListener(self.resetListener) if conn.isAlive(): self.resetListener(conn, torTools.State.INIT)
def makeActionsMenu(): """ Submenu consisting of... Close Menu New Identity Pause / Unpause Reset Tor Exit """ control = cli.controller.getController() manager = control.getTorManager() conn = torTools.getConn() headerPanel = control.getPanel("header") actionsMenu = cli.menu.item.Submenu("Actions") actionsMenu.add(cli.menu.item.MenuItem("Close Menu", None)) actionsMenu.add(cli.menu.item.MenuItem("New Identity", headerPanel.sendNewnym)) if conn.isAlive(): actionsMenu.add(cli.menu.item.MenuItem("Stop Tor", conn.shutdown)) elif manager.isTorrcAvailable(): actionsMenu.add(cli.menu.item.MenuItem("Start Tor", manager.startManagedInstance)) actionsMenu.add(cli.menu.item.MenuItem("Reset Tor", conn.reload)) actionsMenu.add(cli.menu.item.MenuItem("Setup Wizard", cli.wizard.showWizard)) if control.isPaused(): label, arg = "Unpause", False else: label, arg = "Pause", True actionsMenu.add(cli.menu.item.MenuItem(label, functools.partial(control.setPaused, arg))) actionsMenu.add(cli.menu.item.MenuItem("Exit", control.quit)) return actionsMenu
def __init__(self, stdscr, configType, config=None): panel.Panel.__init__(self, stdscr, "configuration", 0) self.sortOrdering = DEFAULT_SORT_ORDER self._config = dict(DEFAULT_CONFIG) if config: config.update(self._config, { "features.config.selectionDetails.height": 0, "features.config.state.colWidth.option": 5, "features.config.state.colWidth.value": 5}) sortFields = Field.values() customOrdering = config.getIntCSV("features.config.order", None, 3, 0, len(sortFields)) if customOrdering: self.sortOrdering = [sortFields[i] for i in customOrdering] self.configType = configType self.confContents = [] self.confImportantContents = [] self.scroller = uiTools.Scroller(True) self.valsLock = threading.RLock() # shows all configuration options if true, otherwise only the ones with # the 'important' flag are shown self.showAll = False # initializes config contents if we're connected conn = torTools.getConn() conn.addStatusListener(self.resetListener) if conn.isAlive(): self.resetListener(conn, torTools.State.INIT)
def getCorrections(self): """ Performs validation on the loaded contents and provides back the corrections. If validation is disabled then this won't provide any results. """ self.valsLock.acquire() # The torrc validation relies on 'GETINFO config-text' which was # introduced in tor 0.2.2.7-alpha so if we're using an earlier version # (or configured to skip torrc validation) then this is a no-op. For more # information see: # https://trac.torproject.org/projects/tor/ticket/2501 if not self.isLoaded(): returnVal = None else: skipValidation = not CONFIG["features.torrc.validate"] skipValidation |= not torTools.getConn().isVersion("0.2.2.7-alpha") if skipValidation: returnVal = {} else: if self.corrections == None: self.corrections = validate(self.contents) returnVal = list(self.corrections) self.valsLock.release() return returnVal
def getMultilineParameters(): """ Provides parameters that can be defined multiple times in the torrc without overwriting the value. """ # fetches config options with the LINELIST (aka 'LineList'), LINELIST_S (aka # 'Dependent'), and LINELIST_V (aka 'Virtual') types global MULTILINE_PARAM if MULTILINE_PARAM == None: conn, multilineEntries = torTools.getConn(), [] configOptionQuery = conn.getInfo("config/names", None) if configOptionQuery: for line in configOptionQuery.strip().split("\n"): confOption, confType = line.strip().split(" ", 1) if confType in ("LineList", "Dependant", "Virtual"): multilineEntries.append(confOption) else: # unable to query tor connection, so not caching results return () MULTILINE_PARAM = multilineEntries return tuple(MULTILINE_PARAM)
def __init__(self, lIpAddr, lPort, fIpAddr, fPort, includePort=True, includeExpandedIpAddr=True): entries.ConnectionPanelLine.__init__(self) self.local = Endpoint(lIpAddr, lPort) self.foreign = Endpoint(fIpAddr, fPort) self.startTime = time.time() self.isInitialConnection = False # overwrite the local fingerprint with ours conn = torTools.getConn() self.local.fingerprintOverwrite = conn.getInfo("fingerprint", None) # True if the connection has matched the properties of a client/directory # connection every time we've checked. The criteria we check is... # client - first hop in an established circuit # directory - matches an established single-hop circuit (probably a # directory mirror) self._possibleClient = True self._possibleDirectory = True # attributes for SOCKS, HIDDEN, and CONTROL connections self.appName = None self.appPid = None self.isAppResolving = False myOrPort = conn.getOption("ORPort", None) myDirPort = conn.getOption("DirPort", None) mySocksPort = conn.getOption("SocksPort", "9050") myCtlPort = conn.getOption("ControlPort", None) myHiddenServicePorts = conn.getHiddenServicePorts() # the ORListenAddress can overwrite the ORPort listenAddr = conn.getOption("ORListenAddress", None) if listenAddr and ":" in listenAddr: myOrPort = listenAddr[listenAddr.find(":") + 1:] if lPort in (myOrPort, myDirPort): self.baseType = Category.INBOUND self.local.isNotORPort = False elif lPort == mySocksPort: self.baseType = Category.SOCKS elif fPort in myHiddenServicePorts: self.baseType = Category.HIDDEN elif lPort == myCtlPort: self.baseType = Category.CONTROL else: self.baseType = Category.OUTBOUND self.foreign.isNotORPort = False self.cachedType = None # includes the port or expanded ip address field when displaying listing # information if true self.includePort = includePort self.includeExpandedIpAddr = includeExpandedIpAddr # cached immutable values used for sorting self.sortIpAddr = connections.ipToInt(self.foreign.getIpAddr()) self.sortPort = int(self.foreign.getPort())
def getCorrections(self): """ Performs validation on the loaded contents and provides back the corrections. If validation is disabled then this won't provide any results. """ self.valsLock.acquire() if not self.isLoaded(): returnVal = None else: torVersion = torTools.getConn().getVersion() skipValidation = not CONFIG["features.torrc.validate"] skipValidation |= ( torVersion is None or not torVersion.meets_requirements( stem.version.Requirement.GETINFO_CONFIG_TEXT)) if skipValidation: log.info( "Skipping torrc validation (requires tor 0.2.2.7-alpha)") returnVal = {} else: if self.corrections == None: self.corrections = validate(self.contents) returnVal = list(self.corrections) self.valsLock.release() return returnVal
def makeActionsMenu(): """ Submenu consisting of... Close Menu New Identity Pause / Unpause Reset Tor Exit """ control = cli.controller.getController() conn = torTools.getConn() headerPanel = control.getPanel("header") actionsMenu = cli.menu.item.Submenu("Actions") actionsMenu.add(cli.menu.item.MenuItem("Close Menu", None)) actionsMenu.add(cli.menu.item.MenuItem("New Identity", headerPanel.sendNewnym)) if conn.isAlive(): actionsMenu.add(cli.menu.item.MenuItem("Stop Tor", conn.shutdown)) actionsMenu.add(cli.menu.item.MenuItem("Reset Tor", conn.reload)) if control.isPaused(): label, arg = "Unpause", False else: label, arg = "Pause", True actionsMenu.add(cli.menu.item.MenuItem(label, functools.partial(control.setPaused, arg))) actionsMenu.add(cli.menu.item.MenuItem("Exit", control.quit)) return actionsMenu
def update(self, status, path): """ Our status and path can change over time if the circuit is still in the process of being built. Updates these attributes of our relay. Arguments: status - new status of the circuit path - list of fingerprints for the series of relays involved in the circuit """ self.status = status self.lines = [self.lines[0]] conn = torTools.getConn() if status == "BUILT" and not self.lines[0].isBuilt: exitIp, exitORPort = conn.getRelayAddress(path[-1], ("192.168.0.1", "0")) self.lines[0].setExit(exitIp, exitORPort, path[-1]) for i in range(len(path)): relayFingerprint = path[i] relayIp, relayOrPort = conn.getRelayAddress(relayFingerprint, ("192.168.0.1", "0")) if i == len(path) - 1: if status == "BUILT": placementType = "Exit" else: placementType = "Extending" elif i == 0: placementType = "Guard" else: placementType = "Middle" placementLabel = "%i / %s" % (i + 1, placementType) self.lines.append(CircLine(relayIp, relayOrPort, relayFingerprint, placementLabel)) self.lines[-1].isLast = True
def getCorrections(self): """ Performs validation on the loaded contents and provides back the corrections. If validation is disabled then this won't provide any results. """ self.valsLock.acquire() if not self.isLoaded(): returnVal = None else: torVersion = torTools.getConn().getVersion() skipValidation = not CONFIG["features.torrc.validate"] skipValidation |= (torVersion is None or not torVersion.meets_requirements(stem.version.Requirement.GETINFO_CONFIG_TEXT)) if skipValidation: log.log(log.INFO, "Skipping torrc validation (requires tor 0.2.2.7-alpha)") returnVal = {} else: if self.corrections == None: self.corrections = validate(self.contents) returnVal = list(self.corrections) self.valsLock.release() return returnVal
def setEventListening(self, events): """ Configures the events Tor listens for, filtering non-tor events from what we request from the controller. This returns a sorted list of the events we successfully set. Arguments: events - event types to attempt to set """ events = set(events) # drops duplicates torEvents = events.intersection(set(TOR_EVENT_TYPES.values())) # adds events unrecognized by arm if we're listening to the 'UNKNOWN' type if "UNKNOWN" in events: torEvents.update(set(getMissingEventTypes())) torConn = torTools.getConn() torConn.removeEventListener(self.registerTorEvent) for eventType in list(torEvents): try: torConn.addEventListener(self.registerTorEvent, eventType) except stem.ProtocolError: torEvents.remove(eventType) # provides back the input set minus events we failed to set return sorted(torEvents)
def getCustomOptions(includeValue=False): """ Provides the torrc parameters that differ from their defaults. Arguments: includeValue - provides the current value with results if true, otherwise this just contains the options """ configText = torTools.getConn().getInfo("config-text", "").strip() configLines = configText.split("\n") # removes any duplicates configLines = list(set(configLines)) # The "GETINFO config-text" query only provides options that differ # from Tor's defaults with the exception of its Log and Nickname entries # which, even if undefined, returns "Log notice stdout" as per: # https://trac.torproject.org/projects/tor/ticket/2362 try: configLines.remove("Log notice stdout") except ValueError: pass try: configLines.remove("Nickname %s" % socket.gethostname()) except ValueError: pass if includeValue: return configLines else: return [line[:line.find(" ")] for line in configLines]
def getConfigLocation(): """ Provides the location of the torrc, raising an IOError with the reason if the path can't be determined. """ conn = torTools.getConn() configLocation = conn.getInfo("config-file") if not configLocation: raise IOError("unable to query the torrc location") # checks if this is a relative path, needing the tor pwd to be appended if configLocation[0] != "/": torPid = conn.getMyPid() failureMsg = "querying tor's pwd failed because %s" if not torPid: raise IOError(failureMsg % "we couldn't get the pid") try: # pwdx results are of the form: # 3799: /home/atagar # 5839: No such process results = sysTools.call("pwdx %s" % torPid) if not results: raise IOError(failureMsg % "pwdx didn't return any results") elif results[0].endswith("No such process"): raise IOError(failureMsg % ("pwdx reported no process for pid " + torPid)) elif len(results) != 1 or results.count(" ") != 1: raise IOError(failureMsg % "we got unexpected output from pwdx") else: pwdPath = results[0][results[0].find(" ") + 1:] configLocation = "%s/%s" % (pwdPath, configLocation) except IOError, exc: raise IOError(failureMsg % ("the pwdx call failed: " + str(exc)))
def new_desc_event(self, event): # updates self._titleStats with updated values conn = torTools.getConn() if not conn.isAlive(): return # keep old values myFingerprint = conn.getInfo("fingerprint", None) if not self._titleStats or not myFingerprint or (event and myFingerprint in event.idlist): stats = [] bwRate = conn.getMyBandwidthRate() bwBurst = conn.getMyBandwidthBurst() bwObserved = conn.getMyBandwidthObserved() bwMeasured = conn.getMyBandwidthMeasured() labelInBytes = CONFIG["features.graph.bw.transferInBytes"] if bwRate and bwBurst: bwRateLabel = str_tools.get_size_label(bwRate, 1, False, labelInBytes) bwBurstLabel = str_tools.get_size_label(bwBurst, 1, False, labelInBytes) # if both are using rounded values then strip off the ".0" decimal if ".0" in bwRateLabel and ".0" in bwBurstLabel: bwRateLabel = bwRateLabel.replace(".0", "") bwBurstLabel = bwBurstLabel.replace(".0", "") stats.append("limit: %s/s" % bwRateLabel) stats.append("burst: %s/s" % bwBurstLabel) # Provide the observed bandwidth either if the measured bandwidth isn't # available or if the measured bandwidth is the observed (this happens # if there isn't yet enough bandwidth measurements). if bwObserved and (not bwMeasured or bwMeasured == bwObserved): stats.append("observed: %s/s" % str_tools.get_size_label(bwObserved, 1, False, labelInBytes)) elif bwMeasured: stats.append("measured: %s/s" % str_tools.get_size_label(bwMeasured, 1, False, labelInBytes)) self._titleStats = stats
def saveOptionDescriptions(path): """ Preserves the current configuration descriptors to the given path. This raises an IOError if unable to do so. Arguments: path - location to persist configuration descriptors """ # make dir if the path doesn't already exist baseDir = os.path.dirname(path) if not os.path.exists(baseDir): os.makedirs(baseDir) outputFile = open(path, "w") CONFIG_DESCRIPTIONS_LOCK.acquire() sortedOptions = CONFIG_DESCRIPTIONS.keys() sortedOptions.sort() torVersion = torTools.getConn().getInfo("version", "") outputFile.write("Tor Version %s\n" % torVersion) for i in range(len(sortedOptions)): option = sortedOptions[i] manEntry = getConfigDescription(option) outputFile.write("%s\nindex: %i\n%s\n%s\n%s\n" % (OPTION_CATEGORY_STR[manEntry.category], manEntry.index, option, manEntry.argUsage, manEntry.description)) if i != len(sortedOptions) - 1: outputFile.write(PERSIST_ENTRY_DIVIDER) outputFile.close() CONFIG_DESCRIPTIONS_LOCK.release()
def __init__(self): graphPanel.GraphStats.__init__(self) # listens for tor reload (sighup) events which can reset the ports tor uses conn = torTools.getConn() self.orPort, self.dirPort, self.controlPort = "0", "0", "0" self.resetListener(conn, torTools.State.INIT) # initialize port values conn.addStatusListener(self.resetListener)
def isClientsAllowed(self): """ True if client connections are permissable, false otherwise. """ conn = torTools.getConn() return "Guard" in conn.getMyFlags([]) or conn.getOption( "BridgeRelay", None) == "1"
def draw(self, panel, width, height): # line of the graph's x-axis labeling labelingLine = graphPanel.GraphStats.getContentHeight( self) + panel.graphHeight - 2 # if display is narrow, overwrites x-axis labels with avg / total stats if width <= COLLAPSE_WIDTH: # clears line panel.addstr(labelingLine, 0, " " * width) graphCol = min((width - 10) / 2, self.maxCol) primaryFooter = "%s, %s" % (self._getAvgLabel(True), self._getTotalLabel(True)) secondaryFooter = "%s, %s" % (self._getAvgLabel(False), self._getTotalLabel(False)) panel.addstr(labelingLine, 1, primaryFooter, uiTools.getColor(self.getColor(True))) panel.addstr(labelingLine, graphCol + 6, secondaryFooter, uiTools.getColor(self.getColor(False))) # provides accounting stats if enabled if self.isAccounting: if torTools.getConn().isAlive(): status = self.accountingInfo["status"] hibernateColor = "green" if status == "soft": hibernateColor = "yellow" elif status == "hard": hibernateColor = "red" elif status == "": # failed to be queried status, hibernateColor = "unknown", "red" panel.addfstr( labelingLine + 2, 0, "<b>Accounting (<%s>%s</%s>)</b>" % (hibernateColor, status, hibernateColor)) resetTime = self.accountingInfo["resetTime"] if not resetTime: resetTime = "unknown" panel.addstr(labelingLine + 2, 35, "Time to reset: %s" % resetTime) used, total = self.accountingInfo["read"], self.accountingInfo[ "readLimit"] if used and total: panel.addstr(labelingLine + 3, 2, "%s / %s" % (used, total), uiTools.getColor(self.getColor(True))) used, total = self.accountingInfo[ "written"], self.accountingInfo["writtenLimit"] if used and total: panel.addstr(labelingLine + 3, 37, "%s / %s" % (used, total), uiTools.getColor(self.getColor(False))) else: panel.addfstr(labelingLine + 2, 0, "<b>Accounting:</b> Connection Closed...")
def __init__(self, stdscr, startTime, config = None): panel.Panel.__init__(self, stdscr, "header", 0) threading.Thread.__init__(self) self.setDaemon(True) self._config = dict(DEFAULT_CONFIG) if config: config.update(self._config) self._isTorConnected = torTools.getConn().isAlive() self._lastUpdate = -1 # time the content was last revised self._halt = False # terminates thread if true self._cond = threading.Condition() # used for pausing the thread # Time when the panel was paused or tor was stopped. This is used to # freeze the uptime statistic (uptime increments normally when None). self._haltTime = None # The last arm cpu usage sampling taken. This is a tuple of the form: # (total arm cpu time, sampling timestamp) # # The initial cpu total should be zero. However, at startup the cpu time # in practice is often greater than the real time causing the initially # reported cpu usage to be over 100% (which shouldn't be possible on # single core systems). # # Setting the initial cpu total to the value at this panel's init tends to # give smoother results (staying in the same ballpark as the second # sampling) so fudging the numbers this way for now. self._armCpuSampling = (sum(os.times()[:3]), startTime) # Last sampling received from the ResourceTracker, used to detect when it # changes. self._lastResourceFetch = -1 # flag to indicate if we've already given file descriptor warnings self._isFdSixtyPercentWarned = False self._isFdNinetyPercentWarned = False self.vals = {} self.valsLock = threading.RLock() self._update(True) # listens for tor reload (sighup) events torTools.getConn().addStatusListener(self.resetListener)
def __init__(self, stdscr, startTime, config=None): panel.Panel.__init__(self, stdscr, "header", 0) threading.Thread.__init__(self) self.setDaemon(True) self._config = dict(DEFAULT_CONFIG) if config: config.update(self._config) self._isTorConnected = torTools.getConn().isAlive() self._lastUpdate = -1 # time the content was last revised self._halt = False # terminates thread if true self._cond = threading.Condition() # used for pausing the thread # Time when the panel was paused or tor was stopped. This is used to # freeze the uptime statistic (uptime increments normally when None). self._haltTime = None # The last arm cpu usage sampling taken. This is a tuple of the form: # (total arm cpu time, sampling timestamp) # # The initial cpu total should be zero. However, at startup the cpu time # in practice is often greater than the real time causing the initially # reported cpu usage to be over 100% (which shouldn't be possible on # single core systems). # # Setting the initial cpu total to the value at this panel's init tends to # give smoother results (staying in the same ballpark as the second # sampling) so fudging the numbers this way for now. self._armCpuSampling = (sum(os.times()[:3]), startTime) # Last sampling received from the ResourceTracker, used to detect when it # changes. self._lastResourceFetch = -1 # flag to indicate if we've already given file descriptor warnings self._isFdSixtyPercentWarned = False self._isFdNinetyPercentWarned = False self.vals = {} self.valsLock = threading.RLock() self._update(True) # listens for tor reload (sighup) events torTools.getConn().addStatusListener(self.resetListener)
def prompt(self): """ Enables the interpretor, prompting for input until the user enters esc or a blank line. """ self.isInputMode = True panel.CURSES_LOCK.acquire() while self.isInputMode: self.redraw(True) # intercepts input so user can cycle through the history validator = textInput.BasicValidator() validator = textInput.HistoryValidator(list(reversed(self.interpretor.getBacklog())), validator) validator = textInput.TabCompleter(self.inputCompleter.getMatches, validator) xOffset = len(torInterpretor.PROMPT[0]) displayLength = len(self.interpretor.getDisplayContents(PROMPT_LINE)) if displayLength > self.maxY - 1: xOffset += 3 # offset for scrollbar inputLine = min(self.maxY - 1, displayLength) inputFormat = getFormat(torInterpretor.INPUT_FORMAT) input = self.getstr(inputLine, xOffset, "", inputFormat, validator = validator) if input == None: input = "" input, isDone = input.strip(), False if not input: # terminate input when we get a blank line isDone = True else: try: self.interpretor.handleQuery(input) except torInterpretor.InterpretorClosed: # Makes our control connection check if its been closed or not torTools.getConn().isAlive() isDone = True if isDone: self.isInputMode = False self.redraw(True) panel.CURSES_LOCK.release()
def connectManagedInstance(self): """ Attempts to connect to a managed tor instance, raising an IOError if unsuccessful. """ torctlConn, authType, authValue = TorCtl.preauth_connect(controlPort = int(CONFIG["wizard.default"]["Control"])) if not torctlConn: msg = "Unable to start tor, try running \"tor -f %s\" to see the error output" % self.getTorrcPath() raise IOError(msg) if authType == TorCtl.AUTH_TYPE.COOKIE: try: torctlConn.authenticate(authValue) torTools.getConn().init(torctlConn) except Exception, exc: raise IOError("Unable to connect to Tor: %s" % exc)
def __init__(self, builder): CliHeaderPanel.__init__(self, None, time.time()) self.builder = builder self.filled = False self._isTorConnected = torTools.getConn().isAlive() gobject.idle_add(self._fill_entries) gobject.timeout_add(3000, self._timeout_fill_entries)
def getCustomOptions(): """ Provides the set of torrc parameters that differ from their defaults. """ customOptions, conn = set(), torTools.getConn() configTextQuery = conn.getInfo("config-text", "").strip().split("\n") for entry in configTextQuery: customOptions.add(entry[:entry.find(" ")]) return customOptions
def prompt(self): """ Enables the interpretor, prompting for input until the user enters esc or a blank line. """ self.isInputMode = True panel.CURSES_LOCK.acquire() while self.isInputMode: self.redraw(True) # intercepts input so user can cycle through the history validator = textInput.BasicValidator() validator = textInput.HistoryValidator(list(reversed(self.interpretor.getBacklog())), validator) validator = textInput.TabCompleter(self.inputCompleter.getMatches, validator) xOffset = len(torInterpretor.PROMPT[0]) displayLength = len(self.interpretor.getDisplayContents(PROMPT_LINE)) if displayLength > self.maxY - 1: xOffset += 3 # offset for scrollbar inputLine = min(self.maxY - 1, displayLength) inputFormat = getFormat(torInterpretor.INPUT_FORMAT) input = self.getstr(inputLine, xOffset, "", inputFormat, validator = validator) input, isDone = input.strip(), False if not input: # terminate input when we get a blank line isDone = True else: try: self.interpretor.handleQuery(input) except torInterpretor.InterpretorClosed: # Makes our control connection check if its been closed or not torTools.getConn().isAlive() isDone = True if isDone: self.isInputMode = False self.redraw(True) panel.CURSES_LOCK.release()
def getLocale(self, default=None): """ Provides the two letter country code for the IP address' locale. Arguments: default - return value if no locale information is available """ conn = torTools.getConn() return conn.getInfo("ip-to-country/%s" % self.ipAddr, default)
def connectManagedInstance(self): """ Attempts to connect to a managed tor instance, raising an IOError if unsuccessful. """ torctlConn, authType, authValue = TorCtl.preauth_connect( controlPort=int(CONFIG["wizard.default"]["Control"])) if not torctlConn: msg = "Unable to start tor, try running \"tor -f %s\" to see the error output" % self.getTorrcPath( ) raise IOError(msg) if authType == TorCtl.AUTH_TYPE.COOKIE: try: torctlConn.authenticate(authValue) torTools.getConn().init(torctlConn) except Exception, exc: raise IOError("Unable to connect to Tor: %s" % exc)
def __init__(self, builder): CliConnectionPanel.__init__(self, None) self.builder = builder conn = torTools.getConn() torPid = conn.getMyPid() torCmdName = sysTools.getProcessName(torPid, 'tor') connections.getResolver(torCmdName, torPid, 'tor') treeStore = self.builder.get_object('treestore_conn') self._wrappedEntryLines = EntryLines(self._entryLines, treeStore)
def handleKey(self, key): isKeystrokeConsumed = True if key in (ord('n'), ord('N')) and torTools.getConn().isNewnymAvailable(): self.sendNewnym() elif key in (ord('r'), ord('R')) and not self._isTorConnected: torctlConn = None allowPortConnection, allowSocketConnection, _ = starter.allowConnectionTypes( ) if os.path.exists(self._config["startup.interface.socket"] ) and allowSocketConnection: try: torctlConn = torTools.connect_socket( self._config["startup.interface.socket"]) except IOError, exc: if not allowPortConnection: cli.popups.showMsg("Unable to reconnect (%s)" % exc, 3) elif not allowPortConnection: cli.popups.showMsg( "Unable to reconnect (socket '%s' doesn't exist)" % self._config["startup.interface.socket"], 3) if not torctlConn and allowPortConnection: try: ctlAddr, ctlPort = self._config[ "startup.interface.ipAddress"], self._config[ "startup.interface.port"] tmpConn, authType, authValue = TorCtl.TorCtl.preauth_connect( ctlAddr, ctlPort) if authType == TorCtl.TorCtl.AUTH_TYPE.PASSWORD: authValue = cli.popups.inputPrompt( "Controller Password: "******"Reconnected to Tor's control port") cli.popups.showMsg("Tor reconnected", 1) except: # displays notice for the first failed connection attempt if exc.args: cli.popups.showMsg( "Unable to reconnect (%s)" % exc, 3)
def _loadConfigOptions(self): """ Fetches the configuration options available from tor or arm. """ self.confContents = [] self.confImportantContents = [] if self.configType == State.TOR: conn, configOptionLines = torTools.getConn(), [] customOptions = torConfig.getCustomOptions() configOptionQuery = conn.getInfo("config/names") if configOptionQuery: configOptionLines = configOptionQuery.strip().split("\n") for line in configOptionLines: # lines are of the form "<option> <type>[ <documentation>]", like: # UseEntryGuards Boolean # documentation is aparently only in older versions (for instance, # 0.2.1.25) lineComp = line.strip().split(" ") confOption, confType = lineComp[0], lineComp[1] # skips private and virtual entries if not configured to show them if not self._config[ "features.config.state.showPrivateOptions"] and confOption.startswith( "__"): continue elif not self._config[ "features.config.state.showVirtualOptions"] and confType == "Virtual": continue self.confContents.append( ConfigEntry(confOption, confType, not confOption in customOptions)) elif self.configType == State.ARM: # loaded via the conf utility armConf = conf.getConfig("arm") for key in armConf.getKeys(): pass # TODO: implement # mirror listing with only the important configuration options self.confImportantContents = [] for entry in self.confContents: if torConfig.isImportant(entry.get(Field.OPTION)): self.confImportantContents.append(entry) # if there aren't any important options then show everything if not self.confImportantContents: self.confImportantContents = self.confContents self.setSortOrder() # initial sorting of the contents
def __init__(self, stdscr, configType, config=None): panel.Panel.__init__(self, stdscr, "configState", 0) self.sortOrdering = DEFAULT_SORT_ORDER self._config = dict(DEFAULT_CONFIG) if config: config.update( self._config, { "features.config.selectionDetails.height": 0, "features.config.state.colWidth.option": 5, "features.config.state.colWidth.value": 5 }) self.sortOrdering = config.getIntCSV("features.config.order", self.sortOrdering, 3, 0, 6) self.configType = configType self.confContents = [] self.scroller = uiTools.Scroller(True) self.valsLock = threading.RLock() if self.configType == TOR_STATE: conn = torTools.getConn() customOptions = torConfig.getCustomOptions() configOptionLines = conn.getInfo("config/names", "").strip().split("\n") for line in configOptionLines: # lines are of the form "<option> <type>", like: # UseEntryGuards Boolean confOption, confType = line.strip().split(" ", 1) # skips private and virtual entries if not set to show them if not self._config[ "features.config.state.showPrivateOptions"] and confOption.startswith( "__"): continue elif not self._config[ "features.config.state.showVirtualOptions"] and confType == "Virtual": continue manEntry = torConfig.getConfigDescription(confOption) self.confContents.append( ConfigEntry(confOption, confType, not confOption in customOptions, manEntry)) self.setSortOrder() # initial sorting of the contents elif self.configType == ARM_STATE: # loaded via the conf utility armConf = conf.getConfig("arm") for key in armConf.getKeys(): pass # TODO: implement
def __init__(self, builder): self.builder = builder self._config = dict(DEFAULT_CONFIG) self._lastUpdate = 0 self.lock = RLock() self.msgLog = deque() self.loggedEvents = setEventListening(expandEvents(STARTUP_EVENTS)) torEventBacklog = deque() if self._config["features.log.prepopulate"]: setRunlevels = list( set.intersection(set(self.loggedEvents), set(log.Runlevel.values()))) readLimit = self._config["features.log.prepopulateReadLimit"] addLimit = self._config["cache.logPanel.size"] torEventBacklog = deque( getLogFileEntries(setRunlevels, readLimit, addLimit, self._config)) armRunlevels = [log.DEBUG, log.INFO, log.NOTICE, log.WARN, log.ERR] log.addListeners(armRunlevels, self._register_arm_event) setRunlevels = [] for i in range(len(armRunlevels)): if "ARM_" + log.Runlevel.values()[i] in self.loggedEvents: setRunlevels.append(armRunlevels[i]) armEventBacklog = deque() for level, msg, eventTime in log._getEntries(setRunlevels): theme = gtkTools.Theme() armEventEntry = LogEntry(eventTime, "ARM_" + level, msg, theme.colors[RUNLEVEL_EVENT_COLOR[level]]) armEventBacklog.appendleft(armEventEntry) while armEventBacklog or torEventBacklog: if not armEventBacklog: self.msgLog.append(torEventBacklog.popleft()) elif not torEventBacklog: self.msgLog.append(armEventBacklog.popleft()) elif armEventBacklog[0].timestamp < torEventBacklog[0].timestamp: self.msgLog.append(torEventBacklog.popleft()) else: self.msgLog.append(armEventBacklog.popleft()) conn = torTools.getConn() conn.addEventListener(TorEventObserver(self.register_event)) conn.addTorCtlListener(self._register_torctl_event) gobject.idle_add(self.fill_log)