tor-commits
Threads by month
- ----- 2025 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
September 2015
- 15 participants
- 1412 discussions
commit 4eda274e7aeef2f40bea415238f23ca23e17bb0f
Author: Damian Johnson <atagar(a)torproject.org>
Date: Mon Aug 31 08:44:31 2015 -0700
Move Category enum to panel
All submodules need this so lets localize it with the other enums in the
module. We'll be consolidating into a single module eventually, but in the
meantime this simplifies the imports.
---
nyx/connections/circ_entry.py | 4 ++--
nyx/connections/conn_entry.py | 38 ++++++--------------------------------
nyx/connections/conn_panel.py | 41 +++++++++++++++++++++++++++++++++--------
nyx/connections/entries.py | 12 ++++++------
4 files changed, 47 insertions(+), 48 deletions(-)
diff --git a/nyx/connections/circ_entry.py b/nyx/connections/circ_entry.py
index 3cf0147..cd42fc8 100644
--- a/nyx/connections/circ_entry.py
+++ b/nyx/connections/circ_entry.py
@@ -69,7 +69,7 @@ class CircHeaderLine(conn_entry.ConnectionLine):
def get_details(self, width):
if not self.is_built:
- detail_format = (curses.A_BOLD, conn_entry.CATEGORY_COLOR[self._entry.get_type()])
+ detail_format = (curses.A_BOLD, conn_panel.CATEGORY_COLOR[self._entry.get_type()])
return [('Building Circuit...', detail_format)]
else:
return conn_entry.ConnectionLine.get_details(self, width)
@@ -127,7 +127,7 @@ class CircLine(conn_entry.ConnectionLine):
return entries.ConnectionPanelLine.get_listing_entry(self, width, current_time, listing_type)
def _get_listing_entry(self, width, current_time, listing_type):
- line_format = nyx.util.ui_tools.get_color(conn_entry.CATEGORY_COLOR[self._entry.get_type()])
+ line_format = nyx.util.ui_tools.get_color(conn_panel.CATEGORY_COLOR[self._entry.get_type()])
# The required widths are the sum of the following:
# initial space (1 character)
diff --git a/nyx/connections/conn_entry.py b/nyx/connections/conn_entry.py
index b2fe648..fa85bc6 100644
--- a/nyx/connections/conn_entry.py
+++ b/nyx/connections/conn_entry.py
@@ -9,32 +9,10 @@ import nyx.util.tracker
import nyx.util.ui_tools
from nyx.util import tor_controller
-from nyx.connections import entries
-
-from stem.util import conf, connection, 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 (nyx, 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',
-}
+from nyx.connections import conn_panel, entries
+from nyx.connections.conn_panel import Category
+
+from stem.util import conf, connection, str_tools
# static data for listing format
# <src> --> <dst> <etc><padding>
@@ -151,7 +129,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
# category - "<type>"
# postType - ") "
- line_format = nyx.util.ui_tools.get_color(CATEGORY_COLOR[entry_type])
+ line_format = nyx.util.ui_tools.get_color(conn_panel.CATEGORY_COLOR[entry_type])
time_width = 6 if CONFIG['features.connection.markInitialConnections'] else 5
draw_entry = [(' ', line_format),
@@ -172,7 +150,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
width - available space to display in
"""
- detail_format = (curses.A_BOLD, CATEGORY_COLOR[self._entry.get_type()])
+ detail_format = (curses.A_BOLD, conn_panel.CATEGORY_COLOR[self._entry.get_type()])
return [(line, detail_format) for line in self._get_detail_content(width)]
def get_etc_content(self, width, listing_type):
@@ -184,8 +162,6 @@ class ConnectionLine(entries.ConnectionPanelLine):
listing_type - primary attribute we're listing connections by
"""
- from nyx.connections import conn_panel
-
# for applications show the command/pid
if self._entry.get_type() in (Category.SOCKS, Category.HIDDEN, Category.CONTROL):
@@ -268,8 +244,6 @@ class ConnectionLine(entries.ConnectionPanelLine):
listing_type - primary attribute we're listing connections by
"""
- from nyx.connections import conn_panel
-
controller = tor_controller()
my_type = self._entry.get_type()
destination_address = self.get_destination_label(26, include_locale = True)
diff --git a/nyx/connections/conn_panel.py b/nyx/connections/conn_panel.py
index 2f6fde3..f2d613e 100644
--- a/nyx/connections/conn_panel.py
+++ b/nyx/connections/conn_panel.py
@@ -12,7 +12,7 @@ import threading
import nyx.popups
import nyx.util.tracker
-from nyx.connections import descriptor_popup, entries, conn_entry
+from nyx.connections import descriptor_popup, entries
from nyx.util import panel, tor_controller, ui_tools
from stem.control import State
@@ -29,6 +29,29 @@ Listing = enum.Enum(('IP_ADDRESS', 'IP Address'), 'FINGERPRINT', 'NICKNAME')
EXIT_USAGE_WIDTH = 15
UPDATE_RATE = 5 # rate in seconds at which we refresh
+# 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')
+
+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',
+}
+
SortAttr = enum.Enum('CATEGORY', 'UPTIME', 'LISTING', 'IP_ADDRESS', 'PORT', 'FINGERPRINT', 'NICKNAME', 'COUNTRY')
SORT_COLORS = {
@@ -130,6 +153,8 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# mark the initially exitsing connection uptimes as being estimates
+ from nyx.connections import conn_entry
+
for entry in self._entries:
if isinstance(entry, conn_entry.ConnectionEntry):
entry.get_lines()[0].is_initial_connection = True
@@ -199,7 +224,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
elif attr == SortAttr.NICKNAME:
return connection_line.get_nickname('z' * 20)
elif attr == SortAttr.CATEGORY:
- return conn_entry.Category.index_of(entry.get_type())
+ return Category.index_of(entry.get_type())
elif attr == SortAttr.UPTIME:
return connection_line.connection.start_time
elif attr == SortAttr.COUNTRY:
@@ -316,7 +341,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
if not selection:
break
- color = conn_entry.CATEGORY_COLOR[selection.get_type()]
+ color = CATEGORY_COLOR[selection.get_type()]
fingerprint = selection.get_fingerprint()
is_close_key = lambda key: key.is_selection() or key.match('d') or key.match('left') or key.match('right')
key = descriptor_popup.show_descriptor_popup(fingerprint, color, self.max_x, is_close_key)
@@ -488,7 +513,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
title = 'Connections:'
else:
counts = collections.Counter([entry.get_type() for entry in entries])
- count_labels = ['%i %s' % (counts[category], category.lower()) for category in conn_entry.Category if counts[category]]
+ count_labels = ['%i %s' % (counts[category], category.lower()) for category in Category if counts[category]]
title = 'Connections (%s):' % ', '.join(count_labels)
self.addstr(0, 0, title, curses.A_STANDOUT)
@@ -530,12 +555,12 @@ class ConnectionPanel(panel.Panel, threading.Thread):
for entry in new_entries:
entry_line = entry.get_lines()[0]
- if entry.is_private() and entry.get_type() == conn_entry.Category.INBOUND:
+ if entry.is_private() and entry.get_type() == Category.INBOUND:
client_locale = entry_line.get_locale(None)
if client_locale:
self._client_locale_usage[client_locale] = self._client_locale_usage.get(client_locale, 0) + 1
- elif entry.get_type() == conn_entry.Category.EXIT:
+ elif entry.get_type() == Category.EXIT:
exit_port = entry_line.connection.remote_port
self._exit_port_usage[exit_port] = self._exit_port_usage.get(exit_port, 0) + 1
@@ -550,9 +575,9 @@ class ConnectionPanel(panel.Panel, threading.Thread):
for entry in new_entries:
line = entry.get_lines()[0]
- if entry.get_type() in (conn_entry.Category.SOCKS, conn_entry.Category.CONTROL):
+ if entry.get_type() in (Category.SOCKS, Category.CONTROL):
local_ports.append(line.connection.remote_port)
- elif entry.get_type() == conn_entry.Category.HIDDEN:
+ elif entry.get_type() == Category.HIDDEN:
remote_ports.append(line.connection.local_port)
nyx.util.tracker.get_port_usage_tracker().query(local_ports, remote_ports)
diff --git a/nyx/connections/entries.py b/nyx/connections/entries.py
index 4c6fa9c..90de9d4 100644
--- a/nyx/connections/entries.py
+++ b/nyx/connections/entries.py
@@ -38,9 +38,9 @@ class Entry(object):
@staticmethod
def from_circuit(circ):
import nyx.connections.circ_entry
- import nyx.connections.conn_entry
+ from nyx.connections.conn_panel import Category
- entry = Entry(nyx.connections.conn_entry.Category.CIRCUIT)
+ entry = Entry(Category.CIRCUIT)
entry._lines = [nyx.connections.circ_entry.CircHeaderLine(entry, circ)]
for fingerprint, _ in circ.path:
@@ -67,19 +67,19 @@ class Entry(object):
:returns: **bool** indicating if connection information is sensive or not
"""
- import nyx.connections.conn_entry
+ from nyx.connections.conn_panel import Category
if not CONFIG['features.connection.showIps']:
return True
connection = self._lines[0].connection
- if self.get_type() == nyx.connections.conn_entry.Category.INBOUND:
+ if self.get_type() == Category.INBOUND:
controller = tor_controller()
if controller.is_user_traffic_allowed().inbound:
return len(nyx.util.tracker.get_consensus_tracker().get_all_relay_fingerprints(connection.remote_address)) == 0
- elif self.get_type() == nyx.connections.conn_entry.Category.EXIT:
+ elif self.get_type() == Category.EXIT:
# DNS connections exiting us aren't private (since they're hitting our
# resolvers). Everything else is.
@@ -162,7 +162,7 @@ class ConnectionPanelLine:
def get_type(connection):
- from nyx.connections.conn_entry import Category
+ from nyx.connections.conn_panel import Category
controller = tor_controller()
if connection.local_port in controller.get_ports(Listener.OR, []):
1
0
commit 9feead4c7cbd42898bc794feb9270601703a6561
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Sep 5 15:19:29 2015 -0700
Move connection colors to attributes
---
nyx/config/attributes.cfg | 18 ++++++++++++++++++
nyx/connection_panel.py | 37 ++++++++-----------------------------
2 files changed, 26 insertions(+), 29 deletions(-)
diff --git a/nyx/config/attributes.cfg b/nyx/config/attributes.cfg
index fe24120..e1d1b9e 100644
--- a/nyx/config/attributes.cfg
+++ b/nyx/config/attributes.cfg
@@ -57,3 +57,21 @@ attr.log_color NS => blue
attr.log_color NEWCONSENSUS => blue
attr.log_color GUARD => yellow
+attr.connection.category_color Inbound => green
+attr.connection.category_color Outbound => blue
+attr.connection.category_color Exit => red
+attr.connection.category_color Hidden => magenta
+attr.connection.category_color Socks => yellow
+attr.connection.category_color Circuit => cyan
+attr.connection.category_color Directory => magenta
+attr.connection.category_color Control => red
+
+attr.connection.sort_color Category => red
+attr.connection.sort_color Uptime => yellow
+attr.connection.sort_color Listing => green
+attr.connection.sort_color Ip Address => blue
+attr.connection.sort_color Port => blue
+attr.connection.sort_color Fingerprint => cyan
+attr.connection.sort_color Nickname => cyan
+attr.connection.sort_color Country => blue
+
diff --git a/nyx/connection_panel.py b/nyx/connection_panel.py
index 9fcacae..f133ff8 100644
--- a/nyx/connection_panel.py
+++ b/nyx/connection_panel.py
@@ -47,31 +47,8 @@ UPDATE_RATE = 5 # rate in seconds at which we refresh
# Control Tor controller (nyx, 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',
-}
-
SortAttr = enum.Enum('CATEGORY', 'UPTIME', 'LISTING', 'IP_ADDRESS', 'PORT', 'FINGERPRINT', 'NICKNAME', 'COUNTRY')
-SORT_COLORS = {
- SortAttr.CATEGORY: 'red',
- SortAttr.UPTIME: 'yellow',
- SortAttr.LISTING: 'green',
- SortAttr.IP_ADDRESS: 'blue',
- SortAttr.PORT: 'blue',
- SortAttr.FINGERPRINT: 'cyan',
- SortAttr.NICKNAME: 'cyan',
- SortAttr.COUNTRY: 'blue',
-}
-
# static data for listing format
# <src> --> <dst> <etc><padding>
@@ -87,6 +64,8 @@ def conf_handler(key, value):
CONFIG = conf.config_dict('nyx', {
+ 'attr.connection.category_color': {},
+ 'attr.connection.sort_color': {},
'features.connection.resolveApps': True,
'features.connection.listing_type': Listing.IP_ADDRESS,
'features.connection.order': [
@@ -320,7 +299,7 @@ class ConnectionLine(object):
# category - "<type>"
# postType - ") "
- line_format = nyx.util.ui_tools.get_color(CATEGORY_COLOR[entry_type])
+ line_format = nyx.util.ui_tools.get_color(CONFIG['attr.connection.category_color'].get(entry_type, 'white'))
draw_entry = [(' ', line_format),
(self._get_listing_content(width - 19, listing_type), line_format),
@@ -341,7 +320,7 @@ class ConnectionLine(object):
width - available space to display in
"""
- detail_format = (curses.A_BOLD, CATEGORY_COLOR[self._entry.get_type()])
+ detail_format = (curses.A_BOLD, CONFIG['attr.connection.category_color'].get(self._entry.get_type(), 'white'))
return [(line, detail_format) for line in self._get_detail_content(width)]
def get_etc_content(self, width, listing_type):
@@ -689,7 +668,7 @@ class CircHeaderLine(ConnectionLine):
@lru_cache()
def get_details(self, width):
if not self.is_built:
- detail_format = (curses.A_BOLD, CATEGORY_COLOR[self._entry.get_type()])
+ detail_format = (curses.A_BOLD, CONFIG['attr.connection.category_color'].get(self._entry.get_type(), 'white'))
return [('Building Circuit...', detail_format)]
else:
return ConnectionLine.get_details(self, width)
@@ -748,7 +727,7 @@ class CircLine(ConnectionLine):
@lru_cache()
def _get_listing_entry(self, width, listing_type):
- line_format = nyx.util.ui_tools.get_color(CATEGORY_COLOR[self._entry.get_type()])
+ line_format = nyx.util.ui_tools.get_color(CONFIG['attr.connection.category_color'].get(self._entry.get_type(), 'white'))
# The required widths are the sum of the following:
# initial space (1 character)
@@ -975,7 +954,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
title_label = 'Connection Ordering:'
options = list(SortAttr)
old_selection = CONFIG['features.connection.order']
- option_colors = dict([(attr, SORT_COLORS[attr]) for attr in options])
+ option_colors = dict([(attr, CONFIG['attr.connection.sort_color'].get(attr, 'white')) for attr in options])
results = nyx.popups.show_sort_dialog(title_label, options, old_selection, option_colors)
if results:
@@ -1044,7 +1023,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
if not selection:
break
- color = CATEGORY_COLOR[selection.get_type()]
+ color = CONFIG['attr.connection.category_color'].get(selection.get_type(), 'white')
fingerprint = selection.get_fingerprint()
is_close_key = lambda key: key.is_selection() or key.match('d') or key.match('left') or key.match('right')
key = nyx.popups.show_descriptor_popup(fingerprint, color, self.max_x, is_close_key)
1
0
commit 89d2e97dcefc8af51200e52128fb909fc6c49771
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Sep 5 09:52:20 2015 -0700
Drop expanded addresses
When we have a lot of space we showed three addresses of the form
'(local) => (externally visible) => (remote)'...
192.168.0.20:56088 --> 174.21.33.26:56088 --> 85.114.132.36:9001
Nice idea but it's confusing as hell for users. Hell, even I didn't know what
these were until I looked at the code. Keeping it simple and just showing the
important internal/external address.
---
nyx/connections/circ_entry.py | 4 ++--
nyx/connections/conn_entry.py | 41 +++--------------------------------------
2 files changed, 5 insertions(+), 40 deletions(-)
diff --git a/nyx/connections/circ_entry.py b/nyx/connections/circ_entry.py
index 84e5b2b..920d599 100644
--- a/nyx/connections/circ_entry.py
+++ b/nyx/connections/circ_entry.py
@@ -46,7 +46,7 @@ class CircHeaderLine(conn_entry.ConnectionLine):
self.is_built = False
self._remote_fingerprint = None
- conn_entry.ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, exit_address, exit_port, 'tcp'), False, False)
+ conn_entry.ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, exit_address, exit_port, 'tcp'), include_port = False)
self.circuit = circ
def get_fingerprint(self, default = None):
@@ -92,7 +92,7 @@ class CircLine(conn_entry.ConnectionLine):
def __init__(self, entry, circ, fingerprint):
relay_ip, relay_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(fingerprint, ('192.168.0.1', 0))
- conn_entry.ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, relay_ip, relay_port, 'tcp'), False)
+ conn_entry.ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, relay_ip, relay_port, 'tcp'), include_port = False)
self._fingerprint = fingerprint
self._is_last = False
diff --git a/nyx/connections/conn_entry.py b/nyx/connections/conn_entry.py
index d76808d..3ed78a9 100644
--- a/nyx/connections/conn_entry.py
+++ b/nyx/connections/conn_entry.py
@@ -37,7 +37,7 @@ class ConnectionLine(object):
Display component of the ConnectionEntry.
"""
- def __init__(self, entry, conn, include_port=True, include_expanded_addresses=True):
+ def __init__(self, entry, conn, include_port = True):
self._entry = entry
self.connection = conn
@@ -45,7 +45,6 @@ class ConnectionLine(object):
# information if true
self.include_port = include_port
- self.include_expanded_addresses = include_expanded_addresses
def get_listing_prefix(self):
"""
@@ -262,19 +261,10 @@ class ConnectionLine(object):
if listing_type == nyx.connection_panel.Listing.IP_ADDRESS:
my_external_address = controller.get_info('address', self.connection.local_address)
- address_differ = my_external_address != self.connection.local_address
- # Expanding doesn't make sense, if the connection isn't actually
- # going through Tor's external IP address. As there isn't a known
- # method for checking if it is, we're checking the type instead.
- #
- # This isn't entirely correct. It might be a better idea to check if
- # the source and destination addresses are both private, but that might
- # not be perfectly reliable either.
+ # Show our external address if it's going through tor.
- is_expansion_type = my_type not in (Category.SOCKS, Category.HIDDEN, Category.CONTROL)
-
- if is_expansion_type:
+ if my_type not in (Category.SOCKS, Category.HIDDEN, Category.CONTROL):
src_address = my_external_address + local_port
else:
src_address = self.connection.local_address + local_port
@@ -293,31 +283,6 @@ class ConnectionLine(object):
used_space += len(src) + len(dst) # base data requires 47 characters
- # Showing the fingerprint (which has the width of 42) has priority over
- # an expanded address field. Hence check if we either have space for
- # both or wouldn't be showing the fingerprint regardless.
-
- is_expanded_address_visible = width > used_space + 28
-
- if is_expanded_address_visible:
- is_expanded_address_visible = width < used_space + 42 or width > used_space + 70
-
- if address_differ and is_expansion_type and is_expanded_address_visible and self.include_expanded_addresses:
- # include the internal address in the src (extra 28 characters)
-
- internal_address = self.connection.local_address + local_port
-
- # If this is an inbound connection then reverse ordering so it's:
- # <foreign> --> <external> --> <internal>
- # when the src and dst are swapped later
-
- if my_type == Category.INBOUND:
- src = '%-21s --> %s' % (src, internal_address)
- else:
- src = '%-21s --> %s' % (internal_address, src)
-
- used_space += 28
-
etc = self.get_etc_content(width - used_space, listing_type)
used_space += len(etc)
elif listing_type == nyx.connection_panel.Listing.FINGERPRINT:
1
0
[nyx/master] Drop features.connection.showColumn.* config options
by atagar@torproject.org 22 Sep '15
by atagar@torproject.org 22 Sep '15
22 Sep '15
commit 93446e76246a24c953a59d6ac5c4b95751d602da
Author: Damian Johnson <atagar(a)torproject.org>
Date: Thu Sep 3 07:53:36 2015 -0700
Drop features.connection.showColumn.* config options
More nyxrc options I don't think anybody's ever used.
---
nyx/connections/conn_entry.py | 24 +++++++++---------------
nyxrc.sample | 6 ------
2 files changed, 9 insertions(+), 21 deletions(-)
diff --git a/nyx/connections/conn_entry.py b/nyx/connections/conn_entry.py
index 1f2439d..d76808d 100644
--- a/nyx/connections/conn_entry.py
+++ b/nyx/connections/conn_entry.py
@@ -29,10 +29,6 @@ LABEL_MIN_PADDING = 2 # min space between listing label and following data
CONFIG = conf.config_dict('nyx', {
'features.connection.showIps': True,
'features.connection.showExitPort': True,
- 'features.connection.showColumn.fingerprint': True,
- 'features.connection.showColumn.nickname': True,
- 'features.connection.showColumn.destination': True,
- 'features.connection.showColumn.expandedIp': True,
})
@@ -194,13 +190,13 @@ class ConnectionLine(object):
etc, used_space = '', 0
if listing_type == nyx.connection_panel.Listing.IP_ADDRESS:
- if width > used_space + 42 and CONFIG['features.connection.showColumn.fingerprint']:
+ if width > used_space + 42:
# show fingerprint (column width: 42 characters)
etc += '%-40s ' % self.get_fingerprint('UNKNOWN')
used_space += 42
- if width > used_space + 10 and CONFIG['features.connection.showColumn.nickname']:
+ if width > used_space + 10:
# show nickname (column width: remainder)
nickname_space = width - used_space
@@ -217,26 +213,24 @@ class ConnectionLine(object):
# ip/port/locale (column width: 28 characters)
is_locale_included = width > used_space + 45
- is_locale_included &= CONFIG['features.connection.showColumn.destination']
if is_locale_included:
nickname_space -= 28
- if CONFIG['features.connection.showColumn.nickname']:
- nickname_label = str_tools.crop(self.get_nickname('UNKNOWN'), nickname_space, 0)
- etc += ('%%-%is ' % nickname_space) % nickname_label
- used_space += nickname_space + 2
+ nickname_label = str_tools.crop(self.get_nickname('UNKNOWN'), nickname_space, 0)
+ etc += ('%%-%is ' % nickname_space) % nickname_label
+ used_space += nickname_space + 2
if is_locale_included:
etc += '%-26s ' % destination_address
used_space += 28
else:
- if width > used_space + 42 and CONFIG['features.connection.showColumn.fingerprint']:
+ if width > used_space + 42:
# show fingerprint (column width: 42 characters)
etc += '%-40s ' % self.get_fingerprint('UNKNOWN')
used_space += 42
- if width > used_space + 28 and CONFIG['features.connection.showColumn.destination']:
+ if width > used_space + 28:
# show destination ip/port/locale (column width: 28 characters)
etc += '%-26s ' % destination_address
used_space += 28
@@ -305,10 +299,10 @@ class ConnectionLine(object):
is_expanded_address_visible = width > used_space + 28
- if is_expanded_address_visible and CONFIG['features.connection.showColumn.fingerprint']:
+ if is_expanded_address_visible:
is_expanded_address_visible = width < used_space + 42 or width > used_space + 70
- if address_differ and is_expansion_type and is_expanded_address_visible and self.include_expanded_addresses and CONFIG['features.connection.showColumn.expandedIp']:
+ if address_differ and is_expansion_type and is_expanded_address_visible and self.include_expanded_addresses:
# include the internal address in the src (extra 28 characters)
internal_address = self.connection.local_address + local_port
diff --git a/nyxrc.sample b/nyxrc.sample
index e453320..d922081 100644
--- a/nyxrc.sample
+++ b/nyxrc.sample
@@ -205,18 +205,12 @@ features.graph.bw.accounting.show true
# false
# showExitPort
# shows port related information of exit connections we relay if true
-# showColumn.*
-# toggles the visability of the connection table columns
features.connection.listingType IP_ADDRESS
features.connection.order CATEGORY, LISTING, UPTIME
features.connection.resolveApps true
features.connection.showIps true
features.connection.showExitPort true
-features.connection.showColumn.fingerprint true
-features.connection.showColumn.nickname true
-features.connection.showColumn.destination true
-features.connection.showColumn.expandedIp true
# Caching parameters
cache.logPanel.size 1000
1
0
22 Sep '15
commit 02327e0bed85ad2e87ce3c0ecb3bb62bcce117dd
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Sep 5 15:00:57 2015 -0700
Consolidate remaining nyx/connections/* module
Ok, trimmed the remaining bits enough that we can consolidate in
connection_panel.py. Still a mess, but now a manageable mess.
---
nyx/connection_panel.py | 594 ++++++++++++++++++++++++++++++++++-
nyx/connections/__init__.py | 10 -
nyx/connections/circ_entry.py | 177 -----------
nyx/connections/conn_entry.py | 453 --------------------------
nyx/connections/descriptor_popup.py | 174 ----------
nyx/popups.py | 167 +++++++++-
setup.py | 2 +-
7 files changed, 752 insertions(+), 825 deletions(-)
diff --git a/nyx/connection_panel.py b/nyx/connection_panel.py
index c583a00..9fcacae 100644
--- a/nyx/connection_panel.py
+++ b/nyx/connection_panel.py
@@ -6,17 +6,18 @@ import re
import time
import collections
import curses
+import datetime
import itertools
import threading
import nyx.popups
import nyx.util.tracker
+import nyx.util.ui_tools
-from nyx.connections import descriptor_popup
from nyx.util import panel, tor_controller, ui_tools
from stem.control import Listener, State
-from stem.util import conf, connection, enum
+from stem.util import conf, connection, enum, str_tools
try:
# added in python 3.2
@@ -71,6 +72,12 @@ SORT_COLORS = {
SortAttr.COUNTRY: 'blue',
}
+# 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
+
def conf_handler(key, value):
if key == 'features.connection.listing_type':
@@ -90,6 +97,10 @@ CONFIG = conf.config_dict('nyx', {
}, conf_handler)
+def to_unix_time(dt):
+ return (dt - datetime.datetime(1970, 1, 1)).total_seconds()
+
+
class Entry(object):
@staticmethod
@lru_cache()
@@ -137,8 +148,7 @@ class ConnectionEntry(Entry):
@lru_cache()
def get_lines(self):
- import nyx.connections.conn_entry
- return [nyx.connections.conn_entry.ConnectionLine(self, self._connection)]
+ return [ConnectionLine(self, self._connection)]
@lru_cache()
def get_type(self):
@@ -201,7 +211,6 @@ class CircuitEntry(Entry):
@lru_cache()
def get_lines(self):
- from nyx.connections.circ_entry import CircHeaderLine, CircLine
return [CircHeaderLine(self, self._circuit)] + [CircLine(self, self._circuit, fp) for fp, _ in self._circuit.path]
def get_type(self):
@@ -211,6 +220,575 @@ class CircuitEntry(Entry):
return False
+class ConnectionLine(object):
+ """
+ Display component of the ConnectionEntry.
+ """
+
+ def __init__(self, entry, conn, include_port = True):
+ self._entry = entry
+ self.connection = conn
+
+ # includes the port or expanded ip address field when displaying listing
+ # information if true
+
+ self.include_port = include_port
+
+ def get_listing_prefix(self):
+ """
+ Provides a list of characters to be appended before the listing entry.
+ """
+
+ return ()
+
+ def get_locale(self, default = None):
+ """
+ Provides the two letter country code for the remote endpoint.
+ """
+
+ return tor_controller().get_info('ip-to-country/%s' % self.connection.remote_address, default)
+
+ def get_fingerprint(self, default = None):
+ """
+ Provides the fingerprint of this relay.
+ """
+
+ if self._entry.get_type() in (Category.OUTBOUND, Category.CIRCUIT, Category.DIRECTORY, Category.EXIT):
+ my_fingerprint = nyx.util.tracker.get_consensus_tracker().get_relay_fingerprint(self.connection.remote_address, self.connection.remote_port)
+ return my_fingerprint if my_fingerprint else default
+ else:
+ return default # inbound connections don't have an ORPort we can resolve
+
+ def get_nickname(self, default = None):
+ """
+ Provides the nickname of this relay.
+ """
+
+ nickname = nyx.util.tracker.get_consensus_tracker().get_relay_nickname(self.get_fingerprint())
+ return nickname if nickname else default
+
+ def get_listing_entry(self, width, current_time, listing_type):
+ """
+ Provides the tuple list for this connection's listing. Lines are composed
+ of the following components:
+ <src> --> <dst> <etc> <uptime> (<type>)
+
+ Listing.IP_ADDRESS:
+ src - <internal addr:port> --> <external addr:port>
+ dst - <destination addr:port>
+ etc - <fingerprint> <nickname>
+
+ Listing.FINGERPRINT:
+ src - localhost
+ dst - <destination fingerprint>
+ etc - <nickname> <destination addr:port>
+
+ Listing.NICKNAME:
+ src - <source nickname>
+ dst - <destination nickname>
+ etc - <fingerprint> <destination addr:port>
+
+ Arguments:
+ width - maximum length of the line
+ current_time - unix timestamp for what the results should consider to be
+ the current time
+ listing_type - primary attribute we're listing connections by
+ """
+
+ # fetch our (most likely cached) display entry for the listing
+
+ my_listing = self._get_listing_entry(width, listing_type)
+
+ # fill in the current uptime and return the results
+
+ time_prefix = '+' if self.connection.is_legacy else ' '
+
+ time_label = time_prefix + '%5s' % str_tools.time_label(current_time - self.connection.start_time, 1)
+ my_listing[2] = (time_label, my_listing[2][1])
+
+ return my_listing
+
+ @lru_cache()
+ def _get_listing_entry(self, width, listing_type):
+ entry_type = self._entry.get_type()
+
+ # Lines are split into the following components in reverse:
+ # init gap - " "
+ # content - "<src> --> <dst> <etc> "
+ # time - "<uptime>"
+ # preType - " ("
+ # category - "<type>"
+ # postType - ") "
+
+ line_format = nyx.util.ui_tools.get_color(CATEGORY_COLOR[entry_type])
+
+ draw_entry = [(' ', line_format),
+ (self._get_listing_content(width - 19, listing_type), line_format),
+ (' ', line_format),
+ (' (', line_format),
+ (entry_type.upper(), line_format | curses.A_BOLD),
+ (')' + ' ' * (9 - len(entry_type)), line_format)]
+
+ return draw_entry
+
+ @lru_cache()
+ def get_details(self, width):
+ """
+ Provides details on the connection, correlated against available consensus
+ data.
+
+ Arguments:
+ width - available space to display in
+ """
+
+ detail_format = (curses.A_BOLD, CATEGORY_COLOR[self._entry.get_type()])
+ return [(line, detail_format) for line in self._get_detail_content(width)]
+
+ def get_etc_content(self, width, listing_type):
+ """
+ Provides the optional content for the connection.
+
+ Arguments:
+ width - maximum length of the line
+ listing_type - primary attribute we're listing connections by
+ """
+
+ # for applications show the command/pid
+
+ if self._entry.get_type() in (Category.SOCKS, Category.HIDDEN, Category.CONTROL):
+ port = self.connection.local_port if self._entry.get_type() == Category.HIDDEN else self.connection.remote_port
+
+ try:
+ process = nyx.util.tracker.get_port_usage_tracker().fetch(port)
+ display_label = '%s (%s)' % (process.name, process.pid) if process.pid else process.name
+ except nyx.util.tracker.UnresolvedResult:
+ display_label = 'resolving...'
+ except nyx.util.tracker.UnknownApplication:
+ display_label = 'UNKNOWN'
+
+ if len(display_label) < width:
+ return ('%%-%is' % width) % display_label
+ else:
+ return ''
+
+ # for everything else display connection/consensus information
+
+ destination_address = self.get_destination_label(26, include_locale = True)
+ etc, used_space = '', 0
+
+ if listing_type == Listing.IP_ADDRESS:
+ if width > used_space + 42:
+ # show fingerprint (column width: 42 characters)
+
+ etc += '%-40s ' % self.get_fingerprint('UNKNOWN')
+ used_space += 42
+
+ if width > used_space + 10:
+ # show nickname (column width: remainder)
+
+ nickname_space = width - used_space
+ nickname_label = str_tools.crop(self.get_nickname('UNKNOWN'), nickname_space, 0)
+ etc += ('%%-%is ' % nickname_space) % nickname_label
+ used_space += nickname_space + 2
+ elif listing_type == Listing.FINGERPRINT:
+ if width > used_space + 17:
+ # show nickname (column width: min 17 characters, consumes any remaining space)
+
+ nickname_space = width - used_space - 2
+
+ # if there's room then also show a column with the destination
+ # ip/port/locale (column width: 28 characters)
+
+ is_locale_included = width > used_space + 45
+
+ if is_locale_included:
+ nickname_space -= 28
+
+ nickname_label = str_tools.crop(self.get_nickname('UNKNOWN'), nickname_space, 0)
+ etc += ('%%-%is ' % nickname_space) % nickname_label
+ used_space += nickname_space + 2
+
+ if is_locale_included:
+ etc += '%-26s ' % destination_address
+ used_space += 28
+ else:
+ if width > used_space + 42:
+ # show fingerprint (column width: 42 characters)
+ etc += '%-40s ' % self.get_fingerprint('UNKNOWN')
+ used_space += 42
+
+ if width > used_space + 28:
+ # show destination ip/port/locale (column width: 28 characters)
+ etc += '%-26s ' % destination_address
+ used_space += 28
+
+ return ('%%-%is' % width) % etc
+
+ def _get_listing_content(self, width, listing_type):
+ """
+ Provides the source, destination, and extra info for our listing.
+
+ Arguments:
+ width - maximum length of the line
+ listing_type - primary attribute we're listing connections by
+ """
+
+ controller = tor_controller()
+ my_type = self._entry.get_type()
+ destination_address = self.get_destination_label(26, include_locale = True)
+
+ # The required widths are the sum of the following:
+ # - room for LABEL_FORMAT and LABEL_MIN_PADDING (11 characters)
+ # - base data for the listing
+ # - that extra field plus any previous
+
+ used_space = len(LABEL_FORMAT % tuple([''] * 4)) + LABEL_MIN_PADDING
+ local_port = ':%s' % self.connection.local_port if self.include_port else ''
+
+ src, dst, etc = '', '', ''
+
+ if listing_type == Listing.IP_ADDRESS:
+ my_external_address = controller.get_info('address', self.connection.local_address)
+
+ # Show our external address if it's going through tor.
+
+ if my_type not in (Category.SOCKS, Category.HIDDEN, Category.CONTROL):
+ src_address = my_external_address + local_port
+ else:
+ src_address = self.connection.local_address + local_port
+
+ if my_type in (Category.SOCKS, Category.CONTROL):
+ # Like inbound connections these need their source and destination to
+ # be swapped. However, this only applies when listing by IP (their
+ # fingerprint and nickname are both for us). Reversing the fields here
+ # to keep the same column alignments.
+
+ src = '%-21s' % destination_address
+ dst = '%-26s' % src_address
+ else:
+ src = '%-21s' % src_address # ip:port = max of 21 characters
+ dst = '%-26s' % destination_address # ip:port (xx) = max of 26 characters
+
+ used_space += len(src) + len(dst) # base data requires 47 characters
+
+ etc = self.get_etc_content(width - used_space, listing_type)
+ used_space += len(etc)
+ elif listing_type == Listing.FINGERPRINT:
+ src = 'localhost'
+ dst = '%-40s' % ('localhost' if my_type == Category.CONTROL else self.get_fingerprint('UNKNOWN'))
+
+ used_space += len(src) + len(dst) # base data requires 49 characters
+
+ etc = self.get_etc_content(width - used_space, listing_type)
+ used_space += len(etc)
+ else:
+ # base data requires 50 min characters
+ src = controller.get_conf('nickname', 'UNKNOWN')
+ dst = controller.get_conf('nickname', 'UNKNOWN') if my_type == Category.CONTROL else self.get_nickname('UNKNOWN')
+
+ min_base_space = 50
+
+ etc = self.get_etc_content(width - used_space - min_base_space, listing_type)
+ used_space += len(etc)
+
+ base_space = width - used_space
+ used_space = width # prevents padding at the end
+
+ if len(src) + len(dst) > base_space:
+ src = str_tools.crop(src, base_space / 3)
+ dst = str_tools.crop(dst, base_space - len(src))
+
+ # pads dst entry to its max space
+
+ dst = ('%%-%is' % (base_space - len(src))) % dst
+
+ if my_type == Category.INBOUND:
+ src, dst = dst, src
+
+ padding = ' ' * (width - used_space + LABEL_MIN_PADDING)
+
+ return LABEL_FORMAT % (src, dst, etc, padding)
+
+ def _get_detail_content(self, width):
+ """
+ Provides a list with detailed information for this connection.
+
+ Arguments:
+ width - max length of lines
+ """
+
+ lines = [''] * 7
+ lines[0] = 'address: %s' % self.get_destination_label(width - 11)
+ lines[1] = 'locale: %s' % ('??' if self._entry.is_private() else self.get_locale('??'))
+
+ # Remaining data concerns the consensus results, with three possible cases:
+ # - if there's a single match then display its details
+ # - if there's multiple potential relays then list all of the combinations
+ # of ORPorts / Fingerprints
+ # - if no consensus data is available then say so (probably a client or
+ # exit connection)
+
+ fingerprint = self.get_fingerprint()
+ controller = tor_controller()
+
+ if fingerprint:
+ lines[1] = '%-13sfingerprint: %s' % (lines[1], fingerprint) # append fingerprint to second line
+
+ router_status_entry = controller.get_network_status(fingerprint, None)
+ server_descriptor = controller.get_server_descriptor(fingerprint, None)
+
+ if router_status_entry:
+ dir_port_label = 'dirport: %s' % router_status_entry.dir_port if router_status_entry.dir_port else ''
+ lines[2] = 'nickname: %-25s orport: %-10s %s' % (router_status_entry.nickname, router_status_entry.or_port, dir_port_label)
+ lines[3] = 'published: %s' % router_status_entry.published.strftime("%H:%M %m/%d/%Y")
+ lines[4] = 'flags: %s' % ', '.join(router_status_entry.flags)
+
+ if server_descriptor:
+ policy_label = server_descriptor.exit_policy.summary() if server_descriptor.exit_policy else 'unknown'
+ lines[5] = 'exit policy: %s' % policy_label
+ lines[3] = '%-35s os: %-14s version: %s' % (lines[3], server_descriptor.operating_system, server_descriptor.tor_version)
+
+ if server_descriptor.contact:
+ lines[6] = 'contact: %s' % server_descriptor.contact
+ else:
+ all_matches = nyx.util.tracker.get_consensus_tracker().get_all_relay_fingerprints(self.connection.remote_address)
+
+ if all_matches:
+ # multiple matches
+ lines[2] = 'Multiple matches, possible fingerprints are:'
+
+ for i in range(len(all_matches)):
+ is_last_line = i == 3
+
+ relay_port, relay_fingerprint = all_matches[i]
+ line_text = '%i. or port: %-5s fingerprint: %s' % (i + 1, relay_port, relay_fingerprint)
+
+ # if there's multiple lines remaining at the end then give a count
+
+ remaining_relays = len(all_matches) - i
+
+ if is_last_line and remaining_relays > 1:
+ line_text = '... %i more' % remaining_relays
+
+ lines[3 + i] = line_text
+
+ if is_last_line:
+ break
+ else:
+ # no consensus entry for this ip address
+ lines[2] = 'No consensus data found'
+
+ # crops any lines that are too long
+
+ for i in range(len(lines)):
+ lines[i] = str_tools.crop(lines[i], width - 2)
+
+ return lines
+
+ def get_destination_label(self, max_length, include_locale = False):
+ """
+ Provides a short description of the destination. This is made up of two
+ components, the base <ip addr>:<port> and an extra piece of information in
+ parentheses. The IP address is scrubbed from private connections.
+
+ Extra information is...
+ - the port's purpose for exit connections
+ - the locale, the address isn't private and isn't on the local network
+ - nothing otherwise
+
+ Arguments:
+ max_length - maximum length of the string returned
+ include_locale - possibly includes the locale
+ """
+
+ # destination of the connection
+
+ address_label = '<scrubbed>' if self._entry.is_private() else self.connection.remote_address
+ port_label = ':%s' % self.connection.remote_port
+ destination_address = address_label + port_label
+
+ # Only append the extra info if there's at least a couple characters of
+ # space (this is what's needed for the country codes).
+
+ if len(destination_address) + 5 <= max_length:
+ space_available = max_length - len(destination_address) - 3
+
+ if self._entry.get_type() == Category.EXIT:
+ purpose = connection.port_usage(self.connection.remote_port)
+
+ if purpose:
+ # BitTorrent is a common protocol to truncate, so just use "Torrent"
+ # if there's not enough room.
+
+ if len(purpose) > space_available and purpose == 'BitTorrent':
+ purpose = 'Torrent'
+
+ # crops with a hyphen if too long
+
+ purpose = str_tools.crop(purpose, space_available, ending = str_tools.Ending.HYPHEN)
+
+ destination_address += ' (%s)' % purpose
+ elif not connection.is_private_address(self.connection.remote_address):
+ extra_info = []
+
+ if include_locale and not tor_controller().is_geoip_unavailable():
+ foreign_locale = self.get_locale('??')
+ extra_info.append(foreign_locale)
+ space_available -= len(foreign_locale) + 2
+
+ if extra_info:
+ destination_address += ' (%s)' % ', '.join(extra_info)
+
+ return destination_address[:max_length]
+
+
+class CircHeaderLine(ConnectionLine):
+ """
+ Initial line of a client entry. This has the same basic format as connection
+ lines except that its etc field has circuit attributes.
+ """
+
+ def __init__(self, entry, circ):
+ if circ.status == 'BUILT':
+ self._remote_fingerprint = circ.path[-1][0]
+ exit_address, exit_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(self._remote_fingerprint, ('192.168.0.1', 0))
+ self.is_built = True
+ else:
+ exit_address, exit_port = '0.0.0.0', 0
+ self.is_built = False
+ self._remote_fingerprint = None
+
+ ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, exit_address, exit_port, 'tcp'), include_port = False)
+ self.circuit = circ
+
+ def get_fingerprint(self, default = None):
+ return self._remote_fingerprint if self._remote_fingerprint else ConnectionLine.get_fingerprint(self, default)
+
+ def get_destination_label(self, max_length, include_locale = False):
+ if not self.is_built:
+ return 'Building...'
+
+ return ConnectionLine.get_destination_label(self, max_length, include_locale)
+
+ def get_etc_content(self, width, listing_type):
+ """
+ Attempts to provide all circuit related stats. Anything that can't be
+ shown completely (not enough room) is dropped.
+ """
+
+ etc_attr = ['Purpose: %s' % self.circuit.purpose.capitalize(), 'Circuit ID: %s' % self.circuit.id]
+
+ for i in range(len(etc_attr), -1, -1):
+ etc_label = ', '.join(etc_attr[:i])
+
+ if len(etc_label) <= width:
+ return ('%%-%is' % width) % etc_label
+
+ return ''
+
+ @lru_cache()
+ def get_details(self, width):
+ if not self.is_built:
+ detail_format = (curses.A_BOLD, CATEGORY_COLOR[self._entry.get_type()])
+ return [('Building Circuit...', detail_format)]
+ else:
+ return ConnectionLine.get_details(self, width)
+
+
+class CircLine(ConnectionLine):
+ """
+ An individual hop in a circuit. This overwrites the displayed listing, but
+ otherwise makes use of the ConnectionLine attributes (for the detail display,
+ caching, etc).
+ """
+
+ def __init__(self, entry, circ, fingerprint):
+ relay_ip, relay_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(fingerprint, ('192.168.0.1', 0))
+ ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, relay_ip, relay_port, 'tcp'), include_port = False)
+ self._fingerprint = fingerprint
+ self._is_last = False
+
+ circ_path = [path_entry[0] for path_entry in circ.path]
+ circ_index = circ_path.index(fingerprint)
+
+ if circ_index == len(circ_path) - 1:
+ placement_type = 'Exit' if circ.status == 'BUILT' else 'Extending'
+ self._is_last = True
+ elif circ_index == 0:
+ placement_type = 'Guard'
+ else:
+ placement_type = 'Middle'
+
+ self.placement_label = '%i / %s' % (circ_index + 1, placement_type)
+
+ def get_fingerprint(self, default = None):
+ self._fingerprint
+
+ def get_listing_prefix(self):
+ if self._is_last:
+ return (ord(' '), curses.ACS_LLCORNER, curses.ACS_HLINE, ord(' '))
+ else:
+ return (ord(' '), curses.ACS_VLINE, ord(' '), ord(' '))
+
+ def get_listing_entry(self, width, current_time, listing_type):
+ """
+ Provides the [(msg, attr)...] listing for this relay in the circuilt
+ listing. Lines are composed of the following components:
+ <bracket> <dst> <etc> <placement label>
+
+ The dst and etc entries largely match their ConnectionEntry counterparts.
+
+ Arguments:
+ width - maximum length of the line
+ current_time - the current unix time (ignored)
+ listing_type - primary attribute we're listing connections by
+ """
+
+ return self._get_listing_entry(width, listing_type)
+
+ @lru_cache()
+ def _get_listing_entry(self, width, listing_type):
+ line_format = nyx.util.ui_tools.get_color(CATEGORY_COLOR[self._entry.get_type()])
+
+ # The required widths are the sum of the following:
+ # initial space (1 character)
+ # bracketing (3 characters)
+ # placement_label (14 characters)
+ # gap between etc and placement label (5 characters)
+
+ baseline_space = 14 + 5
+
+ dst, etc = '', ''
+
+ if listing_type == Listing.IP_ADDRESS:
+ # dst width is derived as:
+ # src (21) + dst (26) + divider (7) + right gap (2) - bracket (3) = 53 char
+
+ dst = '%-53s' % self.get_destination_label(53, include_locale = True)
+
+ # fills the nickname into the empty space here
+
+ dst = '%s%-25s ' % (dst[:25], str_tools.crop(self.get_nickname('UNKNOWN'), 25, 0))
+
+ etc = self.get_etc_content(width - baseline_space - len(dst), listing_type)
+ elif listing_type == Listing.FINGERPRINT:
+ # dst width is derived as:
+ # src (9) + dst (40) + divider (7) + right gap (2) - bracket (3) = 55 char
+
+ dst = '%-55s' % self.get_fingerprint('UNKNOWN')
+ etc = self.get_etc_content(width - baseline_space - len(dst), listing_type)
+ else:
+ # min space for the nickname is 56 characters
+
+ etc = self.get_etc_content(width - baseline_space - 56, listing_type)
+ dst_layout = '%%-%is' % (width - baseline_space - len(etc))
+ dst = dst_layout % self.get_nickname('UNKNOWN')
+
+ return ((dst + etc, line_format),
+ (' ' * (width - baseline_space - len(dst) - len(etc) + 5), line_format),
+ ('%-14s' % self.placement_label, line_format))
+
+
class ConnectionPanel(panel.Panel, threading.Thread):
"""
Listing of connections tor is making, with information correlated against
@@ -280,10 +858,8 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# mark the initially exitsing connection uptimes as being estimates
- from nyx.connections import conn_entry
-
for entry in self._entries:
- if isinstance(entry, conn_entry.ConnectionEntry):
+ if isinstance(entry, ConnectionEntry):
entry.get_lines()[0].is_initial_connection = True
# listens for when tor stops so we know to stop reflecting changes
@@ -471,7 +1047,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
color = CATEGORY_COLOR[selection.get_type()]
fingerprint = selection.get_fingerprint()
is_close_key = lambda key: key.is_selection() or key.match('d') or key.match('left') or key.match('right')
- key = descriptor_popup.show_descriptor_popup(fingerprint, color, self.max_x, is_close_key)
+ key = nyx.popups.show_descriptor_popup(fingerprint, color, self.max_x, is_close_key)
if not key or key.is_selection() or key.match('d'):
break # closes popup
diff --git a/nyx/connections/__init__.py b/nyx/connections/__init__.py
deleted file mode 100644
index 577823a..0000000
--- a/nyx/connections/__init__.py
+++ /dev/null
@@ -1,10 +0,0 @@
-"""
-Resources related to our connection panel.
-"""
-
-__all__ = [
- 'circ_entry',
- 'conn_entry',
- 'descriptor_popup',
- 'entries',
-]
diff --git a/nyx/connections/circ_entry.py b/nyx/connections/circ_entry.py
deleted file mode 100644
index 920d599..0000000
--- a/nyx/connections/circ_entry.py
+++ /dev/null
@@ -1,177 +0,0 @@
-"""
-Connection panel entries for client circuits. This includes a header entry
-followed by an entry for each hop in the circuit. For instance:
-
-89.188.20.246:42667 --> 217.172.182.26 (de) General / Built 8.6m (CIRCUIT)
-| 85.8.28.4 (se) 98FBC3B2B93897A78CDD797EF549E6B62C9A8523 1 / Guard
-| 91.121.204.76 (fr) 546387D93F8D40CFF8842BB9D3A8EC477CEDA984 2 / Middle
-+- 217.172.182.26 (de) 5CFA9EA136C0EA0AC096E5CEA7EB674F1207CF86 3 / Exit
-"""
-
-import curses
-import datetime
-
-import nyx.util.tracker
-import nyx.util.ui_tools
-import nyx.connection_panel
-
-from nyx.connections import conn_entry
-
-from stem.util import str_tools
-
-try:
- # added in python 3.2
- from functools import lru_cache
-except ImportError:
- from stem.util.lru_cache import lru_cache
-
-
-def to_unix_time(dt):
- return (dt - datetime.datetime(1970, 1, 1)).total_seconds()
-
-
-class CircHeaderLine(conn_entry.ConnectionLine):
- """
- Initial line of a client entry. This has the same basic format as connection
- lines except that its etc field has circuit attributes.
- """
-
- def __init__(self, entry, circ):
- if circ.status == 'BUILT':
- self._remote_fingerprint = circ.path[-1][0]
- exit_address, exit_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(self._remote_fingerprint, ('192.168.0.1', 0))
- self.is_built = True
- else:
- exit_address, exit_port = '0.0.0.0', 0
- self.is_built = False
- self._remote_fingerprint = None
-
- conn_entry.ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, exit_address, exit_port, 'tcp'), include_port = False)
- self.circuit = circ
-
- def get_fingerprint(self, default = None):
- return self._remote_fingerprint if self._remote_fingerprint else conn_entry.ConnectionLine.get_fingerprint(self, default)
-
- def get_destination_label(self, max_length, include_locale = False):
- if not self.is_built:
- return 'Building...'
-
- return conn_entry.ConnectionLine.get_destination_label(self, max_length, include_locale)
-
- def get_etc_content(self, width, listing_type):
- """
- Attempts to provide all circuit related stats. Anything that can't be
- shown completely (not enough room) is dropped.
- """
-
- etc_attr = ['Purpose: %s' % self.circuit.purpose.capitalize(), 'Circuit ID: %s' % self.circuit.id]
-
- for i in range(len(etc_attr), -1, -1):
- etc_label = ', '.join(etc_attr[:i])
-
- if len(etc_label) <= width:
- return ('%%-%is' % width) % etc_label
-
- return ''
-
- @lru_cache()
- def get_details(self, width):
- if not self.is_built:
- detail_format = (curses.A_BOLD, nyx.connection_panel.CATEGORY_COLOR[self._entry.get_type()])
- return [('Building Circuit...', detail_format)]
- else:
- return conn_entry.ConnectionLine.get_details(self, width)
-
-
-class CircLine(conn_entry.ConnectionLine):
- """
- An individual hop in a circuit. This overwrites the displayed listing, but
- otherwise makes use of the ConnectionLine attributes (for the detail display,
- caching, etc).
- """
-
- def __init__(self, entry, circ, fingerprint):
- relay_ip, relay_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(fingerprint, ('192.168.0.1', 0))
- conn_entry.ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, relay_ip, relay_port, 'tcp'), include_port = False)
- self._fingerprint = fingerprint
- self._is_last = False
-
- circ_path = [path_entry[0] for path_entry in circ.path]
- circ_index = circ_path.index(fingerprint)
-
- if circ_index == len(circ_path) - 1:
- placement_type = 'Exit' if circ.status == 'BUILT' else 'Extending'
- self._is_last = True
- elif circ_index == 0:
- placement_type = 'Guard'
- else:
- placement_type = 'Middle'
-
- self.placement_label = '%i / %s' % (circ_index + 1, placement_type)
-
- def get_fingerprint(self, default = None):
- self._fingerprint
-
- def get_listing_prefix(self):
- if self._is_last:
- return (ord(' '), curses.ACS_LLCORNER, curses.ACS_HLINE, ord(' '))
- else:
- return (ord(' '), curses.ACS_VLINE, ord(' '), ord(' '))
-
- def get_listing_entry(self, width, current_time, listing_type):
- """
- Provides the [(msg, attr)...] listing for this relay in the circuilt
- listing. Lines are composed of the following components:
- <bracket> <dst> <etc> <placement label>
-
- The dst and etc entries largely match their ConnectionEntry counterparts.
-
- Arguments:
- width - maximum length of the line
- current_time - the current unix time (ignored)
- listing_type - primary attribute we're listing connections by
- """
-
- return self._get_listing_entry(width, listing_type)
-
- @lru_cache()
- def _get_listing_entry(self, width, listing_type):
- line_format = nyx.util.ui_tools.get_color(nyx.connection_panel.CATEGORY_COLOR[self._entry.get_type()])
-
- # The required widths are the sum of the following:
- # initial space (1 character)
- # bracketing (3 characters)
- # placement_label (14 characters)
- # gap between etc and placement label (5 characters)
-
- baseline_space = 14 + 5
-
- dst, etc = '', ''
-
- if listing_type == nyx.connection_panel.Listing.IP_ADDRESS:
- # dst width is derived as:
- # src (21) + dst (26) + divider (7) + right gap (2) - bracket (3) = 53 char
-
- dst = '%-53s' % self.get_destination_label(53, include_locale = True)
-
- # fills the nickname into the empty space here
-
- dst = '%s%-25s ' % (dst[:25], str_tools.crop(self.get_nickname('UNKNOWN'), 25, 0))
-
- etc = self.get_etc_content(width - baseline_space - len(dst), listing_type)
- elif listing_type == nyx.connection_panel.Listing.FINGERPRINT:
- # dst width is derived as:
- # src (9) + dst (40) + divider (7) + right gap (2) - bracket (3) = 55 char
-
- dst = '%-55s' % self.get_fingerprint('UNKNOWN')
- etc = self.get_etc_content(width - baseline_space - len(dst), listing_type)
- else:
- # min space for the nickname is 56 characters
-
- etc = self.get_etc_content(width - baseline_space - 56, listing_type)
- dst_layout = '%%-%is' % (width - baseline_space - len(etc))
- dst = dst_layout % self.get_nickname('UNKNOWN')
-
- return ((dst + etc, line_format),
- (' ' * (width - baseline_space - len(dst) - len(etc) + 5), line_format),
- ('%-14s' % self.placement_label, line_format))
diff --git a/nyx/connections/conn_entry.py b/nyx/connections/conn_entry.py
deleted file mode 100644
index df36dd8..0000000
--- a/nyx/connections/conn_entry.py
+++ /dev/null
@@ -1,453 +0,0 @@
-"""
-Connection panel entries related to actual connections to or from the system
-(ie, results seen by netstat, lsof, etc).
-"""
-
-import curses
-
-import nyx.connection_panel
-import nyx.util.tracker
-import nyx.util.ui_tools
-
-from nyx.util import tor_controller
-from nyx.connection_panel import Category
-
-from stem.util import conf, connection, str_tools
-
-try:
- # added in python 3.2
- from functools import lru_cache
-except ImportError:
- from stem.util.lru_cache import lru_cache
-
-# 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
-
-CONFIG = conf.config_dict('nyx', {
- 'features.connection.showIps': True,
-})
-
-
-class ConnectionLine(object):
- """
- Display component of the ConnectionEntry.
- """
-
- def __init__(self, entry, conn, include_port = True):
- self._entry = entry
- self.connection = conn
-
- # includes the port or expanded ip address field when displaying listing
- # information if true
-
- self.include_port = include_port
-
- def get_listing_prefix(self):
- """
- Provides a list of characters to be appended before the listing entry.
- """
-
- return ()
-
- def get_locale(self, default = None):
- """
- Provides the two letter country code for the remote endpoint.
- """
-
- return tor_controller().get_info('ip-to-country/%s' % self.connection.remote_address, default)
-
- def get_fingerprint(self, default = None):
- """
- Provides the fingerprint of this relay.
- """
-
- if self._entry.get_type() in (Category.OUTBOUND, Category.CIRCUIT, Category.DIRECTORY, Category.EXIT):
- my_fingerprint = nyx.util.tracker.get_consensus_tracker().get_relay_fingerprint(self.connection.remote_address, self.connection.remote_port)
- return my_fingerprint if my_fingerprint else default
- else:
- return default # inbound connections don't have an ORPort we can resolve
-
- def get_nickname(self, default = None):
- """
- Provides the nickname of this relay.
- """
-
- nickname = nyx.util.tracker.get_consensus_tracker().get_relay_nickname(self.get_fingerprint())
- return nickname if nickname else default
-
- def get_listing_entry(self, width, current_time, listing_type):
- """
- Provides the tuple list for this connection's listing. Lines are composed
- of the following components:
- <src> --> <dst> <etc> <uptime> (<type>)
-
- Listing.IP_ADDRESS:
- src - <internal addr:port> --> <external addr:port>
- dst - <destination addr:port>
- etc - <fingerprint> <nickname>
-
- Listing.FINGERPRINT:
- src - localhost
- dst - <destination fingerprint>
- etc - <nickname> <destination addr:port>
-
- Listing.NICKNAME:
- src - <source nickname>
- dst - <destination nickname>
- etc - <fingerprint> <destination addr:port>
-
- Arguments:
- width - maximum length of the line
- current_time - unix timestamp for what the results should consider to be
- the current time
- listing_type - primary attribute we're listing connections by
- """
-
- # fetch our (most likely cached) display entry for the listing
-
- my_listing = self._get_listing_entry(width, listing_type)
-
- # fill in the current uptime and return the results
-
- time_prefix = '+' if self.connection.is_legacy else ' '
-
- time_label = time_prefix + '%5s' % str_tools.time_label(current_time - self.connection.start_time, 1)
- my_listing[2] = (time_label, my_listing[2][1])
-
- return my_listing
-
- @lru_cache()
- def _get_listing_entry(self, width, listing_type):
- entry_type = self._entry.get_type()
-
- # Lines are split into the following components in reverse:
- # init gap - " "
- # content - "<src> --> <dst> <etc> "
- # time - "<uptime>"
- # preType - " ("
- # category - "<type>"
- # postType - ") "
-
- line_format = nyx.util.ui_tools.get_color(nyx.connection_panel.CATEGORY_COLOR[entry_type])
-
- draw_entry = [(' ', line_format),
- (self._get_listing_content(width - 19, listing_type), line_format),
- (' ', line_format),
- (' (', line_format),
- (entry_type.upper(), line_format | curses.A_BOLD),
- (')' + ' ' * (9 - len(entry_type)), line_format)]
-
- return draw_entry
-
- @lru_cache()
- def get_details(self, width):
- """
- Provides details on the connection, correlated against available consensus
- data.
-
- Arguments:
- width - available space to display in
- """
-
- detail_format = (curses.A_BOLD, nyx.connection_panel.CATEGORY_COLOR[self._entry.get_type()])
- return [(line, detail_format) for line in self._get_detail_content(width)]
-
- def get_etc_content(self, width, listing_type):
- """
- Provides the optional content for the connection.
-
- Arguments:
- width - maximum length of the line
- listing_type - primary attribute we're listing connections by
- """
-
- # for applications show the command/pid
-
- if self._entry.get_type() in (Category.SOCKS, Category.HIDDEN, Category.CONTROL):
- port = self.connection.local_port if self._entry.get_type() == Category.HIDDEN else self.connection.remote_port
-
- try:
- process = nyx.util.tracker.get_port_usage_tracker().fetch(port)
- display_label = '%s (%s)' % (process.name, process.pid) if process.pid else process.name
- except nyx.util.tracker.UnresolvedResult:
- display_label = 'resolving...'
- except nyx.util.tracker.UnknownApplication:
- display_label = 'UNKNOWN'
-
- if len(display_label) < width:
- return ('%%-%is' % width) % display_label
- else:
- return ''
-
- # for everything else display connection/consensus information
-
- destination_address = self.get_destination_label(26, include_locale = True)
- etc, used_space = '', 0
-
- if listing_type == nyx.connection_panel.Listing.IP_ADDRESS:
- if width > used_space + 42:
- # show fingerprint (column width: 42 characters)
-
- etc += '%-40s ' % self.get_fingerprint('UNKNOWN')
- used_space += 42
-
- if width > used_space + 10:
- # show nickname (column width: remainder)
-
- nickname_space = width - used_space
- nickname_label = str_tools.crop(self.get_nickname('UNKNOWN'), nickname_space, 0)
- etc += ('%%-%is ' % nickname_space) % nickname_label
- used_space += nickname_space + 2
- elif listing_type == nyx.connection_panel.Listing.FINGERPRINT:
- if width > used_space + 17:
- # show nickname (column width: min 17 characters, consumes any remaining space)
-
- nickname_space = width - used_space - 2
-
- # if there's room then also show a column with the destination
- # ip/port/locale (column width: 28 characters)
-
- is_locale_included = width > used_space + 45
-
- if is_locale_included:
- nickname_space -= 28
-
- nickname_label = str_tools.crop(self.get_nickname('UNKNOWN'), nickname_space, 0)
- etc += ('%%-%is ' % nickname_space) % nickname_label
- used_space += nickname_space + 2
-
- if is_locale_included:
- etc += '%-26s ' % destination_address
- used_space += 28
- else:
- if width > used_space + 42:
- # show fingerprint (column width: 42 characters)
- etc += '%-40s ' % self.get_fingerprint('UNKNOWN')
- used_space += 42
-
- if width > used_space + 28:
- # show destination ip/port/locale (column width: 28 characters)
- etc += '%-26s ' % destination_address
- used_space += 28
-
- return ('%%-%is' % width) % etc
-
- def _get_listing_content(self, width, listing_type):
- """
- Provides the source, destination, and extra info for our listing.
-
- Arguments:
- width - maximum length of the line
- listing_type - primary attribute we're listing connections by
- """
-
- controller = tor_controller()
- my_type = self._entry.get_type()
- destination_address = self.get_destination_label(26, include_locale = True)
-
- # The required widths are the sum of the following:
- # - room for LABEL_FORMAT and LABEL_MIN_PADDING (11 characters)
- # - base data for the listing
- # - that extra field plus any previous
-
- used_space = len(LABEL_FORMAT % tuple([''] * 4)) + LABEL_MIN_PADDING
- local_port = ':%s' % self.connection.local_port if self.include_port else ''
-
- src, dst, etc = '', '', ''
-
- if listing_type == nyx.connection_panel.Listing.IP_ADDRESS:
- my_external_address = controller.get_info('address', self.connection.local_address)
-
- # Show our external address if it's going through tor.
-
- if my_type not in (Category.SOCKS, Category.HIDDEN, Category.CONTROL):
- src_address = my_external_address + local_port
- else:
- src_address = self.connection.local_address + local_port
-
- if my_type in (Category.SOCKS, Category.CONTROL):
- # Like inbound connections these need their source and destination to
- # be swapped. However, this only applies when listing by IP (their
- # fingerprint and nickname are both for us). Reversing the fields here
- # to keep the same column alignments.
-
- src = '%-21s' % destination_address
- dst = '%-26s' % src_address
- else:
- src = '%-21s' % src_address # ip:port = max of 21 characters
- dst = '%-26s' % destination_address # ip:port (xx) = max of 26 characters
-
- used_space += len(src) + len(dst) # base data requires 47 characters
-
- etc = self.get_etc_content(width - used_space, listing_type)
- used_space += len(etc)
- elif listing_type == nyx.connection_panel.Listing.FINGERPRINT:
- src = 'localhost'
- dst = '%-40s' % ('localhost' if my_type == Category.CONTROL else self.get_fingerprint('UNKNOWN'))
-
- used_space += len(src) + len(dst) # base data requires 49 characters
-
- etc = self.get_etc_content(width - used_space, listing_type)
- used_space += len(etc)
- else:
- # base data requires 50 min characters
- src = controller.get_conf('nickname', 'UNKNOWN')
- dst = controller.get_conf('nickname', 'UNKNOWN') if my_type == Category.CONTROL else self.get_nickname('UNKNOWN')
-
- min_base_space = 50
-
- etc = self.get_etc_content(width - used_space - min_base_space, listing_type)
- used_space += len(etc)
-
- base_space = width - used_space
- used_space = width # prevents padding at the end
-
- if len(src) + len(dst) > base_space:
- src = str_tools.crop(src, base_space / 3)
- dst = str_tools.crop(dst, base_space - len(src))
-
- # pads dst entry to its max space
-
- dst = ('%%-%is' % (base_space - len(src))) % dst
-
- if my_type == Category.INBOUND:
- src, dst = dst, src
-
- padding = ' ' * (width - used_space + LABEL_MIN_PADDING)
-
- return LABEL_FORMAT % (src, dst, etc, padding)
-
- def _get_detail_content(self, width):
- """
- Provides a list with detailed information for this connection.
-
- Arguments:
- width - max length of lines
- """
-
- lines = [''] * 7
- lines[0] = 'address: %s' % self.get_destination_label(width - 11)
- lines[1] = 'locale: %s' % ('??' if self._entry.is_private() else self.get_locale('??'))
-
- # Remaining data concerns the consensus results, with three possible cases:
- # - if there's a single match then display its details
- # - if there's multiple potential relays then list all of the combinations
- # of ORPorts / Fingerprints
- # - if no consensus data is available then say so (probably a client or
- # exit connection)
-
- fingerprint = self.get_fingerprint()
- controller = tor_controller()
-
- if fingerprint:
- lines[1] = '%-13sfingerprint: %s' % (lines[1], fingerprint) # append fingerprint to second line
-
- router_status_entry = controller.get_network_status(fingerprint, None)
- server_descriptor = controller.get_server_descriptor(fingerprint, None)
-
- if router_status_entry:
- dir_port_label = 'dirport: %s' % router_status_entry.dir_port if router_status_entry.dir_port else ''
- lines[2] = 'nickname: %-25s orport: %-10s %s' % (router_status_entry.nickname, router_status_entry.or_port, dir_port_label)
- lines[3] = 'published: %s' % router_status_entry.published.strftime("%H:%M %m/%d/%Y")
- lines[4] = 'flags: %s' % ', '.join(router_status_entry.flags)
-
- if server_descriptor:
- policy_label = server_descriptor.exit_policy.summary() if server_descriptor.exit_policy else 'unknown'
- lines[5] = 'exit policy: %s' % policy_label
- lines[3] = '%-35s os: %-14s version: %s' % (lines[3], server_descriptor.operating_system, server_descriptor.tor_version)
-
- if server_descriptor.contact:
- lines[6] = 'contact: %s' % server_descriptor.contact
- else:
- all_matches = nyx.util.tracker.get_consensus_tracker().get_all_relay_fingerprints(self.connection.remote_address)
-
- if all_matches:
- # multiple matches
- lines[2] = 'Multiple matches, possible fingerprints are:'
-
- for i in range(len(all_matches)):
- is_last_line = i == 3
-
- relay_port, relay_fingerprint = all_matches[i]
- line_text = '%i. or port: %-5s fingerprint: %s' % (i + 1, relay_port, relay_fingerprint)
-
- # if there's multiple lines remaining at the end then give a count
-
- remaining_relays = len(all_matches) - i
-
- if is_last_line and remaining_relays > 1:
- line_text = '... %i more' % remaining_relays
-
- lines[3 + i] = line_text
-
- if is_last_line:
- break
- else:
- # no consensus entry for this ip address
- lines[2] = 'No consensus data found'
-
- # crops any lines that are too long
-
- for i in range(len(lines)):
- lines[i] = str_tools.crop(lines[i], width - 2)
-
- return lines
-
- def get_destination_label(self, max_length, include_locale = False):
- """
- Provides a short description of the destination. This is made up of two
- components, the base <ip addr>:<port> and an extra piece of information in
- parentheses. The IP address is scrubbed from private connections.
-
- Extra information is...
- - the port's purpose for exit connections
- - the locale, the address isn't private and isn't on the local network
- - nothing otherwise
-
- Arguments:
- max_length - maximum length of the string returned
- include_locale - possibly includes the locale
- """
-
- # destination of the connection
-
- address_label = '<scrubbed>' if self._entry.is_private() else self.connection.remote_address
- port_label = ':%s' % self.connection.remote_port
- destination_address = address_label + port_label
-
- # Only append the extra info if there's at least a couple characters of
- # space (this is what's needed for the country codes).
-
- if len(destination_address) + 5 <= max_length:
- space_available = max_length - len(destination_address) - 3
-
- if self._entry.get_type() == Category.EXIT:
- purpose = connection.port_usage(self.connection.remote_port)
-
- if purpose:
- # BitTorrent is a common protocol to truncate, so just use "Torrent"
- # if there's not enough room.
-
- if len(purpose) > space_available and purpose == 'BitTorrent':
- purpose = 'Torrent'
-
- # crops with a hyphen if too long
-
- purpose = str_tools.crop(purpose, space_available, ending = str_tools.Ending.HYPHEN)
-
- destination_address += ' (%s)' % purpose
- elif not connection.is_private_address(self.connection.remote_address):
- extra_info = []
-
- if include_locale and not tor_controller().is_geoip_unavailable():
- foreign_locale = self.get_locale('??')
- extra_info.append(foreign_locale)
- space_available -= len(foreign_locale) + 2
-
- if extra_info:
- destination_address += ' (%s)' % ', '.join(extra_info)
-
- return destination_address[:max_length]
diff --git a/nyx/connections/descriptor_popup.py b/nyx/connections/descriptor_popup.py
deleted file mode 100644
index 358784c..0000000
--- a/nyx/connections/descriptor_popup.py
+++ /dev/null
@@ -1,174 +0,0 @@
-"""
-Popup providing the raw descriptor and consensus information for a relay.
-"""
-
-import math
-import curses
-
-import nyx.popups
-
-from nyx.util import tor_controller, ui_tools
-
-from stem.util import str_tools
-
-HEADERS = ['Consensus:', 'Microdescriptor:', 'Server Descriptor:']
-HEADER_COLOR = 'cyan'
-LINE_NUMBER_COLOR = 'yellow'
-
-BLOCK_START, BLOCK_END = '-----BEGIN ', '-----END '
-
-UNRESOLVED_MSG = 'No consensus data available'
-ERROR_MSG = 'Unable to retrieve data'
-
-
-def show_descriptor_popup(fingerprint, color, max_width, is_close_key):
- """
- Provides a dialog showing the descriptors for a given relay.
-
- :param str fingerprint: fingerprint of the relay to be shown
- :param str color: text color of the dialog
- :param int max_width: maximum width of the dialog
- :param function is_close_key: method to indicate if a key should close the
- dialog or not
-
- :returns: :class:`~nyx.util.panel.KeyInput` for the keyboard input that
- closed the dialog
- """
-
- if fingerprint:
- title = 'Consensus Descriptor:'
- lines = _display_text(fingerprint)
- show_line_numbers = True
- else:
- title = 'Consensus Descriptor (%s):' % fingerprint
- lines = [UNRESOLVED_MSG]
- show_line_numbers = False
-
- popup_height, popup_width = _preferred_size(lines, max_width, show_line_numbers)
-
- with nyx.popups.popup_window(popup_height, popup_width) as (popup, _, height):
- if not popup:
- return None
-
- scroll, redraw = 0, True
-
- while True:
- if redraw:
- _draw(popup, title, lines, color, scroll, show_line_numbers)
- redraw = False
-
- key = nyx.controller.get_controller().key_input()
-
- if key.is_scroll():
- new_scroll = ui_tools.get_scroll_position(key, scroll, height - 2, len(lines))
-
- if scroll != new_scroll:
- scroll, redraw = new_scroll, True
- elif is_close_key(key):
- return key
-
-
-def _display_text(fingerprint):
- """
- Provides the descriptors for a relay.
-
- :param str fingerprint: relay fingerprint to be looked up
-
- :returns: **list** with the lines that should be displayed in the dialog
- """
-
- controller = tor_controller()
- router_status_entry = controller.get_network_status(fingerprint, None)
- microdescriptor = controller.get_microdescriptor(fingerprint, None)
- server_descriptor = controller.get_server_descriptor(fingerprint, None)
-
- description = 'Consensus:\n\n%s' % (router_status_entry if router_status_entry else ERROR_MSG)
-
- if server_descriptor:
- description += '\n\nServer Descriptor:\n\n%s' % server_descriptor
-
- if microdescriptor:
- description += '\n\nMicrodescriptor:\n\n%s' % microdescriptor
-
- return description.split('\n')
-
-
-def _preferred_size(text, max_width, show_line_numbers):
- """
- Provides the preferred dimensions of our dialog.
-
- :param list text: lines of text to be shown
- :param int max_width: maximum width the dialog can be
- :param bool show_line_numbers: if we should leave room for line numbers
-
- :returns: **tuple** of the preferred (height, width)
- """
-
- width, height = 0, len(text) + 2
- line_number_width = int(math.log10(len(text))) + 2 if show_line_numbers else 0
- max_content_width = max_width - line_number_width - 4
-
- for line in text:
- width = min(max_width, max(width, len(line) + line_number_width + 4))
- height += len(line) / max_content_width # extra lines due to text wrap
-
- return (height, width)
-
-
-def _draw(popup, title, lines, entry_color, scroll, show_line_numbers):
- def draw_msg(popup, min_x, x, y, width, msg, *attr):
- while msg:
- draw_msg, msg = str_tools.crop(msg, width - x, None, ending = None, get_remainder = True)
-
- if not draw_msg:
- draw_msg, msg = str_tools.crop(msg, width - x), '' # first word is longer than the line
-
- x = popup.addstr(y, x, draw_msg, *attr)
-
- if msg:
- x, y = min_x, y + 1
-
- return x, y
-
- popup.win.erase()
-
- line_number_width = int(math.log10(len(lines))) + 1
- in_block = False # flag indicating if we're currently in crypto content
- width = popup.max_x - 2 # leave space on the right for the border and an empty line
- height = popup.max_y - 2 # height of the dialog without the top and bottom border
- offset = line_number_width + 3 if show_line_numbers else 2
-
- y = 1
-
- for i, line in enumerate(lines):
- keyword, value = line, ''
- color = entry_color
-
- if line in HEADERS:
- color = HEADER_COLOR
- elif line.startswith(BLOCK_START):
- in_block = True
- elif line.startswith(BLOCK_END):
- in_block = False
- elif in_block:
- keyword, value = '', line
- elif ' ' in line and line != UNRESOLVED_MSG and line != ERROR_MSG:
- keyword, value = line.split(' ', 1)
-
- if i < scroll:
- continue
-
- if show_line_numbers:
- popup.addstr(y, 2, str(i + 1).rjust(line_number_width), curses.A_BOLD, LINE_NUMBER_COLOR)
-
- x, y = draw_msg(popup, offset, offset, y, width, keyword, color, curses.A_BOLD)
- x, y = draw_msg(popup, offset, x + 1, y, width, value, color)
-
- y += 1
-
- if y > height:
- break
-
- popup.win.box()
- popup.addstr(0, 0, title, curses.A_STANDOUT)
- popup.win.refresh()
diff --git a/nyx/popups.py b/nyx/popups.py
index 351467f..d2d5ded 100644
--- a/nyx/popups.py
+++ b/nyx/popups.py
@@ -2,16 +2,28 @@
Functions for displaying popups in the interface.
"""
+import math
import curses
import operator
import nyx.controller
from nyx import __version__, __release_date__
-from nyx.util import panel, ui_tools
+from nyx.util import tor_controller, panel, ui_tools
+
+from stem.util import str_tools
NO_STATS_MSG = "Usage stats aren't available yet, press any key..."
+HEADERS = ['Consensus:', 'Microdescriptor:', 'Server Descriptor:']
+HEADER_COLOR = 'cyan'
+LINE_NUMBER_COLOR = 'yellow'
+
+BLOCK_START, BLOCK_END = '-----BEGIN ', '-----END '
+
+UNRESOLVED_MSG = 'No consensus data available'
+ERROR_MSG = 'Unable to retrieve data'
+
def popup_window(height = -1, width = -1, top = 0, left = 0, below_static = True):
"""
@@ -418,3 +430,156 @@ def show_menu(title, options, old_selection):
top_panel.set_title_visible(True)
return selection
+
+
+def show_descriptor_popup(fingerprint, color, max_width, is_close_key):
+ """
+ Provides a dialog showing the descriptors for a given relay.
+
+ :param str fingerprint: fingerprint of the relay to be shown
+ :param str color: text color of the dialog
+ :param int max_width: maximum width of the dialog
+ :param function is_close_key: method to indicate if a key should close the
+ dialog or not
+
+ :returns: :class:`~nyx.util.panel.KeyInput` for the keyboard input that
+ closed the dialog
+ """
+
+ if fingerprint:
+ title = 'Consensus Descriptor:'
+ lines = _display_text(fingerprint)
+ show_line_numbers = True
+ else:
+ title = 'Consensus Descriptor (%s):' % fingerprint
+ lines = [UNRESOLVED_MSG]
+ show_line_numbers = False
+
+ popup_height, popup_width = _preferred_size(lines, max_width, show_line_numbers)
+
+ with popup_window(popup_height, popup_width) as (popup, _, height):
+ if not popup:
+ return None
+
+ scroll, redraw = 0, True
+
+ while True:
+ if redraw:
+ _draw(popup, title, lines, color, scroll, show_line_numbers)
+ redraw = False
+
+ key = nyx.controller.get_controller().key_input()
+
+ if key.is_scroll():
+ new_scroll = ui_tools.get_scroll_position(key, scroll, height - 2, len(lines))
+
+ if scroll != new_scroll:
+ scroll, redraw = new_scroll, True
+ elif is_close_key(key):
+ return key
+
+
+def _display_text(fingerprint):
+ """
+ Provides the descriptors for a relay.
+
+ :param str fingerprint: relay fingerprint to be looked up
+
+ :returns: **list** with the lines that should be displayed in the dialog
+ """
+
+ controller = tor_controller()
+ router_status_entry = controller.get_network_status(fingerprint, None)
+ microdescriptor = controller.get_microdescriptor(fingerprint, None)
+ server_descriptor = controller.get_server_descriptor(fingerprint, None)
+
+ description = 'Consensus:\n\n%s' % (router_status_entry if router_status_entry else ERROR_MSG)
+
+ if server_descriptor:
+ description += '\n\nServer Descriptor:\n\n%s' % server_descriptor
+
+ if microdescriptor:
+ description += '\n\nMicrodescriptor:\n\n%s' % microdescriptor
+
+ return description.split('\n')
+
+
+def _preferred_size(text, max_width, show_line_numbers):
+ """
+ Provides the preferred dimensions of our dialog.
+
+ :param list text: lines of text to be shown
+ :param int max_width: maximum width the dialog can be
+ :param bool show_line_numbers: if we should leave room for line numbers
+
+ :returns: **tuple** of the preferred (height, width)
+ """
+
+ width, height = 0, len(text) + 2
+ line_number_width = int(math.log10(len(text))) + 2 if show_line_numbers else 0
+ max_content_width = max_width - line_number_width - 4
+
+ for line in text:
+ width = min(max_width, max(width, len(line) + line_number_width + 4))
+ height += len(line) / max_content_width # extra lines due to text wrap
+
+ return (height, width)
+
+
+def _draw(popup, title, lines, entry_color, scroll, show_line_numbers):
+ def draw_msg(popup, min_x, x, y, width, msg, *attr):
+ while msg:
+ draw_msg, msg = str_tools.crop(msg, width - x, None, ending = None, get_remainder = True)
+
+ if not draw_msg:
+ draw_msg, msg = str_tools.crop(msg, width - x), '' # first word is longer than the line
+
+ x = popup.addstr(y, x, draw_msg, *attr)
+
+ if msg:
+ x, y = min_x, y + 1
+
+ return x, y
+
+ popup.win.erase()
+
+ line_number_width = int(math.log10(len(lines))) + 1
+ in_block = False # flag indicating if we're currently in crypto content
+ width = popup.max_x - 2 # leave space on the right for the border and an empty line
+ height = popup.max_y - 2 # height of the dialog without the top and bottom border
+ offset = line_number_width + 3 if show_line_numbers else 2
+
+ y = 1
+
+ for i, line in enumerate(lines):
+ keyword, value = line, ''
+ color = entry_color
+
+ if line in HEADERS:
+ color = HEADER_COLOR
+ elif line.startswith(BLOCK_START):
+ in_block = True
+ elif line.startswith(BLOCK_END):
+ in_block = False
+ elif in_block:
+ keyword, value = '', line
+ elif ' ' in line and line != UNRESOLVED_MSG and line != ERROR_MSG:
+ keyword, value = line.split(' ', 1)
+
+ if i < scroll:
+ continue
+
+ if show_line_numbers:
+ popup.addstr(y, 2, str(i + 1).rjust(line_number_width), curses.A_BOLD, LINE_NUMBER_COLOR)
+
+ x, y = draw_msg(popup, offset, offset, y, width, keyword, color, curses.A_BOLD)
+ x, y = draw_msg(popup, offset, x + 1, y, width, value, color)
+
+ y += 1
+
+ if y > height:
+ break
+
+ popup.win.box()
+ popup.addstr(0, 0, title, curses.A_STANDOUT)
+ popup.win.refresh()
diff --git a/setup.py b/setup.py
index f5399ef..f5b1c05 100644
--- a/setup.py
+++ b/setup.py
@@ -99,7 +99,7 @@ setup(
author = nyx.__author__,
author_email = nyx.__contact__,
url = nyx.__url__,
- packages = ['nyx', 'nyx.connections', 'nyx.menu', 'nyx.util'],
+ packages = ['nyx', 'nyx.menu', 'nyx.util'],
keywords = 'tor onion controller',
install_requires = ['stem>=1.4.1'],
package_data = {'nyx': ['config/*', 'resources/*']},
1
0
commit 22a5dc2abcac959a29a351c276f576cd027446a6
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Jul 26 12:14:31 2015 -0700
Expanded SocksPort caused a stacktrace
There might be other spots too, but when tor added additional field to the
SocksPort torrc entry we broke due to expecting an integer.
---
nyx/connections/conn_entry.py | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/nyx/connections/conn_entry.py b/nyx/connections/conn_entry.py
index 42466d9..d945182 100644
--- a/nyx/connections/conn_entry.py
+++ b/nyx/connections/conn_entry.py
@@ -11,6 +11,7 @@ import nyx.util.ui_tools
from nyx.util import tor_controller
from nyx.connections import entries
+from stem.control import Listener
from stem.util import conf, connection, enum, str_tools
# Connection Categories:
@@ -82,10 +83,10 @@ class ConnectionLine(entries.ConnectionPanelLine):
self.application_pid = None
self.is_application_resolving = False
- my_or_port = controller.get_conf('ORPort', None)
- my_dir_port = controller.get_conf('DirPort', None)
- my_socks_port = controller.get_conf('SocksPort', '9050')
- my_ctl_port = controller.get_conf('ControlPort', None)
+ socks_ports = controller.get_ports(Listener.SOCKS, [])
+ or_ports = controller.get_ports(Listener.OR, [])
+ dir_ports = controller.get_ports(Listener.DIR, [])
+ control_ports = controller.get_ports(Listener.CONTROL, [])
# get all target ports in our hidden service configuation
@@ -94,20 +95,13 @@ class ConnectionLine(entries.ConnectionPanelLine):
for hs_config in controller.get_hidden_service_conf({}).values():
my_hidden_service_ports += [entry[2] for entry in hs_config['HiddenServicePort']]
- # the ORListenAddress can overwrite the ORPort
-
- listen_addr = controller.get_conf('ORListenAddress', None)
-
- if listen_addr and ':' in listen_addr:
- my_or_port = listen_addr[listen_addr.find(':') + 1:]
-
- if conn.local_port in (my_or_port, my_dir_port):
+ if conn.local_port in or_ports or conn.local_port in dir_ports:
self.base_type = Category.INBOUND
- elif conn.local_port == my_socks_port:
+ elif conn.local_port in socks_ports:
self.base_type = Category.SOCKS
elif conn.remote_port in my_hidden_service_ports:
self.base_type = Category.HIDDEN
- elif conn.local_port == my_ctl_port:
+ elif conn.local_port in control_ports:
self.base_type = Category.CONTROL
else:
self.base_type = Category.OUTBOUND
1
0
commit e65ce74cecea61bc2ee7683bbc8b82d1674c561b
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Jul 25 13:33:11 2015 -0700
Simplify connection panel title
Premature optimization is the root of all evil. There's no value in
pre-calculating the title in our update loop. Counting a few connections
is damn cheap.
---
nyx/connections/conn_panel.py | 44 +++++++++++++----------------------------
1 file changed, 14 insertions(+), 30 deletions(-)
diff --git a/nyx/connections/conn_panel.py b/nyx/connections/conn_panel.py
index 647a369..26d836d 100644
--- a/nyx/connections/conn_panel.py
+++ b/nyx/connections/conn_panel.py
@@ -4,6 +4,7 @@ Listing of the currently established connections tor has made.
import re
import time
+import collections
import curses
import threading
@@ -68,7 +69,6 @@ class ConnectionPanel(panel.Panel, threading.Thread):
nyx_config.set('features.connection.listing_type', Listing.keys()[Listing.index_of(Listing.FINGERPRINT)])
self._scroller = ui_tools.Scroller(True)
- self._title = 'Connections:' # title line of the panel
self._entries = [] # last fetched display entries
self._entry_lines = [] # individual lines rendered from the entries listing
self._show_details = False # presents the details panel if true
@@ -401,8 +401,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# title label with connection counts
if self.is_title_visible():
- title = 'Connection Details:' if self._show_details else self._title
- self.addstr(0, 0, title, curses.A_STANDOUT)
+ self._draw_title(self._entries)
scroll_offset = 0
@@ -440,6 +439,18 @@ class ConnectionPanel(panel.Panel, threading.Thread):
if draw_line >= height:
break
+ def _draw_title(self, entries):
+ if self._show_details:
+ title = 'Connection Details:'
+ elif not entries:
+ title = 'Connections:'
+ else:
+ counts = collections.Counter([entry.get_lines()[0].get_type() for entry in entries])
+ count_labels = ['%i %s' % (counts[category], category.lower()) for category in conn_entry.Category if counts[category]]
+ title = 'Connections (%s):' % ', '.join(count_labels)
+
+ self.addstr(0, 0, title, curses.A_STANDOUT)
+
def stop(self):
"""
Halts further resolutions and terminates the thread.
@@ -485,33 +496,6 @@ class ConnectionPanel(panel.Panel, threading.Thread):
exit_port = entry_line.foreign.get_port()
self._exit_port_usage[exit_port] = self._exit_port_usage.get(exit_port, 0) + 1
- # Counts the relays in each of the categories. This also flushes the
- # type cache for all of the connections (in case its changed since last
- # fetched).
-
- category_types = list(conn_entry.Category)
- type_counts = dict((type, 0) for type in category_types)
-
- for entry in new_entries:
- if isinstance(entry, conn_entry.ConnectionEntry):
- type_counts[entry.get_lines()[0].get_type()] += 1
- elif isinstance(entry, circ_entry.CircEntry):
- type_counts[conn_entry.Category.CIRCUIT] += 1
-
- # makes labels for all the categories with connections (ie,
- # "21 outbound", "1 control", etc)
-
- count_labels = []
-
- for category in category_types:
- if type_counts[category] > 0:
- count_labels.append('%i %s' % (type_counts[category], category.lower()))
-
- if count_labels:
- self._title = 'Connections (%s):' % ', '.join(count_labels)
- else:
- self._title = 'Connections:'
-
self._entries = new_entries
self._entry_lines = []
1
0
22 Sep '15
commit f240710412e3c5df157ab264a3f5e7c557eda452
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Jul 25 13:40:39 2015 -0700
Use itertools to enumerate connection lines
Simple one-liner to get a flattened list of our connection lines, rather than
loops.
---
nyx/connections/conn_panel.py | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/nyx/connections/conn_panel.py b/nyx/connections/conn_panel.py
index 26d836d..695c32e 100644
--- a/nyx/connections/conn_panel.py
+++ b/nyx/connections/conn_panel.py
@@ -6,6 +6,7 @@ import re
import time
import collections
import curses
+import itertools
import threading
import nyx.popups
@@ -162,11 +163,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
nyx_config.set('features.connection.order', ', '.join(ordering_keys))
self._entries.sort(key = lambda i: (i.get_sort_values(CONFIG['features.connection.order'], self.get_listing_type())))
-
- self._entry_lines = []
-
- for entry in self._entries:
- self._entry_lines += entry.get_lines()
+ self._entry_lines = list(itertools.chain.from_iterable([entry.get_lines() for entry in self._entries]))
def get_listing_type(self):
"""
@@ -496,12 +493,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
exit_port = entry_line.foreign.get_port()
self._exit_port_usage[exit_port] = self._exit_port_usage.get(exit_port, 0) + 1
- self._entries = new_entries
-
- self._entry_lines = []
-
- for entry in self._entries:
- self._entry_lines += entry.get_lines()
+ self._entries, self._entry_lines = new_entries, list(itertools.chain.from_iterable([entry.get_lines() for entry in new_entries]))
self.set_sort_order()
self._last_resource_fetch = current_resolution_count
1
0
22 Sep '15
commit ec33ca2aa9345c83736b229b8440ca83cb80e30b
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Jul 25 19:36:57 2015 -0700
Drop address and port from Endpoint class
Arm had an Endpoint to encapsulate connection information. Great! But Stem
gives us a Connection struct so... yeah. Lets use that.
---
nyx/connections/conn_entry.py | 54 +++++++++++++++--------------------------
nyx/connections/conn_panel.py | 7 +++---
nyx/connections/entries.py | 2 +-
3 files changed, 24 insertions(+), 39 deletions(-)
diff --git a/nyx/connections/conn_entry.py b/nyx/connections/conn_entry.py
index ec1779e..d0ff8dc 100644
--- a/nyx/connections/conn_entry.py
+++ b/nyx/connections/conn_entry.py
@@ -59,34 +59,20 @@ class Endpoint:
"""
def __init__(self, address, port):
- self.address = address
- self.port = port
+ self._address = address
+ self._port = port
self.is_or_port = False # if set, consider the port to possibly be an ORPort
# if set then this overwrites fingerprint lookups
self.fingerprint_overwrite = None
- def get_address(self):
- """
- Provides the address of the endpoint.
- """
-
- return self.address
-
- def get_port(self):
- """
- Provides the port of the endpoint.
- """
-
- return self.port
-
def get_locale(self, default = None):
"""
Provides the two letter country code of this relay.
"""
- return tor_controller().get_info('ip-to-country/%s' % self.address, default)
+ return tor_controller().get_info('ip-to-country/%s' % self._address, default)
def get_fingerprint(self, default = None):
"""
@@ -96,7 +82,7 @@ class Endpoint:
if self.fingerprint_overwrite:
return self.fingerprint_overwrite
- my_fingerprint = nyx.util.tracker.get_consensus_tracker().get_relay_fingerprint(self.address, self.port if self.is_or_port else None)
+ my_fingerprint = nyx.util.tracker.get_consensus_tracker().get_relay_fingerprint(self._address, self._port if self.is_or_port else None)
return my_fingerprint if my_fingerprint else default
def get_nickname(self, default = None):
@@ -191,12 +177,12 @@ class ConnectionLine(entries.ConnectionPanelLine):
ip_value = 0
- for comp in self.foreign.get_address().split('.'):
+ for comp in self.connection.remote_address.split('.'):
ip_value *= 255
ip_value += int(comp)
self.sort_address = ip_value
- self.sort_port = int(self.foreign.get_port())
+ self.sort_port = self.connection.remote_port
def get_listing_entry(self, width, current_time, listing_type):
"""
@@ -307,7 +293,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
controller = tor_controller()
if controller.is_user_traffic_allowed().inbound:
- all_matches = nyx.util.tracker.get_consensus_tracker().get_all_relay_fingerprints(self.foreign.get_address())
+ all_matches = nyx.util.tracker.get_consensus_tracker().get_all_relay_fingerprints(self.connection.remote_address)
return all_matches == []
elif my_type == Category.EXIT:
# DNS connections exiting us aren't private (since they're hitting our
@@ -318,7 +304,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
# will take a bit more work to propagate the information up from the
# connection resolver.
- return self.foreign.get_port() != '53'
+ return self.connection.remote_port != 53
# for everything else this isn't a concern
@@ -351,9 +337,9 @@ class ConnectionLine(entries.ConnectionPanelLine):
# Not a known relay. This might be an exit connection.
exit_policy = controller.get_exit_policy(None)
- port = self.foreign.get_port() if self.foreign.get_port() else None
+ port = self.connection.remote_port if self.connection.remote_port else None
- if exit_policy and exit_policy.can_exit_to(self.foreign.get_address(), port):
+ if exit_policy and exit_policy.can_exit_to(self.connection.remote_address, port):
self.cached_type = Category.EXIT
elif self._possible_client or self._possible_directory:
# This belongs to a known relay. If we haven't eliminated ourselves as
@@ -495,13 +481,13 @@ class ConnectionLine(entries.ConnectionPanelLine):
# - that extra field plus any previous
used_space = len(LABEL_FORMAT % tuple([''] * 4)) + LABEL_MIN_PADDING
- local_port = ':%s' % self.local.get_port() if self.include_port else ''
+ local_port = ':%s' % self.connection.local_port if self.include_port else ''
src, dst, etc = '', '', ''
if listing_type == entries.ListingType.IP_ADDRESS:
- my_external_address = controller.get_info('address', self.local.get_address())
- address_differ = my_external_address != self.local.get_address()
+ my_external_address = controller.get_info('address', self.connection.local_address)
+ address_differ = my_external_address != self.connection.local_address
# Expanding doesn't make sense, if the connection isn't actually
# going through Tor's external IP address. As there isn't a known
@@ -516,7 +502,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
if is_expansion_type:
src_address = my_external_address + local_port
else:
- src_address = self.local.get_address() + local_port
+ src_address = self.connection.local_address + local_port
if my_type in (Category.SOCKS, Category.CONTROL):
# Like inbound connections these need their source and destination to
@@ -544,7 +530,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
if address_differ and is_expansion_type and is_expanded_address_visible and self.include_expanded_addresses and CONFIG['features.connection.showColumn.expandedIp']:
# include the internal address in the src (extra 28 characters)
- internal_address = self.local.get_address() + local_port
+ internal_address = self.connection.local_address + local_port
# If this is an inbound connection then reverse ordering so it's:
# <foreign> --> <external> --> <internal>
@@ -705,7 +691,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
if contact:
lines[6] = 'contact: %s' % contact
else:
- all_matches = nyx.util.tracker.get_consensus_tracker().get_all_relay_fingerprints(self.foreign.get_address())
+ all_matches = nyx.util.tracker.get_consensus_tracker().get_all_relay_fingerprints(self.connection.remote_address)
if all_matches:
# multiple matches
@@ -761,8 +747,8 @@ class ConnectionLine(entries.ConnectionPanelLine):
# destination of the connection
- address_label = '<scrubbed>' if self.is_private() else self.foreign.get_address()
- port_label = ':%s' % self.foreign.get_port() if include_port else ''
+ address_label = '<scrubbed>' if self.is_private() else self.connection.remote_address
+ port_label = ':%s' % self.connection.remote_port if include_port else ''
destination_address = address_label + port_label
# Only append the extra info if there's at least a couple characters of
@@ -772,7 +758,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
space_available = max_length - len(destination_address) - 3
if self.get_type() == Category.EXIT and include_port:
- purpose = connection.port_usage(self.foreign.get_port())
+ purpose = connection.port_usage(self.connection.remote_port)
if purpose:
# BitTorrent is a common protocol to truncate, so just use "Torrent"
@@ -786,7 +772,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
purpose = str_tools.crop(purpose, space_available, ending = str_tools.Ending.HYPHEN)
destination_address += ' (%s)' % purpose
- elif not connection.is_private_address(self.foreign.get_address()):
+ elif not connection.is_private_address(self.connection.remote_address):
extra_info = []
controller = tor_controller()
diff --git a/nyx/connections/conn_panel.py b/nyx/connections/conn_panel.py
index 18fe7e7..193ec90 100644
--- a/nyx/connections/conn_panel.py
+++ b/nyx/connections/conn_panel.py
@@ -490,7 +490,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
if client_locale:
self._client_locale_usage[client_locale] = self._client_locale_usage.get(client_locale, 0) + 1
elif entry_line.get_type() == conn_entry.Category.EXIT:
- exit_port = entry_line.foreign.get_port()
+ exit_port = entry_line.connection.remote_port
self._exit_port_usage[exit_port] = self._exit_port_usage.get(exit_port, 0) + 1
self._entries, self._entry_lines = new_entries, list(itertools.chain.from_iterable([entry.get_lines() for entry in new_entries]))
@@ -516,8 +516,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
app_ports = []
for line in unresolved_lines:
- app_conn = line.local if line.get_type() == conn_entry.Category.HIDDEN else line.foreign
- app_ports.append(app_conn.get_port())
+ app_ports.append(line.connection.local_port if line.get_type() == conn_entry.Category.HIDDEN else line.connection.remote_port)
# Queue up resolution for the unresolved ports (skips if it's still working
# on the last query).
@@ -538,7 +537,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
for line in unresolved_lines:
is_local = line.get_type() == conn_entry.Category.HIDDEN
- line_port = line.local.get_port() if is_local else line.foreign.get_port()
+ line_port = line.connection.local_port if is_local else line.connection.remote_port
if line_port in app_results:
# sets application attributes if there's a result with this as the
diff --git a/nyx/connections/entries.py b/nyx/connections/entries.py
index 301b457..06d3831 100644
--- a/nyx/connections/entries.py
+++ b/nyx/connections/entries.py
@@ -146,7 +146,7 @@ class ConnectionPanelEntry:
elif attr == SortAttr.UPTIME:
return self.start_time
elif attr == SortAttr.COUNTRY:
- if connection_line.connection.is_private_address(self.lines[0].foreign.get_address()):
+ if connection_line.connection.is_private_address(self.lines[0].connection.remote_address):
return ''
else:
return connection_line.foreign.get_locale('')
1
0
commit 24092722fcf6b5eb8620e244ffd5816f7c3ffb19
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Jul 25 14:52:03 2015 -0700
Merge CircEntry class into its parent
Now that we're no longer doing in-place modifications the CircEntry is just a
constructor. Making it a factory method of the parent class rather than its
own. Still more opportunity for simplification, but one step at a time.
---
nyx/connections/circ_entry.py | 74 ++---------------------------------------
nyx/connections/conn_panel.py | 4 +--
nyx/connections/entries.py | 42 +++++++++++++++++++++++
3 files changed, 47 insertions(+), 73 deletions(-)
diff --git a/nyx/connections/circ_entry.py b/nyx/connections/circ_entry.py
index a80bc8a..c49dbc4 100644
--- a/nyx/connections/circ_entry.py
+++ b/nyx/connections/circ_entry.py
@@ -9,7 +9,6 @@ followed by an entry for each hop in the circuit. For instance:
"""
import curses
-import datetime
import nyx.util.tracker
import nyx.util.ui_tools
@@ -19,73 +18,6 @@ from nyx.connections import entries, conn_entry
from stem.util import str_tools
-def to_unix_time(dt):
- return (dt - datetime.datetime(1970, 1, 1)).total_seconds()
-
-
-class CircEntry(conn_entry.ConnectionEntry):
- def __init__(self, circ):
- conn_entry.ConnectionEntry.__init__(self, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, '127.0.0.1', 0, 'tcp'))
-
- self._circuit = circ
- self.circuit_id = circ.id
- self.status = circ.status
-
- # drops to lowercase except the first letter
-
- purpose = circ.purpose
-
- if len(purpose) >= 2:
- purpose = purpose[0].upper() + purpose[1:].lower()
-
- self.lines = [CircHeaderLine(circ)]
-
- # Overwrites attributes of the initial line to make it more fitting as the
- # header for our listing.
-
- self.lines[0].base_type = conn_entry.Category.CIRCUIT
-
- self.update(circ.status, [entry[0] for entry in circ.path])
-
- 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]]
-
- if status == 'BUILT' and not self.lines[0].is_built:
- exit_ip, exit_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(path[-1], ('192.168.0.1', 0))
- self.lines[0].set_exit(exit_ip, exit_port, path[-1])
-
- for i in range(len(path)):
- relay_fingerprint = path[i]
- relay_ip, relay_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(relay_fingerprint, ('192.168.0.1', 0))
-
- if i == len(path) - 1:
- if status == 'BUILT':
- placement_type = 'Exit'
- else:
- placement_type = 'Extending'
- elif i == 0:
- placement_type = 'Guard'
- else:
- placement_type = 'Middle'
-
- placement_label = '%i / %s' % (i + 1, placement_type)
-
- self.lines.append(CircLine(relay_ip, relay_port, relay_fingerprint, placement_label, to_unix_time(self._circuit.created)))
-
- self.lines[-1].is_last = True
-
-
class CircHeaderLine(conn_entry.ConnectionLine):
"""
Initial line of a client entry. This has the same basic format as connection
@@ -93,11 +25,11 @@ class CircHeaderLine(conn_entry.ConnectionLine):
"""
def __init__(self, circ):
- conn_entry.ConnectionLine.__init__(self, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, '0.0.0.0', 0, 'tcp'), False, False)
+ conn_entry.ConnectionLine.__init__(self, nyx.util.tracker.Connection(entries.to_unix_time(circ.created), False, '127.0.0.1', 0, '0.0.0.0', 0, 'tcp'), False, False)
self.circuit_id = circ.id
- self.purpose = circ.purpose
+ self.purpose = circ.purpose.capitalize()
self.is_built = False
- self._timestamp = to_unix_time(circ.created)
+ self._timestamp = entries.to_unix_time(circ.created)
def set_exit(self, exit_address, exit_port, exit_fingerprint):
conn_entry.ConnectionLine.__init__(self, nyx.util.tracker.Connection(self._timestamp, False, '127.0.0.1', 0, exit_address, exit_port, 'tcp'), False, False)
diff --git a/nyx/connections/conn_panel.py b/nyx/connections/conn_panel.py
index 695c32e..364c42f 100644
--- a/nyx/connections/conn_panel.py
+++ b/nyx/connections/conn_panel.py
@@ -12,7 +12,7 @@ import threading
import nyx.popups
import nyx.util.tracker
-from nyx.connections import descriptor_popup, entries, conn_entry, circ_entry
+from nyx.connections import descriptor_popup, entries, conn_entry
from nyx.util import panel, tor_controller, tracker, ui_tools
from stem.control import State
@@ -477,7 +477,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# fetches, not client circuits)
if not (circ.status == 'BUILT' and len(circ.path) == 1):
- new_entries.append(circ_entry.CircEntry(circ))
+ new_entries.append(entries.ConnectionPanelEntry.from_circuit(circ))
# update stats for client and exit connections
diff --git a/nyx/connections/entries.py b/nyx/connections/entries.py
index 9215b37..f4693b0 100644
--- a/nyx/connections/entries.py
+++ b/nyx/connections/entries.py
@@ -4,6 +4,8 @@ entry itself (ie, Tor connection, client circuit, etc) and the lines it
consists of in the listing.
"""
+import datetime
+
from stem.util import enum
# attributes we can list entries by
@@ -28,6 +30,10 @@ SORT_COLORS = {
PORT_COUNT = 65536
+def to_unix_time(dt):
+ return (dt - datetime.datetime(1970, 1, 1)).total_seconds()
+
+
class ConnectionPanelEntry:
"""
Common parent for connection panel entries. This consists of a list of lines
@@ -39,6 +45,42 @@ class ConnectionPanelEntry:
self.lines = []
self.flush_cache = True
+ @staticmethod
+ def from_circuit(circ):
+ import nyx.connections.circ_entry
+ import nyx.connections.conn_entry
+ import nyx.util.tracker
+
+ # TODO: should be ConnectionPanelEntry rather than a ConnectionEntry, but
+ # looks like that presently provides sorting
+
+ entry = nyx.connections.conn_entry.ConnectionEntry(nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, '127.0.0.1', 0, 'tcp'))
+ entry.lines = [nyx.connections.circ_entry.CircHeaderLine(circ)]
+
+ path = [path_entry[0] for path_entry in circ.path]
+
+ if circ.status == 'BUILT':
+ exit_ip, exit_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(path[-1], ('192.168.0.1', 0))
+ entry.lines[0].set_exit(exit_ip, exit_port, path[-1])
+
+ for i, relay_fingerprint in enumerate(path):
+ relay_ip, relay_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(relay_fingerprint, ('192.168.0.1', 0))
+
+ if i == len(path) - 1:
+ placement_type = 'Exit' if circ.status == 'BUILT' else 'Extending'
+ elif i == 0:
+ placement_type = 'Guard'
+ else:
+ placement_type = 'Middle'
+
+ placement_label = '%i / %s' % (i + 1, placement_type)
+
+ entry.lines.append(nyx.connections.circ_entry.CircLine(relay_ip, relay_port, relay_fingerprint, placement_label, to_unix_time(circ.created)))
+
+ entry.lines[-1].is_last = True
+
+ return entry
+
def get_lines(self):
"""
Provides the individual lines in the connection listing.
1
0