From 5c3e5cf17ece5f3f7257a1abf442563fe337e6ed Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sat, 4 Dec 2010 17:35:25 +0100 Subject: [PATCH 1/5] Add sockstat as another connection resolver. --- src/util/connections.py | 20 +++++++++++++++----- 1 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/util/connections.py b/src/util/connections.py index 04599ee..5e56129 100644 --- a/src/util/connections.py +++ b/src/util/connections.py @@ -18,8 +18,8 @@ import threading from util import log, sysTools # enums for connection resolution utilities -CMD_NETSTAT, CMD_SS, CMD_LSOF = range(1, 4) -CMD_STR = {CMD_NETSTAT: "netstat", CMD_SS: "ss", CMD_LSOF: "lsof"} +CMD_NETSTAT, CMD_SS, CMD_LSOF, CMD_SOCKSTAT = range(1, 5) +CMD_STR = {CMD_NETSTAT: "netstat", CMD_SS: "ss", CMD_LSOF: "lsof", CMD_SOCKSTAT: "sockstat"} # 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 @@ -46,6 +46,11 @@ RUN_SS = "ss -np | grep \"\\\"%s\\\",%s\"" # tor 9912 atagar 20u IPv4 33453 TCP 127.0.0.1:9051->127.0.0.1:53308 RUN_LSOF = "lsof -nPi | grep \"%s\s*%s.*(ESTABLISHED)\"" +# c = show only established connections +# output: +# _tor tor 2743 17 tcp4 10.0.0.2:9050 10.0.0.1:49948 +RUN_SOCKSTAT = "sockstat -4c | awk '$2 == \"%s\" {print $6 \" \" $7}'" + RESOLVERS = [] # connection resolvers available via the singleton constructor RESOLVER_FAILURE_TOLERANCE = 3 # number of subsequent failures before moving on to another resolver RESOLVER_SERIAL_FAILURE_MSG = "Querying connections with %s failed, trying %s" @@ -78,6 +83,7 @@ def getConnections(resolutionCmd, processName, processPid = ""): if resolutionCmd == CMD_NETSTAT: cmd = RUN_NETSTAT % (processPid, processName) elif resolutionCmd == CMD_SS: cmd = RUN_SS % (processName, processPid) + elif resolutionCmd == CMD_SOCKSTAT: cmd = RUN_SOCKSTAT % (processName) else: cmd = RUN_LSOF % (processName, processPid) # raises an IOError if the command fails or isn't available @@ -93,6 +99,9 @@ def getConnections(resolutionCmd, processName, processPid = ""): if resolutionCmd == CMD_NETSTAT or resolutionCmd == CMD_SS: localIp, localPort = comp[3].split(":") foreignIp, foreignPort = comp[4].split(":") + elif resolutionCmd == CMD_SOCKSTAT: + localIp, localPort = comp[0].split(":") + foreignIp, foreignPort = comp[1].split(":") else: local, foreign = comp[8].split("->") localIp, localPort = local.split(":") @@ -149,7 +158,7 @@ def getResolver(processName, processPid = ""): def test(): # quick method for testing connection resolution - userInput = raw_input("Enter query ( PROCESS_NAME [PID]): ").split() + userInput = raw_input("Enter query ( PROCESS_NAME [PID]): ").split() # checks if there's enough arguments if len(userInput) == 0: sys.exit(0) @@ -162,6 +171,7 @@ def test(): if userInput[0] == "ss": userInput[0] = CMD_SS elif userInput[0] == "netstat": userInput[0] = CMD_NETSTAT elif userInput[0] == "lsof": userInput[0] = CMD_LSOF + elif userInput[0] == "sockstat": userInput[0] = CMD_SOCKSTAT else: print "unrecognized type of resolver: %s" % userInput[2] sys.exit(1) @@ -245,7 +255,7 @@ class ConnectionResolver(threading.Thread): # sets the default resolver to be the first found in the system's PATH # (left as netstat if none are found) - for resolver in [CMD_NETSTAT, CMD_SS, CMD_LSOF]: + for resolver in [CMD_NETSTAT, CMD_SS, CMD_LSOF, CMD_SOCKSTAT]: if sysTools.isAvailable(CMD_STR[resolver]): self.defaultResolver = resolver break @@ -320,7 +330,7 @@ class ConnectionResolver(threading.Thread): # pick another (non-blacklisted) resolver newResolver = None - for r in [CMD_NETSTAT, CMD_SS, CMD_LSOF]: + for r in [CMD_NETSTAT, CMD_SS, CMD_LSOF, CMD_SOCKSTAT]: if not r in self._resolverBlacklist: newResolver = r break -- 1.7.3.2 From 8f738b0e3f00215842653691c2fbe4732db6cfd7 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sat, 4 Dec 2010 17:36:53 +0100 Subject: [PATCH 2/5] Add pgrep as another way to get the tor pid. --- src/util/torTools.py | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/src/util/torTools.py b/src/util/torTools.py index d18869b..077c2e1 100644 --- a/src/util/torTools.py +++ b/src/util/torTools.py @@ -96,6 +96,7 @@ def getPid(controlPort=9051, pidFilePath=None): 2. "pidof tor" 3. "netstat -npl | grep 127.0.0.1:%s" % 4. "ps -o pid -C tor" + 5. "pgrep tor" If pidof or ps provide multiple tor instances then their results are discarded (since only netstat can differentiate using the control port). This @@ -150,6 +151,16 @@ def getPid(controlPort=9051, pidFilePath=None): if pid.isdigit(): return pid except IOError: pass + # attempts to resolve using pgrep, failing if: + # - tor is running under a different name + # - there are multiple instances of tor + try: + results = sysTools.call("pgrep tor") + if len(results) == 1 and len(results[0].split()) == 1: + pid = results[0].strip() + if pid.isdigit(): return pid + except IOError: pass + return None def getConn(): -- 1.7.3.2 From f99cc12b09faeb8a8567d083f030b32f0c0933a9 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sat, 4 Dec 2010 18:11:42 +0100 Subject: [PATCH 3/5] When using sockstat, let awk also filter for the pid. --- src/util/connections.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util/connections.py b/src/util/connections.py index 5e56129..0773c33 100644 --- a/src/util/connections.py +++ b/src/util/connections.py @@ -5,6 +5,7 @@ utilities: - netstat netstat -npt | grep / - ss ss -p | grep "\"\"," - lsof lsof -nPi | grep "\s*.*(ESTABLISHED)" +- sockstat sockstat -4c | awk '($2 == && $3 == ) {print $6 " " $7}' all queries dump its stderr (directing it to /dev/null). Unfortunately FreeBSD lacks support for the needed netstat flags and has a completely different @@ -47,9 +48,10 @@ RUN_SS = "ss -np | grep \"\\\"%s\\\",%s\"" RUN_LSOF = "lsof -nPi | grep \"%s\s*%s.*(ESTABLISHED)\"" # c = show only established connections +# 4 = show only IPv4 addresses # output: # _tor tor 2743 17 tcp4 10.0.0.2:9050 10.0.0.1:49948 -RUN_SOCKSTAT = "sockstat -4c | awk '$2 == \"%s\" {print $6 \" \" $7}'" +RUN_SOCKSTAT = "sockstat -4c | awk '($2 == \"%s\" && $3 == %s) {print $6 \" \" $7}'" RESOLVERS = [] # connection resolvers available via the singleton constructor RESOLVER_FAILURE_TOLERANCE = 3 # number of subsequent failures before moving on to another resolver @@ -83,7 +85,7 @@ def getConnections(resolutionCmd, processName, processPid = ""): if resolutionCmd == CMD_NETSTAT: cmd = RUN_NETSTAT % (processPid, processName) elif resolutionCmd == CMD_SS: cmd = RUN_SS % (processName, processPid) - elif resolutionCmd == CMD_SOCKSTAT: cmd = RUN_SOCKSTAT % (processName) + elif resolutionCmd == CMD_SOCKSTAT: cmd = RUN_SOCKSTAT % (processName, processPid) else: cmd = RUN_LSOF % (processName, processPid) # raises an IOError if the command fails or isn't available -- 1.7.3.2 From 6a11fdc10da9ef0dfcaac5959db8bfa9783e2fb9 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sat, 4 Dec 2010 18:12:55 +0100 Subject: [PATCH 4/5] Remove no-longer-relevant comment about FreeBSD lacking netstat flags. --- src/util/connections.py | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/src/util/connections.py b/src/util/connections.py index 0773c33..a7373cd 100644 --- a/src/util/connections.py +++ b/src/util/connections.py @@ -7,9 +7,7 @@ utilities: - lsof lsof -nPi | grep "\s*.*(ESTABLISHED)" - sockstat sockstat -4c | awk '($2 == && $3 == ) {print $6 " " $7}' -all queries dump its stderr (directing it to /dev/null). Unfortunately FreeBSD -lacks support for the needed netstat flags and has a completely different -program for 'ss', so this is quite likely to fail there. +all queries dump its stderr (directing it to /dev/null). """ import sys -- 1.7.3.2 From 8821f52c4961a07bb6c76e331a13af001be26026 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sat, 4 Dec 2010 18:19:53 +0100 Subject: [PATCH 5/5] Register sockstat as 'Resolver Util' --- src/interface/controller.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/interface/controller.py b/src/interface/controller.py index d3fe1d6..1045dfc 100644 --- a/src/interface/controller.py +++ b/src/interface/controller.py @@ -1401,7 +1401,7 @@ def drawTorMonitor(stdscr, startTime, loggedEvents, isBlindMode): panels["conn"].sortConnections() elif page == 1 and (key == ord('u') or key == ord('U')): # provides menu to pick identification resolving utility - optionTypes = [None, connections.CMD_NETSTAT, connections.CMD_SS, connections.CMD_LSOF] + optionTypes = [None, connections.CMD_NETSTAT, connections.CMD_SS, connections.CMD_LSOF, connections.CMD_SOCKSTAT] options = ["auto"] + [connections.CMD_STR[util] for util in optionTypes[1:]] initialSelection = connections.getResolver("tor").overwriteResolver # enums correspond to indices -- 1.7.3.2