def __init__(self, processName, processPid = "", resolveRate = None, handle = None): """ Initializes a new resolver daemon. When no longer needed it's suggested that this is stopped. Arguments: processName - name of the process being resolved processPid - pid of the process being resolved resolveRate - time between resolving connections (in seconds, None if chosen dynamically) handle - name used to query this resolver, this is the processName if undefined """ threading.Thread.__init__(self) self.setDaemon(True) self.processName = processName self.processPid = processPid self.resolveRate = resolveRate self.handle = handle if handle else processName self.defaultRate = CONFIG["queries.connections.minRate"] self.lastLookup = -1 self.overwriteResolver = None self.defaultResolver = Resolver.PROC osType = os.uname()[0] self.resolverOptions = getSystemResolvers(osType) log.log(CONFIG["log.connResolverOptions"], "Operating System: %s, Connection Resolvers: %s" % (osType, ", ".join(self.resolverOptions))) # sets the default resolver to be the first found in the system's PATH # (left as netstat if none are found) for resolver in self.resolverOptions: # Resolver strings correspond to their command with the exception of bsd # resolvers. resolverCmd = resolver.replace(" (bsd)", "") if resolver == Resolver.PROC or sysTools.isAvailable(resolverCmd): self.defaultResolver = resolver break self._connections = [] # connection cache (latest results) self._resolutionCounter = 0 # number of successful connection resolutions self._isPaused = False self._halt = False # terminates thread if true self._cond = threading.Condition() # used for pausing the thread self._subsiquentFailures = 0 # number of failed resolutions with the default in a row self._resolverBlacklist = [] # resolvers that have failed to resolve # Number of sequential times the threshold rate's been too low. This is to # avoid having stray spikes up the rate. self._rateThresholdBroken = 0
def __init__(self, processName, processPid="", resolveRate=None): """ Initializes a new resolver daemon. When no longer needed it's suggested that this is stopped. Arguments: processName - name of the process being resolved processPid - pid of the process being resolved resolveRate - time between resolving connections (in seconds, None if chosen dynamically) """ threading.Thread.__init__(self) self.setDaemon(True) self.processName = processName self.processPid = processPid self.resolveRate = resolveRate self.defaultRate = CONFIG["queries.connections.minRate"] self.lastLookup = -1 self.overwriteResolver = None self.defaultResolver = CMD_NETSTAT osType = os.uname()[0] self.resolverOptions = getSystemResolvers(osType) resolverLabels = ", ".join( [CMD_STR[option] for option in self.resolverOptions]) log.log( CONFIG["log.connResolverOptions"], "Operating System: %s, Connection Resolvers: %s" % (osType, resolverLabels)) # sets the default resolver to be the first found in the system's PATH # (left as netstat if none are found) for resolver in self.resolverOptions: if sysTools.isAvailable(CMD_STR[resolver]): self.defaultResolver = resolver break self._connections = [] # connection cache (latest results) self._isPaused = False self._halt = False # terminates thread if true self._cond = threading.Condition() # used for pausing the thread self._subsiquentFailures = 0 # number of failed resolutions with the default in a row self._resolverBlacklist = [] # resolvers that have failed to resolve # Number of sequential times the threshold rate's been too low. This is to # avoid having stray spikes up the rate. self._rateThresholdBroken = 0
def __init__(self, processName, processPid = "", resolveRate = None): """ Initializes a new resolver daemon. When no longer needed it's suggested that this is stopped. Arguments: processName - name of the process being resolved processPid - pid of the process being resolved resolveRate - time between resolving connections (in seconds, None if chosen dynamically) """ threading.Thread.__init__(self) self.setDaemon(True) self.processName = processName self.processPid = processPid self.resolveRate = resolveRate self.defaultRate = CONFIG["queries.connections.minRate"] self.lastLookup = -1 self.overwriteResolver = None self.defaultResolver = CMD_NETSTAT osType = os.uname()[0] self.resolverOptions = getSystemResolvers(osType) resolverLabels = ", ".join([CMD_STR[option] for option in self.resolverOptions]) log.log(CONFIG["log.connResolverOptions"], "Operating System: %s, Connection Resolvers: %s" % (osType, resolverLabels)) # sets the default resolver to be the first found in the system's PATH # (left as netstat if none are found) for resolver in self.resolverOptions: if sysTools.isAvailable(CMD_STR[resolver]): self.defaultResolver = resolver break self._connections = [] # connection cache (latest results) self._isPaused = False self._halt = False # terminates thread if true self._cond = threading.Condition() # used for pausing the thread self._subsiquentFailures = 0 # number of failed resolutions with the default in a row self._resolverBlacklist = [] # resolvers that have failed to resolve # Number of sequential times the threshold rate's been too low. This is to # avoid having stray spikes up the rate. self._rateThresholdBroken = 0
def showWizard(): """ Provides a series of prompts, allowing the user to spawn a customized tor instance. """ if not sysTools.isAvailable("tor"): msg = "Unable to run the setup wizard. Is tor installed?" log.log(log.WARN, msg) return # gets tor's version torVersion = None try: versionQuery = sysTools.call("tor --version") for line in versionQuery: if line.startswith("Tor version "): torVersion = torTools.parseVersion(line.split(" ")[2]) break except IOError, exc: log.log(log.INFO, "'tor --version' query failed: %s" % exc)
controller = cli.controller.getController() manager = controller.getTorManager() relaySelection = RelayType.RESUME if manager.isTorrcAvailable( ) else RelayType.RELAY # excludes options that are either disabled or for a future tor version disabledOpt = list(CONFIG["wizard.disabled"]) for opt, optVersion in VERSION_REQUIREMENTS.items(): if not torVersion or not torTools.isVersion( torVersion, torTools.parseVersion(optVersion)): disabledOpt.append(opt) # the port forwarding option would only work if tor-fw-helper is in the path if not Options.PORTFORWARD in disabledOpt: if not sysTools.isAvailable("tor-fw-helper"): disabledOpt.append(Options.PORTFORWARD) # If we haven't run 'resources/torrcOverride/override.py --init' or lack # permissions then we aren't able to deal with the system wide tor instance. # Also drop the option if we aren't installed since override.py won't be at # the expected path. if not os.path.exists(os.path.dirname( SYSTEM_DROP_PATH)) or not os.path.exists(OVERRIDE_SCRIPT): disabledOpt.append(Options.SYSTEM) # TODO: The STARTUP option is currently disabled in the 'settings.cfg', and I # don't currently have plans to implement it (it would be a big pita, and the # tor deb already handles it). *If* it is implemented then I'd limit support # for the option to Debian and Ubuntu to start with, via the following...
# remembers the last selection made on the type prompt page controller = cli.controller.getController() manager = controller.getTorManager() relaySelection = RelayType.RESUME if manager.isTorrcAvailable() else RelayType.RELAY # excludes options that are either disabled or for a future tor version disabledOpt = list(CONFIG["wizard.disabled"]) for opt, optVersion in VERSION_REQUIREMENTS.items(): if not torVersion or not torTools.isVersion(torVersion, torTools.parseVersion(optVersion)): disabledOpt.append(opt) # the port forwarding option would only work if tor-fw-helper is in the path if not Options.PORTFORWARD in disabledOpt: if not sysTools.isAvailable("tor-fw-helper"): disabledOpt.append(Options.PORTFORWARD) # If we haven't run 'resources/torrcOverride/override.py --init' or lack # permissions then we aren't able to deal with the system wide tor instance. # Also drop the option if we aren't installed since override.py won't be at # the expected path. if not os.path.exists(os.path.dirname(SYSTEM_DROP_PATH)) or not os.path.exists(OVERRIDE_SCRIPT): disabledOpt.append(Options.SYSTEM) # TODO: The STARTUP option is currently disabled in the 'settings.cfg', and I # don't currently have plans to implement it (it would be a big pita, and the # tor deb already handles it). *If* it is implemented then I'd limit support # for the option to Debian and Ubuntu to start with, via the following... # Running at startup is currently only supported for Debian and Ubuntu.
def __init__(self, torPid): self.fdFile, self.fdConn, self.fdMisc = [], [], [] self.fdLimit = 0 self.errorMsg = "" self.scroll = 0 try: ulimitCall = None # retrieves list of open files, options are: # n = no dns lookups, p = by pid, -F = show fields (L = login name, n = opened files) # TODO: better rewrite to take advantage of sysTools if not sysTools.isAvailable("lsof"): raise Exception("error: lsof is unavailable") results = sysTools.call("lsof -np %s -F Ln" % torPid) # if we didn't get any results then tor's probably closed (keep defaults) if len(results) == 0: return torUser = results[1][1:] results = results[2:] # skip first couple lines (pid listing and user) # splits descriptors into buckets according to their type descriptors = [entry[1:].strip() for entry in results] # strips off first character (always an 'n') # checks if read failed due to permission issues isPermissionDenied = True for desc in descriptors: if "Permission denied" not in desc: isPermissionDenied = False break if isPermissionDenied: raise Exception("lsof error: Permission denied") for desc in descriptors: if os.path.exists(desc): self.fdFile.append(desc) elif desc[0] != "/" and ":" in desc: self.fdConn.append(desc) else: self.fdMisc.append(desc) self.fdFile.sort() self.fdConn.sort() self.fdMisc.sort() # This is guessing the open file limit. Unfortunately there's no way # (other than "/usr/proc/bin/pfiles pid | grep rlimit" under Solaris) to # get the file descriptor limit for an arbitrary process. What we need is # for the tor process to provide the return value of the "getrlimit" # function via a GET_INFO call. if torUser.strip() == "debian-tor": # probably loaded via /etc/init.d/tor which changes descriptor limit self.fdLimit = 8192 else: # uses ulimit to estimate (-H is for hard limit, which is what tor uses) ulimitCall = os.popen("ulimit -Hn 2> /dev/null") results = ulimitCall.readlines() if len(results) == 0: raise Exception("error: ulimit is unavailable") self.fdLimit = int(results[0]) # can't use sysTools for this call because ulimit isn't in the path... # so how the **** am I to detect if it's available! #if not sysTools.isAvailable("ulimit"): raise Exception("error: ulimit is unavailable") #results = sysTools.call("ulimit -Hn") #if len(results) == 0: raise Exception("error: ulimit call failed") #self.fdLimit = int(results[0]) except Exception, exc: # problem arose in calling or parsing lsof or ulimit calls self.errorMsg = str(exc)
def __init__(self, torPid): self.fdFile, self.fdConn, self.fdMisc = [], [], [] self.fdLimit = 0 self.errorMsg = "" self.scroll = 0 try: ulimitCall = None # retrieves list of open files, options are: # n = no dns lookups, p = by pid, -F = show fields (L = login name, n = opened files) # TODO: better rewrite to take advantage of sysTools if not sysTools.isAvailable("lsof"): raise Exception("error: lsof is unavailable") results = sysTools.call("lsof -np %s -F Ln" % torPid) # if we didn't get any results then tor's probably closed (keep defaults) if len(results) == 0: return torUser = results[1][1:] results = results[ 2:] # skip first couple lines (pid listing and user) # splits descriptors into buckets according to their type descriptors = [entry[1:].strip() for entry in results ] # strips off first character (always an 'n') # checks if read failed due to permission issues isPermissionDenied = True for desc in descriptors: if "Permission denied" not in desc: isPermissionDenied = False break if isPermissionDenied: raise Exception("lsof error: Permission denied") for desc in descriptors: if os.path.exists(desc): self.fdFile.append(desc) elif desc[0] != "/" and ":" in desc: self.fdConn.append(desc) else: self.fdMisc.append(desc) self.fdFile.sort() self.fdConn.sort() self.fdMisc.sort() # This is guessing the open file limit. Unfortunately there's no way # (other than "/usr/proc/bin/pfiles pid | grep rlimit" under Solaris) to # get the file descriptor limit for an arbitrary process. What we need is # for the tor process to provide the return value of the "getrlimit" # function via a GET_INFO call. if torUser.strip() == "debian-tor": # probably loaded via /etc/init.d/tor which changes descriptor limit self.fdLimit = 8192 else: # uses ulimit to estimate (-H is for hard limit, which is what tor uses) ulimitCall = os.popen("ulimit -Hn 2> /dev/null") results = ulimitCall.readlines() if len(results) == 0: raise Exception("error: ulimit is unavailable") self.fdLimit = int(results[0]) # can't use sysTools for this call because ulimit isn't in the path... # so how the **** am I to detect if it's available! #if not sysTools.isAvailable("ulimit"): raise Exception("error: ulimit is unavailable") #results = sysTools.call("ulimit -Hn") #if len(results) == 0: raise Exception("error: ulimit call failed") #self.fdLimit = int(results[0]) except Exception, exc: # problem arose in calling or parsing lsof or ulimit calls self.errorMsg = str(exc)
def reload(self, issueSighup = False): """ This resets tor (sending a RELOAD signal to the control port) causing tor's internal state to be reset and the torrc reloaded. This can either be done by... - the controller via a RELOAD signal (default and suggested) conn.send_signal("RELOAD") - system reload signal (hup) pkill -sighup tor The later isn't really useful unless there's some reason the RELOAD signal won't do the trick. Both methods raise an IOError in case of failure. Arguments: issueSighup - issues a sighup rather than a controller RELOAD signal """ self.connLock.acquire() raisedException = None if self.isAlive(): if not issueSighup: try: self.conn.send_signal("RELOAD") self._cachedParam = dict([(arg, "") for arg in CACHE_ARGS]) self._cachedConf = {} except Exception, exc: # new torrc parameters caused an error (tor's likely shut down) # BUG: this doesn't work - torrc errors still cause TorCtl to crash... :( # http://bugs.noreply.org/flyspray/index.php?do=details&id=1329 raisedException = IOError(str(exc)) else: try: # Redirects stderr to stdout so we can check error status (output # should be empty if successful). Example error: # pkill: 5592 - Operation not permitted # # note that this may provide multiple errors, even if successful, # hence this: # - only provide an error if Tor fails to log a sighup # - provide the error message associated with the tor pid (others # would be a red herring) if not sysTools.isAvailable("pkill"): raise IOError("pkill command is unavailable") self._isReset = False pkillCall = os.popen("pkill -sighup ^tor$ 2> /dev/stdout") pkillOutput = pkillCall.readlines() pkillCall.close() # Give the sighupTracker a moment to detect the sighup signal. This # is, of course, a possible concurrency bug. However I'm not sure # of a better method for blocking on this... waitStart = time.time() while time.time() - waitStart < 1: time.sleep(0.1) if self._isReset: break if not self._isReset: errorLine, torPid = "", self.getMyPid() if torPid: for line in pkillOutput: if line.startswith("pkill: %s - " % torPid): errorLine = line break if errorLine: raise IOError(" ".join(errorLine.split()[3:])) else: raise IOError("failed silently") self._cachedParam = dict([(arg, "") for arg in CACHE_ARGS]) self._cachedConf = {} except IOError, exc: raisedException = exc