tor-commits
Threads by month
- ----- 2025 -----
- 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
January 2014
- 23 participants
- 2271 discussions
commit 91e5b30e4541e1849b5e5b2041c5fc4e6ee08af7
Author: Damian Johnson <atagar(a)torproject.org>
Date: Mon Jan 27 20:45:41 2014 -0800
Dropping the tor_tools module
Wow, I didn't expect to reach this point this weekend. The tor_tools module was
once a wrapper around TorCtl (providing more user friendly methods, thread
safety, etc). Stem provides all of these so a long term goal with the arm
rewrite has been to drop this module completely. Now we can!
---
arm/util/tor_tools.py | 499 -------------------------------------------------
1 file changed, 499 deletions(-)
diff --git a/arm/util/tor_tools.py b/arm/util/tor_tools.py
deleted file mode 100644
index 1cefa98..0000000
--- a/arm/util/tor_tools.py
+++ /dev/null
@@ -1,499 +0,0 @@
-"""
-Helper for working with an active tor process. This both provides a wrapper for
-accessing stem and notifications of state changes to subscribers.
-"""
-
-import threading
-
-import stem
-import stem.control
-
-from stem.util import log
-
-CONTROLLER = None # singleton Controller instance
-
-UNDEFINED = "<Undefined_ >"
-
-
-def get_conn():
- """
- Singleton constructor for a Controller. Be aware that this starts as being
- uninitialized, needing a stem Controller before it's fully functional.
- """
-
- global CONTROLLER
-
- if CONTROLLER is None:
- CONTROLLER = Controller()
-
- return CONTROLLER
-
-
-class Controller:
- """
- Stem wrapper providing convenience functions (mostly from the days of using
- TorCtl), listener functionality for tor's state, and the capability for
- controller connections to be restarted if closed.
- """
-
- def __init__(self):
- self.controller = None
- self.conn_lock = threading.RLock()
- self._consensus_lookup_cache = {} # lookup cache with network status entries
- self._descriptor_lookup_cache = {} # lookup cache with relay descriptors
-
- def init(self, controller):
- """
- Uses the given stem instance for future operations, notifying listeners
- about the change.
-
- Arguments:
- controller - stem based Controller instance
- """
-
- # TODO: We should reuse our controller instance so event listeners will be
- # re-attached. This is a point of regression until we do... :(
-
- if controller.is_alive() and controller != self.controller:
- self.conn_lock.acquire()
-
- if self.controller:
- self.close() # shut down current connection
-
- self.controller = controller
- log.info("Stem connected to tor version %s" % self.controller.get_version())
-
- self.controller.add_event_listener(self.ns_event, stem.control.EventType.NS)
- self.controller.add_event_listener(self.new_consensus_event, stem.control.EventType.NEWCONSENSUS)
- self.controller.add_event_listener(self.new_desc_event, stem.control.EventType.NEWDESC)
-
- # reset caches for ip -> fingerprint lookups
-
- self._consensus_lookup_cache = {}
- self._descriptor_lookup_cache = {}
-
- self.conn_lock.release()
-
- def close(self):
- """
- Closes the current stem instance and notifies listeners.
- """
-
- self.conn_lock.acquire()
-
- if self.controller:
- self.controller.close()
-
- self.conn_lock.release()
-
- def get_controller(self):
- return self.controller
-
- def is_alive(self):
- """
- Returns True if this has been initialized with a working stem instance,
- False otherwise.
- """
-
- self.conn_lock.acquire()
-
- result = False
-
- if self.controller:
- if self.controller.is_alive():
- result = True
- else:
- self.close()
-
- self.conn_lock.release()
- return result
-
- def get_info(self, param, default = UNDEFINED):
- """
- Queries the control port for the given GETINFO option, providing the
- default if the response is undefined or fails for any reason (error
- response, control port closed, initiated, etc).
-
- Arguments:
- param - GETINFO option to be queried
- default - result if the query fails
- """
-
- self.conn_lock.acquire()
-
- try:
- if not self.is_alive():
- if default != UNDEFINED:
- return default
- else:
- raise stem.SocketClosed()
-
- if default != UNDEFINED:
- return self.controller.get_info(param, default)
- else:
- return self.controller.get_info(param)
- except stem.SocketClosed as exc:
- self.close()
- raise exc
- finally:
- self.conn_lock.release()
-
- def get_option(self, param, default = UNDEFINED, multiple = False):
- """
- Queries the control port for the given configuration option, providing the
- default if the response is undefined or fails for any reason. If multiple
- values exist then this arbitrarily returns the first unless the multiple
- flag is set.
-
- Arguments:
- param - configuration option to be queried
- default - result if the query fails
- multiple - provides a list with all returned values if true, otherwise
- this just provides the first result
- """
-
- self.conn_lock.acquire()
-
- try:
- if not self.is_alive():
- if default != UNDEFINED:
- return default
- else:
- raise stem.SocketClosed()
-
- if default != UNDEFINED:
- return self.controller.get_conf(param, default, multiple)
- else:
- return self.controller.get_conf(param, multiple = multiple)
- except stem.SocketClosed as exc:
- self.close()
- raise exc
- finally:
- self.conn_lock.release()
-
- def set_option(self, param, value = None):
- """
- Issues a SETCONF to set the given option/value pair. An exeptions raised
- if it fails to be set. If no value is provided then this sets the option to
- 0 or NULL.
-
- Arguments:
- param - configuration option to be set
- value - value to set the parameter to (this can be either a string or a
- list of strings)
- """
-
- self.conn_lock.acquire()
-
- try:
- if not self.is_alive():
- raise stem.SocketClosed()
-
- self.controller.set_conf(param, value)
- except stem.SocketClosed as exc:
- self.close()
- raise exc
- finally:
- self.conn_lock.release()
-
- def save_conf(self):
- """
- Calls tor's SAVECONF method.
- """
-
- self.conn_lock.acquire()
-
- if self.is_alive():
- self.controller.save_conf()
-
- self.conn_lock.release()
-
- def get_circuits(self, default = []):
- """
- This provides a list with tuples of the form:
- (circuit_id, status, purpose, (fingerprint1, fingerprint2...))
-
- Arguments:
- default - value provided back if unable to query the circuit-status
- """
-
- # TODO: We're losing caching around this. We should check to see the call
- # volume of this and probably add it to stem.
-
- results = []
-
- for entry in self.controller.get_circuits():
- fingerprints = []
-
- for fp, nickname in entry.path:
- if not fp:
- consensus_entry = self.controller.get_network_status(nickname, None)
-
- if consensus_entry:
- fp = consensus_entry.fingerprint
-
- # It shouldn't be possible for this lookup to fail, but we
- # need to fill something (callers won't expect our own client
- # paths to have unknown relays). If this turns out to be wrong
- # then log a warning.
-
- if not fp:
- log.warn("Unable to determine the fingerprint for a relay in our own circuit: %s" % nickname)
- fp = "0" * 40
-
- fingerprints.append(fp)
-
- results.append((int(entry.id), entry.status, entry.purpose, fingerprints))
-
- if results:
- return results
- else:
- return default
-
- def get_my_flags(self, default = None):
- """
- Provides the flags held by this relay.
-
- Arguments:
- default - result if the query fails or this relay isn't a part of the consensus yet
- """
-
- my_fingerprint = self.get_info("fingerprint", None)
-
- if my_fingerprint:
- my_status_entry = self.controller.get_network_status(my_fingerprint)
-
- if my_status_entry:
- return my_status_entry.flags
-
- return default
-
- def get_version(self):
- """
- Provides the version of our tor instance, this is None if we don't have a
- connection.
- """
-
- self.conn_lock.acquire()
-
- try:
- return self.controller.get_version()
- except stem.SocketClosed:
- self.close()
- return None
- except:
- return None
- finally:
- self.conn_lock.release()
-
- def get_my_user(self):
- """
- Provides the user this process is running under. If unavailable this
- provides None.
- """
-
- return self.controller.get_user(None)
-
- def get_exit_policy(self):
- """
- Provides an ExitPolicy instance for the head of this relay's exit policy
- chain. If there's no active connection then this provides None.
- """
-
- self.conn_lock.acquire()
-
- result = None
-
- if self.is_alive():
- try:
- result = self.controller.get_exit_policy(None)
- except:
- pass
-
- self.conn_lock.release()
-
- return result
-
- def get_consensus_entry(self, relay_fingerprint):
- """
- Provides the most recently available consensus information for the given
- relay. This is none if no such information exists.
-
- Arguments:
- relay_fingerprint - fingerprint of the relay
- """
-
- self.conn_lock.acquire()
-
- result = None
-
- if self.is_alive():
- if not relay_fingerprint in self._consensus_lookup_cache:
- ns_entry = self.get_info("ns/id/%s" % relay_fingerprint, None)
- self._consensus_lookup_cache[relay_fingerprint] = ns_entry
-
- result = self._consensus_lookup_cache[relay_fingerprint]
-
- self.conn_lock.release()
-
- return result
-
- def get_descriptor_entry(self, relay_fingerprint):
- """
- Provides the most recently available descriptor information for the given
- relay. Unless FetchUselessDescriptors is set this may frequently be
- unavailable. If no such descriptor is available then this returns None.
-
- Arguments:
- relay_fingerprint - fingerprint of the relay
- """
-
- self.conn_lock.acquire()
-
- result = None
-
- if self.is_alive():
- if not relay_fingerprint in self._descriptor_lookup_cache:
- desc_entry = self.get_info("desc/id/%s" % relay_fingerprint, None)
- self._descriptor_lookup_cache[relay_fingerprint] = desc_entry
-
- result = self._descriptor_lookup_cache[relay_fingerprint]
-
- self.conn_lock.release()
-
- return result
-
- def get_relay_exit_policy(self, relay_fingerprint):
- """
- Provides the ExitPolicy instance associated with the given relay. The tor
- consensus entries don't indicate if private addresses are rejected or
- address-specific policies, so this is only used as a fallback if a recent
- descriptor is unavailable. This returns None if unable to determine the
- policy.
-
- Arguments:
- relay_fingerprint - fingerprint of the relay
- """
-
- self.conn_lock.acquire()
-
- result = None
-
- if self.is_alive():
- # attempts to fetch the policy via the descriptor
- descriptor = self.controller.get_server_descriptor(relay_fingerprint, None)
-
- if descriptor:
- result = descriptor.exit_policy
-
- self.conn_lock.release()
-
- return result
-
- def add_event_listener(self, listener, *event_types):
- """
- Directs further tor controller events to callback functions of the
- listener. If a new control connection is initialized then this listener is
- reattached.
- """
-
- self.conn_lock.acquire()
-
- if self.is_alive():
- self.controller.add_event_listener(listener, *event_types)
-
- self.conn_lock.release()
-
- def remove_event_listener(self, listener):
- """
- Stops the given event listener from being notified of further events.
- """
-
- self.conn_lock.acquire()
-
- if self.is_alive():
- self.controller.remove_event_listener(listener)
-
- self.conn_lock.release()
-
- def add_status_listener(self, callback):
- """
- Directs further events related to tor's controller status to the callback
- function.
-
- Arguments:
- callback - functor that'll accept the events, expected to be of the form:
- myFunction(controller, event_type)
- """
-
- self.controller.add_status_listener(callback)
-
- def reload(self):
- """
- This resets tor (sending a RELOAD signal to the control port) causing tor's
- internal state to be reset and the torrc reloaded.
- """
-
- self.conn_lock.acquire()
-
- try:
- if self.is_alive():
- try:
- self.controller.signal(stem.Signal.RELOAD)
- except Exception as exc:
- # new torrc parameters caused an error (tor's likely shut down)
- raise IOError(str(exc))
- finally:
- self.conn_lock.release()
-
- def shutdown(self, force = False):
- """
- Sends a shutdown signal to the attached tor instance. For relays the
- actual shutdown is delayed for thirty seconds unless the force flag is
- given. This raises an IOError if a signal is sent but fails.
-
- Arguments:
- force - triggers an immediate shutdown for relays if True
- """
-
- self.conn_lock.acquire()
-
- raised_exception = None
-
- if self.is_alive():
- try:
- is_relay = self.get_option("ORPort", None) is not None
-
- if force:
- self.controller.signal(stem.Signal.HALT)
- else:
- self.controller.signal(stem.Signal.SHUTDOWN)
-
- # shuts down control connection if we aren't making a delayed shutdown
-
- if force or not is_relay:
- self.close()
- except Exception as exc:
- raised_exception = IOError(str(exc))
-
- self.conn_lock.release()
-
- if raised_exception:
- raise raised_exception
-
- def ns_event(self, event):
- self._consensus_lookup_cache = {}
-
- def new_consensus_event(self, event):
- self.conn_lock.acquire()
-
- # reconstructs consensus based mappings
-
- self._consensus_lookup_cache = {}
-
- self.conn_lock.release()
-
- def new_desc_event(self, event):
- self.conn_lock.acquire()
- self._descriptor_lookup_cache = {}
- self.conn_lock.release()
1
0
commit 494f3b9538e7a5885bbe4841c045eb84dc78ddfe
Author: Damian Johnson <atagar(a)torproject.org>
Date: Mon Jan 27 19:38:48 2014 -0800
Removing dependencies on tor_tools
Swapping modules from tor_tools to directly using a stem controller. In several
instances tor_tools provided special handling used in only a single module. In
those cases I'm moving the helper there.
---
arm/config_panel.py | 18 +-
arm/connections/circ_entry.py | 43 +++-
arm/connections/conn_entry.py | 371 +++++++++++++++++++++++++++---
arm/connections/conn_panel.py | 34 ++-
arm/connections/descriptor_popup.py | 8 +-
arm/controller.py | 18 +-
arm/graphing/bandwidth_stats.py | 138 ++++++++++--
arm/graphing/conn_stats.py | 8 +-
arm/graphing/graph_panel.py | 4 +-
arm/graphing/resource_stats.py | 4 +-
arm/log_panel.py | 14 +-
arm/menu/actions.py | 11 +-
arm/starter.py | 6 -
arm/torrc_panel.py | 8 +-
arm/util/tor_config.py | 32 +--
arm/util/tor_tools.py | 423 +----------------------------------
16 files changed, 578 insertions(+), 562 deletions(-)
diff --git a/arm/config_panel.py b/arm/config_panel.py
index c2c2ee5..84f7f3a 100644
--- a/arm/config_panel.py
+++ b/arm/config_panel.py
@@ -9,7 +9,7 @@ import threading
import arm.controller
import popups
-from arm.util import panel, tor_config, tor_tools, ui_tools
+from arm.util import panel, tor_config, tor_controller, ui_tools
import stem.control
@@ -185,7 +185,7 @@ class ConfigEntry():
True if we have no value, false otherwise.
"""
- conf_value = tor_tools.get_conn().get_option(self.get(Field.OPTION), [], True)
+ conf_value = tor_controller().get_conf(self.get(Field.OPTION), [], True)
return not bool(conf_value)
@@ -196,7 +196,7 @@ class ConfigEntry():
value's type to provide a user friendly representation if able.
"""
- conf_value = ", ".join(tor_tools.get_conn().get_option(self.get(Field.OPTION), [], True))
+ conf_value = ", ".join(tor_controller().get_conf(self.get(Field.OPTION), [], True))
# provides nicer values for recognized types
@@ -234,10 +234,10 @@ class ConfigPanel(panel.Panel):
# initializes config contents if we're connected
- conn = tor_tools.get_conn()
- conn.add_status_listener(self.reset_listener)
+ controller = tor_controller()
+ controller.add_status_listener(self.reset_listener)
- if conn.is_alive():
+ if controller.is_alive():
self.reset_listener(None, stem.control.State.INIT, None)
def reset_listener(self, controller, event_type, _):
@@ -256,9 +256,9 @@ class ConfigPanel(panel.Panel):
self.conf_important_contents = []
if self.config_type == State.TOR:
- conn, config_option_lines = tor_tools.get_conn(), []
+ controller, config_option_lines = tor_controller(), []
custom_options = tor_config.get_custom_options()
- config_option_query = conn.get_info("config/names", None)
+ config_option_query = controller.get_info("config/names", None)
if config_option_query:
config_option_lines = config_option_query.strip().split("\n")
@@ -407,7 +407,7 @@ class ConfigPanel(panel.Panel):
# set_option accepts list inputs when there's multiple values
new_value = new_value.split(",")
- tor_tools.get_conn().set_option(config_option, new_value)
+ tor_controller().set_conf(config_option, new_value)
# forces the label to be remade with the new value
diff --git a/arm/connections/circ_entry.py b/arm/connections/circ_entry.py
index cc6b418..4aa3fc8 100644
--- a/arm/connections/circ_entry.py
+++ b/arm/connections/circ_entry.py
@@ -11,7 +11,9 @@ followed by an entry for each hop in the circuit. For instance:
import curses
from arm.connections import entries, conn_entry
-from arm.util import tor_tools, ui_tools
+from arm.util import tor_controller, ui_tools
+
+ADDRESS_LOOKUP_CACHE = {}
class CircEntry(conn_entry.ConnectionEntry):
@@ -48,15 +50,15 @@ class CircEntry(conn_entry.ConnectionEntry):
self.status = status
self.lines = [self.lines[0]]
- conn = tor_tools.get_conn()
+ controller = tor_controller()
if status == "BUILT" and not self.lines[0].is_built:
- exit_ip, exit_port = conn.get_relay_address(path[-1], ("192.168.0.1", "0"))
+ exit_ip, exit_port = get_relay_address(controller, 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 = conn.get_relay_address(relay_fingerprint, ("192.168.0.1", "0"))
+ relay_ip, relay_port = get_relay_address(controller, relay_fingerprint, ("192.168.0.1", "0"))
if i == len(path) - 1:
if status == "BUILT":
@@ -214,3 +216,36 @@ class CircLine(conn_entry.ConnectionLine):
return ((dst + etc, line_format),
(" " * (width - baseline_space - len(dst) - len(etc) + 5), line_format),
("%-14s" % self.placement_label, line_format))
+
+
+def get_relay_address(controller, relay_fingerprint, default = None):
+ """
+ Provides the (IP Address, ORPort) tuple for a given relay. If the lookup
+ fails then this returns the default.
+
+ Arguments:
+ relay_fingerprint - fingerprint of the relay
+ """
+
+ result = default
+
+ if controller.is_alive():
+ # query the address if it isn't yet cached
+ if not relay_fingerprint in ADDRESS_LOOKUP_CACHE:
+ if relay_fingerprint == controller.get_info("fingerprint", None):
+ # this is us, simply check the config
+ my_address = controller.get_info("address", None)
+ my_or_port = controller.get_conf("ORPort", None)
+
+ if my_address and my_or_port:
+ ADDRESS_LOOKUP_CACHE[relay_fingerprint] = (my_address, my_or_port)
+ else:
+ # check the consensus for the relay
+ relay = controller.get_network_status(relay_fingerprint, None)
+
+ if relay:
+ ADDRESS_LOOKUP_CACHE[relay_fingerprint] = (relay.address, relay.or_port)
+
+ result = ADDRESS_LOOKUP_CACHE.get(relay_fingerprint, default)
+
+ return result
diff --git a/arm/connections/conn_entry.py b/arm/connections/conn_entry.py
index a2bf55c..62c01f3 100644
--- a/arm/connections/conn_entry.py
+++ b/arm/connections/conn_entry.py
@@ -6,9 +6,11 @@ Connection panel entries related to actual connections to or from the system
import time
import curses
-from arm.util import tor_tools, ui_tools
+from arm.util import tor_controller, ui_tools
from arm.connections import entries
+import stem.control
+
from stem.util import conf, connection, enum, str_tools
# Connection Categories:
@@ -54,6 +56,17 @@ CONFIG = conf.config_dict("arm", {
"features.connection.showColumn.expandedIp": True,
})
+FINGERPRINT_TRACKER = None
+
+
+def get_fingerprint_tracker():
+ global FINGERPRINT_TRACKER
+
+ if FINGERPRINT_TRACKER is None:
+ FINGERPRINT_TRACKER = FingerprintTracker()
+
+ return FINGERPRINT_TRACKER
+
class Endpoint:
"""
@@ -120,8 +133,8 @@ class Endpoint:
default - return value if no locale information is available
"""
- conn = tor_tools.get_conn()
- return conn.get_info("ip-to-country/%s" % self.address, default)
+ controller = tor_controller()
+ return controller.get_info("ip-to-country/%s" % self.address, default)
def get_fingerprint(self):
"""
@@ -132,14 +145,13 @@ class Endpoint:
if self.fingerprint_overwrite:
return self.fingerprint_overwrite
- conn = tor_tools.get_conn()
- my_fingerprint = conn.get_relay_fingerprint(self.address)
+ my_fingerprint = get_fingerprint_tracker().get_relay_fingerprint(self.address)
# If there were multiple matches and our port is likely the ORPort then
# try again with that to narrow the results.
if not my_fingerprint and not self.is_not_or_port:
- my_fingerprint = conn.get_relay_fingerprint(self.address, self.port)
+ my_fingerprint = get_fingerprint_tracker().get_relay_fingerprint(self.address, self.port)
if my_fingerprint:
return my_fingerprint
@@ -155,8 +167,7 @@ class Endpoint:
my_fingerprint = self.get_fingerprint()
if my_fingerprint != "UNKNOWN":
- conn = tor_tools.get_conn()
- my_nickname = conn.get_relay_nickname(my_fingerprint)
+ my_nickname = get_fingerprint_tracker().get_relay_nickname(my_fingerprint)
if my_nickname:
return my_nickname
@@ -233,8 +244,8 @@ class ConnectionLine(entries.ConnectionPanelLine):
# overwrite the local fingerprint with ours
- conn = tor_tools.get_conn()
- self.local.fingerprint_overwrite = conn.get_info("fingerprint", None)
+ controller = tor_controller()
+ self.local.fingerprint_overwrite = controller.get_info("fingerprint", None)
# True if the connection has matched the properties of a client/directory
# connection every time we've checked. The criteria we check is...
@@ -251,15 +262,15 @@ class ConnectionLine(entries.ConnectionPanelLine):
self.application_pid = None
self.is_application_resolving = False
- my_or_port = conn.get_option("ORPort", None)
- my_dir_port = conn.get_option("DirPort", None)
- my_socks_port = conn.get_option("SocksPort", "9050")
- my_ctl_port = conn.get_option("ControlPort", None)
- my_hidden_service_ports = conn.get_hidden_service_ports()
+ 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)
+ my_hidden_service_ports = get_hidden_service_ports(controller)
# the ORListenAddress can overwrite the ORPort
- listen_addr = conn.get_option("ORListenAddress", None)
+ listen_addr = controller.get_conf("ORListenAddress", None)
if listen_addr and ":" in listen_addr:
my_or_port = listen_addr[listen_addr.find(":") + 1:]
@@ -410,10 +421,19 @@ class ConnectionLine(entries.ConnectionPanelLine):
# if we're a guard or bridge and the connection doesn't belong to a
# known relay then it might be client traffic
- conn = tor_tools.get_conn()
+ controller = tor_controller()
+
+ my_flags = []
+ my_fingerprint = self.get_info("fingerprint", None)
+
+ if my_fingerprint:
+ my_status_entry = self.controller.get_network_status(my_fingerprint)
- if "Guard" in conn.get_my_flags([]) or conn.get_option("BridgeRelay", None) == "1":
- all_matches = conn.get_relay_fingerprint(self.foreign.get_address(), get_all_matches = True)
+ if my_status_entry:
+ my_flags = my_status_entry.flags
+
+ if "Guard" in my_flags or controller.get_conf("BridgeRelay", None) == "1":
+ all_matches = get_fingerprint_tracker().get_relay_fingerprint(self.foreign.get_address(), get_all_matches = True)
return all_matches == []
elif my_type == Category.EXIT:
@@ -451,20 +471,20 @@ class ConnectionLine(entries.ConnectionPanelLine):
# The exitability, circuits, and fingerprints are all cached by the
# tor_tools util keeping this a quick lookup.
- conn = tor_tools.get_conn()
+ controller = tor_controller()
destination_fingerprint = self.foreign.get_fingerprint()
if destination_fingerprint == "UNKNOWN":
# Not a known relay. This might be an exit connection.
- if conn.is_exiting_allowed(self.foreign.get_address(), self.foreign.get_port()):
+ if is_exiting_allowed(controller, self.foreign.get_address(), self.foreign.get_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
# a possible client or directory connection then check if it still
# holds true.
- my_circuits = conn.get_circuits()
+ my_circuits = controller.get_circuits()
if self._possible_client:
# Checks that this belongs to the first hop in a circuit that's
@@ -472,8 +492,8 @@ class ConnectionLine(entries.ConnectionPanelLine):
# a built 1-hop connection since those are most likely a directory
# mirror).
- for _, status, _, path in my_circuits:
- if path and path[0] == destination_fingerprint and (status != "BUILT" or len(path) > 1):
+ for circ in my_circuits:
+ if circ.path and circ.path[0][0] == destination_fingerprint and (circ.status != "BUILT" or len(circ.path) > 1):
self.cached_type = Category.CIRCUIT # matched a probable guard connection
# if we fell through, we can eliminate ourselves as a guard in the future
@@ -483,8 +503,8 @@ class ConnectionLine(entries.ConnectionPanelLine):
if self._possible_directory:
# Checks if we match a built, single hop circuit.
- for _, status, _, path in my_circuits:
- if path and path[0] == destination_fingerprint and status == "BUILT" and len(path) == 1:
+ for circ in my_circuits:
+ if circ.path and circ.path[0][0] == destination_fingerprint and circ.status == "BUILT" and len(circ.path) == 1:
self.cached_type = Category.DIRECTORY
# if we fell through, eliminate ourselves as a directory connection
@@ -606,7 +626,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
listing_type - primary attribute we're listing connections by
"""
- conn = tor_tools.get_conn()
+ controller = tor_controller()
my_type = self.get_type()
destination_address = self.get_destination_label(26, include_locale = True)
@@ -621,7 +641,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
src, dst, etc = "", "", ""
if listing_type == entries.ListingType.IP_ADDRESS:
- my_external_address = conn.get_info("address", self.local.get_address())
+ my_external_address = controller.get_info("address", self.local.get_address())
address_differ = my_external_address != self.local.get_address()
# Expanding doesn't make sense, if the connection isn't actually
@@ -771,13 +791,13 @@ class ConnectionLine(entries.ConnectionPanelLine):
# exit connection)
fingerprint = self.foreign.get_fingerprint()
- conn = tor_tools.get_conn()
+ controller = tor_controller()
if fingerprint != "UNKNOWN":
# single match - display information available about it
- ns_entry = conn.get_consensus_entry(fingerprint)
- desc_entry = conn.get_descriptor_entry(fingerprint)
+ ns_entry = controller.get_info("ns/id/%s" % fingerprint, None)
+ desc_entry = controller.get_info("desc/id/%s" % fingerprint, None)
# append the fingerprint to the second line
@@ -804,7 +824,11 @@ class ConnectionLine(entries.ConnectionPanelLine):
if len(ns_lines) >= 2 and ns_lines[1].startswith("s "):
flags = ns_lines[1][2:]
- exit_policy = conn.get_relay_exit_policy(fingerprint)
+ exit_policy = None
+ descriptor = controller.get_server_descriptor(fingerprint, None)
+
+ if descriptor:
+ exit_policy = descriptor.exit_policy
if exit_policy:
policy_label = exit_policy.summary()
@@ -847,7 +871,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
if contact:
lines[6] = "contact: %s" % contact
else:
- all_matches = conn.get_relay_fingerprint(self.foreign.get_address(), get_all_matches = True)
+ all_matches = get_fingerprint_tracker().get_relay_fingerprint(self.foreign.get_address(), get_all_matches = True)
if all_matches:
# multiple matches
@@ -932,9 +956,9 @@ class ConnectionLine(entries.ConnectionPanelLine):
destination_address += " (%s)" % purpose
elif not connection.is_private_address(self.foreign.get_address()):
extra_info = []
- conn = tor_tools.get_conn()
+ controller = tor_controller()
- if include_locale and not conn.is_geoip_unavailable():
+ if include_locale and not controller.is_geoip_unavailable():
foreign_locale = self.foreign.get_locale("??")
extra_info.append(foreign_locale)
space_available -= len(foreign_locale) + 2
@@ -955,3 +979,280 @@ class ConnectionLine(entries.ConnectionPanelLine):
destination_address += " (%s)" % ", ".join(extra_info)
return destination_address[:max_length]
+
+
+def get_hidden_service_ports(controller, default = []):
+ """
+ Provides the target ports hidden services are configured to use.
+
+ Arguments:
+ default - value provided back if unable to query the hidden service ports
+ """
+
+ result = []
+ hs_options = controller.get_conf_map("HiddenServiceOptions", {})
+
+ for entry in hs_options.get("HiddenServicePort", []):
+ # HiddenServicePort entries are of the form...
+ #
+ # VIRTPORT [TARGET]
+ #
+ # ... with the TARGET being an address, port, or address:port. If the
+ # target port isn't defined then uses the VIRTPORT.
+
+ hs_port = None
+
+ if ' ' in entry:
+ virtport, target = entry.split(' ', 1)
+
+ if ':' in target:
+ hs_port = target.split(':', 1)[1] # target is an address:port
+ elif target.isdigit():
+ hs_port = target # target is a port
+ else:
+ hs_port = virtport # target is an address
+ else:
+ hs_port = entry # just has the virtual port
+
+ if hs_port.isdigit():
+ result.append(hs_port)
+
+ if result:
+ return result
+ else:
+ return default
+
+
+def is_exiting_allowed(controller, ip_address, port):
+ """
+ Checks if the given destination can be exited to by this relay, returning
+ True if so and False otherwise.
+ """
+
+ result = False
+
+ if controller.is_alive():
+ # If we allow any exiting then this could be relayed DNS queries,
+ # otherwise the policy is checked. Tor still makes DNS connections to
+ # test when exiting isn't allowed, but nothing is relayed over them.
+ # I'm registering these as non-exiting to avoid likely user confusion:
+ # https://trac.torproject.org/projects/tor/ticket/965
+
+ our_policy = controller.get_exit_policy(None)
+
+ if our_policy and our_policy.is_exiting_allowed() and port == "53":
+ result = True
+ else:
+ result = our_policy and our_policy.can_exit_to(ip_address, port)
+
+ return result
+
+
+class FingerprintTracker:
+ def __init__(self):
+ # mappings of ip -> [(port, fingerprint), ...]
+
+ self._fingerprint_mappings = None
+
+ # lookup cache with (ip, port) -> fingerprint mappings
+
+ self._fingerprint_lookup_cache = {}
+
+ # lookup cache with fingerprint -> nickname mappings
+
+ self._nickname_lookup_cache = {}
+
+ controller = tor_controller()
+
+ controller.add_event_listener(self.new_consensus_event, stem.control.EventType.NEWCONSENSUS)
+ controller.add_event_listener(self.new_desc_event, stem.control.EventType.NEWDESC)
+
+ def new_consensus_event(self, event):
+ self._fingerprint_lookup_cache = {}
+ self._nickname_lookup_cache = {}
+
+ if self._fingerprint_mappings is not None:
+ self._fingerprint_mappings = self._get_fingerprint_mappings(event.desc)
+
+ def new_desc_event(self, event):
+ # If we're tracking ip address -> fingerprint mappings then update with
+ # the new relays.
+
+ self._fingerprint_lookup_cache = {}
+
+ if self._fingerprint_mappings is not None:
+ desc_fingerprints = [fingerprint for (fingerprint, nickname) in event.relays]
+
+ for fingerprint in desc_fingerprints:
+ # gets consensus data for the new descriptor
+
+ try:
+ desc = tor_controller().get_network_status(fingerprint)
+ except stem.ControllerError:
+ continue
+
+ # updates fingerprintMappings with new data
+
+ if desc.address in self._fingerprint_mappings:
+ # if entry already exists with the same orport, remove it
+
+ orport_match = None
+
+ for entry_port, entry_fingerprint in self._fingerprint_mappings[desc.address]:
+ if entry_port == desc.or_port:
+ orport_match = (entry_port, entry_fingerprint)
+ break
+
+ if orport_match:
+ self._fingerprint_mappings[desc.address].remove(orport_match)
+
+ # add the new entry
+
+ self._fingerprint_mappings[desc.address].append((desc.or_port, desc.fingerprint))
+ else:
+ self._fingerprint_mappings[desc.address] = [(desc.or_port, desc.fingerprint)]
+
+ def get_relay_fingerprint(self, relay_address, relay_port = None, get_all_matches = False):
+ """
+ Provides the fingerprint associated with the given address. If there's
+ multiple potential matches or the mapping is unknown then this returns
+ None. This disambiguates the fingerprint if there's multiple relays on
+ the same ip address by several methods, one of them being to pick relays
+ we have a connection with.
+
+ Arguments:
+ relay_address - address of relay to be returned
+ relay_port - orport of relay (to further narrow the results)
+ get_all_matches - ignores the relay_port and provides all of the
+ (port, fingerprint) tuples matching the given
+ address
+ """
+
+ result = None
+ controller = tor_controller()
+
+ if controller.is_alive():
+ if get_all_matches:
+ # populates the ip -> fingerprint mappings if not yet available
+ if self._fingerprint_mappings is None:
+ self._fingerprint_mappings = self._get_fingerprint_mappings()
+
+ if relay_address in self._fingerprint_mappings:
+ result = self._fingerprint_mappings[relay_address]
+ else:
+ result = []
+ else:
+ # query the fingerprint if it isn't yet cached
+ if not (relay_address, relay_port) in self._fingerprint_lookup_cache:
+ relay_fingerprint = self._get_relay_fingerprint(controller, relay_address, relay_port)
+ self._fingerprint_lookup_cache[(relay_address, relay_port)] = relay_fingerprint
+
+ result = self._fingerprint_lookup_cache[(relay_address, relay_port)]
+
+ return result
+
+ def get_relay_nickname(self, relay_fingerprint):
+ """
+ Provides the nickname associated with the given relay. This provides None
+ if no such relay exists, and "Unnamed" if the name hasn't been set.
+
+ Arguments:
+ relay_fingerprint - fingerprint of the relay
+ """
+
+ result = None
+ controller = tor_controller()
+
+ if controller.is_alive():
+ # query the nickname if it isn't yet cached
+ if not relay_fingerprint in self._nickname_lookup_cache:
+ if relay_fingerprint == controller.get_info("fingerprint", None):
+ # this is us, simply check the config
+ my_nickname = controller.get_conf("Nickname", "Unnamed")
+ self._nickname_lookup_cache[relay_fingerprint] = my_nickname
+ else:
+ ns_entry = controller.get_network_status(relay_fingerprint, None)
+
+ if ns_entry:
+ self._nickname_lookup_cache[relay_fingerprint] = ns_entry.nickname
+
+ result = self._nickname_lookup_cache[relay_fingerprint]
+
+ return result
+
+ def _get_relay_fingerprint(self, controller, relay_address, relay_port):
+ """
+ Provides the fingerprint associated with the address/port combination.
+
+ Arguments:
+ relay_address - address of relay to be returned
+ relay_port - orport of relay (to further narrow the results)
+ """
+
+ # If we were provided with a string port then convert to an int (so
+ # lookups won't mismatch based on type).
+
+ if isinstance(relay_port, str):
+ relay_port = int(relay_port)
+
+ # checks if this matches us
+
+ if relay_address == controller.get_info("address", None):
+ if not relay_port or str(relay_port) == controller.get_conf("ORPort", None):
+ return controller.get_info("fingerprint", None)
+
+ # if we haven't yet populated the ip -> fingerprint mappings then do so
+
+ if self._fingerprint_mappings is None:
+ self._fingerprint_mappings = self._get_fingerprint_mappings()
+
+ potential_matches = self._fingerprint_mappings.get(relay_address)
+
+ if not potential_matches:
+ return None # no relay matches this ip address
+
+ if len(potential_matches) == 1:
+ # There's only one relay belonging to this ip address. If the port
+ # matches then we're done.
+
+ match = potential_matches[0]
+
+ if relay_port and match[0] != relay_port:
+ return None
+ else:
+ return match[1]
+ elif relay_port:
+ # Multiple potential matches, so trying to match based on the port.
+ for entry_port, entry_fingerprint in potential_matches:
+ if entry_port == relay_port:
+ return entry_fingerprint
+
+ return None
+
+ def _get_fingerprint_mappings(self, descriptors = None):
+ """
+ Provides IP address to (port, fingerprint) tuple mappings for all of the
+ currently cached relays.
+
+ Arguments:
+ descriptors - router status entries (fetched if not provided)
+ """
+
+ results = {}
+ controller = tor_controller()
+
+ if controller.is_alive():
+ # fetch the current network status if not provided
+
+ if not descriptors:
+ try:
+ descriptors = controller.get_network_statuses()
+ except stem.ControllerError:
+ descriptors = []
+
+ # construct mappings of ips to relay data
+
+ for desc in descriptors:
+ results.setdefault(desc.address, []).append((desc.or_port, desc.fingerprint))
+
+ return results
diff --git a/arm/connections/conn_panel.py b/arm/connections/conn_panel.py
index 5ccd880..fe9b5a6 100644
--- a/arm/connections/conn_panel.py
+++ b/arm/connections/conn_panel.py
@@ -11,7 +11,7 @@ import arm.popups
import arm.util.tracker
from arm.connections import count_popup, descriptor_popup, entries, conn_entry, circ_entry
-from arm.util import panel, tor_tools, tracker, ui_tools
+from arm.util import panel, tor_controller, tracker, ui_tools
from stem.control import State
from stem.util import conf, connection, enum
@@ -88,8 +88,8 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# If we're a bridge and been running over a day then prepopulates with the
# last day's clients.
- conn = tor_tools.get_conn()
- bridge_clients = conn.get_info("status/clients-seen", None)
+ controller = tor_controller()
+ bridge_clients = controller.get_info("status/clients-seen", None)
if bridge_clients:
# Response has a couple arguments...
@@ -129,7 +129,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# listens for when tor stops so we know to stop reflecting changes
- conn.add_status_listener(self.tor_state_listener)
+ controller.add_status_listener(self.tor_state_listener)
def tor_state_listener(self, controller, event_type, _):
"""
@@ -217,18 +217,30 @@ class ConnectionPanel(panel.Panel, threading.Thread):
True if client connections are permissable, false otherwise.
"""
- conn = tor_tools.get_conn()
- return "Guard" in conn.get_my_flags([]) or conn.get_option("BridgeRelay", None) == "1"
+ controller = tor_controller()
+
+ my_flags = []
+ my_fingerprint = self.get_info("fingerprint", None)
+
+ if my_fingerprint:
+ my_status_entry = self.controller.get_network_status(my_fingerprint)
+
+ if my_status_entry:
+ my_flags = my_status_entry.flags
+
+ return "Guard" in my_flags or controller.get_conf("BridgeRelay", None) == "1"
def is_exits_allowed(self):
"""
True if exit connections are permissable, false otherwise.
"""
- if not tor_tools.get_conn().get_option("ORPort", None):
+ controller = tor_controller()
+
+ if not controller.get_conf("ORPort", None):
return False # no ORPort
- policy = tor_tools.get_conn().get_exit_policy()
+ policy = controller.get_exit_policy(None)
return policy and policy.is_exiting_allowed()
@@ -508,12 +520,12 @@ class ConnectionPanel(panel.Panel, threading.Thread):
new_connections = [(conn.local_address, conn.local_port, conn.remote_address, conn.remote_port) for conn in conn_resolver.get_connections()]
new_circuits = {}
- for circuit_id, status, purpose, path in tor_tools.get_conn().get_circuits():
+ for circ in tor_controller().get_circuits():
# Skips established single-hop circuits (these are for directory
# fetches, not client circuits)
- if not (status == "BUILT" and len(path) == 1):
- new_circuits[circuit_id] = (status, purpose, path)
+ if not (circ.status == "BUILT" and len(circ.path) == 1):
+ new_circuits[circ.id] = (circ.status, circ.purpose, [entry[0] for entry in circ.path])
# Populates new_entries with any of our old entries that still exist.
# This is both for performance and to keep from resetting the uptime
diff --git a/arm/connections/descriptor_popup.py b/arm/connections/descriptor_popup.py
index 6dbad9c..9404224 100644
--- a/arm/connections/descriptor_popup.py
+++ b/arm/connections/descriptor_popup.py
@@ -8,7 +8,7 @@ import curses
import arm.popups
import arm.connections.conn_entry
-from arm.util import panel, tor_tools, ui_tools
+from arm.util import panel, tor_controller, ui_tools
# field keywords used to identify areas for coloring
@@ -116,10 +116,10 @@ def get_display_text(fingerprint):
if not fingerprint:
return [UNRESOLVED_MSG]
- conn, description = tor_tools.get_conn(), []
+ controller, description = tor_controller(), []
description.append("ns/id/%s" % fingerprint)
- consensus_entry = conn.get_consensus_entry(fingerprint)
+ consensus_entry = controller.get_info("ns/id/%s" % fingerprint, None)
if consensus_entry:
description += consensus_entry.split("\n")
@@ -127,7 +127,7 @@ def get_display_text(fingerprint):
description += [ERROR_MSG, ""]
description.append("desc/id/%s" % fingerprint)
- descriptor_entry = conn.get_descriptor_entry(fingerprint)
+ descriptor_entry = controller.get_info("desc/id/%s" % fingerprint, None)
if descriptor_entry:
description += descriptor_entry.split("\n")
diff --git a/arm/controller.py b/arm/controller.py
index e684215..e1c3991 100644
--- a/arm/controller.py
+++ b/arm/controller.py
@@ -22,9 +22,11 @@ import arm.graphing.resource_stats
import arm.connections.conn_panel
import arm.util.tracker
+import stem
+
from stem.control import State
-from arm.util import panel, tor_config, tor_tools, ui_tools
+from arm.util import panel, tor_config, tor_controller, ui_tools
from stem.util import conf, enum, log, system
@@ -128,7 +130,7 @@ def init_controller(stdscr, start_time):
# functioning. It'll have circuits, but little else. If this is the case then
# notify the user and tell them what they can do to fix it.
- controller = tor_tools.get_conn().controller
+ controller = tor_controller()
if controller.get_conf("DisableDebuggerAttachment", None) == "1":
log.notice("Tor is preventing system utilities like netstat and lsof from working. This means that arm can't provide you with connection information. You can change this by adding 'DisableDebuggerAttachment 0' to your torrc and restarting tor. For more information see...\nhttps://trac.torproject.org/3313")
@@ -195,7 +197,7 @@ def init_controller(stdscr, start_time):
# prepopulates bandwidth values from state file
- if CONFIG["features.graph.bw.prepopulate"] and tor_tools.get_conn().is_alive():
+ if CONFIG["features.graph.bw.prepopulate"] and tor_controller().is_alive():
is_successful = bw_stats.prepopulate_from_state()
if is_successful:
@@ -528,7 +530,7 @@ class Controller:
if is_shutdown_flag_present:
try:
- tor_tools.get_conn().shutdown()
+ tor_controller().close()
except IOError as exc:
arm.popups.show_msg(str(exc), 3, curses.A_BOLD)
@@ -541,10 +543,10 @@ def heartbeat_check(is_unresponsive):
is_unresponsive - flag for if we've indicated to be responsive or not
"""
- conn = tor_tools.get_conn()
- last_heartbeat = conn.controller.get_latest_heartbeat()
+ controller = tor_controller()
+ last_heartbeat = controller.get_latest_heartbeat()
- if conn.is_alive():
+ if controller.is_alive():
if not is_unresponsive and (time.time() - last_heartbeat) >= 10:
is_unresponsive = True
log.notice("Relay unresponsive (last heartbeat: %s)" % time.ctime(last_heartbeat))
@@ -674,7 +676,7 @@ def start_arm(stdscr):
if confirmation_key in (ord('x'), ord('X')):
try:
- tor_tools.get_conn().reload()
+ tor_controller().signal(stem.Signal.RELOAD)
except IOError as exc:
log.error("Error detected when reloading tor: %s" % exc.strerror)
elif key == ord('h') or key == ord('H'):
diff --git a/arm/graphing/bandwidth_stats.py b/arm/graphing/bandwidth_stats.py
index 9cba96f..b781d3e 100644
--- a/arm/graphing/bandwidth_stats.py
+++ b/arm/graphing/bandwidth_stats.py
@@ -9,7 +9,7 @@ import curses
import arm.controller
from arm.graphing import graph_panel
-from arm.util import tor_tools, ui_tools
+from arm.util import tor_controller, ui_tools
from stem.control import State
from stem.util import conf, log, str_tools, system
@@ -65,13 +65,13 @@ class BandwidthStats(graph_panel.GraphStats):
# listens for tor reload (sighup) events which can reset the bandwidth
# rate/burst and if tor's using accounting
- conn = tor_tools.get_conn()
+ controller = tor_controller()
self._title_stats, self.is_accounting = [], False
if not is_pause_buffer:
- self.reset_listener(conn.get_controller(), State.INIT, None) # initializes values
+ self.reset_listener(controller, State.INIT, None) # initializes values
- conn.add_status_listener(self.reset_listener)
+ controller.add_status_listener(self.reset_listener)
# Initialized the bandwidth totals to the values reported by Tor. This
# uses a controller options introduced in ticket 2345:
@@ -83,12 +83,12 @@ class BandwidthStats(graph_panel.GraphStats):
self.initial_primary_total = 0
self.initial_secondary_total = 0
- read_total = conn.get_info("traffic/read", None)
+ read_total = controller.get_info("traffic/read", None)
if read_total and read_total.isdigit():
self.initial_primary_total = int(read_total) / 1024 # Bytes -> KB
- write_total = conn.get_info("traffic/written", None)
+ write_total = controller.get_info("traffic/written", None)
if write_total and write_total.isdigit():
self.initial_secondary_total = int(write_total) / 1024 # Bytes -> KB
@@ -138,8 +138,8 @@ class BandwidthStats(graph_panel.GraphStats):
# checks that this is a relay (if ORPort is unset, then skip)
- conn = tor_tools.get_conn()
- or_port = conn.get_option("ORPort", None)
+ controller = tor_controller()
+ or_port = controller.get_conf("ORPort", None)
if or_port == "0":
return
@@ -150,7 +150,7 @@ class BandwidthStats(graph_panel.GraphStats):
# something else
uptime = None
- query_pid = conn.controller.get_pid(None)
+ query_pid = controller.get_pid(None)
if query_pid:
query_param = ["%cpu", "rss", "%mem", "etime"]
@@ -174,7 +174,7 @@ class BandwidthStats(graph_panel.GraphStats):
# get the user's data directory (usually '~/.tor')
- data_dir = conn.get_option("DataDirectory", None)
+ data_dir = controller.get_conf("DataDirectory", None)
if not data_dir:
msg = PREPOPULATE_FAILURE_MSG % "data directory not found"
@@ -313,7 +313,7 @@ class BandwidthStats(graph_panel.GraphStats):
# provides accounting stats if enabled
if self.is_accounting:
- if tor_tools.get_conn().is_alive():
+ if tor_controller().is_alive():
status = self.accounting_info["status"]
hibernate_color = "green"
@@ -402,19 +402,19 @@ class BandwidthStats(graph_panel.GraphStats):
def new_desc_event(self, event):
# updates self._title_stats with updated values
- conn = tor_tools.get_conn()
+ controller = tor_controller()
- if not conn.is_alive():
+ if not controller.is_alive():
return # keep old values
- my_fingerprint = conn.get_info("fingerprint", None)
+ my_fingerprint = controller.get_info("fingerprint", None)
if not self._title_stats or not my_fingerprint or (event and my_fingerprint in event.idlist):
stats = []
- bw_rate = conn.get_my_bandwidth_rate()
- bw_burst = conn.get_my_bandwidth_burst()
- bw_observed = conn.get_my_bandwidth_observed()
- bw_measured = conn.get_my_bandwidth_measured()
+ bw_rate = get_my_bandwidth_rate(controller)
+ bw_burst = get_my_bandwidth_burst(controller)
+ bw_observed = get_my_bandwidth_observed(controller)
+ bw_measured = get_my_bandwidth_measured(controller)
label_in_bytes = CONFIG["features.graph.bw.transferInBytes"]
if bw_rate and bw_burst:
@@ -460,13 +460,13 @@ class BandwidthStats(graph_panel.GraphStats):
Any failed lookups result in a mapping to an empty string.
"""
- conn = tor_tools.get_conn()
+ controller = tor_controller()
queried = dict([(arg, "") for arg in ACCOUNTING_ARGS])
- queried["status"] = conn.get_info("accounting/hibernating", None)
+ queried["status"] = controller.get_info("accounting/hibernating", None)
# provides a nicely formatted reset time
- end_interval = conn.get_info("accounting/interval-end", None)
+ end_interval = controller.get_info("accounting/interval-end", None)
if end_interval:
# converts from gmt to local with respect to DST
@@ -491,8 +491,8 @@ class BandwidthStats(graph_panel.GraphStats):
# number of bytes used and in total for the accounting period
- used = conn.get_info("accounting/bytes", None)
- left = conn.get_info("accounting/bytes-left", None)
+ used = controller.get_info("accounting/bytes", None)
+ left = controller.get_info("accounting/bytes-left", None)
if used and left:
used_comp, left_comp = used.split(" "), left.split(" ")
@@ -506,3 +506,95 @@ class BandwidthStats(graph_panel.GraphStats):
self.accounting_info = queried
self.accounting_last_updated = time.time()
+
+
+def get_my_bandwidth_rate(controller):
+ """
+ Provides the effective relaying bandwidth rate of this relay. Currently
+ this doesn't account for SETCONF events.
+ """
+
+ # effective relayed bandwidth is the minimum of BandwidthRate,
+ # MaxAdvertisedBandwidth, and RelayBandwidthRate (if set)
+
+ effective_rate = int(controller.get_conf("BandwidthRate", None))
+
+ relay_rate = controller.get_conf("RelayBandwidthRate", None)
+
+ if relay_rate and relay_rate != "0":
+ effective_rate = min(effective_rate, int(relay_rate))
+
+ max_advertised = controller.get_conf("MaxAdvertisedBandwidth", None)
+
+ if max_advertised:
+ effective_rate = min(effective_rate, int(max_advertised))
+
+ if effective_rate is not None:
+ return effective_rate
+ else:
+ return None
+
+
+def get_my_bandwidth_burst(controller):
+ """
+ Provides the effective bandwidth burst rate of this relay. Currently this
+ doesn't account for SETCONF events.
+ """
+
+ # effective burst (same for BandwidthBurst and RelayBandwidthBurst)
+ effective_burst = int(controller.get_conf("BandwidthBurst", None))
+
+ relay_burst = controller.get_conf("RelayBandwidthBurst", None)
+
+ if relay_burst and relay_burst != "0":
+ effective_burst = min(effective_burst, int(relay_burst))
+
+ if effective_burst is not None:
+ return effective_burst
+ else:
+ return None
+
+
+def get_my_bandwidth_observed(controller):
+ """
+ Provides the relay's current observed bandwidth (the throughput determined
+ from historical measurements on the client side). This is used in the
+ heuristic used for path selection if the measured bandwidth is undefined.
+ This is fetched from the descriptors and hence will get stale if
+ descriptors aren't periodically updated.
+ """
+
+ my_fingerprint = controller.get_info("fingerprint", None)
+
+ if my_fingerprint:
+ my_descriptor = controller.get_server_descriptor(my_fingerprint)
+
+ if my_descriptor:
+ return my_descriptor.observed_bandwidth
+
+ return None
+
+
+def get_my_bandwidth_measured(controller):
+ """
+ Provides the relay's current measured bandwidth (the throughput as noted by
+ the directory authorities and used by clients for relay selection). This is
+ undefined if not in the consensus or with older versions of Tor. Depending
+ on the circumstances this can be from a variety of things (observed,
+ measured, weighted measured, etc) as described by:
+ https://trac.torproject.org/projects/tor/ticket/1566
+ """
+
+ # TODO: Tor is documented as providing v2 router status entries but
+ # actually looks to be v3. This needs to be sorted out between stem
+ # and tor.
+
+ my_fingerprint = controller.get_info("fingerprint", None)
+
+ if my_fingerprint:
+ my_status_entry = controller.get_network_status(my_fingerprint)
+
+ if my_status_entry and hasattr(my_status_entry, 'bandwidth'):
+ return my_status_entry.bandwidth
+
+ return None
diff --git a/arm/graphing/conn_stats.py b/arm/graphing/conn_stats.py
index 6694647..5e2d2f5 100644
--- a/arm/graphing/conn_stats.py
+++ b/arm/graphing/conn_stats.py
@@ -5,7 +5,7 @@ Tracks stats concerning tor's current connections.
import arm.util.tracker
from arm.graphing import graph_panel
-from arm.util import tor_tools
+from arm.util import tor_controller
from stem.control import State
@@ -21,10 +21,10 @@ class ConnStats(graph_panel.GraphStats):
# listens for tor reload (sighup) events which can reset the ports tor uses
- conn = tor_tools.get_conn()
+ controller = tor_controller()
self.or_port, self.dir_port, self.control_port = "0", "0", "0"
- self.reset_listener(conn.get_controller(), State.INIT, None) # initialize port values
- conn.add_status_listener(self.reset_listener)
+ self.reset_listener(controller, State.INIT, None) # initialize port values
+ controller.add_status_listener(self.reset_listener)
def clone(self, new_copy=None):
if not new_copy:
diff --git a/arm/graphing/graph_panel.py b/arm/graphing/graph_panel.py
index 8d2b5ca..f36b090 100644
--- a/arm/graphing/graph_panel.py
+++ b/arm/graphing/graph_panel.py
@@ -24,7 +24,7 @@ import arm.controller
import stem.control
-from arm.util import panel, tor_tools, ui_tools
+from arm.util import panel, tor_controller, ui_tools
from stem.util import conf, enum, str_tools
@@ -121,7 +121,7 @@ class GraphStats:
# tracks BW events
- tor_tools.get_conn().add_event_listener(self.bandwidth_event, stem.control.EventType.BW)
+ tor_controller().add_event_listener(self.bandwidth_event, stem.control.EventType.BW)
def clone(self, new_copy=None):
"""
diff --git a/arm/graphing/resource_stats.py b/arm/graphing/resource_stats.py
index 2803bd1..71b6790 100644
--- a/arm/graphing/resource_stats.py
+++ b/arm/graphing/resource_stats.py
@@ -5,7 +5,7 @@ Tracks the system resource usage (cpu and memory) of the tor process.
import arm.util.tracker
from arm.graphing import graph_panel
-from arm.util import tor_tools
+from arm.util import tor_controller
from stem.util import str_tools
@@ -17,7 +17,7 @@ class ResourceStats(graph_panel.GraphStats):
def __init__(self):
graph_panel.GraphStats.__init__(self)
- self.query_pid = tor_tools.get_conn().controller.get_pid(None)
+ self.query_pid = tor_controller().get_pid(None)
self.last_counter = None
def clone(self, new_copy=None):
diff --git a/arm/log_panel.py b/arm/log_panel.py
index bf96782..f782e6b 100644
--- a/arm/log_panel.py
+++ b/arm/log_panel.py
@@ -19,7 +19,7 @@ from stem.util import conf, log, system
import arm.arguments
import arm.popups
from arm import __version__
-from arm.util import panel, tor_tools, ui_tools
+from arm.util import panel, tor_controller, ui_tools
RUNLEVEL_EVENT_COLOR = {
log.DEBUG: "magenta",
@@ -146,7 +146,7 @@ def get_log_file_entries(runlevels, read_limit = None, add_limit = None):
logging_types, logging_location = None, None
- for logging_entry in tor_tools.get_conn().get_option("Log", [], True):
+ for logging_entry in tor_controller().get_conf("Log", [], True):
# looks for an entry like: notice file /var/log/tor/notices.log
entry_comp = logging_entry.split()
@@ -539,8 +539,8 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
# adds listeners for tor and stem events
- conn = tor_tools.get_conn()
- conn.add_status_listener(self._reset_listener)
+ controller = tor_controller()
+ controller.add_status_listener(self._reset_listener)
# opens log file if we'll be saving entries
@@ -1191,12 +1191,12 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
if "UNKNOWN" in events:
tor_events.update(set(arm.arguments.missing_event_types()))
- tor_conn = tor_tools.get_conn()
- tor_conn.remove_event_listener(self.register_tor_event)
+ controller = tor_controller()
+ controller.remove_event_listener(self.register_tor_event)
for event_type in list(tor_events):
try:
- tor_conn.add_event_listener(self.register_tor_event, event_type)
+ controller.add_event_listener(self.register_tor_event, event_type)
except stem.ProtocolError:
tor_events.remove(event_type)
diff --git a/arm/menu/actions.py b/arm/menu/actions.py
index c968099..3aa941d 100644
--- a/arm/menu/actions.py
+++ b/arm/menu/actions.py
@@ -10,8 +10,9 @@ import arm.menu.item
import arm.graphing.graph_panel
import arm.util.tracker
-from arm.util import tor_tools, ui_tools
+from arm.util import tor_controller, ui_tools
+import stem
import stem.util.connection
from stem.util import conf, str_tools
@@ -60,16 +61,16 @@ def make_actions_menu():
"""
control = arm.controller.get_controller()
- conn = tor_tools.get_conn()
+ controller = tor_controller()
header_panel = control.get_panel("header")
actions_menu = arm.menu.item.Submenu("Actions")
actions_menu.add(arm.menu.item.MenuItem("Close Menu", None))
actions_menu.add(arm.menu.item.MenuItem("New Identity", header_panel.send_newnym))
- if conn.is_alive():
- actions_menu.add(arm.menu.item.MenuItem("Stop Tor", conn.shutdown))
+ if controller.is_alive():
+ actions_menu.add(arm.menu.item.MenuItem("Stop Tor", controller.close))
- actions_menu.add(arm.menu.item.MenuItem("Reset Tor", conn.reload))
+ actions_menu.add(arm.menu.item.MenuItem("Reset Tor", functools.partial(controller.signal, stem.Signal.RELOAD)))
if control.is_paused():
label, arg = "Unpause", False
diff --git a/arm/starter.py b/arm/starter.py
index 8bb1300..9493415 100644
--- a/arm/starter.py
+++ b/arm/starter.py
@@ -18,7 +18,6 @@ import arm.arguments
import arm.controller
import arm.util.panel
import arm.util.tor_config
-import arm.util.tor_tools
import arm.util.tracker
import arm.util.ui_tools
@@ -68,11 +67,6 @@ def main():
try:
controller = init_controller(args)
authenticate(controller, CONFIG.get('tor.password', None), CONFIG.get('tor.chroot', ''))
-
- # TODO: Our tor_controller() method will gradually replace the tor_tools
- # module, but until that we need to initialize it too.
-
- arm.util.tor_tools.get_conn().init(controller)
except ValueError as exc:
print exc
exit(1)
diff --git a/arm/torrc_panel.py b/arm/torrc_panel.py
index 7957abc..e561478 100644
--- a/arm/torrc_panel.py
+++ b/arm/torrc_panel.py
@@ -8,7 +8,7 @@ import threading
import arm.popups
-from arm.util import panel, tor_config, tor_tools, ui_tools
+from arm.util import panel, tor_config, tor_controller, ui_tools
from stem.control import State
from stem.util import conf, enum
@@ -52,10 +52,10 @@ class TorrcPanel(panel.Panel):
# listens for tor reload (sighup) events
- conn = tor_tools.get_conn()
- conn.add_status_listener(self.reset_listener)
+ controller = tor_controller()
+ controller.add_status_listener(self.reset_listener)
- if conn.is_alive():
+ if controller.is_alive():
self.reset_listener(None, State.INIT, None)
def reset_listener(self, controller, event_type, _):
diff --git a/arm/util/tor_config.py b/arm/util/tor_config.py
index 84d2882..33b53a3 100644
--- a/arm/util/tor_config.py
+++ b/arm/util/tor_config.py
@@ -9,7 +9,7 @@ import threading
import stem.version
-from arm.util import tor_tools, ui_tools
+from arm.util import tor_controller, ui_tools
from stem.util import conf, enum, log, str_tools, system
@@ -171,7 +171,7 @@ def load_option_descriptions(load_path = None, check_version = True):
if version_line.startswith("Tor Version "):
file_version = version_line[12:]
loaded_version = file_version
- tor_version = tor_tools.get_conn().get_info("version", "")
+ tor_version = tor_controller().get_info("version", "")
if check_version and file_version != tor_version:
msg = "wrong version, tor is %s but the file's from %s" % (tor_version, file_version)
@@ -226,8 +226,8 @@ def load_option_descriptions(load_path = None, check_version = True):
# Fetches all options available with this tor instance. This isn't
# vital, and the valid_options are left empty if the call fails.
- conn, valid_options = tor_tools.get_conn(), []
- config_option_query = conn.get_info("config/names", None)
+ controller, valid_options = tor_controller(), []
+ config_option_query = controller.get_info("config/names", None)
if config_option_query:
for line in config_option_query.strip().split("\n"):
@@ -340,7 +340,7 @@ def save_option_descriptions(path):
sorted_options = CONFIG_DESCRIPTIONS.keys()
sorted_options.sort()
- tor_version = tor_tools.get_conn().get_info("version", "")
+ tor_version = tor_controller().get_info("version", "")
output_file.write("Tor Version %s\n" % tor_version)
for i in range(len(sorted_options)):
@@ -420,9 +420,9 @@ def get_config_location():
path can't be determined.
"""
- conn = tor_tools.get_conn()
- config_location = conn.get_info("config-file", None)
- tor_pid, tor_prefix = conn.controller.get_pid(None), CONFIG['tor.chroot']
+ controller = tor_controller()
+ config_location = controller.get_info("config-file", None)
+ tor_pid, tor_prefix = controller.controller.get_pid(None), CONFIG['tor.chroot']
if not config_location:
raise IOError("unable to query the torrc location")
@@ -446,9 +446,9 @@ def get_multiline_parameters():
global MULTILINE_PARAM
if MULTILINE_PARAM is None:
- conn, multiline_entries = tor_tools.get_conn(), []
+ controller, multiline_entries = tor_controller(), []
- config_option_query = conn.get_info("config/names", None)
+ config_option_query = controller.get_info("config/names", None)
if config_option_query:
for line in config_option_query.strip().split("\n"):
@@ -474,7 +474,7 @@ def get_custom_options(include_value = False):
this just contains the options
"""
- config_text = tor_tools.get_conn().get_info("config-text", "").strip()
+ config_text = tor_controller().get_info("config-text", "").strip()
config_lines = config_text.split("\n")
# removes any duplicates
@@ -548,7 +548,7 @@ def save_conf(destination = None, contents = None):
# double check that "GETINFO config-text" is unavailable rather than just
# giving an empty result
- if tor_tools.get_conn().get_info("config-text", None) is None:
+ if tor_controller().get_info("config-text", None) is None:
raise IOError("determining the torrc requires Tor version 0.2.2.7")
current_location = None
@@ -572,7 +572,7 @@ def save_conf(destination = None, contents = None):
if is_saveconf:
try:
- tor_tools.get_conn().save_conf()
+ tor_controller().save_conf()
try:
get_torrc().load()
@@ -623,7 +623,7 @@ def validate(contents = None):
contents - torrc contents
"""
- conn = tor_tools.get_conn()
+ controller = tor_controller()
custom_options = get_custom_options()
issues_found, seen_options = [], []
@@ -708,7 +708,7 @@ def validate(contents = None):
# issues GETCONF to get the values tor's currently configured to use
- tor_values = conn.get_option(option, [], True)
+ tor_values = controller.get_conf(option, [], True)
# multiline entries can be comma separated values (for both tor and conf)
@@ -950,7 +950,7 @@ class Torrc():
if not self.is_loaded():
return_val = None
else:
- tor_version = tor_tools.get_conn().get_version()
+ tor_version = tor_controller().get_version(None)
skip_validation = not CONFIG["features.torrc.validate"]
skip_validation |= (tor_version is None or not tor_version >= stem.version.Requirement.GETINFO_CONFIG_TEXT)
diff --git a/arm/util/tor_tools.py b/arm/util/tor_tools.py
index 4575616..1cefa98 100644
--- a/arm/util/tor_tools.py
+++ b/arm/util/tor_tools.py
@@ -8,7 +8,7 @@ import threading
import stem
import stem.control
-from stem.util import log, system
+from stem.util import log
CONTROLLER = None # singleton Controller instance
@@ -39,10 +39,6 @@ class Controller:
def __init__(self):
self.controller = None
self.conn_lock = threading.RLock()
- self._fingerprint_mappings = None # mappings of ip -> [(port, fingerprint), ...]
- self._fingerprint_lookup_cache = {} # lookup cache with (ip, port) -> fingerprint mappings
- self._nickname_lookup_cache = {} # lookup cache with fingerprint -> nickname mappings
- self._address_lookup_cache = {} # lookup cache with fingerprint -> (ip address, or port) mappings
self._consensus_lookup_cache = {} # lookup cache with network status entries
self._descriptor_lookup_cache = {} # lookup cache with relay descriptors
@@ -73,10 +69,6 @@ class Controller:
# reset caches for ip -> fingerprint lookups
- self._fingerprint_mappings = None
- self._fingerprint_lookup_cache = {}
- self._nickname_lookup_cache = {}
- self._address_lookup_cache = {}
self._consensus_lookup_cache = {}
self._descriptor_lookup_cache = {}
@@ -258,147 +250,6 @@ class Controller:
else:
return default
- def get_hidden_service_ports(self, default = []):
- """
- Provides the target ports hidden services are configured to use.
-
- Arguments:
- default - value provided back if unable to query the hidden service ports
- """
-
- result = []
- hs_options = self.controller.get_conf_map("HiddenServiceOptions", {})
-
- for entry in hs_options.get("HiddenServicePort", []):
- # HiddenServicePort entries are of the form...
- #
- # VIRTPORT [TARGET]
- #
- # ... with the TARGET being an address, port, or address:port. If the
- # target port isn't defined then uses the VIRTPORT.
-
- hs_port = None
-
- if ' ' in entry:
- virtport, target = entry.split(' ', 1)
-
- if ':' in target:
- hs_port = target.split(':', 1)[1] # target is an address:port
- elif target.isdigit():
- hs_port = target # target is a port
- else:
- hs_port = virtport # target is an address
- else:
- hs_port = entry # just has the virtual port
-
- if hs_port.isdigit():
- result.append(hs_port)
-
- if result:
- return result
- else:
- return default
-
- def get_my_bandwidth_rate(self, default = None):
- """
- Provides the effective relaying bandwidth rate of this relay. Currently
- this doesn't account for SETCONF events.
-
- Arguments:
- default - result if the query fails
- """
-
- # effective relayed bandwidth is the minimum of BandwidthRate,
- # MaxAdvertisedBandwidth, and RelayBandwidthRate (if set)
-
- effective_rate = int(self.get_option("BandwidthRate", None))
-
- relay_rate = self.get_option("RelayBandwidthRate", None)
-
- if relay_rate and relay_rate != "0":
- effective_rate = min(effective_rate, int(relay_rate))
-
- max_advertised = self.get_option("MaxAdvertisedBandwidth", None)
-
- if max_advertised:
- effective_rate = min(effective_rate, int(max_advertised))
-
- if effective_rate is not None:
- return effective_rate
- else:
- return default
-
- def get_my_bandwidth_burst(self, default = None):
- """
- Provides the effective bandwidth burst rate of this relay. Currently this
- doesn't account for SETCONF events.
-
- Arguments:
- default - result if the query fails
- """
-
- # effective burst (same for BandwidthBurst and RelayBandwidthBurst)
- effective_burst = int(self.get_option("BandwidthBurst", None))
-
- relay_burst = self.get_option("RelayBandwidthBurst", None)
-
- if relay_burst and relay_burst != "0":
- effective_burst = min(effective_burst, int(relay_burst))
-
- if effective_burst is not None:
- return effective_burst
- else:
- return default
-
- def get_my_bandwidth_observed(self, default = None):
- """
- Provides the relay's current observed bandwidth (the throughput determined
- from historical measurements on the client side). This is used in the
- heuristic used for path selection if the measured bandwidth is undefined.
- This is fetched from the descriptors and hence will get stale if
- descriptors aren't periodically updated.
-
- Arguments:
- default - result if the query fails
- """
-
- my_fingerprint = self.get_info("fingerprint", None)
-
- if my_fingerprint:
- my_descriptor = self.controller.get_server_descriptor(my_fingerprint)
-
- if my_descriptor:
- return my_descriptor.observed_bandwidth
-
- return default
-
- def get_my_bandwidth_measured(self, default = None):
- """
- Provides the relay's current measured bandwidth (the throughput as noted by
- the directory authorities and used by clients for relay selection). This is
- undefined if not in the consensus or with older versions of Tor. Depending
- on the circumstances this can be from a variety of things (observed,
- measured, weighted measured, etc) as described by:
- https://trac.torproject.org/projects/tor/ticket/1566
-
- Arguments:
- default - result if the query fails
- """
-
- # TODO: Tor is documented as providing v2 router status entries but
- # actually looks to be v3. This needs to be sorted out between stem
- # and tor.
-
- my_fingerprint = self.get_info("fingerprint", None)
-
- if my_fingerprint:
- my_status_entry = self.controller.get_network_status(my_fingerprint)
-
- if my_status_entry and hasattr(my_status_entry, 'bandwidth'):
- return my_status_entry.bandwidth
-
- return default
-
def get_my_flags(self, default = None):
"""
Provides the flags held by this relay.
@@ -435,17 +286,6 @@ class Controller:
finally:
self.conn_lock.release()
- def is_geoip_unavailable(self):
- """
- Provides true if we've concluded that our geoip database is unavailable,
- false otherwise.
- """
-
- if self.is_alive():
- return self.controller.is_geoip_unavailable()
- else:
- return False
-
def get_my_user(self):
"""
Provides the user this process is running under. If unavailable this
@@ -454,34 +294,6 @@ class Controller:
return self.controller.get_user(None)
- def is_exiting_allowed(self, ip_address, port):
- """
- Checks if the given destination can be exited to by this relay, returning
- True if so and False otherwise.
- """
-
- self.conn_lock.acquire()
-
- result = False
-
- if self.is_alive():
- # If we allow any exiting then this could be relayed DNS queries,
- # otherwise the policy is checked. Tor still makes DNS connections to
- # test when exiting isn't allowed, but nothing is relayed over them.
- # I'm registering these as non-exiting to avoid likely user confusion:
- # https://trac.torproject.org/projects/tor/ticket/965
-
- our_policy = self.get_exit_policy()
-
- if our_policy and our_policy.is_exiting_allowed() and port == "53":
- result = True
- else:
- result = our_policy and our_policy.can_exit_to(ip_address, port)
-
- self.conn_lock.release()
-
- return result
-
def get_exit_policy(self):
"""
Provides an ExitPolicy instance for the head of this relay's exit policy
@@ -551,80 +363,6 @@ class Controller:
return result
- def get_relay_fingerprint(self, relay_address, relay_port = None, get_all_matches = False):
- """
- Provides the fingerprint associated with the given address. If there's
- multiple potential matches or the mapping is unknown then this returns
- None. This disambiguates the fingerprint if there's multiple relays on
- the same ip address by several methods, one of them being to pick relays
- we have a connection with.
-
- Arguments:
- relay_address - address of relay to be returned
- relay_port - orport of relay (to further narrow the results)
- get_all_matches - ignores the relay_port and provides all of the
- (port, fingerprint) tuples matching the given
- address
- """
-
- self.conn_lock.acquire()
-
- result = None
-
- if self.is_alive():
- if get_all_matches:
- # populates the ip -> fingerprint mappings if not yet available
- if self._fingerprint_mappings is None:
- self._fingerprint_mappings = self._get_fingerprint_mappings()
-
- if relay_address in self._fingerprint_mappings:
- result = self._fingerprint_mappings[relay_address]
- else:
- result = []
- else:
- # query the fingerprint if it isn't yet cached
- if not (relay_address, relay_port) in self._fingerprint_lookup_cache:
- relay_fingerprint = self._get_relay_fingerprint(relay_address, relay_port)
- self._fingerprint_lookup_cache[(relay_address, relay_port)] = relay_fingerprint
-
- result = self._fingerprint_lookup_cache[(relay_address, relay_port)]
-
- self.conn_lock.release()
-
- return result
-
- def get_relay_nickname(self, relay_fingerprint):
- """
- Provides the nickname associated with the given relay. This provides None
- if no such relay exists, and "Unnamed" if the name hasn't been set.
-
- Arguments:
- relay_fingerprint - fingerprint of the relay
- """
-
- self.conn_lock.acquire()
-
- result = None
-
- if self.is_alive():
- # query the nickname if it isn't yet cached
- if not relay_fingerprint in self._nickname_lookup_cache:
- if relay_fingerprint == self.get_info("fingerprint", None):
- # this is us, simply check the config
- my_nickname = self.get_option("Nickname", "Unnamed")
- self._nickname_lookup_cache[relay_fingerprint] = my_nickname
- else:
- ns_entry = self.controller.get_network_status(relay_fingerprint, None)
-
- if ns_entry:
- self._nickname_lookup_cache[relay_fingerprint] = ns_entry.nickname
-
- result = self._nickname_lookup_cache[relay_fingerprint]
-
- self.conn_lock.release()
-
- return result
-
def get_relay_exit_policy(self, relay_fingerprint):
"""
Provides the ExitPolicy instance associated with the given relay. The tor
@@ -652,45 +390,6 @@ class Controller:
return result
- def get_relay_address(self, relay_fingerprint, default = None):
- """
- Provides the (IP Address, ORPort) tuple for a given relay. If the lookup
- fails then this returns the default.
-
- Arguments:
- relay_fingerprint - fingerprint of the relay
- """
-
- self.conn_lock.acquire()
-
- result = default
-
- if self.is_alive():
- # query the address if it isn't yet cached
- if not relay_fingerprint in self._address_lookup_cache:
- if relay_fingerprint == self.get_info("fingerprint", None):
- # this is us, simply check the config
- my_address = self.get_info("address", None)
- my_or_port = self.get_option("ORPort", None)
-
- if my_address and my_or_port:
- self._address_lookup_cache[relay_fingerprint] = (my_address, my_or_port)
- else:
- # check the consensus for the relay
- ns_entry = self.get_consensus_entry(relay_fingerprint)
-
- if ns_entry:
- ns_line_comp = ns_entry.split("\n")[0].split(" ")
-
- if len(ns_line_comp) >= 8:
- self._address_lookup_cache[relay_fingerprint] = (ns_line_comp[6], ns_line_comp[7])
-
- result = self._address_lookup_cache.get(relay_fingerprint, default)
-
- self.conn_lock.release()
-
- return result
-
def add_event_listener(self, listener, *event_types):
"""
Directs further tor controller events to callback functions of the
@@ -790,131 +489,11 @@ class Controller:
# reconstructs consensus based mappings
- self._fingerprint_lookup_cache = {}
- self._nickname_lookup_cache = {}
- self._address_lookup_cache = {}
self._consensus_lookup_cache = {}
- if self._fingerprint_mappings is not None:
- self._fingerprint_mappings = self._get_fingerprint_mappings(event.desc)
-
self.conn_lock.release()
def new_desc_event(self, event):
self.conn_lock.acquire()
-
- desc_fingerprints = [fingerprint for (fingerprint, nickname) in event.relays]
-
- # If we're tracking ip address -> fingerprint mappings then update with
- # the new relays.
-
- self._fingerprint_lookup_cache = {}
self._descriptor_lookup_cache = {}
-
- if self._fingerprint_mappings is not None:
- for fingerprint in desc_fingerprints:
- # gets consensus data for the new descriptor
-
- try:
- desc = self.controller.get_network_status(fingerprint)
- except stem.ControllerError:
- continue
-
- # updates fingerprintMappings with new data
-
- if desc.address in self._fingerprint_mappings:
- # if entry already exists with the same orport, remove it
-
- orport_match = None
-
- for entry_port, entry_fingerprint in self._fingerprint_mappings[desc.address]:
- if entry_port == desc.or_port:
- orport_match = (entry_port, entry_fingerprint)
- break
-
- if orport_match:
- self._fingerprint_mappings[desc.address].remove(orport_match)
-
- # add the new entry
-
- self._fingerprint_mappings[desc.address].append((desc.or_port, desc.fingerprint))
- else:
- self._fingerprint_mappings[desc.address] = [(desc.or_port, desc.fingerprint)]
-
self.conn_lock.release()
-
- def _get_fingerprint_mappings(self, descriptors = None):
- """
- Provides IP address to (port, fingerprint) tuple mappings for all of the
- currently cached relays.
-
- Arguments:
- descriptors - router status entries (fetched if not provided)
- """
-
- results = {}
-
- if self.is_alive():
- # fetch the current network status if not provided
-
- if not descriptors:
- try:
- descriptors = self.controller.get_network_statuses()
- except stem.ControllerError:
- descriptors = []
-
- # construct mappings of ips to relay data
-
- for desc in descriptors:
- results.setdefault(desc.address, []).append((desc.or_port, desc.fingerprint))
-
- return results
-
- def _get_relay_fingerprint(self, relay_address, relay_port):
- """
- Provides the fingerprint associated with the address/port combination.
-
- Arguments:
- relay_address - address of relay to be returned
- relay_port - orport of relay (to further narrow the results)
- """
-
- # If we were provided with a string port then convert to an int (so
- # lookups won't mismatch based on type).
-
- if isinstance(relay_port, str):
- relay_port = int(relay_port)
-
- # checks if this matches us
-
- if relay_address == self.get_info("address", None):
- if not relay_port or relay_port == self.get_option("ORPort", None):
- return self.get_info("fingerprint", None)
-
- # if we haven't yet populated the ip -> fingerprint mappings then do so
-
- if self._fingerprint_mappings is None:
- self._fingerprint_mappings = self._get_fingerprint_mappings()
-
- potential_matches = self._fingerprint_mappings.get(relay_address)
-
- if not potential_matches:
- return None # no relay matches this ip address
-
- if len(potential_matches) == 1:
- # There's only one relay belonging to this ip address. If the port
- # matches then we're done.
-
- match = potential_matches[0]
-
- if relay_port and match[0] != relay_port:
- return None
- else:
- return match[1]
- elif relay_port:
- # Multiple potential matches, so trying to match based on the port.
- for entry_port, entry_fingerprint in potential_matches:
- if entry_port == relay_port:
- return entry_fingerprint
-
- return None
1
0

[torbrowser/maint-2.4] Making the recommended versions list actually be JSON might help.
by mikeperry@torproject.org 28 Jan '14
by mikeperry@torproject.org 28 Jan '14
28 Jan '14
commit ad816ea3426358deed6737d236bdf208f6cb2409
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Mon Jan 27 20:44:04 2014 -0800
Making the recommended versions list actually be JSON might help.
---
build-scripts/recommended-versions | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build-scripts/recommended-versions b/build-scripts/recommended-versions
index e51e468..49c3eb1 100644
--- a/build-scripts/recommended-versions
+++ b/build-scripts/recommended-versions
@@ -4,7 +4,7 @@
"3.5-rc-1-Windows",
"3.5-Linux",
"3.5-MacOS",
-"3.5-Windows"
+"3.5-Windows",
"3.5.1-Linux",
"3.5.1-MacOS",
"3.5.1-Windows"
1
0

28 Jan '14
commit c341333df9e1cbcd4478f858be851ddaea1309ce
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Mon Jan 27 20:28:00 2014 -0800
Add 3.5.1 to recommended versions.
This seems barely not a security update. We could go either way, but for now
let's just list it as accepted before removing 3.5.
---
build-scripts/recommended-versions | 3 +++
1 file changed, 3 insertions(+)
diff --git a/build-scripts/recommended-versions b/build-scripts/recommended-versions
index 7606bdc..e51e468 100644
--- a/build-scripts/recommended-versions
+++ b/build-scripts/recommended-versions
@@ -5,4 +5,7 @@
"3.5-Linux",
"3.5-MacOS",
"3.5-Windows"
+"3.5.1-Linux",
+"3.5.1-MacOS",
+"3.5.1-Windows"
]
1
0
commit 529eac49524ef020646630e5b98213522fca0ca9
Merge: 8404942 c341333
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Mon Jan 27 20:28:47 2014 -0800
Merge branch 'maint-2.4'
build-scripts/recommended-versions | 3 +++
1 file changed, 3 insertions(+)
1
0

28 Jan '14
commit c341333df9e1cbcd4478f858be851ddaea1309ce
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Mon Jan 27 20:28:00 2014 -0800
Add 3.5.1 to recommended versions.
This seems barely not a security update. We could go either way, but for now
let's just list it as accepted before removing 3.5.
---
build-scripts/recommended-versions | 3 +++
1 file changed, 3 insertions(+)
diff --git a/build-scripts/recommended-versions b/build-scripts/recommended-versions
index 7606bdc..e51e468 100644
--- a/build-scripts/recommended-versions
+++ b/build-scripts/recommended-versions
@@ -5,4 +5,7 @@
"3.5-Linux",
"3.5-MacOS",
"3.5-Windows"
+"3.5.1-Linux",
+"3.5.1-MacOS",
+"3.5.1-Windows"
]
1
0

[translation/tails-misc_completed] Update translations for tails-misc_completed
by translation@torproject.org 28 Jan '14
by translation@torproject.org 28 Jan '14
28 Jan '14
commit 8e38247c3e029e1017b024d0bd566f49dfc894e4
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jan 28 02:16:27 2014 +0000
Update translations for tails-misc_completed
---
km.po | 453 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 453 insertions(+)
diff --git a/km.po b/km.po
new file mode 100644
index 0000000..759f09b
--- /dev/null
+++ b/km.po
@@ -0,0 +1,453 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# soksophea <sksophea(a)gmail.com>, 2014
+msgid ""
+msgstr ""
+"Project-Id-Version: The Tor Project\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-01-10 12:23+0100\n"
+"PO-Revision-Date: 2014-01-28 02:00+0000\n"
+"Last-Translator: soksophea <sksophea(a)gmail.com>\n"
+"Language-Team: Khmer (http://www.transifex.com/projects/p/torproject/language/km/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: km\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: config/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready-notification.sh:31
+msgid "Tor is ready"
+msgstr "Tor ááºâááœá
áá¶ááâá áŸá"
+
+#: config/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready-notification.sh:32
+msgid "You can now access the Internet."
+msgstr "á¥á¡áŒáâá¢áááâá¢á¶á
âááááŸâá¢áážáááºáá·áâáá¶áá"
+
+#: config/chroot_local-includes/etc/whisperback/config.py:64
+#, python-format
+msgid ""
+"<h1>Help us fix your bug!</h1>\n"
+"<p>Read <a href=\"%s\">our bug reporting instructions</a>.</p>\n"
+"<p><strong>Do not include more personal information than\n"
+"needed!</strong></p>\n"
+"<h2>About giving us an email address</h2>\n"
+"<p>If you don't mind disclosing some bits of your identity\n"
+"to Tails developers, you can provide an email address to\n"
+"let us ask more details about the bug. Additionally entering\n"
+"a public PGP key enables us to encrypt such future\n"
+"communication.</p>\n"
+"<p>Anyone who can see this reply will probably infer you are\n"
+"a Tails user. Time to wonder how much you trust your\n"
+"Internet and mailbox providers?</p>\n"
+msgstr "<h1>ááœáâááœáâááŸáâááŸáááážâááâááá á»á!</h1>\n<p>Read <a href=\"%s\">ááá
áááážâáááá¶áâá¢ááážâááááâáá¶ááá¶áááâááá á»áâááááâááŸá</a>á</p>\n<p><strong>áá»áâáááá
áŒáâáááááá¶áâáááá¶ááááááœáâá
áááŸáâáá¶áâáá¶áâáá¶ááá¶á!</strong></p>\n<h2>á¢ááážâáá¶áâáááááâá¢á¶áááááá¶áâá¢áážááá</h2>\n<p>ááŸâá¢áááâáá·áâáááâáá¶ááâáá ááŒáâáááááâá¢áááááááá¶áâááááâá¢áááâááááá áááá¶ááâá¢áááâá¢áá·áááááá Tails ááŒá
áá¶á á¢áááâá¢á¶á
âáááááâá¢á¶áááááá¶áâá¢áážáááâááŸáááážâá²ááâááŸáâááœáâáááá
¢á·áâá¢ááážâááá á»áá áááááá¶ááâáááá
áŒáâáá¶áááááááá¹á PGP áá¶áá¶áááâáááâá¢áá»áááá¶áâá²ááâááœáâááŸáâáá¶ááâáááâááŒáâááááá¶ááâáááá¶ááááááâá¢áá¶ááá</p>\n<p>á¢áááâáááâá¢á¶á
âááŸáâááŸáâá
ááááŸáâááâááá áá¹áâááááá·áááá¶áâáá¶âá¢áááâááºáá¶âá¢áááááá០Tails á ááŸâá¢áááâáá»áá
á·áááâá¢áážáááºáá·á áá·áâáááá»áá áá»áâáááááâáááá¶ááááâáááá¢ááâáááá»áááâááááâá¢áááâááááá·áâáá¶?</p>\n"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:136
+msgid "OpenPGP encryption applet"
+msgstr "á¢á¶áááááááâáá¶áâáá¶ááâáááâááŒá OpenPGP"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:139
+msgid "Exit"
+msgstr "á
áá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:141
+msgid "About"
+msgstr "á¢áááž"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:192
+msgid "Encrypt Clipboard with _Passphrase"
+msgstr "áá¶ááâáááâááŒáâáááá¶áâááááááâáááá¶ááâáááâááááŸâáá¶áááááááá¶áá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:195
+msgid "Sign/Encrypt Clipboard with Public _Keys"
+msgstr "á
á»áá ááááááá¶/áá¶ááâáááâááŒáâáááá¶áâááááááâáááá¶ááâáááâááááŸâáá¶áááâááááá¹áâáá¶áá¶ááá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:200
+msgid "_Decrypt/Verify Clipboard"
+msgstr "áááâáááááŒá/ááááááááá¶ááâáááá¶áâááááááâáááá¶áá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:204
+msgid "_Manage Keys"
+msgstr "áááááááááâáá¶áááâááááá¹á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:244
+msgid "The clipboard does not contain valid input data."
+msgstr "áááá¶áâááááááâáááá¶ááâáá·áâáá¶áâáá·ááááááâáááá¹áááááŒáá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:294
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:296
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:298
+msgid "Unknown Trust"
+msgstr "áá·áâáá»áá
á·ááá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:300
+msgid "Marginal Trust"
+msgstr "áá»áá
á·áááâááááá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:302
+msgid "Full Trust"
+msgstr "áá»áá
á·áááâáá¶áááááá»á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:304
+msgid "Ultimate Trust"
+msgstr "áá»áá
á·áááâáááá»á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:357
+msgid "Name"
+msgstr "ááááá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:358
+msgid "Key ID"
+msgstr "áááâááááá¶ááâáá¶áááâááááá¹á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:359
+msgid "Status"
+msgstr "áááá¶ááá¶á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:391
+msgid "Fingerprint:"
+msgstr "áááá¶áâáááá¶áááá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:394
+msgid "User ID:"
+msgid_plural "User IDs:"
+msgstr[0] "áááâááááá¶ááâá¢áááááááŸá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:424
+msgid "None (Don't sign)"
+msgstr "áááá¶á (áá»áâá
á»áá ááááááá¶)"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:487
+msgid "Select recipients:"
+msgstr "ááááŸáâá¢ááááááœáá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:495
+msgid "Hide recipients"
+msgstr "áá¶ááâá¢ááááááœá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:498
+msgid ""
+"Hide the user IDs of all recipients of an encrypted message. Otherwise "
+"anyone that sees the encrypted message can see who the recipients are."
+msgstr "áá¶ááâáááâááááá¶ááâá¢áááááááŸâááááâá¢ááááááœáâáá¶áâáááâáá¶áâáá¶ááâáááâááŒáâáá¶ááá¢ááá ááŸáá·áááŒá
áááááá á¢áááâáááâááŸáâááŸáâáá¶áâáááâáá¶áâáá¶ááâáááâááŒá á¢á¶á
âááŸáâááŸáâá¢ááááááœáâáááá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:504
+msgid "Sign message as:"
+msgstr "á
á»áá ááááááá¶âáá¶á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:508
+msgid "Choose keys"
+msgstr "ááááŸáâáá¶áááâááááá¹á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:548
+msgid "Do you trust these keys?"
+msgstr "ááŸâá¢áááâáá»áá
á·áááâáá¶áááááááá¹áâáá¶áááááâáá?"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:551
+msgid "The following selected key is not fully trusted:"
+msgid_plural "The following selected keys are not fully trusted:"
+msgstr[0] "áá¶áááâááááá¹áâáááâáá¶áâááááŸáâáá¶ááááááâááºâáá·áâáá¶áâáá»áá
á·áááâáá¶áááááá»áâááá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:569
+msgid "Do you trust this key enough to use it anyway?"
+msgid_plural "Do you trust these keys enough to use them anyway?"
+msgstr[0] "ááŸâá¢áááâáá»áá
á·áááâáá¶áááâááááá¹áâáá¶áááááâáá¶âá¢á¶á
âááááŸâáá¶áâáááâá¬áá?"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:582
+msgid "No keys selected"
+msgstr "áá·áâáá¶áâááááŸáâáá¶áááâááááá¹á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:584
+msgid ""
+"You must select a private key to sign the message, or some public keys to "
+"encrypt the message, or both."
+msgstr "á¢áááâááááŒáâááááŸáââáá¶áááâááááá¹áâá¯áááâááŸáááážâá
á»áá ááááááá¶âáá¶á á¬âááááŸáâáá¶áááâááááá¹áâáá¶áá¶áááâááœáâá
áááœáâááŸáááážâáá¶ááâáááâááŒáâáá¶á á¬âááááŸáâáá¶áááážá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:612
+msgid "No keys available"
+msgstr "áá·áâáá¶áâáá¶áááâááááá¹á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:614
+msgid ""
+"You need a private key to sign messages or a public key to encrypt messages."
+msgstr "á¢áááâááááŒáâáá¶áâáá¶áááâááááá¹áâá¯áááâááŸáááážâá
á»áá ááááááá¶âáá¶á á¬âáá¶áááâááááá¹áâáá¶ááá¶áááâááŸáááážâáá¶ááâáááâááŒáâáá¶áá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:742
+msgid "GnuPG error"
+msgstr "ááá á»á GnuPG"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:763
+msgid "Therefore the operation cannot be performed."
+msgstr "ááŒá
ááááâááááá·ááááá·áá¶áâáá·áâá¢á¶á
âááááŸááá¶áâáá¶áâááá"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:813
+msgid "GnuPG results"
+msgstr "áááááá GnuPG"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:819
+msgid "Output of GnuPG:"
+msgstr "ááááááâáááá
ááâáááá GnuPGÂ á"
+
+#: config/chroot_local-includes/usr/local/bin/gpgApplet:844
+msgid "Other messages provided by GnuPG:"
+msgstr "áá¶áâááááááááâáááâáá¶áâáááááâááá GnuPGÂ á"
+
+#: config/chroot_local-includes/usr/local/bin/iceweasel:12
+msgid "Tor is not ready"
+msgstr "Tor ááºâáá·ááá¶ááâááœá
áá¶ááâáá"
+
+#: config/chroot_local-includes/usr/local/bin/iceweasel:13
+msgid "Tor is not ready. Start Tor Browser anyway?"
+msgstr "Tor ááºâáá·ááá¶ááâááœá
áá¶ááâááá á
á¶ááááááŸáâáááááá·áážâá¢áážáááºáá·á Tor ááááááâá¬?"
+
+#: config/chroot_local-includes/usr/local/bin/iceweasel:14
+msgid "Start Tor Browser"
+msgstr "á
á¶ááááááŸáâáááááá·áážâá¢áážáááºáá·á Tor"
+
+#: config/chroot_local-includes/usr/local/bin/iceweasel:15
+msgid "Cancel"
+msgstr "áááááá"
+
+#: config/chroot_local-includes/usr/local/bin/shutdown_helper_applet:34
+msgid "Shutdown Immediately"
+msgstr "áá·áâáááá¶áá"
+
+#: config/chroot_local-includes/usr/local/bin/shutdown_helper_applet:35
+msgid "Reboot Immediately"
+msgstr "á
á¶ááááááŸâá¡áŸááá·áâáááá¶á"
+
+#: config/chroot_local-includes/usr/local/bin/shutdown_helper_applet:72
+msgid "Shutdown Helper"
+msgstr "áá·áâáááááá·áážâááááœá"
+
+#: config/chroot_local-includes/usr/local/bin/tails-about:13
+msgid "not available"
+msgstr "áá·áâáá¶á"
+
+#: config/chroot_local-includes/usr/local/bin/tails-about:16
+#: ../config/chroot_local-includes/usr/share/desktop-directories/Tails.directory.in.h:1
+msgid "Tails"
+msgstr "Tails"
+
+#: config/chroot_local-includes/usr/local/bin/tails-about:17
+msgid "The Amnesic Incognito Live System"
+msgstr "The Amnesic Incognito Live System"
+
+#: config/chroot_local-includes/usr/local/bin/tails-about:18
+#, python-format
+msgid ""
+"Build information:\n"
+"%s"
+msgstr "áááááá¶áâáááá¶ááá¶á\n%s"
+
+#: config/chroot_local-includes/usr/local/bin/tails-about:20
+msgid "About Tails"
+msgstr "á¢áááž Tails"
+
+#: config/chroot_local-includes/usr/local/sbin/tails-additional-software:115
+#: config/chroot_local-includes/usr/local/sbin/tails-additional-software:121
+#: config/chroot_local-includes/usr/local/sbin/tails-additional-software:125
+msgid "Your additional software"
+msgstr "áááááá·áážâááááâá¢áááâáááááá"
+
+#: config/chroot_local-includes/usr/local/sbin/tails-additional-software:116
+#: config/chroot_local-includes/usr/local/sbin/tails-additional-software:126
+msgid ""
+"The upgrade failed. This might be due to a network problem. Please check "
+"your network connection, try to restart Tails, or read the system log to "
+"understand better the problem."
+msgstr "áá¶áâááááŸâáá
áá
á»áááááááá¶áâáá¶áâááá¶áááá áá¶âá¢á¶á
âááááá¶áâáááá á¶âááááá¶áá ááŒáâáá·áá·áááâáá¶áâááááá¶ááâááááá¶áâááááâá¢ááá ááœá
âáá¶áááááâá
á¶ááááááŸá Tails á¡áŸááá·á á¬âá¢á¶áâáááááá ááá»âááááááááâááŸáááážâáá¹áâá
ááá¶ááâá¢ááážâáááá á¶á"
+
+#: config/chroot_local-includes/usr/local/sbin/tails-additional-software:122
+msgid "The upgrade was successful."
+msgstr "áá¶áâááááŸâáá
áá
á»áááááááá¶áâáááâáááááá"
+
+#: config/chroot_local-includes/usr/local/bin/tails-htp-notify-user:52
+msgid "Synchronizing the system's clock"
+msgstr "ááááŸâáááá¶áááááâáá¶á¡á·áá¶âáááááááá"
+
+#: config/chroot_local-includes/usr/local/bin/tails-htp-notify-user:53
+msgid ""
+"Tor needs an accurate clock to work properly, especially for Hidden "
+"Services. Please wait..."
+msgstr "Tor ááááŒááá¶áâáá¶á¡á·áá¶âáááâááááá¶ááâááŸáááážâááááŸááá¶áâáááá¹áááááŒá áá·áááâááááá¶ááâáááá¶ááááâáá¶ááá ááŒáâáááá
á¶á..."
+
+#: config/chroot_local-includes/usr/local/bin/tails-htp-notify-user:87
+msgid "Failed to synchronize the clock!"
+msgstr "áá¶áâááááŸâáááá¶áááááâáá¶á¡á·áá¶âáá¶áâááá¶ááá!"
+
+#: config/chroot_local-includes/usr/local/bin/tails-security-check:145
+msgid "This version of Tails has known security issues:"
+msgstr "ááááâáááá Tails áááâááºâáááá¶ááâáááá á¶âáá»ááááá·áá¶áá"
+
+#: config/chroot_local-includes/usr/local/bin/tails-start-i2p:62
+msgid "Starting I2P..."
+msgstr "áááá»áâá
á¶ááááááŸá I2P..."
+
+#: config/chroot_local-includes/usr/local/bin/tails-start-i2p:63
+msgid "The I2P router console will be opened on start."
+msgstr "áá»áááŒáâááááááá I2P áá¹áâááŸáâáá
âáááâá
á¶ááááááŸáá"
+
+#: config/chroot_local-includes/usr/local/bin/tails-start-i2p:82
+#: config/chroot_local-includes/usr/local/bin/tails-start-i2p:124
+msgid "I2P failed to start"
+msgstr "áá¶áâá
á¶ááááááŸá I2P áá¶áâááá¶ááá"
+
+#: config/chroot_local-includes/usr/local/bin/tails-start-i2p:83
+msgid ""
+"Make sure that you have a working Internet connection, then try to start I2P"
+" again."
+msgstr "ááŒáâáááá¶ááâáá¶âá¢áááâáá¶áâáá¶áâááááá¶ááâá¢áážáááºáá·áâáááâááááŸááá¶á ááááá¶ááááâáááá¶áá¶áâá
á¶ááááááŸá I2P áááááááá"
+
+#: config/chroot_local-includes/usr/local/bin/tails-start-i2p:125
+msgid ""
+"Something went wrong when I2P was starting. Look in the logs in the "
+"following directory for more information:"
+msgstr "áá¶áâáááá á¶âááá I2P á
á¶ááááááŸáá ááŸáâáááááá ááá»âáá
âáááá»áâááâáá¶ááááááâááááá¶ááâáááááá¶áâáááá¢á·áá"
+
+#: config/chroot_local-includes/usr/local/bin/tails-virt-notify-user:53
+msgid "Warning: virtual machine detected!"
+msgstr "ááááá¶áá áá¶áâááâááŸáâááá¶ááážáâáá·áááá·á!"
+
+#: config/chroot_local-includes/usr/local/bin/tails-virt-notify-user:55
+msgid ""
+"Both the host operating system and the virtualization software are able to "
+"monitor what you are doing in Tails."
+msgstr "áá¶ááâááááááááâááááá·ááááá·áá¶áâááá¶ááážá áá·áâáááááá·áážâáá·áááá·áâááºâá¢á¶á
âááááœááá·áá·áááâá¢ááážâáááâá¢áááâáááá»áâááááŸâáá
âáááá»á Tails áá¶áá"
+
+#: config/chroot_local-includes/usr/local/bin/tails-virt-notify-user:57
+msgid ""
+"<a "
+"href='file:///usr/share/doc/tails/website/doc/advanced_topics/virtualization.en.html'>Learn"
+" more...</a>"
+msgstr "<a href='file:///usr/share/doc/tails/website/doc/advanced_topics/virtualization.en.html'>ááááááááâáááááá...</a>"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:57
+msgid "error:"
+msgstr "ááá á»áá"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:58
+msgid "Error"
+msgstr "ááá á»á"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:68
+msgid "Do you really want to launch the Unsafe Browser?"
+msgstr "ááŸâá¢áááâáá·ááá¶âá
ááâá
á¶ááááááŸáâáááááá·áážâáááá¶áâáá»ááááá·áá¶áâáááâá¬?"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:70
+msgid ""
+"Network activity within the Unsafe Browser is <b>not anonymous</b>. Only use"
+" the Unsafe Browser if necessary, for example if you have to login or "
+"register to activate your Internet connection."
+msgstr "ááááááá¶áâááááá¶áâáá
âáááá»áâáááááá·áážâá¢áážáááºáá·áâáááá¶áâáá»ááááá·áá¶áâáẠ<b>áá·ááááâá¢áá¶áá·á</b> á ááááŸâáááááá·áážâá¢áážáááºáá·áâáááá¶áâáá»ááááá·áá¶áâááâáááâáááâá
á¶ááá¶á
áâááá»ááááá á§áá¶á áááâááŸâá¢áááâááááŒáâá
áŒá á¬âá
á»ááááááâááŸáááážâááááŸá²ááâáá¶áâááááá¶ááâá¢áážáááºáá·áâááááâá¢áááâáááááá"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:71
+msgid "_Launch"
+msgstr "á
á¶ááááááŸá"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:72
+msgid "_Exit"
+msgstr "á
áá"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:82
+msgid "Starting the Unsafe Browser..."
+msgstr "áááá»áâá
á¶ááááááŸáâáááááá·áážâáááá¶áâáá»ááááá·áá¶á..."
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:83
+msgid "This may take a while, so please be patient."
+msgstr "áá¶âá¢á¶á
âááááŸâáááâááœáâááá ááŒá
ááááâááŒáâáááááá¶âá¢áááááááá"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:101
+msgid "Failed to setup chroot."
+msgstr "áá¶áâááá¶áááâáááá»áâáá¶áâááá¡áŸá chroot á"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:175
+#: ../config/chroot_local-includes/usr/share/applications/unsafe-browser.desktop.in.h:1
+msgid "Unsafe Browser"
+msgstr "áááááá·áážâá¢áážáááºáá·áâáááá¶áâáá»ááááá·áá¶á"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:215
+msgid "Shutting down the Unsafe Browser..."
+msgstr "áááá»áâáá·áâáááááá·áážâá¢áážáááºáá·áâáááá¶áâáá»ááááá·áá¶á..."
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:216
+msgid ""
+"This may take a while, and you may not restart the Unsafe Browser until it "
+"is properly shut down."
+msgstr "áá¶âá¢á¶á
âááááŸâáááâááœáâááá ááŒá
ááááâá¢áááâáá·áâááááŒáâá
á¶ááááááŸáâáááááá·áážâá¢áážáááºáá·áâáááá¶áâáá»ááááá·áá¶áâá¡áŸááá·áâá¡áŸá áá áŒááááâáá¶âáá¶áâáá·áâáááâáááá¹áááááŒáá"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:228
+msgid "Failed to restart Tor."
+msgstr "áá¶áâááá¶áááâáááá»áâáá¶áâá
á¶ááááááŸá Tor á"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:236
+msgid ""
+"Another Unsafe Browser is currently running, or being cleaned up. Please "
+"retry in a while."
+msgstr "áááááá·áážâá¢áážáááºáá·áâáááá¶áâáá»ááááá·áá¶áâáááááâáá
áá
á»ááááááâáááá»áââááááŸááá¶á á¬âáááá»áâááááŒáâáá¶áâáááá¢á¶áá ááŒáâáááá¶áá¶áâáááááááâáá
âáááâááááá¶ááá"
+
+#: config/chroot_local-includes/usr/local/sbin/unsafe-browser:249
+msgid ""
+"No DNS server was obtained through DHCP or manually configured in "
+"NetworkManager."
+msgstr "áá·áâáá¶áâáááœáâááá¶ááážáâáá DNS áá¶á DHCP á¬âáá¶áâáá¶áâáááááâáá
áá¶ááááááááâáááâááâáá
âáááá»áâáááááá·áážâáááááááááâááááá¶áá"
+
+#: config/chroot_local-includes/usr/share/tails/truecrypt-wrapper.disabled:11
+msgid "TrueCrypt will soon be removed from Tails"
+msgstr "TrueCrypt áá¹áâááááŒáâáá¶áâáá»áá
ááâááž Tails áááá»áâáááâáá¶ááá"
+
+#: config/chroot_local-includes/usr/share/tails/truecrypt-wrapper.disabled:12
+msgid ""
+"TrueCrypt will soon be removed from Tails due to license and development "
+"concerns."
+msgstr "TrueCrypt áá¹áâááááŒáâáá¶áâáá»áá
ááâááž Tails áááá»áâáááâáá¶ááá ááááá¶áâá¢á¶áááá¶ááááá áá·áâáá¶áâá¢áá·áááá"
+
+#: ../config/chroot_local-includes/etc/skel/Desktop/Report_an_error.desktop.in.h:1
+msgid "Report an error"
+msgstr "áá¶ááá¶áááâááá á»á"
+
+#: ../config/chroot_local-includes/etc/skel/Desktop/Tails_documentation.desktop.in.h:1
+msgid "Tails documentation"
+msgstr "á¯ááá¶á Tails"
+
+#: ../config/chroot_local-includes/usr/share/applications/i2p.desktop.in.h:1
+msgid "Anonymous overlay network "
+msgstr "á¢áá¶áá·áâáá
âááŸâááááá¶á"
+
+#: ../config/chroot_local-includes/usr/share/applications/i2p.desktop.in.h:2
+msgid "i2p"
+msgstr "i2p"
+
+#: ../config/chroot_local-includes/usr/share/applications/i2p.desktop.in.h:3
+msgid "Anonymous overlay network"
+msgstr "á¢áá¶áá·áâáá
âááŸâááááá¶á"
+
+#: ../config/chroot_local-includes/usr/share/applications/tails-reboot.desktop.in.h:1
+msgid "Reboot"
+msgstr "á
á¶ááááááŸáâá¡áŸááá·á"
+
+#: ../config/chroot_local-includes/usr/share/applications/tails-reboot.desktop.in.h:2
+msgid "Immediately reboot computer"
+msgstr "á
á¶ááááááŸáâáá»áááááŒáááâá¡áŸááá·áâáááá¶áá"
+
+#: ../config/chroot_local-includes/usr/share/applications/tails-shutdown.desktop.in.h:1
+msgid "Power Off"
+msgstr "áá·á"
+
+#: ../config/chroot_local-includes/usr/share/applications/tails-shutdown.desktop.in.h:2
+msgid "Immediately shut down computer"
+msgstr "áá·áâáá»áááááŒáááâáááá¶áá"
+
+#: ../config/chroot_local-includes/usr/share/applications/unsafe-browser.desktop.in.h:2
+msgid "Browse the World Wide Web without anonymity"
+msgstr "ááááŸáâáááááááááá¶áâáááâáááá¶áâá¢áá¶áá·ááá¶á"
+
+#: ../config/chroot_local-includes/usr/share/applications/unsafe-browser.desktop.in.h:3
+msgid "Unsafe Web Browser"
+msgstr "áááááá·áážâá¢áážáááºáá·áâáááá¶áâáá»ááááá·áá¶á"
+
+#: ../config/chroot_local-includes/usr/share/desktop-directories/Tails.directory.in.h:2
+msgid "Tails specific tools"
+msgstr "á§áááááâáá¶áááá¶ááâáááá Tails"
1
0

[translation/tails-misc] Update translations for tails-misc
by translation@torproject.org 28 Jan '14
by translation@torproject.org 28 Jan '14
28 Jan '14
commit efb9169f75233e93e307460c8238d9387862c82f
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jan 28 02:16:25 2014 +0000
Update translations for tails-misc
---
km.po | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/km.po b/km.po
index c843afc..759f09b 100644
--- a/km.po
+++ b/km.po
@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-10 12:23+0100\n"
-"PO-Revision-Date: 2014-01-28 01:40+0000\n"
+"PO-Revision-Date: 2014-01-28 02:00+0000\n"
"Last-Translator: soksophea <sksophea(a)gmail.com>\n"
"Language-Team: Khmer (http://www.transifex.com/projects/p/torproject/language/km/)\n"
"MIME-Version: 1.0\n"
@@ -204,11 +204,11 @@ msgstr "Tor គឺមិនទាន់រួចរាល់ទេ។
#: config/chroot_local-includes/usr/local/bin/iceweasel:14
msgid "Start Tor Browser"
-msgstr ""
+msgstr "ចាប់ផ្ដើមកម្មវិធីអ៊ីនធឺណិត Tor"
#: config/chroot_local-includes/usr/local/bin/iceweasel:15
msgid "Cancel"
-msgstr "Cancel"
+msgstr "បោះបង់"
#: config/chroot_local-includes/usr/local/bin/shutdown_helper_applet:34
msgid "Shutdown Immediately"
1
0

[translation/tails-greeter] Update translations for tails-greeter
by translation@torproject.org 28 Jan '14
by translation@torproject.org 28 Jan '14
28 Jan '14
commit f2713140053c5f84287f294a960bc60fcd0c53a3
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jan 28 02:16:10 2014 +0000
Update translations for tails-greeter
---
km/km.po | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/km/km.po b/km/km.po
index e654096..9d7709e 100644
--- a/km/km.po
+++ b/km/km.po
@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-10 12:01+0100\n"
-"PO-Revision-Date: 2014-01-28 01:41+0000\n"
+"PO-Revision-Date: 2014-01-28 01:50+0000\n"
"Last-Translator: Sutha <sutha(a)open.org.kh>\n"
"Language-Team: Khmer (http://www.transifex.com/projects/p/torproject/language/km/)\n"
"MIME-Version: 1.0\n"
1
0

[translation/tails-persistence-setup] Update translations for tails-persistence-setup
by translation@torproject.org 28 Jan '14
by translation@torproject.org 28 Jan '14
28 Jan '14
commit 15152a0117a7d6054b7b6a9c4679a25275b0eeda
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jan 28 02:16:07 2014 +0000
Update translations for tails-persistence-setup
---
km/km.po | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/km/km.po b/km/km.po
index 8b65733..dd61533 100644
--- a/km/km.po
+++ b/km/km.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: Tails developers <tails(a)boum.org>\n"
"POT-Creation-Date: 2014-01-18 21:00+0100\n"
-"PO-Revision-Date: 2014-01-28 01:40+0000\n"
+"PO-Revision-Date: 2014-01-28 01:50+0000\n"
"Last-Translator: runasand <runa.sandvik(a)gmail.com>\n"
"Language-Team: Khmer (http://www.transifex.com/projects/p/torproject/language/km/)\n"
"MIME-Version: 1.0\n"
1
0