[tor-commits] [nyx/master] Retrieve connection information despite DisableDebuggerAttachment
atagar at torproject.org
atagar at torproject.org
Mon Feb 1 04:20:53 UTC 2016
commit 53fbe024898e96d9564ba982448f5c048acd0be0
Author: Damian Johnson <atagar at torproject.org>
Date: Sun Jan 31 20:08:40 2016 -0800
Retrieve connection information despite DisableDebuggerAttachment
For years tor's DisableDebuggerAttachment has been the bane of nyx. The feature
wasn't intended to effect us, but screws with proc permissions breaking every
connection resolver we have...
https://trac.torproject.org/projects/tor/ticket/15259
Currently we read /proc/<pid>/fd to get connection inodes, then use that
determine what from /proc/net/tcp belongs to our process. Tor's
DisableDebuggerAttachment breaks that by making /proc/<pid>/fd only readable by
root. However, even without knowing the inodes we can identify tor related
connections by if they go to a relay or our ORPort/DirPort/ControlPort. This is
exactly what nyx already does to identify a connection's type.
TL;DR. Connection resolution works all the time now. Only drawbacks are...
* Connection resolution can't work until we have consensus information. This
can take a few seconds so we don't show connections right away.
* When resolving this way we can't show client or exit connections. Nyx
already scrubbed these so it's not a big loss, but means we now don't even
show that they exist.
If the user sets 'DisableDebuggerAttachment 0' in their torrc we still do
connection resolution via the normal method.
---
nyx/controller.py | 33 +++------------------------------
nyx/util/__init__.py | 4 ++++
nyx/util/tracker.py | 37 ++++++++++++++++++++++++++++++++++---
3 files changed, 41 insertions(+), 33 deletions(-)
diff --git a/nyx/controller.py b/nyx/controller.py
index 7ff6e53..ee647a7 100644
--- a/nyx/controller.py
+++ b/nyx/controller.py
@@ -115,37 +115,10 @@ def init_controller(stdscr, start_time):
if CONFIG['features.panels.show.connection']:
page_panels.append([nyx.connection_panel.ConnectionPanel(stdscr)])
- # The DisableDebuggerAttachment will prevent our connection panel from really
- # functioning. It'll have circuits, but little else. If this is the case then
- # notify the user and tell them what they can do to fix it.
-
controller = tor_controller()
-
- if controller.get_conf('DisableDebuggerAttachment', None) == '1':
- log.notice("Tor is preventing system utilities like netstat and lsof from working. This means that nyx can't provide you with connection information. You can change this by adding 'DisableDebuggerAttachment 0' to your torrc and restarting tor. For more information see...\nhttps://trac.torproject.org/3313")
- nyx.util.tracker.get_connection_tracker().set_paused(True)
- else:
- # Configures connection resoultions. This is paused/unpaused according to
- # if Tor's connected or not.
-
- controller.add_status_listener(conn_reset_listener)
-
- tor_pid = controller.get_pid(None)
-
- if tor_pid:
- # use the tor pid to help narrow connection results
- tor_cmd = system.name_by_pid(tor_pid)
-
- if tor_cmd is None:
- tor_cmd = 'tor'
-
- resolver = nyx.util.tracker.get_connection_tracker()
- log.info('Operating System: %s, Connection Resolvers: %s' % (os.uname()[0], ', '.join(resolver._resolvers)))
- else:
- # constructs singleton resolver and, if tor isn't connected, initizes
- # it to be paused
-
- nyx.util.tracker.get_connection_tracker().set_paused(not controller.is_alive())
+ controller.add_status_listener(conn_reset_listener)
+ resolver = nyx.util.tracker.get_connection_tracker()
+ log.info('Operating System: %s, Connection Resolvers: %s' % (os.uname()[0], ', '.join(resolver._resolvers)))
# third page: config
diff --git a/nyx/util/__init__.py b/nyx/util/__init__.py
index 0f53ab6..a7b2e8d 100644
--- a/nyx/util/__init__.py
+++ b/nyx/util/__init__.py
@@ -31,6 +31,10 @@ TESTING = False
stem.control.CACHEABLE_GETINFO_PARAMS = list(stem.control.CACHEABLE_GETINFO_PARAMS) + ['address']
+# disable trace level messages about cache hits
+
+stem.control.LOG_CACHE_FETCHES = False
+
try:
uses_settings = stem.util.conf.uses_settings('nyx', os.path.join(BASE_DIR, 'config'), lazy_load = False)
except IOError as exc:
diff --git a/nyx/util/tracker.py b/nyx/util/tracker.py
index ffd24c9..f218630 100644
--- a/nyx/util/tracker.py
+++ b/nyx/util/tracker.py
@@ -52,7 +52,7 @@ import threading
import stem.control
-from stem.util import conf, connection, proc, str_tools, system
+from stem.util import conf, connection, enum, proc, str_tools, system
from nyx.util import log, tor_controller
@@ -67,6 +67,10 @@ 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.
@@ -476,7 +480,6 @@ class ConnectionTracker(Daemon):
self._connections = []
self._start_times = {} # connection => (unix_timestamp, is_legacy)
- self._resolvers = connection.system_resolvers()
self._custom_resolver = None
self._is_first_run = True
@@ -486,6 +489,15 @@ class ConnectionTracker(Daemon):
self._failure_count = 0
self._rate_too_low_count = 0
+ # If 'DisableDebuggerAttachment 0' is set we can do normal connection
+ # resolution. Otherwise connection resolution by inference is the only game
+ # in town.
+
+ if tor_controller().get_conf('DisableDebuggerAttachment', None) == '0':
+ self._resolvers = connection.system_resolvers()
+ else:
+ self._resolvers = [CustomResolver.INFERENCE]
+
def _task(self, process_pid, process_name):
if self._custom_resolver:
resolver = self._custom_resolver
@@ -500,7 +512,26 @@ class ConnectionTracker(Daemon):
start_time = time.time()
new_connections, new_start_times = [], {}
- for conn in connection.get_connections(resolver, process_pid = process_pid, process_name = process_name):
+ if resolver == CustomResolver.INFERENCE:
+ # provide connections going to a relay or one of our tor ports
+
+ connections = []
+ controller = tor_controller()
+ consensus_tracker = get_consensus_tracker()
+
+ for conn in proc.connections(user = controller.get_user(None)):
+ if conn.remote_port in consensus_tracker.get_relay_fingerprints(conn.remote_address):
+ connections.append(conn) # outbound to another relay
+ elif conn.local_port in controller.get_ports(stem.control.Listener.OR, []):
+ connections.append(conn) # inbound to our ORPort
+ elif conn.local_port in controller.get_ports(stem.control.Listener.DIR, []):
+ connections.append(conn) # inbound to our DirPort
+ elif conn.local_port in controller.get_ports(stem.control.Listener.CONTROL, []):
+ connections.append(conn) # controller connection
+ else:
+ connections = connection.get_connections(resolver, process_pid = process_pid, process_name = process_name)
+
+ for conn in connections:
conn_start_time, is_legacy = self._start_times.get(conn, (start_time, self._is_first_run))
new_start_times[conn] = (conn_start_time, is_legacy)
new_connections.append(Connection(conn_start_time, is_legacy, *conn))
More information about the tor-commits
mailing list