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
- 213386 discussions

r24349: {arm} Rearranging connection panel resources, abstracting the cont (in arm/trunk/src: interface interface/connections util)
by Damian Johnson 13 Mar '11
by Damian Johnson 13 Mar '11
13 Mar '11
Author: atagar
Date: 2011-03-13 04:58:18 +0000 (Sun, 13 Mar 2011)
New Revision: 24349
Added:
arm/trunk/src/interface/connections/connEntry.py
arm/trunk/src/interface/connections/entries.py
Removed:
arm/trunk/src/interface/connections/listings.py
Modified:
arm/trunk/src/interface/connections/__init__.py
arm/trunk/src/interface/connections/connPanel.py
arm/trunk/src/interface/controller.py
arm/trunk/src/util/connections.py
arm/trunk/src/util/enum.py
arm/trunk/src/util/uiTools.py
Log:
Rearranging connection panel resources, abstracting the content away from the panel itself. This is to make it more extendable and supporting of multi-line entries (pre-reqs for my plans to display client circuits).
Modified: arm/trunk/src/interface/connections/__init__.py
===================================================================
--- arm/trunk/src/interface/connections/__init__.py 2011-03-13 01:38:32 UTC (rev 24348)
+++ arm/trunk/src/interface/connections/__init__.py 2011-03-13 04:58:18 UTC (rev 24349)
@@ -2,5 +2,5 @@
Panels, popups, and handlers comprising the arm user interface.
"""
-__all__ = ["connPanel", "entry"]
+__all__ = ["connEntry", "connPanel", "entries"]
Added: arm/trunk/src/interface/connections/connEntry.py
===================================================================
--- arm/trunk/src/interface/connections/connEntry.py (rev 0)
+++ arm/trunk/src/interface/connections/connEntry.py 2011-03-13 04:58:18 UTC (rev 24349)
@@ -0,0 +1,694 @@
+"""
+Connection panel entries related to actual connections to or from the system
+(ie, results seen by netstat, lsof, etc).
+"""
+
+import time
+import curses
+
+from util import connections, enum, torTools, uiTools
+from interface.connections import entries
+
+# Connection Categories:
+# Inbound Relay connection, coming to us.
+# Outbound Relay connection, leaving us.
+# Exit Outbound relay connection leaving the Tor network.
+# Client Circuits for our client traffic.
+# Application Socks connections using Tor.
+# Directory Fetching tor consensus information.
+# Control Tor controller (arm, vidalia, etc).
+
+Category = enum.Enum("INBOUND", "OUTBOUND", "EXIT", "CLIENT", "APPLICATION", "DIRECTORY", "CONTROL")
+CATEGORY_COLOR = {Category.INBOUND: "green", Category.OUTBOUND: "blue",
+ Category.EXIT: "red", Category.CLIENT: "cyan",
+ Category.APPLICATION: "yellow", Category.DIRECTORY: "magenta",
+ Category.CONTROL: "red"}
+
+# static data for listing format
+# <src> --> <dst> <etc><padding>
+LABEL_FORMAT = "%s --> %s %s%s"
+LABEL_MIN_PADDING = 2 # min space between listing label and following data
+
+CONFIG = {"features.connection.showColumn.fingerprint": True,
+ "features.connection.showColumn.nickname": True,
+ "features.connection.showColumn.destination": True,
+ "features.connection.showColumn.expanedIp": True}
+
+def loadConfig(config):
+ config.update(CONFIG)
+
+class Endpoint:
+ """
+ Collection of attributes associated with a connection endpoint. This is a
+ thin wrapper for torUtil functions, making use of its caching for
+ performance.
+ """
+
+ def __init__(self, ipAddr, port):
+ self.ipAddr = ipAddr
+ self.port = port
+
+ # if true, we treat the port as an ORPort when searching for matching
+ # fingerprints (otherwise the ORPort is assumed to be unknown)
+ self.isORPort = False
+
+ def getIpAddr(self):
+ """
+ Provides the IP address of the endpoint.
+ """
+
+ return self.ipAddr
+
+ def getPort(self):
+ """
+ Provides the port of the endpoint.
+ """
+
+ return self.port
+
+ def getHostname(self, default = None):
+ """
+ Provides the hostname associated with the relay's address. This is a
+ non-blocking call and returns None if the address either can't be resolved
+ or hasn't been resolved yet.
+
+ Arguments:
+ default - return value if no hostname is available
+ """
+
+ # TODO: skipping all hostname resolution to be safe for now
+ #try:
+ # myHostname = hostnames.resolve(self.ipAddr)
+ #except:
+ # # either a ValueError or IOError depending on the source of the lookup failure
+ # myHostname = None
+ #
+ #if not myHostname: return default
+ #else: return myHostname
+
+ return default
+
+ def getLocale(self):
+ """
+ Provides the two letter country code for the IP address' locale. This
+ proivdes None if it can't be determined.
+ """
+
+ conn = torTools.getConn()
+ return conn.getInfo("ip-to-country/%s" % self.ipAddr)
+
+ def getFingerprint(self):
+ """
+ Provides the fingerprint of the relay, returning "UNKNOWN" if it can't be
+ determined.
+ """
+
+ conn = torTools.getConn()
+ orPort = self.port if self.isORPort else None
+ myFingerprint = conn.getRelayFingerprint(self.ipAddr, orPort)
+
+ if myFingerprint: return myFingerprint
+ else: return "UNKNOWN"
+
+ def getNickname(self):
+ """
+ Provides the nickname of the relay, retuning "UNKNOWN" if it can't be
+ determined.
+ """
+
+ conn = torTools.getConn()
+ orPort = self.port if self.isORPort else None
+ myFingerprint = conn.getRelayFingerprint(self.ipAddr, orPort)
+
+ if myFingerprint: return conn.getRelayNickname(myFingerprint)
+ else: return "UNKNOWN"
+
+class ConnectionEntry(entries.ConnectionPanelEntry):
+ """
+ Represents a connection being made to or from this system. These only
+ concern real connections so it includes the inbound, outbound, directory,
+ application, and controller categories.
+ """
+
+ def __init__(self, lIpAddr, lPort, fIpAddr, fPort):
+ entries.ConnectionPanelEntry.__init__(self)
+ self.lines = [ConnectionLine(lIpAddr, lPort, fIpAddr, fPort)]
+
+ def getSortValue(self, attr, listingType):
+ """
+ Provides the value of a single attribute used for sorting purposes.
+ """
+
+ if attr == entries.SortAttr.IP_ADDRESS:
+ return self.lines[0].sortIpAddr
+ elif attr == entries.SortAttr.PORT:
+ return self.lines[0].sortPort
+ elif attr == entries.SortAttr.HOSTNAME:
+ return self.lines[0].foreign.getHostname("")
+ elif attr == entries.SortAttr.FINGERPRINT:
+ return self.lines[0].foreign.getFingerprint()
+ elif attr == entries.SortAttr.NICKNAME:
+ myNickname = self.lines[0].foreign.getNickname()
+ if myNickname == "UNKNOWN": return "z" * 20 # orders at the end
+ else: return myNickname.lower()
+ elif attr == entries.SortAttr.CATEGORY:
+ return Category.indexOf(self.lines[0].getType())
+ elif attr == entries.SortAttr.UPTIME:
+ return self.lines[0].startTime
+ elif attr == entries.SortAttr.COUNTRY:
+ if connections.isIpAddressPrivate(self.lines[0].foreign.getIpAddr()): return ""
+ else: return self.lines[0].foreign.getLocale()
+ else:
+ return entries.ConnectionPanelEntry.getSortValue(self, attr, listingType)
+
+class ConnectionLine(entries.ConnectionPanelLine):
+ """
+ Display component of the ConnectionEntry.
+ """
+
+ def __init__(self, lIpAddr, lPort, fIpAddr, fPort):
+ entries.ConnectionPanelLine.__init__(self)
+
+ self.local = Endpoint(lIpAddr, lPort)
+ self.foreign = Endpoint(fIpAddr, fPort)
+ self.startTime = time.time()
+
+ # True if the connection has matched the properties of a client/directory
+ # connection every time we've checked. The criteria we check is...
+ # client - first hop in an established circuit
+ # directory - matches an established single-hop circuit (probably a
+ # directory mirror)
+
+ self._possibleClient = True
+ self._possibleDirectory = True
+
+ conn = torTools.getConn()
+ myOrPort = conn.getOption("ORPort")
+ myDirPort = conn.getOption("DirPort")
+ mySocksPort = conn.getOption("SocksPort", "9050")
+ myCtlPort = conn.getOption("ControlPort")
+
+ # the ORListenAddress can overwrite the ORPort
+ listenAddr = conn.getOption("ORListenAddress")
+ if listenAddr and ":" in listenAddr:
+ myOrPort = listenAddr[listenAddr.find(":") + 1:]
+
+ if lPort in (myOrPort, myDirPort):
+ self.baseType = Category.INBOUND
+ self.local.isORPort = True
+ elif lPort == mySocksPort:
+ self.baseType = Category.APPLICATION
+ elif lPort == myCtlPort:
+ self.baseType = Category.CONTROL
+ else:
+ self.baseType = Category.OUTBOUND
+ self.foreign.isORPort = True
+
+ self.cachedType = None
+
+ # cached immutable values used for sorting
+ self.sortIpAddr = connections.ipToInt(self.foreign.getIpAddr())
+ self.sortPort = int(self.foreign.getPort())
+
+ def getListingEntry(self, width, currentTime, listingType):
+ """
+ Provides the DrawEntry for this connection's listing. The line is made up
+ of six components:
+ <src> --> <dst> <etc> <uptime> (<type>)
+
+ ListingType.IP_ADDRESS:
+ src - <internal addr:port> --> <external addr:port>
+ dst - <destination addr:port>
+ etc - <fingerprint> <nickname>
+
+ ListingType.HOSTNAME:
+ src - localhost:<port>
+ dst - <destination hostname:port>
+ etc - <destination addr:port> <fingerprint> <nickname>
+
+ ListingType.FINGERPRINT:
+ src - localhost
+ dst - <destination fingerprint>
+ etc - <nickname> <destination addr:port>
+
+ ListingType.NICKNAME:
+ src - <source nickname>
+ dst - <destination nickname>
+ etc - <fingerprint> <destination addr:port>
+
+ Arguments:
+ width - maximum length of the line
+ currentTime - unix timestamp for what the results should consider to be
+ the current time
+ listingType - primary attribute we're listing connections by
+ """
+
+ # fetch our (most likely cached) display entry for the listing
+ myListing = entries.ConnectionPanelLine.getListingEntry(self, width, currentTime, listingType)
+
+ # fill in the current uptime and return the results
+ timeEntry = myListing.getNext()
+ timeEntry.text = "%5s" % uiTools.getTimeLabel(currentTime - self.startTime, 1)
+
+ return myListing
+
+ def _getListingEntry(self, width, currentTime, listingType):
+ entryType = self.getType()
+
+ # Lines are split into the following components in reverse:
+ # content - "<src> --> <dst> <etc> "
+ # time - "<uptime>"
+ # preType - " ("
+ # category - "<type>"
+ # postType - ") "
+
+ lineFormat = uiTools.getColor(CATEGORY_COLOR[entryType])
+
+ drawEntry = uiTools.DrawEntry(")" + " " * (9 - len(entryType)), lineFormat)
+ drawEntry = uiTools.DrawEntry(entryType.upper(), lineFormat | curses.A_BOLD, drawEntry)
+ drawEntry = uiTools.DrawEntry(" (", lineFormat, drawEntry)
+ drawEntry = uiTools.DrawEntry(" " * 5, lineFormat, drawEntry)
+ drawEntry = uiTools.DrawEntry(self._getListingContent(width - 17, listingType), lineFormat, drawEntry)
+ return drawEntry
+
+ def _getDetails(self, width):
+ """
+ Provides details on the connection, correlated against available consensus
+ data.
+
+ Arguments:
+ width - available space to display in
+ """
+
+ detailFormat = curses.A_BOLD | uiTools.getColor(CATEGORY_COLOR[self.getType()])
+ return [uiTools.DrawEntry(line, detailFormat) for line in self._getDetailContent(width)]
+
+ def resetDisplay(self):
+ entries.ConnectionPanelLine.resetDisplay(self)
+ self.cachedType = None
+
+ def isPrivate(self):
+ """
+ Returns true if the endpoint is private, possibly belonging to a client
+ connection or exit traffic.
+ """
+
+ myType = self.getType()
+
+ if myType == Category.INBOUND:
+ # if the connection doesn't belong to a known relay then it might be
+ # client traffic
+
+ return self.foreign.getFingerprint() == "UNKNOWN"
+ elif myType == Category.EXIT:
+ # DNS connections exiting us aren't private (since they're hitting our
+ # resolvers). Everything else, however, is.
+
+ # TODO: Ideally this would also double check that it's a UDP connection
+ # (since DNS is the only UDP connections Tor will relay), however this
+ # will take a bit more work to propagate the information up from the
+ # connection resolver.
+ return self.foreign.getPort() != "53"
+
+ # for everything else this isn't a concern
+ return False
+
+ def getType(self):
+ """
+ Provides our best guess at the current type of the connection. This
+ depends on consensus results, our current client circuts, etc. Results
+ are cached until this entry's display is reset.
+ """
+
+ # caches both to simplify the calls and to keep the type consistent until
+ # we want to reflect changes
+ if not self.cachedType:
+ if self.baseType == Category.OUTBOUND:
+ # Currently the only non-static categories are OUTBOUND vs...
+ # - EXIT since this depends on the current consensus
+ # - CLIENT if this is likely to belong to our guard usage
+ # - DIRECTORY if this is a single-hop circuit (directory mirror?)
+ #
+ # The exitability, circuits, and fingerprints are all cached by the
+ # torTools util keeping this a quick lookup.
+
+ conn = torTools.getConn()
+ destFingerprint = self.foreign.getFingerprint()
+
+ if destFingerprint == "UNKNOWN":
+ # Not a known relay. This might be an exit connection.
+
+ if conn.isExitingAllowed(self.foreign.getIpAddr(), self.foreign.getPort()):
+ self.cachedType = Category.EXIT
+ elif self._possibleClient or self._possibleDirectory:
+ # 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.
+
+ myCircuits = conn.getCircuits()
+
+ if self._possibleClient:
+ # Checks that this belongs to the first hop in a circuit that's
+ # either unestablished or longer than a single hop (ie, anything but
+ # a built 1-hop connection since those are most likely a directory
+ # mirror).
+
+ for status, _, path in myCircuits:
+ if path[0] == destFingerprint and (status != "BUILT" or len(path) > 1):
+ self.cachedType = Category.CLIENT # matched a probable guard connection
+
+ # if we fell through, we can eliminate ourselves as a guard in the future
+ if not self.cachedType:
+ self._possibleClient = False
+
+ if self._possibleDirectory:
+ # Checks if we match a built, single hop circuit.
+
+ for status, _, path in myCircuits:
+ if path[0] == destFingerprint and status == "BUILT" and len(path) == 1:
+ self.cachedType = Category.DIRECTORY
+
+ # if we fell through, eliminate ourselves as a directory connection
+ if not self.cachedType:
+ self._possibleDirectory = False
+
+ if not self.cachedType:
+ self.cachedType = self.baseType
+
+ return self.cachedType
+
+ def _getListingContent(self, width, listingType):
+ """
+ Provides the source, destination, and extra info for our listing.
+
+ Arguments:
+ width - maximum length of the line
+ listingType - primary attribute we're listing connections by
+ """
+
+ conn = torTools.getConn()
+ myType = self.getType()
+ dstAddress = self._getDestinationLabel(26, includeLocale = True)
+
+ # The required widths are the sum of the following:
+ # - room for LABEL_FORMAT and LABEL_MIN_PADDING (11 characters)
+ # - base data for the listing
+ # - that extra field plus any previous
+
+ usedSpace = len(LABEL_FORMAT % tuple([""] * 4)) + LABEL_MIN_PADDING
+
+ src, dst, etc = "", "", ""
+ if listingType == entries.ListingType.IP_ADDRESS:
+ myExternalIpAddr = conn.getInfo("address", self.local.getIpAddr())
+ addrDiffer = myExternalIpAddr != self.local.getIpAddr()
+
+ srcAddress = "%s:%s" % (myExternalIpAddr, self.local.getPort())
+ src = "%-21s" % srcAddress # ip:port = max of 21 characters
+ dst = "%-26s" % dstAddress # ip:port (xx) = max of 26 characters
+
+ usedSpace += len(src) + len(dst) # base data requires 47 characters
+
+ if width > usedSpace + 42 and CONFIG["features.connection.showColumn.fingerprint"]:
+ # show fingerprint (column width: 42 characters)
+ etc += "%-40s " % self.foreign.getFingerprint()
+ usedSpace += 42
+
+ if addrDiffer and width > usedSpace + 28 and CONFIG["features.connection.showColumn.expanedIp"]:
+ # include the internal address in the src (extra 28 characters)
+ internalAddress = "%s:%s" % (self.local.getIpAddr(), self.local.getPort())
+ src = "%-21s --> %s" % (internalAddress, src)
+ usedSpace += 28
+
+ if width > usedSpace + 10 and CONFIG["features.connection.showColumn.nickname"]:
+ # show nickname (column width: remainder)
+ nicknameSpace = width - usedSpace
+ nicknameLabel = uiTools.cropStr(self.foreign.getNickname(), nicknameSpace, 0)
+ etc += ("%%-%is " % nicknameSpace) % nicknameLabel
+ usedSpace += nicknameSpace + 2
+ elif listingType == entries.ListingType.HOSTNAME:
+ # 15 characters for source, and a min of 40 reserved for the destination
+ src = "localhost:%-5s" % self.local.getPort()
+ usedSpace += len(src)
+ minHostnameSpace = 40
+
+ if width > usedSpace + minHostnameSpace + 28 and CONFIG["features.connection.showColumn.destination"]:
+ # show destination ip/port/locale (column width: 28 characters)
+ etc += "%-26s " % dstAddress
+ usedSpace += 28
+
+ if width > usedSpace + minHostnameSpace + 42 and CONFIG["features.connection.showColumn.fingerprint"]:
+ # show fingerprint (column width: 42 characters)
+ etc += "%-40s " % self.foreign.getFingerprint()
+ usedSpace += 42
+
+ if width > usedSpace + minHostnameSpace + 17 and CONFIG["features.connection.showColumn.nickname"]:
+ # show nickname (column width: min 17 characters, uses half of the remainder)
+ nicknameSpace = 15 + (width - (usedSpace + minHostnameSpace + 17)) / 2
+ nicknameLabel = uiTools.cropStr(self.foreign.getNickname(), nicknameSpace, 0)
+ etc += ("%%-%is " % nicknameSpace) % nicknameLabel
+ usedSpace += (nicknameSpace + 2)
+
+ hostnameSpace = width - usedSpace
+ usedSpace = width # prevents padding at the end
+ if self.isPrivate():
+ dst = ("%%-%is" % hostnameSpace) % "<scrubbed>"
+ else:
+ hostname = self.foreign.getHostname(self.foreign.getIpAddr())
+ port = self.foreign.getPort()
+
+ # truncates long hostnames and sets dst to <hostname>:<port>
+ hostname = uiTools.cropStr(hostname, hostnameSpace, 0)
+ dst = "%s:%-5s" % (hostname, port)
+ dst = ("%%-%is" % hostnameSpace) % dst
+ elif listingType == entries.ListingType.FINGERPRINT:
+ src = "localhost"
+ if myType == Category.CONTROL: dst = "localhost"
+ else: dst = self.foreign.getFingerprint()
+ dst = "%-40s" % dst
+
+ usedSpace += len(src) + len(dst) # base data requires 49 characters
+
+ if width > usedSpace + 17:
+ # show nickname (column width: min 17 characters, consumes any remaining space)
+ nicknameSpace = width - usedSpace
+
+ # if there's room then also show a column with the destination
+ # ip/port/locale (column width: 28 characters)
+ isIpLocaleIncluded = width > usedSpace + 45
+ isIpLocaleIncluded &= CONFIG["features.connection.showColumn.destination"]
+ if isIpLocaleIncluded: nicknameSpace -= 28
+
+ if CONFIG["features.connection.showColumn.nickname"]:
+ nicknameSpace = width - usedSpace - 28 if isIpLocaleIncluded else width - usedSpace
+ nicknameLabel = uiTools.cropStr(self.foreign.getNickname(), nicknameSpace, 0)
+ etc += ("%%-%is " % nicknameSpace) % nicknameLabel
+ usedSpace += nicknameSpace + 2
+
+ if isIpLocaleIncluded:
+ etc += "%-26s " % dstAddress
+ usedSpace += 28
+ else:
+ # base data requires 50 min characters
+ src = self.local.getNickname()
+ if myType == Category.CONTROL: dst = self.local.getNickname()
+ else: dst = self.foreign.getNickname()
+ minBaseSpace = 50
+
+ if width > usedSpace + minBaseSpace + 42 and CONFIG["features.connection.showColumn.fingerprint"]:
+ # show fingerprint (column width: 42 characters)
+ etc += "%-40s " % self.foreign.getFingerprint()
+ usedSpace += 42
+
+ if width > usedSpace + minBaseSpace + 28 and CONFIG["features.connection.showColumn.destination"]:
+ # show destination ip/port/locale (column width: 28 characters)
+ etc += "%-26s " % dstAddress
+ usedSpace += 28
+
+ baseSpace = width - usedSpace
+ usedSpace = width # prevents padding at the end
+
+ if len(src) + len(dst) > baseSpace:
+ src = uiTools.cropStr(src, baseSpace / 3)
+ dst = uiTools.cropStr(dst, baseSpace - len(src))
+
+ # pads dst entry to its max space
+ dst = ("%%-%is" % (baseSpace - len(src))) % dst
+
+ if myType == Category.INBOUND: src, dst = dst, src
+ padding = " " * (width - usedSpace + LABEL_MIN_PADDING)
+ return LABEL_FORMAT % (src, dst, etc, padding)
+
+ def _getDetailContent(self, width):
+ """
+ Provides a list with detailed information for this connectoin.
+
+ Arguments:
+ width - max length of lines
+ """
+
+ lines = [""] * 7
+ lines[0] = "address: %s" % self._getDestinationLabel(width - 11)
+ lines[1] = "locale: %s" % ("??" if self.isPrivate() else self.foreign.getLocale())
+
+ # Remaining data concerns the consensus results, with three possible cases:
+ # - if there's a single match then display its details
+ # - if there's multiple potenial relays then list all of the combinations
+ # of ORPorts / Fingerprints
+ # - if no consensus data is available then say so (probably a client or
+ # exit connection)
+
+ fingerprint = self.foreign.getFingerprint()
+ conn = torTools.getConn()
+
+ if fingerprint != "UNKNOWN":
+ # single match - display information available about it
+ nsEntry = conn.getConsensusEntry(fingerprint)
+ descEntry = conn.getDescriptorEntry(fingerprint)
+
+ # append the fingerprint to the second line
+ lines[1] = "%-13sfingerprint: %s" % (lines[1], fingerprint)
+
+ if nsEntry:
+ # example consensus entry:
+ # r murble R8sCM1ar1sS2GulQYFVmvN95xsk RJr6q+wkTFG+ng5v2bdCbVVFfA4 2011-02-21 00:25:32 195.43.157.85 443 0
+ # s Exit Fast Guard Named Running Stable Valid
+ # w Bandwidth=2540
+ # p accept 20-23,43,53,79-81,88,110,143,194,443
+
+ nsLines = nsEntry.split("\n")
+
+ firstLineComp = nsLines[0].split(" ")
+ if len(firstLineComp) >= 9:
+ _, nickname, _, _, pubDate, pubTime, _, orPort, dirPort = firstLineComp[:9]
+ else: nickname, pubDate, pubTime, orPort, dirPort = "", "", "", "", ""
+
+ flags = nsLines[1][2:]
+ microExit = nsLines[3][2:]
+
+ dirPortLabel = "" if dirPort == "0" else "dirport: %s" % dirPort
+ lines[2] = "nickname: %-25s orport: %-10s %s" % (nickname, orPort, dirPortLabel)
+ lines[3] = "published: %s %s" % (pubDate, pubTime)
+ lines[4] = "flags: %s" % flags.replace(" ", ", ")
+ lines[5] = "exit policy: %s" % microExit.replace(",", ", ")
+
+ if descEntry:
+ torVersion, platform, contact = "", "", ""
+
+ for descLine in descEntry.split("\n"):
+ if descLine.startswith("platform"):
+ # has the tor version and platform, ex:
+ # platform Tor 0.2.1.29 (r318f470bc5f2ad43) on Linux x86_64
+
+ torVersion = descLine[13:descLine.find(" ", 13)]
+ platform = descLine[descLine.rfind(" on ") + 4:]
+ elif descLine.startswith("contact"):
+ contact = descLine[8:]
+
+ # clears up some highly common obscuring
+ for alias in (" at ", " AT "): contact = contact.replace(alias, "@")
+ for alias in (" dot ", " DOT "): contact = contact.replace(alias, ".")
+
+ break # contact lines come after the platform
+
+ lines[3] = "%-35s os: %-14s version: %s" % (lines[3], platform, torVersion)
+
+ # contact information is an optional field
+ if contact: lines[6] = "contact: %s" % contact
+ else:
+ allMatches = conn.getRelayFingerprint(self.foreign.getIpAddr(), getAllMatches = True)
+
+ if allMatches:
+ # multiple matches
+ lines[2] = "Muliple matches, possible fingerprints are:"
+
+ for i in range(len(allMatches)):
+ isLastLine = i == 3
+
+ relayPort, relayFingerprint = allMatches[i]
+ lineText = "%i. or port: %-5s fingerprint: %s" % (i, relayPort, relayFingerprint)
+
+ # if there's multiple lines remaining at the end then give a count
+ remainingRelays = len(allMatches) - i
+ if isLastLine and remainingRelays > 1:
+ lineText = "... %i more" % remainingRelays
+
+ lines[3 + i] = lineText
+
+ if isLastLine: break
+ else:
+ # no consensus entry for this ip address
+ lines[2] = "No consensus data found"
+
+ # crops any lines that are too long
+ for i in range(len(lines)):
+ lines[i] = uiTools.cropStr(lines[i], width - 2)
+
+ return lines
+
+ def _getDestinationLabel(self, maxLength, includeLocale=False, includeHostname=False):
+ """
+ Provides a short description of the destination. This is made up of two
+ components, the base <ip addr>:<port> and an extra piece of information in
+ parentheses. The IP address is scrubbed from private connections.
+
+ Extra information is...
+ - the port's purpose for exit connections
+ - the locale and/or hostname if set to do so, the address isn't private,
+ and isn't on the local network
+ - nothing otherwise
+
+ Arguments:
+ maxLength - maximum length of the string returned
+ includeLocale - possibly includes the locale
+ includeHostname - possibly includes the hostname
+ """
+
+ # destination of the connection
+ if self.isPrivate():
+ dstAddress = "<scrubbed>:%s" % self.foreign.getPort()
+ else:
+ dstAddress = "%s:%s" % (self.foreign.getIpAddr(), self.foreign.getPort())
+
+ # Only append the extra info if there's at least a couple characters of
+ # space (this is what's needed for the country codes).
+ if len(dstAddress) + 5 <= maxLength:
+ spaceAvailable = maxLength - len(dstAddress) - 3
+
+ if self.getType() == Category.EXIT:
+ purpose = connections.getPortUsage(self.foreign.getPort())
+
+ if purpose:
+ # BitTorrent is a common protocol to truncate, so just use "Torrent"
+ # if there's not enough room.
+ if len(purpose) > spaceAvailable and purpose == "BitTorrent":
+ purpose = "Torrent"
+
+ # crops with a hyphen if too long
+ purpose = uiTools.cropStr(purpose, spaceAvailable, endType = uiTools.Ending.HYPHEN)
+
+ dstAddress += " (%s)" % purpose
+ elif not connections.isIpAddressPrivate(self.foreign.getIpAddr()):
+ extraInfo = []
+
+ if includeLocale:
+ foreignLocale = self.foreign.getLocale()
+ extraInfo.append(foreignLocale)
+ spaceAvailable -= len(foreignLocale) + 2
+
+ if includeHostname:
+ dstHostname = self.foreign.getHostname()
+
+ if dstHostname:
+ # determines the full space availabe, taking into account the ", "
+ # dividers if there's multipe pieces of extra data
+
+ maxHostnameSpace = spaceAvailable - 2 * len(extraInfo)
+ dstHostname = uiTools.cropStr(dstHostname, maxHostnameSpace)
+ extraInfo.append(dstHostname)
+ spaceAvailable -= len(dstHostname)
+
+ if extraInfo:
+ dstAddress += " (%s)" % ", ".join(extraInfo)
+
+ return dstAddress[:maxLength]
+
Modified: arm/trunk/src/interface/connections/connPanel.py
===================================================================
--- arm/trunk/src/interface/connections/connPanel.py 2011-03-13 01:38:32 UTC (rev 24348)
+++ arm/trunk/src/interface/connections/connPanel.py 2011-03-13 04:58:18 UTC (rev 24349)
@@ -6,8 +6,8 @@
import curses
import threading
-from interface.connections import listings
-from util import connections, enum, log, panel, torTools, uiTools
+from interface.connections import entries, connEntry
+from util import connections, enum, panel, uiTools
DEFAULT_CONFIG = {"features.connection.listingType": 0,
"features.connection.refreshRate": 10}
@@ -18,7 +18,7 @@
# listing types
Listing = enum.Enum(("IP_ADDRESS", "IP Address"), "HOSTNAME", "FINGERPRINT", "NICKNAME")
-DEFAULT_SORT_ORDER = (listings.SortAttr.CATEGORY, listings.SortAttr.LISTING, listings.SortAttr.UPTIME)
+DEFAULT_SORT_ORDER = (entries.SortAttr.CATEGORY, entries.SortAttr.LISTING, entries.SortAttr.UPTIME)
class ConnectionPanel(panel.Panel, threading.Thread):
"""
@@ -33,12 +33,13 @@
self._sortOrdering = DEFAULT_SORT_ORDER
self._config = dict(DEFAULT_CONFIG)
+
if config:
config.update(self._config, {
"features.connection.listingType": (0, len(Listing.values()) - 1),
"features.connection.refreshRate": 1})
- sortFields = listings.SortAttr.values()
+ sortFields = entries.SortAttr.values()
customOrdering = config.getIntCSV("features.connection.order", None, 3, 0, len(sortFields))
if customOrdering:
@@ -48,6 +49,7 @@
self._scroller = uiTools.Scroller(True)
self._title = "Connections:" # title line of the panel
self._connections = [] # last fetched connections
+ self._connectionLines = [] # individual lines in the connection listing
self._showDetails = False # presents the details panel if true
self._lastUpdate = -1 # time the content was last revised
@@ -55,13 +57,12 @@
self._pauseTime = None # time when the panel was paused
self._halt = False # terminates thread if true
self._cond = threading.Condition() # used for pausing the thread
+ self.valsLock = threading.RLock()
# Last sampling received from the ConnectionResolver, used to detect when
# it changes.
self._lastResourceFetch = -1
- self.valsLock = threading.RLock()
-
self._update() # populates initial entries
# TODO: should listen for tor shutdown
@@ -95,6 +96,10 @@
self.valsLock.acquire()
if ordering: self._sortOrdering = ordering
self._connections.sort(key=lambda i: (i.getSortValues(self._sortOrdering, self._listingType)))
+
+ self._connectionLines = []
+ for entry in self._connections:
+ self._connectionLines += entry.getLines()
self.valsLock.release()
def setListingType(self, listingType):
@@ -109,7 +114,7 @@
self._listingType = listingType
# if we're sorting by the listing then we need to resort
- if listings.SortAttr.LISTING in self._sortOrdering:
+ if entries.SortAttr.LISTING in self._sortOrdering:
self.setSortOrder()
self.valsLock.release()
@@ -120,7 +125,7 @@
if uiTools.isScrollKey(key):
pageHeight = self.getPreferredSize()[0] - 1
if self._showDetails: pageHeight -= (DETAILS_HEIGHT + 1)
- isChanged = self._scroller.handleKey(key, self._connections, pageHeight)
+ isChanged = self._scroller.handleKey(key, self._connectionLines, pageHeight)
if isChanged: self.redraw(True)
elif uiTools.isSelectionKey(key):
self._showDetails = not self._showDetails
@@ -152,14 +157,21 @@
# extra line when showing the detail panel is for the bottom border
detailPanelOffset = DETAILS_HEIGHT + 1 if self._showDetails else 0
- isScrollbarVisible = len(self._connections) > height - detailPanelOffset - 1
+ isScrollbarVisible = len(self._connectionLines) > height - detailPanelOffset - 1
- scrollLoc = self._scroller.getScrollLoc(self._connections, height - detailPanelOffset - 1)
- cursorSelection = self._scroller.getCursorSelection(self._connections)
+ scrollLoc = self._scroller.getScrollLoc(self._connectionLines, height - detailPanelOffset - 1)
+ cursorSelection = self._scroller.getCursorSelection(self._connectionLines)
# draws the detail panel if currently displaying it
if self._showDetails:
- self._drawSelectionPanel(cursorSelection, width, isScrollbarVisible)
+ # This is a solid border unless the scrollbar is visible, in which case a
+ # 'T' pipe connects the border to the bar.
+ uiTools.drawBox(self, 0, 0, width, DETAILS_HEIGHT + 2)
+ if isScrollbarVisible: self.addch(DETAILS_HEIGHT + 1, 1, curses.ACS_TTEE)
+
+ drawEntries = cursorSelection.getDetails(width)
+ for i in range(min(len(drawEntries), DETAILS_HEIGHT)):
+ drawEntries[i].render(self, 1 + i, 2)
# title label with connection counts
title = "Connection Details:" if self._showDetails else self._title
@@ -168,38 +180,18 @@
scrollOffset = 0
if isScrollbarVisible:
scrollOffset = 3
- self.addScrollBar(scrollLoc, scrollLoc + height - detailPanelOffset - 1, len(self._connections), 1 + detailPanelOffset)
+ self.addScrollBar(scrollLoc, scrollLoc + height - detailPanelOffset - 1, len(self._connectionLines), 1 + detailPanelOffset)
currentTime = self._pauseTime if self._pauseTime else time.time()
- for lineNum in range(scrollLoc, len(self._connections)):
- entry = self._connections[lineNum]
- drawLine = lineNum + detailPanelOffset + 1 - scrollLoc
+ for lineNum in range(scrollLoc, len(self._connectionLines)):
+ entryLine = self._connectionLines[lineNum]
- entryType = entry.getType()
- lineFormat = uiTools.getColor(listings.CATEGORY_COLOR[entryType])
- if entry == cursorSelection: lineFormat |= curses.A_STANDOUT
+ # hilighting if this is the selected line
+ extraFormat = curses.A_STANDOUT if entryLine == cursorSelection else curses.A_NORMAL
- # Lines are split into three components (prefix, category, and suffix)
- # since the category includes the bold attribute (otherwise, all use
- # lineFormat).
- xLoc = scrollOffset
-
- # prefix (entry data which is largely static, plus the time label)
- # the right content (time and type) takes seventeen columns
- entryLabel = entry.getLabel(self._listingType, width - scrollOffset - 17)
- timeLabel = uiTools.getTimeLabel(currentTime - entry.startTime, 1)
- prefixLabel = "%s%5s (" % (entryLabel, timeLabel)
-
- self.addstr(drawLine, xLoc, prefixLabel, lineFormat)
- xLoc += len(prefixLabel)
-
- # category
- self.addstr(drawLine, xLoc, entryType.upper(), lineFormat | curses.A_BOLD)
- xLoc += len(entryType)
-
- # suffix (ending parentheses plus padding so lines are the same length)
- self.addstr(drawLine, xLoc, ")" + " " * (9 - len(entryType)), lineFormat)
-
+ drawEntry = entryLine.getListingEntry(width - scrollOffset, currentTime, self._listingType)
+ drawLine = lineNum + detailPanelOffset + 1 - scrollLoc
+ drawEntry.render(self, drawLine, scrollOffset, extraFormat)
if drawLine >= height: break
self.valsLock.release()
@@ -232,25 +224,33 @@
newConnections = []
# preserves any ConnectionEntries they already exist
- for conn in self._connections:
- connAttr = (conn.local.getIpAddr(), conn.local.getPort(),
- conn.foreign.getIpAddr(), conn.foreign.getPort())
-
- if connAttr in currentConnections:
- newConnections.append(conn)
- currentConnections.remove(connAttr)
+ for entry in self._connections:
+ if isinstance(entry, connEntry.ConnectionEntry):
+ connLine = entry.getLines()[0]
+ connAttr = (connLine.local.getIpAddr(), connLine.local.getPort(),
+ connLine.foreign.getIpAddr(), connLine.foreign.getPort())
+
+ if connAttr in currentConnections:
+ newConnections.append(entry)
+ currentConnections.remove(connAttr)
+ # reset any display attributes for the entries we're keeping
+ for entry in newConnections:
+ entry.resetDisplay()
+
# add new entries for any additions
for lIp, lPort, fIp, fPort in currentConnections:
- newConnections.append(listings.ConnectionEntry(lIp, lPort, fIp, fPort))
+ newConnections.append(connEntry.ConnectionEntry(lIp, lPort, fIp, fPort))
# Counts the relays in each of the categories. This also flushes the
# type cache for all of the connections (in case its changed since last
# fetched).
- categoryTypes = listings.Category.values()
+ categoryTypes = connEntry.Category.values()
typeCounts = dict((type, 0) for type in categoryTypes)
- for conn in newConnections: typeCounts[conn.getType(True)] += 1
+ for entry in newConnections:
+ if isinstance(entry, connEntry.ConnectionEntry):
+ typeCounts[entry.getLines()[0].getType()] += 1
# makes labels for all the categories with connections (ie,
# "21 outbound", "1 control", etc)
@@ -264,116 +264,12 @@
else: self._title = "Connections:"
self._connections = newConnections
+
+ self._connectionLines = []
+ for entry in self._connections:
+ self._connectionLines += entry.getLines()
+
self.setSortOrder()
self._lastResourceFetch = currentResolutionCount
self.valsLock.release()
-
- def _drawSelectionPanel(self, selection, width, isScrollbarVisible):
- """
- Renders a panel for details on the selected connnection.
- """
-
- # This is a solid border unless the scrollbar is visible, in which case a
- # 'T' pipe connects the border to the bar.
- uiTools.drawBox(self, 0, 0, width, DETAILS_HEIGHT + 2)
- if isScrollbarVisible: self.addch(DETAILS_HEIGHT + 1, 1, curses.ACS_TTEE)
-
- selectionFormat = curses.A_BOLD | uiTools.getColor(listings.CATEGORY_COLOR[selection.getType()])
- lines = [""] * 7
-
- lines[0] = "address: %s" % selection.getDestinationLabel(width - 11, listings.DestAttr.NONE)
- lines[1] = "locale: %s" % ("??" if selection.isPrivate() else selection.foreign.getLocale())
-
- # Remaining data concerns the consensus results, with three possible cases:
- # - if there's a single match then display its details
- # - if there's multiple potenial relays then list all of the combinations
- # of ORPorts / Fingerprints
- # - if no consensus data is available then say so (probably a client or
- # exit connection)
-
- fingerprint = selection.foreign.getFingerprint()
- conn = torTools.getConn()
-
- if fingerprint != "UNKNOWN":
- # single match - display information available about it
- nsEntry = conn.getConsensusEntry(fingerprint)
- descEntry = conn.getDescriptorEntry(fingerprint)
-
- # append the fingerprint to the second line
- lines[1] = "%-13sfingerprint: %s" % (lines[1], fingerprint)
-
- if nsEntry:
- # example consensus entry:
- # r murble R8sCM1ar1sS2GulQYFVmvN95xsk RJr6q+wkTFG+ng5v2bdCbVVFfA4 2011-02-21 00:25:32 195.43.157.85 443 0
- # s Exit Fast Guard Named Running Stable Valid
- # w Bandwidth=2540
- # p accept 20-23,43,53,79-81,88,110,143,194,443
-
- nsLines = nsEntry.split("\n")
-
- firstLineComp = nsLines[0].split(" ")
- if len(firstLineComp) >= 9:
- _, nickname, _, _, pubDate, pubTime, _, orPort, dirPort = firstLineComp[:9]
- else: nickname, pubDate, pubTime, orPort, dirPort = "", "", "", "", ""
-
- flags = nsLines[1][2:]
- microExit = nsLines[3][2:]
-
- dirPortLabel = "" if dirPort == "0" else "dirport: %s" % dirPort
- lines[2] = "nickname: %-25s orport: %-10s %s" % (nickname, orPort, dirPortLabel)
- lines[3] = "published: %s %s" % (pubDate, pubTime)
- lines[4] = "flags: %s" % flags.replace(" ", ", ")
- lines[5] = "exit policy: %s" % microExit.replace(",", ", ")
-
- if descEntry:
- torVersion, patform, contact = "", "", ""
-
- for descLine in descEntry.split("\n"):
- if descLine.startswith("platform"):
- # has the tor version and platform, ex:
- # platform Tor 0.2.1.29 (r318f470bc5f2ad43) on Linux x86_64
-
- torVersion = descLine[13:descLine.find(" ", 13)]
- platform = descLine[descLine.rfind(" on ") + 4:]
- elif descLine.startswith("contact"):
- contact = descLine[8:]
-
- # clears up some highly common obscuring
- for alias in (" at ", " AT "): contact = contact.replace(alias, "@")
- for alias in (" dot ", " DOT "): contact = contact.replace(alias, ".")
-
- break # contact lines come after the platform
-
- lines[3] = "%-36s os: %-14s version: %s" % (lines[3], platform, torVersion)
-
- # contact information is an optional field
- if contact: lines[6] = "contact: %s" % contact
- else:
- allMatches = conn.getRelayFingerprint(selection.foreign.getIpAddr(), getAllMatches = True)
-
- if allMatches:
- # multiple matches
- lines[2] = "Muliple matches, possible fingerprints are:"
-
- for i in range(len(allMatches)):
- isLastLine = i == 3
-
- relayPort, relayFingerprint = allMatches[i]
- lineText = "%i. or port: %-5s fingerprint: %s" % (i, relayPort, relayFingerprint)
-
- # if there's multiple lines remaining at the end then give a count
- remainingRelays = len(allMatches) - i
- if isLastLine and remainingRelays > 1:
- lineText = "... %i more" % remainingRelays
-
- lines[3 + i] = lineText
-
- if isLastLine: break
- else:
- # no consensus entry for this ip address
- lines[2] = "No consensus data found"
-
- for i in range(len(lines)):
- lineText = uiTools.cropStr(lines[i], width - 2)
- self.addstr(1 + i, 2, lineText, selectionFormat)
Added: arm/trunk/src/interface/connections/entries.py
===================================================================
--- arm/trunk/src/interface/connections/entries.py (rev 0)
+++ arm/trunk/src/interface/connections/entries.py 2011-03-13 04:58:18 UTC (rev 24349)
@@ -0,0 +1,155 @@
+"""
+Interface for entries in the connection panel. These consist of two parts: the
+entry itself (ie, Tor connection, client circuit, etc) and the lines it
+consists of in the listing.
+"""
+
+from util import enum
+
+# attributes we can list entries by
+ListingType = enum.Enum(("IP_ADDRESS", "IP Address"), "HOSTNAME", "FINGERPRINT", "NICKNAME")
+
+SortAttr = enum.Enum("CATEGORY", "UPTIME", "LISTING", "IP_ADDRESS", "PORT",
+ "HOSTNAME", "FINGERPRINT", "NICKNAME", "COUNTRY")
+
+SORT_COLORS = {SortAttr.CATEGORY: "red", SortAttr.UPTIME: "yellow",
+ SortAttr.LISTING: "green", SortAttr.IP_ADDRESS: "blue",
+ SortAttr.PORT: "blue", SortAttr.HOSTNAME: "magenta",
+ SortAttr.FINGERPRINT: "cyan", SortAttr.NICKNAME: "cyan",
+ SortAttr.COUNTRY: "blue"}
+
+class ConnectionPanelEntry:
+ """
+ Common parent for connection panel entries. This consists of a list of lines
+ in the panel listing. This caches results until the display indicates that
+ they should be flushed.
+ """
+
+ def __init__(self):
+ self.lines = []
+ self.flushCache = True
+
+ def getLines(self):
+ """
+ Provides the individual lines in the connection listing.
+ """
+
+ if self.flushCache:
+ self.lines = self._getLines(self.lines)
+ self.flushCache = False
+
+ return self.lines
+
+ def _getLines(self, oldResults):
+ # implementation of getLines
+
+ for line in oldResults:
+ line.resetDisplay()
+
+ return oldResults
+
+ def getSortValues(self, sortAttrs, listingType):
+ """
+ Provides the value used in comparisons to sort based on the given
+ attribute.
+
+ Arguments:
+ sortAttrs - list of SortAttr values for the field being sorted on
+ listingType - ListingType enumeration for the attribute we're listing
+ entries by
+ """
+
+ return [self.getSortValue(attr, listingType) for attr in sortAttrs]
+
+ def getSortValue(self, attr, listingType):
+ """
+ Provides the value of a single attribute used for sorting purposes.
+
+ Arguments:
+ attr - list of SortAttr values for the field being sorted on
+ listingType - ListingType enumeration for the attribute we're listing
+ entries by
+ """
+
+ if attr == SortAttr.LISTING:
+ if listingType == ListingType.IP_ADDRESS:
+ return self.getSortValue(SortAttr.IP_ADDRESS, listingType)
+ elif listingType == ListingType.HOSTNAME:
+ return self.getSortValue(SortAttr.HOSTNAME, listingType)
+ elif listingType == ListingType.FINGERPRINT:
+ return self.getSortValue(SortAttr.FINGERPRINT, listingType)
+ elif listingType == ListingType.NICKNAME:
+ return self.getSortValue(SortAttr.NICKNAME, listingType)
+
+ return ""
+
+ def resetDisplay(self):
+ """
+ Flushes cached display results.
+ """
+
+ self.flushCache = True
+
+class ConnectionPanelLine:
+ """
+ Individual line in the connection panel listing.
+ """
+
+ def __init__(self):
+ # cache for displayed information
+ self._listingCache = None
+ self._listingCacheArgs = (None, None)
+
+ self._detailsCache = None
+ self._detailsCacheArgs = None
+
+ def getListingEntry(self, width, currentTime, listingType):
+ """
+ Provides a DrawEntry instance for contents to be displayed in the
+ connection panel listing.
+
+ Arguments:
+ width - available space to display in
+ currentTime - unix timestamp for what the results should consider to be
+ the current time (this may be ignored due to caching)
+ listingType - ListingType enumeration for the highest priority content
+ to be displayed
+ """
+
+ if self._listingCacheArgs != (width, listingType):
+ self._listingCache = self._getListingEntry(width, currentTime, listingType)
+ self._listingCacheArgs = (width, listingType)
+
+ return self._listingCache
+
+ def _getListingEntry(self, width, currentTime, listingType):
+ # implementation of getListingEntry
+ return None
+
+ def getDetails(self, width):
+ """
+ Provides a list of DrawEntry instances with detailed information for this
+ connection.
+
+ Arguments:
+ width - available space to display in
+ """
+
+ if self._detailsCacheArgs != width:
+ self._detailsCache = self._getDetails(width)
+ self._detailsCacheArgs = width
+
+ return self._detailsCache
+
+ def _getDetails(self, width):
+ # implementation of getListing
+ return []
+
+ def resetDisplay(self):
+ """
+ Flushes cached display results.
+ """
+
+ self._listingCacheArgs = (None, None)
+ self._detailsCacheArgs = None
+
Deleted: arm/trunk/src/interface/connections/listings.py
===================================================================
--- arm/trunk/src/interface/connections/listings.py 2011-03-13 01:38:32 UTC (rev 24348)
+++ arm/trunk/src/interface/connections/listings.py 2011-03-13 04:58:18 UTC (rev 24349)
@@ -1,570 +0,0 @@
-"""
-Entries for connections related to the Tor process.
-"""
-
-import time
-
-from util import connections, enum, hostnames, torTools, uiTools
-
-# Connection Categories:
-# Inbound Relay connection, coming to us.
-# Outbound Relay connection, leaving us.
-# Exit Outbound relay connection leaving the Tor network.
-# Client Circuits for our client traffic.
-# Application Socks connections using Tor.
-# Directory Fetching tor consensus information.
-# Control Tor controller (arm, vidalia, etc).
-
-DestAttr = enum.Enum("NONE", "LOCALE", "HOSTNAME")
-Category = enum.Enum("INBOUND", "OUTBOUND", "EXIT", "CLIENT", "APPLICATION", "DIRECTORY", "CONTROL")
-CATEGORY_COLOR = {Category.INBOUND: "green", Category.OUTBOUND: "blue",
- Category.EXIT: "red", Category.CLIENT: "cyan",
- Category.APPLICATION: "yellow", Category.DIRECTORY: "magenta",
- Category.CONTROL: "red"}
-
-SortAttr = enum.Enum("CATEGORY", "UPTIME", "LISTING", "IP_ADDRESS", "PORT",
- "HOSTNAME", "FINGERPRINT", "NICKNAME", "COUNTRY")
-SORT_COLORS = {SortAttr.CATEGORY: "red", SortAttr.UPTIME: "yellow",
- SortAttr.LISTING: "green", SortAttr.IP_ADDRESS: "blue",
- SortAttr.PORT: "blue", SortAttr.HOSTNAME: "magenta",
- SortAttr.FINGERPRINT: "cyan", SortAttr.NICKNAME: "cyan",
- SortAttr.COUNTRY: "blue"}
-
-# static data for listing format
-# <src> --> <dst> <etc><padding>
-LABEL_FORMAT = "%s --> %s %s%s"
-LABEL_MIN_PADDING = 2 # min space between listing label and following data
-
-CONFIG = {"features.connection.showColumn.fingerprint": True,
- "features.connection.showColumn.nickname": True,
- "features.connection.showColumn.destination": True,
- "features.connection.showColumn.expanedIp": True}
-
-def loadConfig(config):
- config.update(CONFIG)
-
-class Endpoint:
- """
- Collection of attributes associated with a connection endpoint. This is a
- thin wrapper for torUtil functions, making use of its caching for
- performance.
- """
-
- def __init__(self, ipAddr, port):
- self.ipAddr = ipAddr
- self.port = port
-
- # if true, we treat the port as an ORPort when searching for matching
- # fingerprints (otherwise the ORPort is assumed to be unknown)
- self.isORPort = False
-
- def getIpAddr(self):
- """
- Provides the IP address of the endpoint.
- """
-
- return self.ipAddr
-
- def getPort(self):
- """
- Provides the port of the endpoint.
- """
-
- return self.port
-
- def getHostname(self, default = None):
- """
- Provides the hostname associated with the relay's address. This is a
- non-blocking call and returns None if the address either can't be resolved
- or hasn't been resolved yet.
-
- Arguments:
- default - return value if no hostname is available
- """
-
- # TODO: skipping all hostname resolution to be safe for now
- #try:
- # myHostname = hostnames.resolve(self.ipAddr)
- #except:
- # # either a ValueError or IOError depending on the source of the lookup failure
- # myHostname = None
- #
- #if not myHostname: return default
- #else: return myHostname
-
- return default
-
- def getLocale(self):
- """
- Provides the two letter country code for the IP address' locale. This
- proivdes None if it can't be determined.
- """
-
- conn = torTools.getConn()
- return conn.getInfo("ip-to-country/%s" % self.ipAddr)
-
- def getFingerprint(self):
- """
- Provides the fingerprint of the relay, returning "UNKNOWN" if it can't be
- determined.
- """
-
- conn = torTools.getConn()
- orPort = self.port if self.isORPort else None
- myFingerprint = conn.getRelayFingerprint(self.ipAddr, orPort)
-
- if myFingerprint: return myFingerprint
- else: return "UNKNOWN"
-
- def getNickname(self):
- """
- Provides the nickname of the relay, retuning "UNKNOWN" if it can't be
- determined.
- """
-
- conn = torTools.getConn()
- orPort = self.port if self.isORPort else None
- myFingerprint = conn.getRelayFingerprint(self.ipAddr, orPort)
-
- if myFingerprint: return conn.getRelayNickname(myFingerprint)
- else: return "UNKNOWN"
-
-class ConnectionEntry:
- """
- Represents a connection being made to or from this system. These only
- concern real connections so it only includes the inbound, outbound,
- directory, application, and controller categories.
- """
-
- def __init__(self, lIpAddr, lPort, fIpAddr, fPort):
- self.local = Endpoint(lIpAddr, lPort)
- self.foreign = Endpoint(fIpAddr, fPort)
- self.startTime = time.time()
-
- self._labelCache = ""
- self._labelCacheArgs = (None, None)
-
- # True if the connection has matched the properties of a client/directory
- # connection every time we've checked. The criteria we check is...
- # client - first hop in an established circuit
- # directory - matches an established single-hop circuit (probably a
- # directory mirror)
-
- self._possibleClient = True
- self._possibleDirectory = True
-
- conn = torTools.getConn()
- myOrPort = conn.getOption("ORPort")
- myDirPort = conn.getOption("DirPort")
- mySocksPort = conn.getOption("SocksPort", "9050")
- myCtlPort = conn.getOption("ControlPort")
- myAuthorities = conn.getMyDirAuthorities()
-
- # the ORListenAddress can overwrite the ORPort
- listenAddr = conn.getOption("ORListenAddress")
- if listenAddr and ":" in listenAddr:
- myOrPort = listenAddr[listenAddr.find(":") + 1:]
-
- if lPort in (myOrPort, myDirPort):
- self.baseType = Category.INBOUND
- self.local.isORPort = True
- elif lPort == mySocksPort:
- self.baseType = Category.APPLICATION
- elif lPort == myCtlPort:
- self.baseType = Category.CONTROL
- elif (fIpAddr, fPort) in myAuthorities:
- self.baseType = Category.DIRECTORY
- else:
- self.baseType = Category.OUTBOUND
- self.foreign.isORPort = True
-
- self.cachedType = None
-
- # cached immutable values used for sorting
- self.sortIpAddr = _ipToInt(self.foreign.getIpAddr())
- self.sortPort = int(self.foreign.getPort())
-
- def getType(self, reset=False):
- """
- Provides the category this connection belongs to. This isn't always static
- since it can rely on dynamic information (like the current consensus).
-
- Arguments:
- reset - determines if the type has changed if true, otherwise this
- provides the same result as the last call
- """
-
- # caches both to simplify the calls and to keep the type consistent until
- # we want to reflect changes
- if reset or not self.cachedType:
- self.cachedType = self._getType()
-
- return self.cachedType
-
- def getDestinationLabel(self, maxLength, extraAttr=DestAttr.NONE):
- """
- Provides a short description of the destination. This is made up of two
- components, the base <ip addr>:<port> and an extra piece of information in
- parentheses. The IP address is scrubbed from private connections.
-
- Extra information is...
- - the port's purpose for exit connections
- - the extraAttr if the address isn't private and isn't on the local network
- - nothing otherwise
-
- Arguments:
- maxLength - maximum length of the string returned
- """
-
- # destination of the connection
- if self.isPrivate():
- dstAddress = "<scrubbed>:%s" % self.foreign.getPort()
- else:
- dstAddress = "%s:%s" % (self.foreign.getIpAddr(), self.foreign.getPort())
-
- # Only append the extra info if there's at least a couple characters of
- # space (this is what's needed for the country codes).
- if len(dstAddress) + 5 <= maxLength:
- spaceAvailable = maxLength - len(dstAddress) - 3
-
- if self.getType() == Category.EXIT:
- purpose = connections.getPortUsage(self.foreign.getPort())
-
- if purpose:
- # BitTorrent is a common protocol to truncate, so just use "Torrent"
- # if there's not enough room.
- if len(purpose) > spaceAvailable and purpose == "BitTorrent":
- purpose = "Torrent"
-
- # crops with a hyphen if too long
- purpose = uiTools.cropStr(purpose, spaceAvailable, endType = uiTools.Ending.HYPHEN)
-
- dstAddress += " (%s)" % purpose
- elif not connections.isIpAddressPrivate(self.foreign.getIpAddr()):
- if extraAttr == DestAttr.LOCALE:
- dstAddress += " (%s)" % self.foreign.getLocale()
- elif extraAttr == DestAttr.HOSTNAME:
- dstHostname = self.foreign.getHostname()
-
- if dstHostname:
- dstAddress += " (%s)" % uiTools.cropStr(dstHostname, spaceAvailable)
-
- return dstAddress[:maxLength]
-
- def isPrivate(self):
- """
- Returns true if the endpoint is private, possibly belonging to a client
- connection or exit traffic.
- """
-
- myType = self.getType()
-
- if myType == Category.INBOUND:
- # if the connection doesn't belong to a known relay then it might be
- # client traffic
-
- return self.foreign.getFingerprint() == "UNKNOWN"
- elif myType == Category.EXIT:
- # DNS connections exiting us aren't private (since they're hitting our
- # resolvers). Everything else, however, is.
-
- # TODO: Ideally this would also double check that it's a UDP connection
- # (since DNS is the only UDP connections Tor will relay), however this
- # will take a bit more work to propagate the information up from the
- # connection resolver.
- return self.foreign.getPort() != "53"
-
- # for everything else this isn't a concern
- return False
-
- def getSortValues(self, sortAttrs, listingType):
- """
- Provides the value used in comparisons to sort based on the given
- attribute.
-
- Arguments:
- sortAttrs - list of SortAttr values for the field being sorted on
- listingType - primary attribute we're listing connections by
- """
-
- return [self._getSortValue(attr, listingType) for attr in sortAttrs]
-
- def getLabel(self, listingType, width):
- """
- Provides the formatted display string for this entry in the listing with
- the given constraints. Labels are made up of six components:
- <src> --> <dst> <etc> <uptime> (<type>)
- this provides the first three components padded to fill up to the uptime.
-
- Listing.IP_ADDRESS:
- src - <internal addr:port> --> <external addr:port>
- dst - <destination addr:port>
- etc - <fingerprint> <nickname>
-
- Listing.HOSTNAME:
- src - localhost:<port>
- dst - <destination hostname:port>
- etc - <destination addr:port> <fingerprint> <nickname>
-
- Listing.FINGERPRINT:
- src - localhost
- dst - <destination fingerprint>
- etc - <nickname> <destination addr:port>
-
- Listing.NICKNAME:
- src - <source nickname>
- dst - <destination nickname>
- etc - <fingerprint> <destination addr:port>
-
- Arguments:
- listingType - primary attribute we're listing connections by
- width - maximum length of the entry
- """
-
- # late import for the Listing enum (doing it in the header errors due to a
- # circular import)
- from interface.connections import connPanel
-
- # if our cached entries are still valid then use that
- if self._labelCacheArgs == (listingType, width):
- return self._labelCache
-
- conn = torTools.getConn()
- myType = self.getType()
- dstAddress = self.getDestinationLabel(26, DestAttr.LOCALE)
-
- # The required widths are the sum of the following:
- # - room for LABEL_FORMAT and LABEL_MIN_PADDING (11 characters)
- # - base data for the listing
- # - that extra field plus any previous
-
- usedSpace = len(LABEL_FORMAT % tuple([""] * 4)) + LABEL_MIN_PADDING
-
- src, dst, etc = "", "", ""
- if listingType == connPanel.Listing.IP_ADDRESS:
- myExternalIpAddr = conn.getInfo("address", self.local.getIpAddr())
- addrDiffer = myExternalIpAddr != self.local.getIpAddr()
-
- srcAddress = "%s:%s" % (myExternalIpAddr, self.local.getPort())
- src = "%-21s" % srcAddress # ip:port = max of 21 characters
- dst = "%-26s" % dstAddress # ip:port (xx) = max of 26 characters
-
- usedSpace += len(src) + len(dst) # base data requires 47 characters
-
- if width > usedSpace + 42 and CONFIG["features.connection.showColumn.fingerprint"]:
- # show fingerprint (column width: 42 characters)
- etc += "%-40s " % self.foreign.getFingerprint()
- usedSpace += 42
-
- if addrDiffer and width > usedSpace + 28 and CONFIG["features.connection.showColumn.expanedIp"]:
- # include the internal address in the src (extra 28 characters)
- internalAddress = "%s:%s" % (self.local.getIpAddr(), self.local.getPort())
- src = "%-21s --> %s" % (internalAddress, src)
- usedSpace += 28
-
- if width > usedSpace + 10 and CONFIG["features.connection.showColumn.nickname"]:
- # show nickname (column width: remainder)
- nicknameSpace = width - usedSpace
- nicknameLabel = uiTools.cropStr(self.foreign.getNickname(), nicknameSpace, 0)
- etc += ("%%-%is " % nicknameSpace) % nicknameLabel
- usedSpace += nicknameSpace + 2
- elif listingType == connPanel.Listing.HOSTNAME:
- # 15 characters for source, and a min of 40 reserved for the destination
- src = "localhost:%-5s" % self.local.getPort()
- usedSpace += len(src)
- minHostnameSpace = 40
-
- if width > usedSpace + minHostnameSpace + 28 and CONFIG["features.connection.showColumn.destination"]:
- # show destination ip/port/locale (column width: 28 characters)
- etc += "%-26s " % dstAddress
- usedSpace += 28
-
- if width > usedSpace + minHostnameSpace + 42 and CONFIG["features.connection.showColumn.fingerprint"]:
- # show fingerprint (column width: 42 characters)
- etc += "%-40s " % self.foreign.getFingerprint()
- usedSpace += 42
-
- if width > usedSpace + minHostnameSpace + 17 and CONFIG["features.connection.showColumn.nickname"]:
- # show nickname (column width: min 17 characters, uses half of the remainder)
- nicknameSpace = 15 + (width - (usedSpace + minHostnameSpace + 17)) / 2
- nicknameLabel = uiTools.cropStr(self.foreign.getNickname(), nicknameSpace, 0)
- etc += ("%%-%is " % nicknameSpace) % nicknameLabel
- usedSpace += (nicknameSpace + 2)
-
- hostnameSpace = width - usedSpace
- usedSpace = width # prevents padding at the end
- if self.isPrivate():
- dst = ("%%-%is" % hostnameSpace) % "<scrubbed>"
- else:
- hostname = self.foreign.getHostname(self.foreign.getIpAddr())
- port = self.foreign.getPort()
-
- # truncates long hostnames and sets dst to <hostname>:<port>
- hostname = uiTools.cropStr(hostname, hostnameSpace, 0)
- dst = "%s:%-5s" % (hostname, port)
- dst = ("%%-%is" % hostnameSpace) % dst
- elif listingType == connPanel.Listing.FINGERPRINT:
- src = "localhost"
- if myType == Category.CONTROL: dst = "localhost"
- else: dst = self.foreign.getFingerprint()
- dst = "%-40s" % dst
-
- usedSpace += len(src) + len(dst) # base data requires 49 characters
-
- if width > usedSpace + 17:
- # show nickname (column width: min 17 characters, consumes any remaining space)
- nicknameSpace = width - usedSpace
-
- # if there's room then also show a column with the destination
- # ip/port/locale (column width: 28 characters)
- isIpLocaleIncluded = width > usedSpace + 45
- isIpLocaleIncluded &= CONFIG["features.connection.showColumn.destination"]
- if isIpLocaleIncluded: nicknameSpace -= 28
-
- if CONFIG["features.connection.showColumn.nickname"]:
- nicknameSpace = width - usedSpace - 28 if isIpLocaleIncluded else width - usedSpace
- nicknameLabel = uiTools.cropStr(self.foreign.getNickname(), nicknameSpace, 0)
- etc += ("%%-%is " % nicknameSpace) % nicknameLabel
- usedSpace += nicknameSpace + 2
-
- if isIpLocaleIncluded:
- etc += "%-26s " % dstAddress
- usedSpace += 28
- else:
- # base data requires 50 min characters
- src = self.local.getNickname()
- if myType == Category.CONTROL: dst = self.local.getNickname()
- else: dst = self.foreign.getNickname()
- minBaseSpace = 50
-
- if width > usedSpace + minBaseSpace + 42 and CONFIG["features.connection.showColumn.fingerprint"]:
- # show fingerprint (column width: 42 characters)
- etc += "%-40s " % self.foreign.getFingerprint()
- usedSpace += 42
-
- if width > usedSpace + minBaseSpace + 28 and CONFIG["features.connection.showColumn.destination"]:
- # show destination ip/port/locale (column width: 28 characters)
- etc += "%-26s " % dstAddress
- usedSpace += 28
-
- baseSpace = width - usedSpace
- usedSpace = width # prevents padding at the end
-
- if len(src) + len(dst) > baseSpace:
- src = uiTools.cropStr(src, baseSpace / 3)
- dst = uiTools.cropStr(dst, baseSpace - len(src))
-
- # pads dst entry to its max space
- dst = ("%%-%is" % (baseSpace - len(src))) % dst
-
- if myType == Category.INBOUND: src, dst = dst, src
- padding = " " * (width - usedSpace + LABEL_MIN_PADDING)
- self._labelCache = LABEL_FORMAT % (src, dst, etc, padding)
- self._labelCacheArgs = (listingType, width)
-
- return self._labelCache
-
- def _getType(self):
- """
- Provides our best guess at the current type of the connection. This
- depends on consensus results, our current client circuts, etc.
- """
-
- if self.baseType == Category.OUTBOUND:
- # Currently the only non-static categories are OUTBOUND vs...
- # - EXIT since this depends on the current consensus
- # - CLIENT if this is likely to belong to our guard usage
- # - DIRECTORY if this is a single-hop circuit (directory mirror?)
- #
- # The exitability, circuits, and fingerprints are all cached by the
- # torTools util keeping this a quick lookup.
-
- conn = torTools.getConn()
- destFingerprint = self.foreign.getFingerprint()
-
- if destFingerprint == "UNKNOWN":
- # Not a known relay. This might be an exit connection.
-
- if conn.isExitingAllowed(self.foreign.getIpAddr(), self.foreign.getPort()):
- return Category.EXIT
- elif self._possibleClient or self._possibleDirectory:
- # 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.
-
- myCircuits = conn.getCircuits()
-
- if self._possibleClient:
- # Checks that this belongs to the first hop in a circuit that's
- # either unestablished or longer than a single hop (ie, anything but
- # a built 1-hop connection since those are most likely a directory
- # mirror).
-
- for status, _, path in myCircuits:
- if path[0] == destFingerprint and (status != "BUILT" or len(path) > 1):
- return Category.CLIENT # matched a probable guard connection
-
- # fell through, we can eliminate ourselves as a guard in the future
- self._possibleClient = False
-
- if self._possibleDirectory:
- # Checks if we match a built, single hop circuit.
-
- for status, _, path in myCircuits:
- if path[0] == destFingerprint and status == "BUILT" and len(path) == 1:
- return Category.DIRECTORY
-
- # fell through, eliminate ourselves as a directory connection
- self._possibleDirectory = False
-
- return self.baseType
-
- def _getSortValue(self, sortAttr, listingType):
- """
- Provides the value of a single attribute used for sorting purposes.
- """
-
- from interface.connections import connPanel
-
- if sortAttr == SortAttr.IP_ADDRESS: return self.sortIpAddr
- elif sortAttr == SortAttr.PORT: return self.sortPort
- elif sortAttr == SortAttr.HOSTNAME: return self.foreign.getHostname("")
- elif sortAttr == SortAttr.FINGERPRINT: return self.foreign.getFingerprint()
- elif sortAttr == SortAttr.NICKNAME:
- myNickname = self.foreign.getNickname()
-
- if myNickname == "UNKNOWN": return "z" * 20 # orders at the end
- else: return myNickname.lower()
- elif sortAttr == SortAttr.CATEGORY: return Category.indexOf(self.getType())
- elif sortAttr == SortAttr.UPTIME: return self.startTime
- elif sortAttr == SortAttr.COUNTRY:
- if connections.isIpAddressPrivate(self.foreign.getIpAddr()): return ""
- else: return self.foreign.getLocale()
- elif sortAttr == SortAttr.LISTING:
- if listingType == connPanel.Listing.IP_ADDRESS:
- return self._getSortValue(SortAttr.IP_ADDRESS, listingType)
- elif listingType == connPanel.Listing.HOSTNAME:
- return self._getSortValue(SortAttr.HOSTNAME, listingType)
- elif listingType == connPanel.Listing.FINGERPRINT:
- return self._getSortValue(SortAttr.FINGERPRINT, listingType)
- elif listingType == connPanel.Listing.NICKNAME:
- return self._getSortValue(SortAttr.NICKNAME, listingType)
-
- return ""
-
-def _ipToInt(ipAddr):
- """
- Provides an integer representation of the ip address, suitable for sorting.
-
- Arguments:
- ipAddr - ip address to be converted
- """
-
- total = 0
-
- for comp in ipAddr.split("."):
- total *= 255
- total += int(comp)
-
- return total
-
Modified: arm/trunk/src/interface/controller.py
===================================================================
--- arm/trunk/src/interface/controller.py 2011-03-13 01:38:32 UTC (rev 24348)
+++ arm/trunk/src/interface/controller.py 2011-03-13 04:58:18 UTC (rev 24349)
@@ -25,7 +25,8 @@
import fileDescriptorPopup
import interface.connections.connPanel
-import interface.connections.listings
+import interface.connections.connEntry
+import interface.connections.entries
from util import conf, log, connections, hostnames, panel, sysTools, torConfig, torTools, uiTools
import graphing.bandwidthStats
import graphing.connStats
@@ -425,7 +426,7 @@
config = conf.getConfig("arm")
config.update(CONFIG)
graphing.graphPanel.loadConfig(config)
- interface.connections.listings.loadConfig(config)
+ interface.connections.connEntry.loadConfig(config)
# adds events needed for arm functionality to the torTools REQ_EVENTS mapping
# (they're then included with any setControllerEvents call, and log a more
@@ -1602,7 +1603,7 @@
panel.CURSES_LOCK.release()
elif page == 2 and (key == ord('l') or key == ord('L')):
# provides a menu to pick the primary information we list connections by
- options = interface.connections.connPanel.Listing.values()
+ options = interface.connections.entries.ListingType.values()
initialSelection = options.index(panels["conn2"]._listingType)
# hides top label of connection panel and pauses the display
@@ -1624,9 +1625,9 @@
elif page == 2 and (key == ord('s') or key == ord('S')):
# set ordering for connection options
titleLabel = "Connection Ordering:"
- options = interface.connections.listings.SortAttr.values()
+ options = interface.connections.entries.SortAttr.values()
oldSelection = panels["conn2"]._sortOrdering
- optionColors = dict([(attr, interface.connections.listings.SORT_COLORS[attr]) for attr in options])
+ optionColors = dict([(attr, interface.connections.entries.SORT_COLORS[attr]) for attr in options])
results = showSortDialog(stdscr, panels, isPaused, page, titleLabel, options, oldSelection, optionColors)
if results:
Modified: arm/trunk/src/util/connections.py
===================================================================
--- arm/trunk/src/util/connections.py 2011-03-13 01:38:32 UTC (rev 24348)
+++ arm/trunk/src/util/connections.py 2011-03-13 04:58:18 UTC (rev 24349)
@@ -153,6 +153,22 @@
return False
+def ipToInt(ipAddr):
+ """
+ Provides an integer representation of the ip address, suitable for sorting.
+
+ Arguments:
+ ipAddr - ip address to be converted
+ """
+
+ total = 0
+
+ for comp in ipAddr.split("."):
+ total *= 255
+ total += int(comp)
+
+ return total
+
def getPortUsage(port):
"""
Provides the common use of a given port. If no useage is known then this
Modified: arm/trunk/src/util/enum.py
===================================================================
--- arm/trunk/src/util/enum.py 2011-03-13 01:38:32 UTC (rev 24348)
+++ arm/trunk/src/util/enum.py 2011-03-13 04:58:18 UTC (rev 24349)
@@ -12,12 +12,12 @@
>>> pets.DOG
'Skippy'
>>> pets.CAT
-"Cat"
+'Cat'
or with entirely custom string components as an unordered enum with:
>>> pets = LEnum(DOG="Skippy", CAT="Kitty", FISH="Nemo")
>>> pets.CAT
-"Kitty"
+'Kitty'
"""
def toCamelCase(label):
Modified: arm/trunk/src/util/uiTools.py
===================================================================
--- arm/trunk/src/util/uiTools.py 2011-03-13 01:38:32 UTC (rev 24348)
+++ arm/trunk/src/util/uiTools.py 2011-03-13 04:58:18 UTC (rev 24349)
@@ -409,6 +409,53 @@
except ValueError:
raise ValueError(errorMsg)
+class DrawEntry:
+ """
+ Renderable content, encapsulating the text and formatting. These can be
+ chained together to compose lines with multiple types of formatting.
+ """
+
+ def __init__(self, text, format=curses.A_NORMAL, nextEntry=None):
+ self.text = text
+ self.format = format
+ self.nextEntry = nextEntry
+
+ def getNext(self):
+ """
+ Provides the next DrawEntry in the chain.
+ """
+
+ return self.nextEntry
+
+ def setNext(self, nextEntry):
+ """
+ Sets additional content to be drawn after this entry. If None then
+ rendering is terminated after this entry.
+
+ Arguments:
+ nextEntry - DrawEntry instance to be rendered after this one
+ """
+
+ self.nextEntry = nextEntry
+
+ def render(self, drawPanel, y, x, extraFormat=curses.A_NORMAL):
+ """
+ Draws this content at the given position.
+
+ Arguments:
+ drawPanel - context in which to be drawn
+ y - vertical location
+ x - horizontal location
+ extraFormat - additional formatting
+ """
+
+ drawFormat = self.format | extraFormat
+ drawPanel.addstr(y, x, self.text, drawFormat)
+
+ # if there's additional content to show then render it too
+ if self.nextEntry:
+ self.nextEntry.render(drawPanel, y, x + len(self.text), extraFormat)
+
class Scroller:
"""
Tracks the scrolling position when there might be a visible cursor. This
1
0

r24348: {website} re-order the 'in the media' page to be chronological by newe (website/trunk/press/en)
by Andrew Lewman 13 Mar '11
by Andrew Lewman 13 Mar '11
13 Mar '11
Author: phobos
Date: 2011-03-13 01:38:32 +0000 (Sun, 13 Mar 2011)
New Revision: 24348
Modified:
website/trunk/press/en/inthemedia.wml
Log:
re-order the 'in the media' page to be chronological by newest to
oldest.
Modified: website/trunk/press/en/inthemedia.wml
===================================================================
--- website/trunk/press/en/inthemedia.wml 2011-03-12 22:04:22 UTC (rev 24347)
+++ website/trunk/press/en/inthemedia.wml 2011-03-13 01:38:32 UTC (rev 24348)
@@ -11,15 +11,18 @@
</div>
<div id="maincol">
<!-- PUT CONTENT AFTER THIS TAG -->
-
+
<h1>Media Appearances</h1>
-<h2>Interviews & Appearances</h2>
-
-<p> Major news organizations including the New York Times, Forbes, Al
-Jazeera, Washington Post, Le Monde, NPR, and the BBC have sought out or
+<p>Major news organizations including the New York Times, Forbes, Al
+Jazeera, Washington Post, Le Monde, NPR, BBC, and more have sought out or
quoted Tor Project members due to their expertise on anonymity, privacy,
-and Internet censorship issues. Some samples: </p>
+and Internet censorship issues.</p>
+<p>Since Tor is widely used throughout the world, it is mentioned
+regularly in the press. This list is not comprehensive, but illustrates
+some of the significant Tor-related stories that have popped up.</p>
+<p>A sample of such media appearances and mentions is below in order of
+newest to oldest: </p>
<table width="100%" cellpadding="3" cellspacing="0">
<thead style="background-color: #e5e5e5;">
@@ -29,14 +32,14 @@
<th>Topic</th>
</tr>
</thead>
-<tr>
+<tr style="background-color: #e5e5e5;">
<td>2011 March 10</td>
<td>NyTeknik</td>
<td><a
href="http://www.nyteknik.se/nyheter/it_telekom/internet/article3123594.ece">Svenska
biståndspengar till Facebookrevolutionen</a></td>
</tr>
-<tr style="background-color: #e5e5e5;">
+<tr>
<td>2011 March 09</td>
<td>Washington Post</td>
<td><a
@@ -44,6 +47,13 @@
funding tech firms that help Mideast dissidents evade government
censors</a></td>
</td>
+<tr style="background-color: #e5e5e5;">
+<td>2011 February 17</td>
+<td>Walpole Times</td>
+<td><a
+href="http://www.wickedlocal.com/walpole/news/x95296113/Tor-Project-a-Walpole-bas…">Tor
+Project, a Walpole-based company, helps Egyptians avoid Internet censorship during protests</a></td>
+</tr>
<tr>
<td>2011 January 31</td>
<td>NPR: WBUR</td>
@@ -53,188 +63,81 @@
Censorship Online</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
-<td>2011 January 30</td>
-<td>Fox 25 News - Boston</td>
-<td><a
-href="http://www.myfoxboston.com/dpp/news/local/local-company-helps-give-egyptian…">Local
-company helps give Egyptians internet access</a></td>
-</tr>
-<tr>
-<td>2011 January 30</td>
-<td>New England Cable News</td>
-<td><a
-href="http://www.necn.com/01/30/11/Mass-company-helps-activists-avoid-onlin/landi…">Mass.
-company helps activists avoid online government censorship</a></td>
-</tr>
-<tr style="background-color: #e5e5e5;">
-<td>2010 Sept 17</td>
-<td>NPR: On the media</td>
-<td><a href="http://www.onthemedia.org/transcripts/2010/09/17/05">On the
-Media: Interview with Jacob Appelbaum</a>.</td>
-</tr>
-<tr>
-<td>2010 Mar 11</td>
-<td>ABC Australia</td>
-<td><a href="http://www.abc.net.au/rn/futuretense/stories/2010/2837736.htm">Future Tense: The Deep Web</a></td>
-</tr>
-<tr style="background-color: #e5e5e5;">
-<td>2009 Jul 02</td>
-<td>NED/CIMA</td>
-<td><a href="http://cima.ned.org/events/new-media-in-iran.html">The Role of New Media in the Iranian Elections</a></td>
-</tr>
-<tr>
-<td>2009 Apr 06</td>
-<td>Al Jazeera</td>
-<td><a href="http://www.youtube.com/watch?v=vuatxUN2cUQ">Global Village
-Voices showcases Tor</a></td>
-</tr>
-<tr style="background-color: #e5e5e5;">
-<td>2009 Mar 12</td>
-<td>BBC World Service</td>
-<td><a href="http://bbcworldservicetrust.wordpress.com/2009/03/12/12-march-world-day-aga…">Steven J Murdoch interviewed about Tor and Censorship</a></td>
-</tr>
-<tr>
-<td>2009 Feb 13</td>
-<td>Hearsay Culture</td>
-<td><a href="http://www.hearsayculture.com/?p=307">Hearsay Culture Radio Interview/Podcast</a></td>
-</tr>
-<tr style="background-color: #e5e5e5;">
-<td>2008 Dec 29</td>
-<td>nu.nl</td>
-<td><a href="http://www.nu.nl/internet/1891289/anoniem-browsen-voor-gsm-in-de-maak.html">Anoniem browsen voor gsm in de maak</a></td>
-</tr>
-<tr>
-<td>2006 Apr 11</td>
-<td>PBS Frontline</td>
-<td><a href="http://pbs.gen.in/wgbh/pages/frontline/tankman/internet/tech.html">Chipping Away at China's Great Firewall</a></td>
-</tr>
-<tr style="background-color: #e5e5e5;">
-<td>2006 Feb 28</td>
-<td>PC World</td>
-<td><a href="http://www.pcworld.com/article/id,124891-page,1/article.html">
-Outsmarting the Online Privacy Snoops</a></td>
-</tr>
-<tr>
-<td>2006 Feb 27</td>
-<td>Forbes</td>
-<td><a href="http://members.forbes.com/global/2006/0227/018A_2.html">
-Cracks In the Wall</a>. Discussion of Tor being used for evading censorship by repressive
-governments. </td>
-</tr>
-<tr style="background-color: #e5e5e5;">
-<td>2006 Feb 20</td>
-<td>The Boston Globe</td>
-<td><a href="http://members.forbes.com/global/2006/0227/018A_2.html">
-Beating censorship on the Internet</a></td>
-</tr>
-<tr>
-<td>2006 Feb 15</td>
-<td>CBS Evening News</td>
-<td><a href="http://www.cbsnews.com/stories/2006/02/15/eveningnews/main1321785.shtml?sou…">
-Cracking The 'Great Firewall Of China'</a>. Roger Dingledine appeared on the show to discuss Tor, starting at
-1:04 into the video.</td>
-</tr>
-<tr style="background-color: #e5e5e5;">
-<td>2006 Feb 15</td>
-<td>CNBC - Closing Bell</td>
-<td>TV Appearance by Roger Dingledine at 4:25pm. (no link)</td>
-</tr>
-<tr>
-<td>2006 Jan 27</td>
-<td>Fox News/eWeek</td>
-<td><a href="http://www.foxnews.com/story/0,2933,183005,00.html"> Web
-Anonymizers Suddenly Get Very Popular</a></td>
-</tr>
-<tr>
-<td>2006 Jan 25</td>
-<td>New York Times</td>
-<td><a href="http://www.nytimes.com/2006/01/25/technology/techspecial2/25privacy.html?_r…">
-Privacy for People Who Don't Show Their Navels</a></td>
-</tr>
-<tr style="background-color: #e5e5e5;">
-<td>2005 Aug 6</td>
-<td>New Scientist</td>
-<td><a href="http://www.eurekalert.org/pub_releases/2005-08/ns-wwa080305.php">Why we all need pornography</a></td>
-</tr>
-</table>
-
-<br/>
-
-<h2>Articles</h2>
-
-<p> Since Tor is widely used throughout the world, it is mentioned regularly in the press.
-This list is not comprehensive, but illustrates some of the significant
-Tor-related stories that have popped up. </p>
-
-<table width="100%" cellpadding="3" cellspacing="0">
-<thead style="background-color: #e5e5e5;">
-<tr>
-<th width="10%">Date</th>
-<th width="15%">Publication</th>
-<th>Topic</th>
-</tr>
-</thead>
-<tr>
-<td>2011 February 17</td>
-<td>Walpole Times</td>
-<td><a
-href="http://www.wickedlocal.com/walpole/news/x95296113/Tor-Project-a-Walpole-bas…">Tor
-Project, a Walpole-based company, helps Egyptians avoid Internet censorship during protests</a></td>
-</tr>
-<tr style="background-color: #e5e5e5;">
<td>2011 February 01</td>
<td>Discovery News</td>
<td><a
-href="http://news.discovery.com/tech/egypt-internet-online-protesters-110201.html">Egypt's
+href="http://news.discovery.com/tech/egypt-internet-online-protesters-110201.
+html">Egypt's
Internet Block Incomplete But Damaging</a></td>
</tr>
<tr>
<td>2011 January 31</td>
<td>IDG Poland</td>
<td><a
-href="http://www.idg.pl/news/366773/Egipt.blokuje.Internet.aktywisci.szukaja.alte…">Egipt
+href="http://www.idg.pl/news/366773/Egipt.blokuje.Internet.aktywisci.szukaja.
+alternatyw.html">Egipt
blokuje Internet, aktywiści szukają alternatyw</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2011 January 31</td>
<td>New Scientist</td>
<td><a
-href="http://www.newscientist.com/blogs/onepercent/2011/01/egypt-remains-official…">How
+href="http://www.newscientist.com/blogs/onepercent/2011/01/egypt-remains-
+officially-offli.html">How
Egypt is getting online</a></td>
</tr>
<tr>
<td>2011 January 31</td>
<td>El Pais</td>
<td><a
-href="http://www.elpais.com/articulo/internacional/Sortear/censura/golpe/fax/elpe…">Sortear
+href="http://www.elpais.com/articulo/internacional/Sortear/censura/golpe/fax/
+elpepuint/20110130elpepuint_14/Tes">Sortear
la censura a golpe de fax</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2011 January 30</td>
+<td>Fox 25 News - Boston</td>
+<td><a
+href="http://www.myfoxboston.com/dpp/news/local/local-company-helps-give-egyptian…">Local
+company helps give Egyptians internet access</a></td>
+</tr>
+<tr>
+<td>2011 January 30</td>
+<td>New England Cable News</td>
+<td><a
+href="http://www.necn.com/01/30/11/Mass-company-helps-activists-avoid-onlin/landi…">Mass.
+company helps activists avoid online government censorship</a></td>
+</tr>
+<tr style="background-color: #e5e5e5;">
+<td>2011 January 30</td>
<td>Boston Globe</td>
<td><a
-href="http://www.boston.com/news/local/massachusetts/articles/2011/01/30/mass_gro…">Foreign
+href="http://www.boston.com/news/local/massachusetts/articles/2011/01/30/
+mass_groups_software_helps_avoid_censorship/">Foreign
activists stay covered online</a></td>
</tr>
<tr>
<td>2011 January 29</td>
<td>SvD.se</td>
<td><a
-href="http://www.svd.se/nyheter/utrikes/tor-oppnar-dorrar-for-natdissidenter_5902…">Tor
+href="http://www.svd.se/nyheter/utrikes/tor-oppnar-dorrar-for-
+natdissidenter_5902693.svd">Tor
öppnar dörrar för nätdissidenter</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2011 January 29</td>
<td>ComputerWorld</td>
<td><a
-href="http://www.computerworld.com/s/article/9207058/Without_Internet_Egyptians_f…">Without
+href="http://www.computerworld.com/s/article/9207058/
+Without_Internet_Egyptians_find_new_ways_to_get_online?taxonomyId=16">Without
Internet, Egyptians find new ways to get online.</a></td>
</tr>
<tr>
<td>2011 January 28</td>
<td>Globe and Mail</td>
<td><a
-href="https://www.theglobeandmail.com/news/technology/in-a-span-of-minutes-a-coun…">In
+href="https://www.theglobeandmail.com/news/technology/in-a-span-of-minutes-a-
+country-goes-offline/article1887207/">In
a span of minutes, a country goes offline</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
@@ -254,14 +157,21 @@
<td>2010 November 03</td>
<td>metro sverige</td>
<td><a
-href="http://www.metro.se/2010/11/03/73897/sida-hjalper-utsatta-bli-anonyma-pa-n/">Sida
-hjälper utsatta bli anonyma på nätet</a></td>
+href="http://www.metro.se/2010/11/03/73897/sida-hjalper-utsatta-bli-anonyma-pa-n
+/">Sida hjälper utsatta bli anonyma på nätet</a></td>
</tr>
+<tr style="background-color: #e5e5e5;">
+<td>2010 Sept 17</td>
+<td>NPR: On the media</td>
+<td><a href="http://www.onthemedia.org/transcripts/2010/09/17/05">On the
+Media: Interview with Jacob Appelbaum</a>.</td>
+</tr>
<tr>
<td>2010 August 01</td>
<td>PC Format - Poland</td>
<td><a
-href="http://www.pcformat.pl/index.php/artykul/aid/1236/t/google-facebook-nas-szp…">Google
+href="http://www.pcformat.pl/index.php/artykul/aid/1236/t/google-facebook-nas-
+szpieguj-jak-chroni-prywatno-w-sieci">Google
and Facebook are spying on us</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
@@ -276,145 +186,214 @@
<td>2010 May 25</td>
<td>The Australian</td>
<td><a
-href="http://www.theaustralian.com.au/australian-it/call-to-join-tor-network-to-f…">
+href="http://www.theaustralian.com.au/australian-it/call-to-join-tor-network-to-
+fight-censorship/story-e6frgakx-1225870756466">
Call to join Tor network to fight censorship</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2010 Mar 17</td>
<td>PC World Poland</td>
-<td><a href="http://www.idg.pl/news/356993/Anonimowosc.w.Sieci.html">Anonymity in the Web</a></td>
+<td><a href="http://www.idg.pl/news/356993/Anonimowosc.w.Sieci.html">Anonymity
+in the Web</a></td>
</tr>
<tr>
+<td>2010 Mar 11</td>
+<td>ABC Australia</td>
+<td><a href="http://www.abc.net.au/rn/futuretense/stories/2010/2837736.htm">Future Tense: The Deep Web</a></td>
+</tr>
+<tr>
<td>2010 Mar 09</td>
<td>PC Pro UK</td>
-<td><a href="http://www.pcpro.co.uk/features/356254/the-dark-side-of-the-web">The dark side of the web</a></td>
+<td><a
+href="http://www.pcpro.co.uk/features/356254/the-dark-side-of-the-web">The dark
+side of the web</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Dec 29</td>
<td>Times Online</td>
<td><a
-href="http://www.timesonline.co.uk/tol/news/world/middle_east/article6969958.ece">When
+href="http://www.timesonline.co.uk/tol/news/world/middle_east/article6969958.
+ece">When
Iran’s regime falls this will be remembered as the YouTube revolution </a></td>
</tr>
<tr>
<td>2009 Oct 15</td>
<td>Technology Review</td>
-<td><a href="http://www.technologyreview.com/web/23736/?a=f">China Cracks Down on Tor Anonymity Network</a></td>
+<td><a href="http://www.technologyreview.com/web/23736/?a=f">China Cracks Down
+on Tor Anonymity Network</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Sep 30</td>
<td>BusinessWeek</td>
-<td><a href="http://www.businessweek.com/globalbiz/content/sep2009/gb20090930_620354.htm">China's Online Censors Work Overtime</a></td>
+<td><a
+href="http://www.businessweek.com/globalbiz/content/sep2009/gb20090930_620354.
+htm">China's Online Censors Work Overtime</a></td>
</tr>
<tr>
<td>2009 Aug 19</td>
<td>Reuters</td>
-<td><a href="http://www.reuters.com/article/internetNews/idUSTRE57I4IE20090819?pageNumbe…">Web tools help protect human rights activists</a></td>
+<td><a
+href="http://www.reuters.com/article/internetNews/idUSTRE57I4IE20090819?
+pageNumber=1&virtualBrandChannel=0&sp=true">Web tools help protect human
+rights activists</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Aug 10</td>
<td>Technology Review</td>
-<td><a href="http://www.technologyreview.com/blog/editors/23958/?nlid=2255">How to Build Anonymity Into the Internet</a></td>
+<td><a href="http://www.technologyreview.com/blog/editors/23958/?nlid=2255">How
+to Build Anonymity Into the Internet</a></td>
</tr>
<tr>
<td>2009 Jul 26</td>
<td>Washington Times</td>
-<td><a href="http://www.washingtontimes.com/news/2009/jul/26/senate-help-iran-dodge-inte…">Senate OKs funds to thwart Iran Web censors</a></td>
+<td><a
+href="http://www.washingtontimes.com/news/2009/jul/26/senate-help-iran-dodge-
+internet-censorship/">Senate OKs funds to thwart Iran Web censors</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Jul 26</td>
<td>Boston Globe</td>
-<td><a href="http://www.boston.com/news/nation/washington/articles/2009/07/26/us_to_incr…">US set to hike aid aimed at Iranians</a></td>
+<td><a
+href="http://www.boston.com/news/nation/washington/articles/2009/07/26/
+us_to_increase_funding_for_hackivists_aiding_iranians/">US set to hike aid aimed
+at Iranians</a></td>
</tr>
<tr>
<td>2009 Jul 24</td>
<td>Associated Press</td>
-<td><a href="http://www.google.com/hostednews/ap/article/ALeqM5hTf-p6Iy3sWHK8BRR58npGosL…">Iran activists work to elude crackdown on Internet</a></td>
+<td><a
+href="http://www.google.com/hostednews/ap/article/ALeqM5hTf-
+p6Iy3sWHK8BRR58npGosLC3AD99L01QO0">Iran activists work to elude crackdown on
+Internet</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Jul 08</td>
<td>Tehran Bureau</td>
-<td><a href="http://tehranbureau.com/geeks-globe-rally-iranians-online/">Geeks Around the Globe Rally to Help Iranians Online</a></td>
+<td><a href="http://tehranbureau.com/geeks-globe-rally-iranians-online/">Geeks
+Around the Globe Rally to Help Iranians Online</a></td>
</tr>
+<tr style="background-color: #e5e5e5;">
+<td>2009 Jul 02</td>
+<td>NED/CIMA</td>
+<td><a href="http://cima.ned.org/events/new-media-in-iran.html">The Role of New Media in the Iranian Elections</a></td>
+</tr>
<tr>
<td>2009 Jun 26</td>
<td>Washington Times</td>
-<td><a href="http://www.washingtontimes.com/news/2009/jun/26/protesters-use-navy-technol…">Iranian protesters avoid censorship with Navy technology</a></td>
+<td><a
+href="http://www.washingtontimes.com/news/2009/jun/26/protesters-use-navy-
+technology-to-avoid-censorship/?feat=home_headlines">Iranian protesters avoid
+censorship with Navy technology</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Jun 29</td>
<td>EFF</td>
-<td><a href="http://www.eff.org/deeplinks/2009/06/help-protesters-iran-run-tor-relays-br…">Help Protesters in Iran: Run a Tor Bridge or a Tor Relay</a></td>
+<td><a
+href="http://www.eff.org/deeplinks/2009/06/help-protesters-iran-run-tor-relays-
+bridges">Help Protesters in Iran: Run a Tor Bridge or a Tor Relay</a></td>
</tr>
<tr>
<td>2009 Jun 24</td>
<td>Daily Finance</td>
-<td><a href="http://www.dailyfinance.com/2009/06/24/nokia-and-siemens-in-iran-controvers…">Nokia and Siemens in Iran controversy</a></td>
+<td><a
+href="http://www.dailyfinance.com/2009/06/24/nokia-and-siemens-in-iran-
+controversy/">Nokia and Siemens in Iran controversy</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Jun 18</td>
<td>Wall Street Journal</td>
-<td><a href="http://blogs.wsj.com/digits/2009/06/18/iranians-using-tor-to-anonymize-web-…">Iranians Using Tor to Anonymize Web Use</a></td>
+<td><a
+href="http://blogs.wsj.com/digits/2009/06/18/iranians-using-tor-to-anonymize-web
+-use/">Iranians Using Tor to Anonymize Web Use</a></td>
</tr>
<tr>
<td>2009 Jun 19</td>
<td>O'Reilly Radar</td>
-<td><a href="http://radar.oreilly.com/2009/06/tor-and-the-legality-of-runnin.html">Dramatic Increase in Number of Tor Clients from Iran: Interview with Tor Project and the EFF</a></td>
+<td><a
+href="http://radar.oreilly.com/2009/06/tor-and-the-legality-of-runnin.html">
+Dramatic Increase in Number of Tor Clients from Iran: Interview with Tor Project
+and the EFF</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Jun 18</td>
<td>Deutsche Welle</td>
-<td><a href="http://www.dw-world.de/dw/article/0,,4400882,00.html">Internet proxies let Iranians and others connect to blocked Web sites</a></td>
+<td><a href="http://www.dw-world.de/dw/article/0,,4400882,00.html">Internet
+proxies let Iranians and others connect to blocked Web sites</a></td>
</tr>
<tr>
<td>2009 Jun 18</td>
<td>Technology Review</td>
-<td><a href="http://www.technologyreview.com/web/22893/">The Web vs. the Republic of Iran</a></td>
+<td><a href="http://www.technologyreview.com/web/22893/">The Web vs. the
+Republic of Iran</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Jun 17</td>
<td>CNet News</td>
-<td><a href="http://news.cnet.com/8301-13578_3-10267287-38.html">Iranians find ways to bypass Net censors</a></td>
+<td><a href="http://news.cnet.com/8301-13578_3-10267287-38.html">Iranians find
+ways to bypass Net censors</a></td>
</tr>
<tr>
<td>2009 Jun 17</td>
<td>ComputerWorld</td>
-<td><a href="http://www.computerworld.com/action/article.do?command=viewArticleBasic&…">Iran's leaders fight Internet; Internet wins (so far)</a></td>
+<td><a
+href="http://www.computerworld.com/action/article.do?command=viewArticleBasic&
+amp;articleId=9134471&intsrc=news_ts_head">Iran's leaders fight Internet;
+Internet wins (so far)</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 May 29</td>
<td>Le Monde</td>
-<td><a href="http://www.lemonde.fr/actualite-medias/article/2009/05/29/les-censeurs-du-n…">Les censeurs du Net</a></td>
+<td><a
+href="http://www.lemonde.fr/actualite-medias/article/2009/05/29/les-censeurs-du-
+net_1199993_3236.html">Les censeurs du Net</a></td>
</tr>
<tr>
<td>2009 May 15</td>
<td>Mass High Tech</td>
-<td><a href="http://www.masshightech.com/stories/2009/05/11/newscolumn2-Tor-tackles-Net-…">Tor tackles Net privacy</a></td>
+<td><a
+href="http://www.masshightech.com/stories/2009/05/11/newscolumn2-Tor-tackles-Net
+-privacy-game-makers-flock-to-Hub.html">Tor tackles Net privacy</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 May 01</td>
<td>New York Times</td>
-<td><a href="http://www.nytimes.com/2009/05/01/technology/01filter.html">Iranians and Others Outwit Net Censors</a></td>
+<td><a
+href="http://www.nytimes.com/2009/05/01/technology/01filter.html">Iranians and
+Others Outwit Net Censors</a></td>
</tr>
<tr>
<td>2009 Apr 23</td>
<td>Technology Review</td>
-<td><a href="http://www.technologyreview.com/computing/22427/?a=f">Dissent Made Safer: How anonymity technology could save free speech on the Internet.</a></td>
+<td><a href="http://www.technologyreview.com/computing/22427/?a=f">Dissent Made
+Safer: How anonymity technology could save free speech on the
+Internet.</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Apr 22</td>
<td>Le Monde</td>
-<td><a href="http://bugbrother.blog.lemonde.fr/2009/04/22/comment-contourner-la-cybersur…">How to circumvent cybersurveillance</a></td>
+<td><a
+href="http://bugbrother.blog.lemonde.fr/2009/04/22/comment-contourner-la-
+cybersurveillance/">How to circumvent cybersurveillance</a></td>
</tr>
<tr>
<td>2009 Apr 06</td>
<td>Reader's Digest</td>
-<td><a href="http://www.rd.com/advice-and-know-how/how-to-hide-anything/article122219.ht…">How to Hide Anything</a></td>
+<td><a
+href="http://www.rd.com/advice-and-know-how/how-to-hide-anything/article122219.
+html">How to Hide Anything</a></td>
</tr>
+<tr>
+<td>2009 Apr 06</td>
+<td>Al Jazeera</td>
+<td><a href="http://www.youtube.com/watch?v=vuatxUN2cUQ">Global Village
+Voices showcases Tor</a></td>
+</tr>
<tr style="background-color: #e5e5e5;">
<td>2009 Mar 18</td>
<td>Marie Claire</td>
-<td><a href="http://www.marieclaire.com/career-money/career-coach/manage-online--web-ima…">How to Manage Your Web Footprint</a></td>
+<td><a
+href="http://www.marieclaire.com/career-money/career-coach/manage-online--web-
+image">How to Manage Your Web Footprint</a></td>
</tr>
<tr>
<td>2009 Mar 13</td>
@@ -424,16 +403,35 @@
Kindness of Strangers</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
+<td>2009 Mar 12</td>
+<td>BBC World Service</td>
+<td><a href="http://bbcworldservicetrust.wordpress.com/2009/03/12/12-march-world-day-aga…">Steven J Murdoch interviewed about Tor and Censorship</a></td>
+</tr>
+<tr style="background-color: #e5e5e5;">
<td>2009 Mar 03</td>
<td>Orf Austria</td>
-<td><a href="http://futurezone.orf.at/stories/1503028/">WIRTSCHAFTSKAMMER column</a></td>
+<td><a href="http://futurezone.orf.at/stories/1503028/">WIRTSCHAFTSKAMMER
+column</a></td>
</tr>
<tr>
<td>2009 Feb 18</td>
<td>Bangkok Post</td>
-<td><a href="http://www.bangkokpost.com/tech/technews/11872/the-old-fake-404-not-found-r…">The old fake "404 not found" routine</a></td>
+<td><a
+href="http://www.bangkokpost.com/tech/technews/11872/the-old-fake-404-not-found-
+routine">The old fake "404 not found" routine</a></td>
</tr>
+<tr>
+<td>2009 Feb 13</td>
+<td>Hearsay Culture</td>
+<td><a href="http://www.hearsayculture.com/?p=307">Hearsay Culture Radio Interview/Podcast</a></td>
+</tr>
<tr style="background-color: #e5e5e5;">
+<td>2008 Dec 29</td>
+<td>nu.nl</td>
+<td><a href="http://www.nu.nl/internet/1891289/anoniem-browsen-voor-gsm-in-de-maak.html">Anoniem browsen voor gsm in de maak</a></td>
+</tr>
+<tr>
+<tr style="background-color: #e5e5e5;">
<td>2008 Dec 14</td>
<td>PC Magazine: Middle & Near East</td>
<td><a
@@ -451,29 +449,34 @@
<td>2008 Aug 22</td>
<td>The Sydney Morning Herald</td>
<td><a
-href="http://www.smh.com.au/news/web/the-china-syndrome/2008/08/20/1218911800889.…">The
+href="http://www.smh.com.au/news/web/the-china-syndrome/2008/08/20/1218911800889
+.html">The
China Syndrome</a></td>
</tr>
<tr>
<td>2008 Aug 20</td>
<td>Scientific American</td>
<td><a
-href="http://www.sciam.com/article.cfm?id=cryptography-how-to-keep-your-secrets-s…">Cryptography:
+href="http://www.sciam.com/article.cfm?id=cryptography-how-to-keep-your-secrets-
+safe">Cryptography:
How to Keep Your Secrets Safe</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2008 Aug 05</td>
<td>Guardian UK</td>
<td><a
-href="http://www.guardian.co.uk/commentisfree/2008/aug/05/china.censorship">Vaulting
+href="http://www.guardian.co.uk/commentisfree/2008/aug/05/china.censorship">
+Vaulting
the great firewall</a></td>
</tr>
<tr>
<td>2008 Aug 10</td>
<td>Tech Radar UK</td>
<td><a
-href="http://www.techradar.com/news/internet/web/freedom-stick-highlights-chinese…">Freedom
-Stick highlights Chinese 'net censorship: USB drive promises anonymous surfing for the paranoid</a>
+href="http://www.techradar.com/news/internet/web/freedom-stick-highlights-
+chinese-net-censorship-449233">Freedom
+Stick highlights Chinese 'net censorship: USB drive promises anonymous surfing
+for the paranoid</a>
</td>
</tr>
<tr style="background-color: #e5e5e5;">
@@ -488,7 +491,8 @@
<td>2008 Aug 07</td>
<td>PC World</td>
<td><a
-href="http://www.pcworld.com/article/149399-3/15_great_free_privacy_downloads.html">15
+href="http://www.pcworld.com/article/149399-3/15_great_free_privacy_downloads.
+html">15
Great, Free Privacy Downloads</a>. Tor is Number 1.
</td>
</tr>
@@ -512,16 +516,21 @@
<td>2008 May 24</td>
<td>Groupo Estado</td>
<td><a
-href="http://blog.estadao.com.br/blog/cruz/?title=cfp08_navegacao_anonima_na_rede…">Interview
+href="http://blog.estadao.com.br/blog/cruz/?title=
+cfp08_navegacao_anonima_na_rede&more=1&c=1&tb=1&pb=1&cat=
+525">Interview
at Computers, Freedom, and Privacy 2008 Conference</a>
</td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2008 Mar 12</td>
<td>SearchSecurity.com</td>
-<td><a href="http://searchsecurity.techtarget.com/news/article/0,289142,sid14_gci1305120…">
+<td><a
+href="http://searchsecurity.techtarget.com/news/article/0,289142,
+sid14_gci1305120,00.html">
Tor network 'bridges' help evade blockers</a>.
-Covers new Tor features designed to overcome filtering and blocking that prevent access
+Covers new Tor features designed to overcome filtering and blocking that prevent
+access
to the Tor network.
</td>
</tr>
@@ -538,571 +547,337 @@
<td><a href="http://www.pcworld.com/article/id,142094-pg,1/article.html">
Hackers Can Expose Masked Surfers, Study Says</a>
A report on <a href="http://www.lightbluetouchpaper.org/2007/12/10/covert-channel-vulnerabilitie…">
-Steven Murdoch's recent PhD thesis</a>. Steven <a
-href="<blog>media-coverage-%2526quot%3Bcovert-channel-vulnerabilities-anonymity-systems%2526quot%3B">
+Steven Murdoch's recent PhD thesis</a>. Steven <a href="<blog>media-coverage-%2526quot%3Bcovert-channel-vulnerabilities-anonymity-systems%2526quot%3B">
responds on the Tor Blog</a>.</td>
</tr>
<tr style="background-color: #e5e5e5;">
<td>2007 Sep 21</td>
<td>Wired HowTo Blog</td>
-<td><a href="http://howto.wired.com/wiredhowtos/index.cgi?page_name=be_a_whistle_blower;…">
-Be a Whistleblower</a>. Wired recommends Tor for whistleblowers who wish to remain anonymous.
-</td>
+<td><a href="http://howto.wired.com/wiredhowtos/index.cgi?page_name=be_a_whistle_blower;…">Be a Whistleblower</a>. Wired recommends Tor for whistleblowers who wish to remain anonymous.</td>
</tr>
-
<tr>
<td>2007 Sep 16</td>
<td>Cnet</td>
-<td><a href="http://news.cnet.com/8301-13739_3-9779225-46.html">
- Tor anonymity server admin arrested</a>. A Tor exit node operator from Germany was arrested and then released once the police realized
- their mistake. Unfortunately, the hassle <a href="http://arstechnica.com/news.ars/post/20070917-tor-node-operator-after-run-i…"> caused this operator to shut down the node</a>.
- We have an <a href="<page docs/faq-abuse>"> Abuse FAQ for Tor Relay Operators</a>, as well as a <a href="<page eff/tor-legal-faq>">
- Legal FAQ for Tor Relay Operators</a> with advice on how to handle such issues if you are operating a Tor relay.
- </td>
+<td><a href="http://news.cnet.com/8301-13739_3-9779225-46.html">Tor anonymity server admin arrested</a>. A Tor exit node operator from Germany was arrested and then released once the police realized their mistake. Unfortunately, the hassle <a href="http://arstechnica.com/news.ars/post/20070917-tor-node-operator-after-run-i…"> caused this operator to shut down the node</a>. We have an <a href="<page docs/faq-abuse>"> Abuse FAQ for Tor Relay Operators</a>, as well as a <a href="<page eff/tor-legal-faq>"> Legal FAQ for Tor Relay Operators</a> with advice on how to handle such issues if you are operating a Tor relay.</td>
</tr>
-
<tr style="background-color: #e5e5e5;">
<td>2007 Sep 10</td>
<td>Wired</td>
-<td> <a href="http://www.wired.com/politics/security/news/2007/09/embassy_hacks">
-Rogue Nodes Turn Tor Anonymizer Into Eavesdropper's Paradise</a><br/>
-Swedish computer security consultant Dan Egerstad monitored the traffic going through a Tor exit node
-he was running, then published unencrypted account and password information.
-Note that the better articles covering this event correctly indicate that this is not a security
-flaw or design problem with Tor - Tor provides anonymity, but does not
-encrypt anything going to or from an exit node. You <strong>must</strong> use SSL (https) while
-browsing to ensure end-to-end encryption.
-Also covered in
-<a href="http://www.theinquirer.net/en/inquirer/news/2007/09/10/tor-network-exposes-…">
-The Inquirer</a>, <a href="http://www.infoworld.com/article/07/09/10/Security-researcher-intercepts-em…">
-InfoWorld</a>, <a href="http://www.smh.com.au/articles/2007/11/12/1194766589522.html?page=fullpage#…">
-The Sydney Morning Herald</a>,
-<a href="http://www.securityfocus.com/news/11486">
-Security Focus</a>, <a href="http://arstechnica.com/news.ars/post/20070910-security-expert-used-tor-to-c…">
-ars technica</a>, and many others. It was reported as early as August 31, 2007 on the
-<a href="http://blog.wired.com/27bstroke6/2007/08/embassy-e-mail-.html">
-Wired Blog</a>, before Mr. Egerstad revealed that he had obtained the information via his Tor exit node.
-In the end, Mr. Egerstad was arrested, which was covered by
-<a href="http://www.theregister.co.uk/2007/11/15/tor_hacker_arrest/">
-The Register</a>, <a href="http://www.smh.com.au/news/security/police-swoop-on-hacker-of-the-year/2007…">
-The Sydney Morning Herald</a>, <a href="http://blogs.zdnet.com/Berlind/?p=900">
-ZDNet</a>, and <a href="http://blog.wired.com/27bstroke6/2007/11/swedish-researc.html"> Wired Blog</a>.
-</td>
+<td> <a href="http://www.wired.com/politics/security/news/2007/09/embassy_hacks"> Rogue Nodes Turn Tor Anonymizer Into Eavesdropper's Paradise</a><br/> Swedish computer security consultant Dan Egerstad monitored the traffic going through a Tor exit node he was running, then published unencrypted account and password information. Note that the better articles covering this event correctly indicate that this is not a security flaw or design problem with Tor - Tor provides anonymity, but does not encrypt anything going to or from an exit node. You <strong>must</strong> use SSL (https) while browsing to ensure end-to-end encryption. Also covered in <a href="http://www.theinquirer.net/en/inquirer/news/2007/09/10/tor-network-exposes-…"> The Inquirer</a>, <a href="http://www.infoworld.com/article/07/09/10/Security-researcher-intercepts-em…"> InfoWorld</a>, <a href="http://www.smh.com.au/articles/2007/11/12/1194766589
522.html?page=fullpage#contentSwap2">The Sydney Morning Herald</a>, <a href="http://www.securityfocus.com/news/11486">Security Focus</a>, <a href="http://arstechnica.com/news.ars/post/20070910-security-expert-used-tor-to-c…"> ars technica</a>, and many others. It was reported as early as August 31, 2007 on the <a href="http://blog.wired.com/27bstroke6/2007/08/embassy-e-mail-.html"> Wired Blog</a>, before Mr. Egerstad revealed that he had obtained the information via his Tor exit node. In the end, Mr. Egerstad was arrested, which was covered by <a href="http://www.theregister.co.uk/2007/11/15/tor_hacker_arrest/"> The Register</a>, <a href="http://www.smh.com.au/news/security/police-swoop-on-hacker-of-the-year/2007…"> The Sydney Morning Herald</a>, <a href="http://blogs.zdnet.com/Berlind/?p=900"> ZDNet</a>, and <a href="http://blog.wired.com/27bstroke6/2007/11/swedish-researc.html"> Wired
Blog</a>.</td>
</tr>
-
<tr>
<td>2007 Jul 27</td>
<td>Wired Blog</td>
-<td><a href="http://blog.wired.com/27bstroke6/2007/07/cyber-jihadists.html"> Cyber Jihadists Embrace Tor</a><br/>
-A pointer to a <a href="http://ddanchev.blogspot.com/2007/07/cyber-jihadists-and-tor.html">
-blog</a> that posted screenshots of Arabic instructions on using Tor, ostensibly for jihadists. Make sure to read Shava Nerad's reply
-at the bottom of the article.
-</td>
+<td><a href="http://blog.wired.com/27bstroke6/2007/07/cyber-jihadists.html"> Cyber Jihadists Embrace Tor</a><br/> A pointer to a <a href="http://ddanchev.blogspot.com/2007/07/cyber-jihadists-and-tor.html"> blog</a> that posted screenshots of Arabic instructions on using Tor, ostensibly for jihadists. Make sure to read Shava Nerad's reply at the bottom of the article.</td>
</tr>
-
<tr style="background-color: #e5e5e5;">
<td>2007 Jun 22</td>
<td>Bangkok Post</td>
-<td> <a href="http://www.asiamedia.ucla.edu/article-southeastasia.asp?parentid=72388">
-The problems with censorship</a>. Mentions anecdotes that "everyone" has Tor installed in Thailand to avoid censorship.
-</td>
+<td> <a href="http://www.asiamedia.ucla.edu/article-southeastasia.asp?parentid=72388"> The problems with censorship</a>. Mentions anecdotes that "everyone" has Tor installed in Thailand to avoid censorship.</td>
</tr>
-
<tr>
<td>2007 Mar 15</td>
<td>World Changing</td>
-<td><a href="http://www.worldchanging.com/archives/006309.html">
-Blogging Where Speech Isn’t Free</a><br/>
-Coverage of former Tor Executive Director Shava Nerad's participation at an
-<a href="http://2007.sxsw.com/interactive/programming/panels/?action=show&id=IAP…">
-SXSW panel</a>, where she explained how Tor can help bloggers.
-</td>
+<td><a href="http://www.worldchanging.com/archives/006309.html"> Blogging Where Speech Isn’t Free</a><br/> Coverage of former Tor Executive Director Shava Nerad's participation at an <a href="http://2007.sxsw.com/interactive/programming/panels/?action=show&id=IAP…"> SXSW panel</a>, where she explained how Tor can help bloggers.</td>
</tr>
-
<tr style="background-color: #e5e5e5;">
<td>2007 Mar 8</td>
<td>Security Focus</td>
-<td><a href="http://www.securityfocus.com/news/11447/1">
-Tor hack proposed to catch criminals</a>.
-Coverage of a toolset called "Torment" for monitoring exit nodes, and responses from the
-Tor Project illustrating why this approach may not be a good idea.
-</td>
+<td><a href="http://www.securityfocus.com/news/11447/1"> Tor hack proposed to catch criminals</a>. Coverage of a toolset called "Torment" for monitoring exit nodes, and responses from the Tor Project illustrating why this approach may not be a good idea.</td>
</tr>
-
<tr>
<td>2007 Feb 1</td>
<td>Dr Dobb's</td>
-<td><a href="http://www.ddj.com/security/197002414">
-Tor Project Protects Anonymous Sources</a>.
-An introduction to Tor, including technical and historical background.
-</td>
+<td><a href="http://www.ddj.com/security/197002414"> Tor Project Protects Anonymous Sources</a>. An introduction to Tor, including technical and historical background. </td>
</tr>
-
<tr style="background-color: #e5e5e5;">
<td>2006 Oct 19</td>
<td>Wired Threat Level</td>
-<td><a href="http://blog.wired.com/27bstroke6/2006/10/the_onion_route.html">
-The Onion Router (TOR) is Leaky (Leeky)</a>.
-Explains why you need something like Privoxy
-in addition to the core Tor code to ensure your anonymity. If you use the
-Vidalia bundle, it installs and configures Privoxy automatically, but it can't
-hurt to understand why it is necessary.
-</td>
+<td><a href="http://blog.wired.com/27bstroke6/2006/10/the_onion_route.html"> The Onion Router (TOR) is Leaky (Leeky)</a>. Explains why you need something like Privoxy in addition to the core Tor code to ensure your anonymity. If you use the Vidalia bundle, it installs and configures Privoxy automatically, but it can't hurt to understand why it is necessary.</td>
</tr>
-
<tr>
<td>2006 Aug 18</td>
<td>NPR</td>
-<td><a href="http://www.npr.org/templates/story/story.php?storyId=5168456">
-Tips for Protecting Privacy Online</a>.
-Kevin Bankston of the EFF recommends Tor during an NPR interview.
-Tor information begins at 8:15 into the program.
-</td>
+<td><a href="http://www.npr.org/templates/story/story.php?storyId=5168456"> Tips for Protecting Privacy Online</a>. Kevin Bankston of the EFF recommends Tor during an NPR interview. Tor information begins at 8:15 into the program.</td>
</tr>
-
<tr style="background-color: #e5e5e5;">
<td>2006 Jul 5</td>
<td>MSNBC</td>
-<td><a href="http://www.msnbc.msn.com/id/13718446/page/2/">
-Defending liberties in high-tech world</a>.
-Mentions EFF funding for Tor as one of its significant nonlitigation projects.
-</td>
+<td><a href="http://www.msnbc.msn.com/id/13718446/page/2/"> Defending liberties in high-tech world</a>. Mentions EFF funding for Tor as one of its significant nonlitigation projects.</td>
</tr>
-
+<td>2006 Apr 11</td>
+<td>PBS Frontline</td>
+<td><a href="http://pbs.gen.in/wgbh/pages/frontline/tankman/internet/tech.html">Chipping Away at China's Great Firewall</a></td>
+</tr>
+<tr style="background-color: #e5e5e5;">
+<td>2006 Feb 28</td>
+<td>PC World</td>
+<td><a href="http://www.pcworld.com/article/id,124891-page,1/article.html">Outsmarting the Online Privacy Snoops</a></td>
+</tr>
<tr>
- <td>
- 2006 Feb 15
- </td>
- <td>
- Network Secure</td>
- <td><a href="http://www.network-secure.de/index.php?option=com_content&task=view&…">
- Tor: Anonymisierungswerkzeug entwickelt</a> (German)<br/>
- </td>
+<td>2006 Feb 27</td>
+<td>Forbes</td>
+<td><a href="http://members.forbes.com/global/2006/0227/018A_2.html"> Cracks In the Wall</a>. Discussion of Tor being used for evading censorship by repressive governments.</td>
</tr>
-
<tr style="background-color: #e5e5e5;">
- <td>
- 2006 Feb 13
- </td>
- <td>
- Wall Street Journal</td>
-<td> <a href="http://online.wsj.com/article/SB113979965346572150.html">
- Chinese Censors Of Internet Face 'Hacktivists' in U.S.</a><br/>
- Full article text can also be found
- <a href="http://yaleglobal.yale.edu/display.article?id=6981">here</a>.
- </td>
+<td>2006 Feb 20</td>
+<td>The Boston Globe</td>
+<td><a href="http://members.forbes.com/global/2006/0227/018A_2.html"> Beating censorship on the Internet</a></td>
</tr>
-
<tr>
- <td>
- 2006 Jan 31
- </td>
- <td>
- Technology Review</td>
-<td> <a href="http://www.technologyreview.com/Infotech/16216/page2/">
- Evading the Google Eye</a><br/>
- </td>
+<td>2006 Feb 15</td>
+<td>CBS Evening News</td>
+<td><a href="http://www.cbsnews.com/stories/2006/02/15/eveningnews/main1321785.shtml?sou…"> Cracking The 'Great Firewall Of China'</a>. Roger Dingledine appeared on the show to discuss Tor, starting at 1:04 into the video.</td>
</tr>
-
<tr style="background-color: #e5e5e5;">
- <td>
- 2006 Jan 29
- </td>
- <td>
- New York Times</td>
-<td> <a href="http://www.nytimes.com/2006/01/29/weekinreview/29basic.html">
- How to Outwit the World's Internet Censors</a><br/>
- </td>
+<td>2006 Feb 15</td>
+<td>CNBC - Closing Bell</td>
+<td>TV Appearance by Roger Dingledine at 4:25pm. (no link)</td>
</tr>
-
<tr>
- <td>
- 2006 Jan 23
- </td>
- <td>
- NPR Talk of the Nation</td>
-<td> <a href="http://www.npr.org/templates/story/story.php?storyId=5168456">
- Search Engines and Privacy Rights on the Web</a><br/>
- <a href="http://xeni.net/">Xeni Jardin</a>
- recommends Tor at 33:30 into the program.
- </td>
+<td>2006 Feb 15</td>
+<td>Network Secure</td>
+<td><a href="http://www.network-secure.de/index.php?option=com_content&task=view&…">Tor: Anonymisierungswerkzeug entwickelt</a> (German)</td>
</tr>
+<tr style="background-color: #e5e5e5;">
+<td>2006 Feb 13</td>
+<td>Wall Street Journal</td>
+<td><a href="http://online.wsj.com/article/SB113979965346572150.html"> Chinese Censors Of Internet Face 'Hacktivists' in U.S.</a>Full article text can also be found
+<a href="http://yaleglobal.yale.edu/display.article?id=6981">here</a>.</td>
+</tr>
+<tr>
+<td>2006 Jan 31</td>
+<td>Technology Review</td>
+<td><a href="http://www.technologyreview.com/Infotech/16216/page2/">Evading the Google Eye</a></td>
+</tr>
+<tr style="background-color: #e5e5e5;">
+<td>2006 Jan 29</td>
+<td>New York Times</td>
+<td><a href="http://www.nytimes.com/2006/01/29/weekinreview/29basic.html"> How to Outwit the World's Internet Censors</a></td>
+</tr>
+<tr>
+<td>2006 Jan 27</td>
+<td>Fox News/eWeek</td>
+<td><a href="http://www.foxnews.com/story/0,2933,183005,00.html"> Web Anonymizers Suddenly Get Very Popular</a></td>
+</tr>
+<tr>
+<td>2006 Jan 25</td>
+<td>New York Times</td>
+<td><a href="http://www.nytimes.com/2006/01/25/technology/techspecial2/25privacy.html?_r…"> Privacy for People Who Don't Show Their Navels</a></td>
+</tr>
+<tr>
+<td>2006 Jan 23</td>
+<td>NPR Talk of the Nation</td>
+<td><a href="http://www.npr.org/templates/story/story.php?storyId=5168456"> Search Engines and Privacy Rights on the Web</a><br/> <a href="http://xeni.net/">Xeni Jardin</a> recommends Tor at 33:30 into the program.</td>
+</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2006 Feb 15
- </td>
- <td>
- Punto Informatico</td>
-<td> <a href="http://punto-informatico.it/p.aspx?i=1430903">
- TOR c'è</a> (Italian)<br/>
- </td>
+<td>2006 Feb 15</td>
+<td>Punto Informatico</td>
+<td><a href="http://punto-informatico.it/p.aspx?i=1430903"> TOR c'è</a> (Italian)</td>
</tr>
<tr>
- <td>
- 2006 Jan 20
- </td>
- <td>
- Wired</td>
-<td> <a href="http://www.wired.com/science/discoveries/news/2006/01/70051?currentPage=2">
- How to Foil Search Engine Snoops</a><br/>
- </td>
+<td>2006 Jan 20</td>
+<td>Wired</td>
+<td><a href="http://www.wired.com/science/discoveries/news/2006/01/70051?currentPage=2"> How to Foil Search Engine Snoops</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2006 Jan 20
- </td>
- <td>
- NPR</td>
-<td><a href="http://www.npr.org/templates/story/story.php?storyId=5165854">
- Google Records Subpoena Raises Privacy Fears</a><br/>
- </td>
+<td>2006 Jan 20</td>
+<td>NPR</td>
+<td><a href="http://www.npr.org/templates/story/story.php?storyId=5165854"> Google Records Subpoena Raises Privacy Fears</a></td>
</tr>
<tr>
- <td>
- 2005 Sep 30
- </td>
- <td>
- Viva o Linux</td>
- <td> <a href="http://www.vivaolinux.com.br/artigos/verArtigo.php?codigo=2759">
- TOR: A Internet sem rastreabilidade</a> (Portuguese)<br/>
- </td>
+<td>2005 Sep 30</td>
+<td>Viva o Linux</td>
+<td><a href="http://www.vivaolinux.com.br/artigos/verArtigo.php?codigo=2759"> TOR: A Internet sem rastreabilidade</a> (Portuguese)</td>
</tr>
-
<tr style="background-color: #e5e5e5;">
- <td>
- 2005 Jul 12
- </td>
- <td>
- IEEE Computer Society's Technical Committee on Security and Privacy</td>
-<td> <a href="http://www.ieee-security.org/Cipher/Newsbriefs/2005/071805.html#TOR">
- Onion routing application Tor makes PCWorld's top 100</a><br/>
- </td>
+<td>2005 Aug 6</td>
+<td>New Scientist</td>
+<td><a href="http://www.eurekalert.org/pub_releases/2005-08/ns-wwa080305.php">Why we all need pornography</a></td>
</tr>
+<tr style="background-color: #e5e5e5;">
+<td>2005 Jul 12</td>
+<td>IEEE Computer Society's Technical Committee on Security and Privacy</td>
+<td><a href="http://www.ieee-security.org/Cipher/Newsbriefs/2005/071805.html#TOR"> Onion routing application Tor makes PCWorld's top 100</a></td>
+</tr>
<tr>
- <td>
- 2005 Jun 22
- </td>
- <td>
- The Unofficial Apple Blog</td>
-<td> <a href="http://www.tuaw.com/2005/06/22/privacy-watch-tor/">
- Privacy Watch: Tor</a><br/>
- </td>
+<td>2005 Jun 22</td>
+<td>The Unofficial Apple Blog</td>
+<td><a href="http://www.tuaw.com/2005/06/22/privacy-watch-tor/"> Privacy Watch: Tor</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2005 Jun 10
- </td>
- <td>
- The New Zealand Herald</td>
-<td> <a href="http://www.nzherald.co.nz/section/story.cfm?c_id=5&objectid=10329896">
- China's internet censorship stranglehold can't last</a><br/>
- </td>
+<td>2005 Jun 10</td>
+<td>The New Zealand Herald</td>
+<td><a href="http://www.nzherald.co.nz/section/story.cfm?c_id=5&objectid=10329896"> China's internet censorship stranglehold can't last</a></td>
</tr>
<tr>
- <td>
- 2005 Jun 8
- </td>
- <td>
- American Public Radio</td>
-<td> <a href="http://www.publicradio.org/columns/futuretense/2005/06/08.shtml">
- An Internet privacy tool called "Tor"</a><br/>
- </td>
+<td>2005 Jun 8</td>
+<td>American Public Radio</td>
+<td><a href="http://www.publicradio.org/columns/futuretense/2005/06/08.shtml"> An Internet privacy tool called "Tor"</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2005 Jun 1
- </td>
- <td>
- PC World</td>
-<td> <a href="http://www.pcworld.com/article/id,120763-page,4/article.html">
- The 100 Best Products of 2005</a><br/>
- Tor is ranked #40 on the list.
- </td>
+<td>2005 Jun 1</td>
+<td>PC World</td>
+<td><a href="http://www.pcworld.com/article/id,120763-page,4/article.html"> The 100 Best Products of 2005</a><br/> Tor is ranked #40 on the list. </td>
</tr>
<tr>
- <td>
- 2005 Jun 1
- </td>
- <td>
- Linux Weekly News</td>
-<td> <a href="http://lwn.net/Articles/138242/">
- A Look at The Onion Router (Tor)</a><br/>
- </td>
+<td>2005 Jun 1</td>
+<td>Linux Weekly News</td>
+<td><a href="http://lwn.net/Articles/138242/"> A Look at The Onion Router (Tor)</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2005 May 22
- </td>
- <td>
- Slashdot</td>
-<td> <a href="http://yro.slashdot.org/article.pl?sid=05/05/22/0113244">
- Tor Anonymity Network Reaches 100 Verified Nodes</a><br/>
- </td>
+<td>2005 May 22</td>
+<td>Slashdot</td>
+<td><a href="http://yro.slashdot.org/article.pl?sid=05/05/22/0113244"> Tor Anonymity Network Reaches 100 Verified Nodes</a></td>
</tr>
<tr>
- <td>
- 2005 May 20
- </td>
- <td>
- Security.uz</td>
-<td> <a href="http://security.uz/news/default.asp?id=10541">
- Tor - мощный анонимайзер для всех ОС</a> (Russian)<br/>
- </td>
+<td>2005 May 20</td>
+<td>Security.uz</td>
+<td><a href="http://security.uz/news/default.asp?id=10541"> Tor - мощный анонимайзер для всех ОС</a> (Russian)</td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2005 May 19
- </td>
- <td>
- WebPlanet</td>
-<td> <a href="http://webplanet.ru/news/security/2005/5/19/tor.html">
- Tor: распределенная система анонимного серфинга</a> (Russian)<br/>
- </td>
+<td>2005 May 19</td>
+<td>WebPlanet</td>
+<td><a href="http://webplanet.ru/news/security/2005/5/19/tor.html"> Tor: распределенная система анонимного серфинга</a> (Russian)</td>
</tr>
<tr>
- <td>
- 2005 May 17
- </td>
- <td>
- Wired</td>
-<td> <a href="http://www.wired.com/politics/security/news/2005/05/67542?currentPage=all">
- Tor Torches Online Tracking</a><br/>
- Also available in
- <a href="http://wiredvision.jp/archives/200505/2005051904.html">Japanese</a>.
- </td>
+<td>2005 May 17</td>
+<td>Wired</td>
+<td><a
+href="http://www.wired.com/politics/security/news/2005/05/67542?currentPage=all"> Tor Torches Online Tracking</a>. Also available in <a href="http://wiredvision.jp/archives/200505/2005051904.html">Japanese</a>.</td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2005 May 17
- </td>
- <td>
- XBiz</td>
-<td> <a href="http://xbiz.com/news/8761">
- Navy Project Allows Anonymous Browsing</a><br/>
- </td>
+<td>2005 May 17</td>
+<td>XBiz</td>
+<td><a href="http://xbiz.com/news/8761"> Navy Project Allows Anonymous Browsing</a></td>
</tr>
<tr>
- <td>
- 2005 Apr 13
- </td>
- <td>
- Heise online</td>
-<td> <a href="http://www.heise.de/newsticker/meldung/58506">
- CFP: Vom kafkaesken Schwinden der Anonymität</a> (German)<br/>
- </td>
+<td>2005 Apr 13</td>
+<td>Heise online</td>
+<td><a href="http://www.heise.de/newsticker/meldung/58506"> CFP: Vom kafkaesken Schwinden der Anonymität</a> (German)</td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2005 Apr 5
- </td>
- <td>
- Libero</td>
-<td> <a href="http://magazine.libero.it/internetlife/scienzaeweb/ne208.phtml">
- Anonimato on line, ecco Tor</a> (Italian)<br/>
- </td>
+<td>2005 Apr 5</td>
+<td>Libero</td>
+<td><a href="http://magazine.libero.it/internetlife/scienzaeweb/ne208.phtml"> Anonimato on line, ecco Tor</a> (Italian)</td>
</tr>
<tr>
- <td>
- 2005 Jan 4
- </td>
- <td>
- Internetnews</td>
-<td> <a href="http://www.internetnews.com/dev-news/article.php/3454521">
- EFF Throws Support to 'Anonymous' Internet Project</a><br/>
- </td>
+<td>2005 Jan 4</td>
+<td>Internetnews</td>
+<td><a href="http://www.internetnews.com/dev-news/article.php/3454521"> EFF Throws Support to 'Anonymous' Internet Project</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2005 Mar 31
- </td>
- <td>
- Linux.com</td>
-<td> <a href="http://www.linux.com/articles/43713?tid=19&tid=78">
- Securing your online privacy with Tor</a><br/>
- </td>
+<td>2005 Mar 31</td>
+<td>Linux.com</td>
+<td><a href="http://www.linux.com/articles/43713?tid=19&tid=78"> Securing your online privacy with Tor</a></td>
</tr>
<tr>
- <td>
- 2004 Dec 27
- </td>
- <td>
- BoingBoing</td>
-<td> <a href="http://www.boingboing.net/2004/12/27/eff-helping-produce-.html">
- EFF helping produce anonymizing software</a><br/>
- </td>
+<td>2004 Dec 27</td>
+<td>BoingBoing</td>
+<td><a href="http://www.boingboing.net/2004/12/27/eff-helping-produce-.html"> EFF helping produce anonymizing software</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2004 Dec 25
- </td>
- <td>
- Kansas City infozine</td>
-<td> <a href="http://www.infozine.com/news/stories/op/storiesView/sid/4933/">
- EFF Joins Forces with Tor Software Project</a><br/>
- </td>
+<td>2004 Dec 25</td>
+<td>Kansas City infozine</td>
+<td><a href="http://www.infozine.com/news/stories/op/storiesView/sid/4933/"> EFF Joins Forces with Tor Software Project</a></td>
</tr>
<tr>
- <td>
- 2004 Dec 23
- </td>
- <td>
- golem.de</td>
-<td> <a href="http://www.golem.de/0412/35340.html">
- EFF unterstützt Anonymisierer Tor</a> (German)<br/>
- </td>
+<td>2004 Dec 23</td>
+<td>golem.de</td>
+<td><a href="http://www.golem.de/0412/35340.html"> EFF unterstützt Anonymisierer Tor</a> (German)</td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2004 Dec 23
- </td>
- <td>
- SuicideGirls</td>
-<td> <a href="http://suicidegirls.com/news/technology/6150/">
- New Routing Software Allows Anonymous Internet Use</a><br/>
- </td>
+<td>2004 Dec 23</td>
+<td>SuicideGirls</td>
+<td><a href="http://suicidegirls.com/news/technology/6150/"> New Routing Software Allows Anonymous Internet Use</a></td>
</tr>
<tr>
- <td>
- 2004 Dec 18
- </td>
- <td>
- P2Pnet</td>
-<td> <a href="http://p2pnet.net/story/3357">
- EFF to sponsor Tor</a><br/>
- </td>
+<td>2004 Dec 18</td>
+<td>P2Pnet</td>
+<td><a href="http://p2pnet.net/story/3357"> EFF to sponsor Tor</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2004 Dec 22
- </td>
- <td>
- Slashdot</td>
-<td> <a href="http://yro.slashdot.org/article.pl?sid=04/12/22/2031229&tid=95&tid=…">
- EFF Promotes Freenet-like System Tor</a><br/>
- </td>
+<td>2004 Dec 22</td>
+<td>Slashdot</td>
+<td><a href="http://yro.slashdot.org/article.pl?sid=04/12/22/2031229&tid=95&tid=…"> EFF Promotes Freenet-like System Tor</a></td>
</tr>
<tr>
- <td>
- 2004 Nov 16
- </td>
- <td>
- AlterNet</td>
-<td> <a href="http://www.alternet.org/columnists/story/20523/">
- Heavy Traffic</a><br/>
- </td>
+<td>2004 Nov 16</td>
+<td>AlterNet</td>
+<td><a href="http://www.alternet.org/columnists/story/20523/"> Heavy Traffic</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2004 Aug 30
- </td>
- <td>
- Newsweek</td>
-<td> Technology: Instant Security (no link)<br/>
- </td>
+<td>2004 Aug 30</td>
+<td>Newsweek</td>
+<td>Technology: Instant Security (no link)</td>
</tr>
<tr>
- <td>
- 2004 Aug 16
- </td>
- <td>
- Eweek</td>
-<td> <a href="http://www.eweek.com/c/a/Security/Dont-Fear-Internet-Anonymity-Tools/">
- Don't Fear Internet Anonymity Tools</a><br/>
- </td>
+<td>2004 Aug 16</td>
+<td>Eweek</td>
+<td><a href="http://www.eweek.com/c/a/Security/Dont-Fear-Internet-Anonymity-Tools/"> Don't Fear Internet Anonymity Tools</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2004 Aug 6
- </td>
- <td>
- HCC magazine</td>
-<td> <a href="http://www.hcc.nl/eCache/DEF/21/083.html">
- Anoniem surfen met hulp van marine VS</a> (Dutch)<br/>
- </td>
+<td>2004 Aug 6</td>
+<td>HCC magazine</td>
+<td><a href="http://www.hcc.nl/eCache/DEF/21/083.html"> Anoniem surfen met hulp van marine VS</a> (Dutch)</td>
</tr>
<tr>
- <td>
- 2004 Aug 6
- </td>
- <td>
- Golem</td>
-<td> <a href="http://www.golem.de/0408/32835.html">
- Tor: Anonymisierer nutzt Onion-Routing</a><br/>
- </td>
+<td>2004 Aug 6</td>
+<td>Golem</td>
+<td><a href="http://www.golem.de/0408/32835.html"> Tor: Anonymisierer nutzt Onion-Routing</a></td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2004 Aug 5
- </td>
- <td>
- Network World Security</td>
-<td> <a href="http://www.networkworld.com/details/7088.html">
- Onion routing</a><br/>
- </td>
+<td>2004 Aug 5</td>
+<td>Network World Security</td>
+<td><a href="http://www.networkworld.com/details/7088.html"> Onion routing</a></td>
</tr>
<tr>
- <td>
- 2004 May 8
- </td>
- <td>
- Wired</td>
-<td> <a href="http://www.wired.com/politics/security/news/2004/08/64464">
- Onion Routing Averts Prying Eyes</a><br/>
- Also in <a href="http://hotwired.goo.ne.jp/news/news/technology/story/20040806301.html">Japanese</a>.
- </td>
+<td>2004 May 8</td>
+<td>Wired</td>
+<td><a href="http://www.wired.com/politics/security/news/2004/08/64464"> Onion Routing Averts Prying Eyes</a>. Also in <a href="http://hotwired.goo.ne.jp/news/news/technology/story/20040806301.html">Japanese</a>.</td>
</tr>
<tr style="background-color: #e5e5e5;">
- <td>
- 2004 Mar 8
- </td>
- <td>
- CNET Japan blog</td>
-<td> <a href="http://japan.cnet.com/blog/umeda/2004/03/08/entry_post_126/">
- Yearning of hackers and insecurity</a> (Japanese)<br/>
- </td>
+<td>2004 Mar 8</td>
+<td>CNET Japan blog</td>
+<td><a href="http://japan.cnet.com/blog/umeda/2004/03/08/entry_post_126/"> Yearning of hackers and insecurity</a> (Japanese)</td>
</tr>
<tr>
- <td>
- 1999 Apr 13
- </td>
- <td>
- Wired</td>
-<td> <a href="http://www.wired.com/science/discoveries/news/1999/04/19091">
- Anonymous Web Surfing? Uh-Uh</a><br/>
- </td>
+<td>1999 Apr 13</td>
+<td>Wired</td>
+<td><a href="http://www.wired.com/science/discoveries/news/1999/04/19091"> Anonymous Web Surfing? Uh-Uh</a></td>
</tr>
</table>
@@ -1117,4 +892,4 @@
<!-- END SIDECOL -->
</div>
<!-- END CONTENT -->
-#include <foot.wmi>
+#include <foot.wmi>
1
0

r24347: {website} More changes requested by intrigeri (replacing amnesia.boum. (in website/trunk: docs/en getinvolved/en projects/en torbutton/en)
by Damian Johnson 12 Mar '11
by Damian Johnson 12 Mar '11
12 Mar '11
Author: atagar
Date: 2011-03-12 22:04:22 +0000 (Sat, 12 Mar 2011)
New Revision: 24347
Modified:
website/trunk/docs/en/faq.wml
website/trunk/docs/en/trademark-faq.wml
website/trunk/getinvolved/en/volunteer.wml
website/trunk/projects/en/projects.wml
website/trunk/torbutton/en/torbutton-faq.wml
Log:
More changes requested by intrigeri (replacing amnesia.boum.org with tails.boum.org and stripping the parenthesis from "Amnesic")
Modified: website/trunk/docs/en/faq.wml
===================================================================
--- website/trunk/docs/en/faq.wml 2011-03-12 21:50:36 UTC (rev 24346)
+++ website/trunk/docs/en/faq.wml 2011-03-12 22:04:22 UTC (rev 24347)
@@ -690,7 +690,7 @@
<h3><a class="anchor" href="#LiveCD">Is there a LiveCD or other bundle that includes Tor?</a></h3>
<p>
- Yes. Use <a href="https://amnesia.boum.org/">The (Amnesic) Incognito
+ Yes. Use <a href="https://tails.boum.org/">The Amnesic Incognito
Live System</a> or <a href="<page projects/torbrowser>">the Tor Browser
Bundle</a>.
</p>
Modified: website/trunk/docs/en/trademark-faq.wml
===================================================================
--- website/trunk/docs/en/trademark-faq.wml 2011-03-12 21:50:36 UTC (rev 24346)
+++ website/trunk/docs/en/trademark-faq.wml 2011-03-12 22:04:22 UTC (rev 24347)
@@ -74,7 +74,7 @@
<p>Yes. A few open source, non-commercial projects are Tor trademark
licensees:</p>
<ul>
- <li><a href="https://amnesia.boum.org/">The (Amnesic) Incognito Live
+ <li><a href="https://tails.boum.org/">The Amnesic Incognito Live
System</a></li>
<li>Portable Tor</li>
<li><a href="http://torstatus.kgprog.com/">Kprog Tor Status</a></li>
Modified: website/trunk/getinvolved/en/volunteer.wml
===================================================================
--- website/trunk/getinvolved/en/volunteer.wml 2011-03-12 21:50:36 UTC (rev 24346)
+++ website/trunk/getinvolved/en/volunteer.wml 2011-03-12 22:04:22 UTC (rev 24347)
@@ -116,7 +116,7 @@
<td>Usability</td>
<td>Sys Admin</td>
<td>Heavy</td>
- <td><a href="https://amnesia.boum.org/chat/">#tails</a></td>
+ <td><a href="https://tails.boum.org/chat/">#tails</a></td>
</tr>
<tr>
@@ -304,13 +304,13 @@
</p>
<a id="project-tails"></a>
- <h3><a href="https://amnesia.boum.org/">The (Amnesic) Incognito Live System</a> (<a
+ <h3><a href="https://tails.boum.org/">The Amnesic Incognito Live System</a> (<a
href="http://git.immerda.ch/?p=amnesia.git;a=summary">code</a>, <a
- href="https://amnesia.boum.org/bugs/">bug
+ href="https://tails.boum.org/bugs/">bug
tracker</a>)</h3>
<p>
- The (Amnesic) Incognito Live System is a live CD/USB distribution
+ The Amnesic Incognito Live System is a live CD/USB distribution
preconfigured so that everything is safely routed through Tor and leaves no
trace on the local system. This is a merger of the Amnesia and <a
href="http://www.anonymityanywhere.com/incognito/">Incognito</a> projects,
@@ -671,7 +671,7 @@
indeed involve getting familiar with some modern GNU/Linux Desktop
technologies such as D-Bus, GNOME and GConf. Python/GTK+ is probably the
best suited language for the task.</p>
- <p>For more information see <a href="https://amnesia.boum.org/todo/boot_menu/">https://amnesia.boum.org/todo/boot_menu/</a></p>
+ <p>For more information see <a href="https://tails.boum.org/todo/boot_menu/">https://tails.boum.org/todo/boot_menu/</a></p>
</li>
<!--
@@ -1088,7 +1088,7 @@
<p>Anyone undertaking this project must be familiar with GNU/Linux, and
preferably with Debian. Being able to (quickly learn to) write clean and
safe programs in shell is also needed.</p>
- <p>For more information, see <a href="https://amnesia.boum.org/todo/persistence/">https://amnesia.boum.org/todo/persistence/</a>.</p>
+ <p>For more information, see <a href="https://tails.boum.org/todo/persistence/">https://tails.boum.org/todo/persistence/</a>.</p>
<a id="torsocksForOSX"></a>
<li>
@@ -1406,7 +1406,7 @@
<li>How can we make the various LiveCD/USB systems easier
to maintain, improve, and document? One example is <a
- href="https://amnesia.boum.org/">The (Amnesic) Incognito Live
+ href="https://tails.boum.org/">The Amnesic Incognito Live
System</a>.
</li>
Modified: website/trunk/projects/en/projects.wml
===================================================================
--- website/trunk/projects/en/projects.wml 2011-03-12 21:50:36 UTC (rev 24346)
+++ website/trunk/projects/en/projects.wml 2011-03-12 22:04:22 UTC (rev 24347)
@@ -52,8 +52,8 @@
Orbot/Tor.</p>
</td>
<td>
-<div class="name"><a href="https://amnesia.boum.org/">Tails</a></div>
-<p>The (Amnesic) Incognito Live System is a live CD/USB distribution
+<div class="name"><a href="https://tails.boum.org/">Tails</a></div>
+<p>The Amnesic Incognito Live System is a live CD/USB distribution
preconfigured so that everything is safely routed through Tor and leaves no
trace on the local system.</p>
</td>
Modified: website/trunk/torbutton/en/torbutton-faq.wml
===================================================================
--- website/trunk/torbutton/en/torbutton-faq.wml 2011-03-12 21:50:36 UTC (rev 24346)
+++ website/trunk/torbutton/en/torbutton-faq.wml 2011-03-12 22:04:22 UTC (rev 24347)
@@ -80,7 +80,7 @@
IP address</a>, and <a
href="http://epic.org/privacy/cookies/flash.html">storing their own
cookies</a>. It is possible to use a LiveCD solution such as
- or <a href="https://amnesia.boum.org/">The (Amnesic) Incognito Live System</a> that creates a
+ or <a href="https://tails.boum.org/">The Amnesic Incognito Live System</a> that creates a
secure, transparent proxy to protect you from proxy bypass, however issues
with local IP address discovery and Flash cookies still remain. </p>
@@ -90,7 +90,7 @@
local censors potentially noticing you visit them, you can enable plugins by
going into the Torbutton Preferences->Security Settings->Dynamic Content
tab and unchecking "Disable plugins during Tor usage" box. If you do this
- without The (Amnesic) Incognito Live System or appropriate firewall
+ without The Amnesic Incognito Live System or appropriate firewall
rules, we strongly suggest you at least use <a
href="https://addons.mozilla.org/en-US/firefox/addon/722">NoScript</a> to <a
href="http://noscript.net/features#contentblocking">block plugins</a>. You do
1
0

[torbutton/master] Bug 1624: Use nsIDOMCrypto::logout() if available.
by mikeperry@torproject.org 12 Mar '11
by mikeperry@torproject.org 12 Mar '11
12 Mar '11
commit c3e547482161b45bfdab76be7471acbc54510ad7
Author: Mike Perry <mikeperry-git(a)fscked.org>
Date: Sat Mar 12 13:52:42 2011 -0800
Bug 1624: Use nsIDOMCrypto::logout() if available.
This is the new official way of clearing SSL Session IDs and other TLS state.
---
src/chrome/content/torbutton.js | 23 ++++++++++++++++-------
1 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/src/chrome/content/torbutton.js b/src/chrome/content/torbutton.js
index 3fe8145..5170be1 100644
--- a/src/chrome/content/torbutton.js
+++ b/src/chrome/content/torbutton.js
@@ -1562,13 +1562,22 @@ function torbutton_update_status(mode, force_update) {
auth.clearAll();
}
- // This clears the SSL Identifier Cache.
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=448747 and
- // http://mxr.mozilla.org/security/source/security/manager/ssl/src/nsNSSCompon…
- m_tb_prefs.setBoolPref("security.enable_ssl2",
- !m_tb_prefs.getBoolPref("security.enable_ssl2"));
- m_tb_prefs.setBoolPref("security.enable_ssl2",
- !m_tb_prefs.getBoolPref("security.enable_ssl2"));
+ try {
+ var secMgr = Cc["@mozilla.org/security/crypto;1"].
+ getService(Ci.nsIDOMCrypto);
+ secMgr.logout();
+ torbutton_log(3, "nsIDOMCrypto logout succeeded");
+ } catch(e) {
+ torbutton_log(4, "Failed to use nsIDOMCrypto to clear SSL Session ids. Falling back to old method. Error: "+e);
+
+ // This clears the SSL Identifier Cache.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=448747 and
+ // http://mxr.mozilla.org/security/source/security/manager/ssl/src/nsNSSCompon…
+ m_tb_prefs.setBoolPref("security.enable_ssl2",
+ !m_tb_prefs.getBoolPref("security.enable_ssl2"));
+ m_tb_prefs.setBoolPref("security.enable_ssl2",
+ !m_tb_prefs.getBoolPref("security.enable_ssl2"));
+ }
// This clears the undo tab history.
var tabs = m_tb_prefs.getIntPref("browser.sessionstore.max_tabs_undo");
1
0

r24346: {website} Replacing TAILS with Tails as per intrigeri's request. (in website/trunk: getinvolved/en projects/en)
by Damian Johnson 12 Mar '11
by Damian Johnson 12 Mar '11
12 Mar '11
Author: atagar
Date: 2011-03-12 21:50:36 +0000 (Sat, 12 Mar 2011)
New Revision: 24346
Modified:
website/trunk/getinvolved/en/volunteer.wml
website/trunk/projects/en/projects.wml
Log:
Replacing TAILS with Tails as per intrigeri's request.
Modified: website/trunk/getinvolved/en/volunteer.wml
===================================================================
--- website/trunk/getinvolved/en/volunteer.wml 2011-03-12 21:24:27 UTC (rev 24345)
+++ website/trunk/getinvolved/en/volunteer.wml 2011-03-12 21:50:36 UTC (rev 24346)
@@ -112,7 +112,7 @@
</tr>
<tr class="alt">
- <td><a href="#project-tails">TAILS</a></td>
+ <td><a href="#project-tails">Tails</a></td>
<td>Usability</td>
<td>Sys Admin</td>
<td>Heavy</td>
@@ -656,11 +656,11 @@
Skill Level: <i>Medium to High</i>
<br>
Likely Mentors: <i>intrigeri, anonym</i>
- <p>Several major upcoming TAILS features need to gather user input at
+ <p>Several major upcoming Tails features need to gather user input at
startup time: bridges support, persistence, MAC address anonymization,
etc.</p>
<p>Existing boot menus lack the graphical widgets and generally
- user-friendliness needed. Hence it was decided to implement TAILS startup
+ user-friendliness needed. Hence it was decided to implement Tails startup
menu in GDM3: GDM3's default login/password prompt needs to be replaced
with a custom GTK+ application hereby named tails-greeter that allows the
user to provide any input necessary.</p>
@@ -1046,7 +1046,7 @@
coordinates, author's name and so on. Anyone who wants to anonymously
publish a file can thus far too easily de-anonymize herself.</p>
<p>A set of tools allowing users to easily inspect and clean up meta-data in files
- would benefit Tor users, and would e.g. be shipped in TAILS.</p>
+ would benefit Tor users, and would e.g. be shipped in Tails.</p>
<p>A graphical user interface is a must, but library and command-line
interfaces are most welcome so that future work can add support for
cleaning published files to various publishing tools, such as desktop
@@ -1072,15 +1072,15 @@
<br>
Likely Mentors: <i>intrigeri, anonym</i>
<p>Data persistence is a somewhat tricky topic in a Live system context,
- especially one such as TAILS, which is explicitly designed to avoid
+ especially one such as Tails, which is explicitly designed to avoid
leaving any trace of its use.</p>
<p>Some real-life use cases, however, require some kind of data
- persistence. To start with, TAILS should (carefully) support persistence of
+ persistence. To start with, Tails should (carefully) support persistence of
application-specific configurations (e.g. GnuPG keyring) and of a user
- arbitrary data store. Note that persistence in TAILS will always be opt-in
+ arbitrary data store. Note that persistence in Tails will always be opt-in
and require encrypted storage.</p>
<p>The backend work consists of improving Debian Live's existing
- persistence features to make them suit the specific context of TAILS. A trust
+ persistence features to make them suit the specific context of Tails. A trust
relationship is already established with upstream who is happy to merge our
changes. The codebase is not that small and much refactoring is needed, so
this really is a programming project rather than a fire'n'forget shell
Modified: website/trunk/projects/en/projects.wml
===================================================================
--- website/trunk/projects/en/projects.wml 2011-03-12 21:24:27 UTC (rev 24345)
+++ website/trunk/projects/en/projects.wml 2011-03-12 21:50:36 UTC (rev 24346)
@@ -52,7 +52,7 @@
Orbot/Tor.</p>
</td>
<td>
-<div class="name"><a href="https://amnesia.boum.org/">TAILS</a></div>
+<div class="name"><a href="https://amnesia.boum.org/">Tails</a></div>
<p>The (Amnesic) Incognito Live System is a live CD/USB distribution
preconfigured so that everything is safely routed through Tor and leaves no
trace on the local system.</p>
1
0

r24345: {website} alas, zooko.com appears to have its https version down (website/trunk/docs/en)
by Roger Dingledine 12 Mar '11
by Roger Dingledine 12 Mar '11
12 Mar '11
Author: arma
Date: 2011-03-12 21:24:27 +0000 (Sat, 12 Mar 2011)
New Revision: 24345
Modified:
website/trunk/docs/en/hidden-services.wml
Log:
alas, zooko.com appears to have its https version down
Modified: website/trunk/docs/en/hidden-services.wml
===================================================================
--- website/trunk/docs/en/hidden-services.wml 2011-03-11 23:55:54 UTC (rev 24344)
+++ website/trunk/docs/en/hidden-services.wml 2011-03-12 21:24:27 UTC (rev 24345)
@@ -56,7 +56,7 @@
service name, it serves an important goal: Everyone – including
the introduction points, the distributed hash table directory, and of course the
clients – can verify that they are talking to the right hidden
- service. See also <a href="https://zooko.com/distnames.html">Zooko's
+ service. See also <a href="http://zooko.com/distnames.html">Zooko's
conjecture</a> that out of Decentralized, Secure, and Human-Meaningful,
you can achieve at most two. Perhaps one day somebody will implement a <a
href="http://www.skyhunter.com/marcs/petnames/IntroPetNames.html">Petname</a>
1
0

12 Mar '11
commit fcb7268013177b13a29f091e1c54ddcac97b5b12
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Sat Mar 12 08:27:32 2011 +0100
Add generated tarballs to .gitignore.
---
task-2680/.gitignore | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/task-2680/.gitignore b/task-2680/.gitignore
index 134e86d..6378a79 100644
--- a/task-2680/.gitignore
+++ b/task-2680/.gitignore
@@ -3,4 +3,5 @@
bridge-descriptors/
commons-codec-1.4.jar
consensuses/
+*.tar.bz2
1
0

[metrics-tasks/master] Add detect-censorship.R script for #2718.
by karsten@torproject.org 12 Mar '11
by karsten@torproject.org 12 Mar '11
12 Mar '11
commit 667d9a51b739f76808e5d84abca72be4b7f84dc6
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Sat Mar 12 08:26:55 2011 +0100
Add detect-censorship.R script for #2718.
---
task-2718/.gitignore | 3 ++
task-2718/README | 5 ++++
task-2718/detect-censorship.R | 52 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/task-2718/.gitignore b/task-2718/.gitignore
new file mode 100644
index 0000000..673fa5f
--- /dev/null
+++ b/task-2718/.gitignore
@@ -0,0 +1,3 @@
+direct-users.csv
+*.pdf
+
diff --git a/task-2718/README b/task-2718/README
new file mode 100644
index 0000000..807142a
--- /dev/null
+++ b/task-2718/README
@@ -0,0 +1,5 @@
+Here's how you run the censorship detector prototype:
+
+ $ wget https://metrics.torproject.org/csv/direct-users.csv
+ $ R --slave -f detect-censorship.R
+
diff --git a/task-2718/detect-censorship.R b/task-2718/detect-censorship.R
new file mode 100644
index 0000000..f27e863
--- /dev/null
+++ b/task-2718/detect-censorship.R
@@ -0,0 +1,52 @@
+# Tor Censorship Detector
+# Usage: R --slave < detect-censorship.R
+
+# Read CSV file containing daily user number estimates.
+direct <- read.csv("direct-users.csv")
+
+# Start plotting everything to a single PDF (with multiple pages).
+pdf("detect-censorship.pdf")
+
+# Convert the column containing daily Iranian users to a time series
+# object, starting on the 263th day of 2009 with a frequency of 365 days.
+# We're probably off by a day or two, but this should be fine for now.
+all <- ts(direct$ir, start = c(2009, 263), frequency = 365)
+
+# Uncomment to print the time series values.
+#print(all)
+
+# Let's try our approach for the last 365 days to see if we detect any
+# blocking in that time period. In the final version of this script, we'd
+# only have a single run with i = 1.
+for (i in 365:1) {
+ idx <- length(direct$date) - i
+
+ # Convert the daily Iranian users until i days in the past to a time
+ # series object.
+ x <- ts(direct$ir[1:idx], start = c(2009, 263), frequency = 365)
+
+ # Apply an ARIMA(1, 0, 1) model to the time series.
+ x.fit = arima(x, order = c(1, 0, 1))
+
+ # Predict 10 dates ahead.
+ x.fore=predict(x.fit, n.ahead=10)
+
+ # Calculate a lower bound. Here we use the predicted value minus three
+ # standard errors.
+ L = x.fore$pred - 3*x.fore$se
+
+ # If the observed daily user number is lower than our predicted lower
+ # bound, plot the data and lower bound.
+ if (direct$ir[idx + 1] < L[1]) {
+
+ # Plot the full time series.
+ ts.plot(all)
+
+ # Add a line for the ten predicted values.
+ lines(L, col = "red", lwd = 2)
+ }
+}
+
+# Close the PDF device.
+dev.off()
+
1
0
commit d52a99dc77dc77008b871da8bb2f95995d1abb6a
Merge: 0b07b5d d34a5cd
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Fri Mar 11 23:34:46 2011 -0500
Merge remote branch 'origin/maint-0.2.2'
changes/hsdir_assignment | 8 ++++++++
src/or/dirserv.c | 19 ++++++++++++++++++-
src/or/dirvote.c | 2 +-
src/or/rephist.c | 14 ++++++++++++++
src/or/rephist.h | 1 +
5 files changed, 42 insertions(+), 2 deletions(-)
diff --combined src/or/dirserv.c
index 4f06de1,40136a1..cbf8c36
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@@ -16,7 -16,6 +16,7 @@@
#include "hibernate.h"
#include "microdesc.h"
#include "networkstatus.h"
+#include "nodelist.h"
#include "policies.h"
#include "rephist.h"
#include "router.h"
@@@ -44,6 -43,8 +44,8 @@@
extern time_t time_of_process_start; /* from main.c */
+ extern long stats_n_seconds_working; /* from main.c */
+
/** Do we need to regenerate the v1 directory when someone asks for it? */
static time_t the_directory_is_dirty = 1;
/** Do we need to regenerate the v1 runningrouters document when somebody
@@@ -66,6 -67,8 +68,6 @@@ static char *format_versions_list(confi
struct authdir_config_t;
static int add_fingerprint_to_dir(const char *nickname, const char *fp,
struct authdir_config_t *list);
-static uint32_t dirserv_router_get_status(const routerinfo_t *router,
- const char **msg);
static uint32_t
dirserv_get_status_impl(const char *fp, const char *nickname,
const char *address,
@@@ -73,8 -76,7 +75,8 @@@
const char *platform, const char *contact,
const char **msg, int should_log);
static void clear_cached_dir(cached_dir_t *d);
-static signed_descriptor_t *get_signed_descriptor_by_fp(const char *fp,
+static const signed_descriptor_t *get_signed_descriptor_by_fp(
+ const char *fp,
int extrainfo,
time_t publish_cutoff);
static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg);
@@@ -303,7 -305,7 +305,7 @@@ dirserv_load_fingerprint_file(void
*
* If the status is 'FP_REJECT' and <b>msg</b> is provided, set
* *<b>msg</b> to an explanation of why. */
-static uint32_t
+uint32_t
dirserv_router_get_status(const routerinfo_t *router, const char **msg)
{
char d[DIGEST_LEN];
@@@ -325,7 -327,7 +327,7 @@@
/** Return true if there is no point in downloading the router described by
* <b>rs</b> because this directory would reject it. */
int
-dirserv_would_reject_router(routerstatus_t *rs)
+dirserv_would_reject_router(const routerstatus_t *rs)
{
uint32_t res;
@@@ -360,7 -362,7 +362,7 @@@ dirserv_get_name_status(const char *id_
return 0;
}
-/** Helper: As dirserv_get_router_status, but takes the router fingerprint
+/** Helper: As dirserv_router_get_status, but takes the router fingerprint
* (hex, no spaces), nickname, address (used for logging only), IP address, OR
* port, platform (logging only) and contact info (logging only) as arguments.
*
@@@ -375,7 -377,7 +377,7 @@@ dirserv_get_status_impl(const char *id_
const char **msg, int should_log)
{
int reject_unlisted = get_options()->AuthDirRejectUnlisted;
- uint32_t result = 0;
+ uint32_t result;
router_status_t *status_by_digest;
if (!fingerprint_list)
@@@ -539,7 -541,7 +541,7 @@@ dirserv_router_has_valid_address(router
*/
int
authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
- int complain)
+ int complain, int *valid_out)
{
/* Okay. Now check whether the fingerprint is recognized. */
uint32_t status = dirserv_router_get_status(ri, msg);
@@@ -580,24 -582,15 +582,24 @@@
*msg = "Rejected: Address is not an IP, or IP is a private address.";
return -1;
}
- /* Okay, looks like we're willing to accept this one. */
- ri->is_named = (status & FP_NAMED) ? 1 : 0;
- ri->is_valid = (status & FP_INVALID) ? 0 : 1;
- ri->is_bad_directory = (status & FP_BADDIR) ? 1 : 0;
- ri->is_bad_exit = (status & FP_BADEXIT) ? 1 : 0;
+
+ *valid_out = ! (status & FP_INVALID);
return 0;
}
+/** Update the relevant flags of <b>node</b> based on our opinion as a
+ * directory authority in <b>authstatus</b>, as returned by
+ * dirserv_router_get_status or equivalent. */
+void
+dirserv_set_node_flags_from_authoritative_status(node_t *node,
+ uint32_t authstatus)
+{
+ node->is_valid = (authstatus & FP_INVALID) ? 0 : 1;
+ node->is_bad_directory = (authstatus & FP_BADDIR) ? 1 : 0;
+ node->is_bad_exit = (authstatus & FP_BADEXIT) ? 1 : 0;
+}
+
/** True iff <b>a</b> is more severe than <b>b</b>. */
static int
WRA_MORE_SEVERE(was_router_added_t a, was_router_added_t b)
@@@ -722,7 -715,7 +724,7 @@@ dirserv_add_descriptor(routerinfo_t *ri
* from this server. (We do this here and not in router_add_to_routerlist
* because we want to be able to accept the newest router descriptor that
* another authority has, so we all converge on the same one.) */
- ri_old = router_get_by_digest(ri->cache_info.identity_digest);
+ ri_old = router_get_mutable_by_digest(ri->cache_info.identity_digest);
if (ri_old && ri_old->cache_info.published_on < ri->cache_info.published_on
&& router_differences_are_cosmetic(ri_old, ri)
&& !router_is_me(ri)) {
@@@ -766,7 -759,8 +768,7 @@@
routerlist_descriptors_added(changed, 0);
smartlist_free(changed);
if (!*msg) {
- *msg = ri->is_valid ? "Descriptor for valid server accepted" :
- "Descriptor for invalid server accepted";
+ *msg = "Descriptor accepted";
}
log_info(LD_DIRSERV,
"Added descriptor from '%s' (source: %s): %s.",
@@@ -781,12 -775,12 +783,12 @@@
static was_router_added_t
dirserv_add_extrainfo(extrainfo_t *ei, const char **msg)
{
- routerinfo_t *ri;
+ const routerinfo_t *ri;
int r;
tor_assert(msg);
*msg = NULL;
- ri = router_get_by_digest(ei->cache_info.identity_digest);
+ ri = router_get_by_id_digest(ei->cache_info.identity_digest);
if (!ri) {
*msg = "No corresponding router descriptor for extra-info descriptor";
extrainfo_free(ei);
@@@ -821,65 -815,54 +823,65 @@@
static void
directory_remove_invalid(void)
{
- int i;
int changed = 0;
routerlist_t *rl = router_get_routerlist();
+ smartlist_t *nodes = smartlist_create();
+ smartlist_add_all(nodes, nodelist_get_list());
- routerlist_assert_ok(rl);
-
- for (i = 0; i < smartlist_len(rl->routers); ++i) {
+ SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) {
const char *msg;
- routerinfo_t *ent = smartlist_get(rl->routers, i);
- uint32_t r = dirserv_router_get_status(ent, &msg);
+ routerinfo_t *ent = node->ri;
+ uint32_t r;
+ if (!ent)
+ continue;
+ r = dirserv_router_get_status(ent, &msg);
if (r & FP_REJECT) {
log_info(LD_DIRSERV, "Router '%s' is now rejected: %s",
ent->nickname, msg?msg:"");
routerlist_remove(rl, ent, 0, time(NULL));
changed = 1;
continue;
}
- if (bool_neq((r & FP_NAMED), ent->is_named)) {
+#if 0
+ if (bool_neq((r & FP_NAMED), ent->auth_says_is_named)) {
log_info(LD_DIRSERV,
"Router '%s' is now %snamed.", ent->nickname,
(r&FP_NAMED)?"":"un");
ent->is_named = (r&FP_NAMED)?1:0;
changed = 1;
}
- if (bool_neq((r & FP_INVALID), !ent->is_valid)) {
+ if (bool_neq((r & FP_UNNAMED), ent->auth_says_is_unnamed)) {
+ log_info(LD_DIRSERV,
+ "Router '%s' is now %snamed. (FP_UNNAMED)", ent->nickname,
+ (r&FP_NAMED)?"":"un");
+ ent->is_named = (r&FP_NUNAMED)?0:1;
+ changed = 1;
+ }
+#endif
+ if (bool_neq((r & FP_INVALID), !node->is_valid)) {
log_info(LD_DIRSERV, "Router '%s' is now %svalid.", ent->nickname,
(r&FP_INVALID) ? "in" : "");
- ent->is_valid = (r&FP_INVALID)?0:1;
+ node->is_valid = (r&FP_INVALID)?0:1;
changed = 1;
}
- if (bool_neq((r & FP_BADDIR), ent->is_bad_directory)) {
+ if (bool_neq((r & FP_BADDIR), node->is_bad_directory)) {
log_info(LD_DIRSERV, "Router '%s' is now a %s directory", ent->nickname,
(r & FP_BADDIR) ? "bad" : "good");
- ent->is_bad_directory = (r&FP_BADDIR) ? 1: 0;
+ node->is_bad_directory = (r&FP_BADDIR) ? 1: 0;
changed = 1;
}
- if (bool_neq((r & FP_BADEXIT), ent->is_bad_exit)) {
+ if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) {
log_info(LD_DIRSERV, "Router '%s' is now a %s exit", ent->nickname,
(r & FP_BADEXIT) ? "bad" : "good");
- ent->is_bad_exit = (r&FP_BADEXIT) ? 1: 0;
+ node->is_bad_exit = (r&FP_BADEXIT) ? 1: 0;
changed = 1;
}
- }
+ } SMARTLIST_FOREACH_END(node);
if (changed)
directory_set_dirty();
routerlist_assert_ok(rl);
+ smartlist_free(nodes);
}
/** Mark the directory as <b>dirty</b> -- when we're next asked for a
@@@ -918,11 -901,10 +920,11 @@@ directory_set_dirty(void
* as running iff <b>is_live</b> is true.
*/
static char *
-list_single_server_status(routerinfo_t *desc, int is_live)
+list_single_server_status(const routerinfo_t *desc, int is_live)
{
char buf[MAX_NICKNAME_LEN+HEX_DIGEST_LEN+4]; /* !nickname=$hexdigest\0 */
char *cp;
+ const node_t *node;
tor_assert(desc);
@@@ -930,8 -912,7 +932,8 @@@
if (!is_live) {
*cp++ = '!';
}
- if (desc->is_valid) {
+ node = node_get_by_id(desc->cache_info.identity_digest);
+ if (node && node->is_valid) {
strlcpy(cp, desc->nickname, sizeof(buf)-(cp-buf));
cp += strlen(cp);
*cp++ = '=';
@@@ -970,8 -951,6 +972,8 @@@ dirserv_set_router_is_running(routerinf
unreachable.
*/
int answer;
+ node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest);
+ tor_assert(node);
if (router_is_me(router)) {
/* We always know if we are down ourselves. */
@@@ -996,7 -975,7 +998,7 @@@
rep_hist_note_router_unreachable(router->cache_info.identity_digest, now);
}
- router->is_running = answer;
+ node->is_running = answer;
}
/** Based on the routerinfo_ts in <b>routers</b>, allocate the
@@@ -1024,8 -1003,6 +1026,8 @@@ list_server_status_v1(smartlist_t *rout
rs_entries = smartlist_create();
SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
+ const node_t *node = node_get_by_id(ri->cache_info.identity_digest);
+ tor_assert(node);
if (authdir) {
/* Update router status in routerinfo_t. */
dirserv_set_router_is_running(ri, now);
@@@ -1033,13 -1010,12 +1035,13 @@@
if (for_controller) {
char name_buf[MAX_VERBOSE_NICKNAME_LEN+2];
char *cp = name_buf;
- if (!ri->is_running)
+ if (!node->is_running)
*cp++ = '!';
router_get_verbose_nickname(cp, ri);
smartlist_add(rs_entries, tor_strdup(name_buf));
} else if (ri->cache_info.published_on >= cutoff) {
- smartlist_add(rs_entries, list_single_server_status(ri, ri->is_running));
+ smartlist_add(rs_entries, list_single_server_status(ri,
+ node->is_running));
}
} SMARTLIST_FOREACH_END(ri);
@@@ -1077,12 -1053,12 +1079,12 @@@ format_versions_list(config_line_t *ln
* not hibernating, and not too old. Else return 0.
*/
static int
-router_is_active(routerinfo_t *ri, time_t now)
+router_is_active(const routerinfo_t *ri, const node_t *node, time_t now)
{
time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
if (ri->cache_info.published_on < cutoff)
return 0;
- if (!ri->is_running || !ri->is_valid || ri->is_hibernating)
+ if (!node->is_running || !node->is_valid || ri->is_hibernating)
return 0;
return 1;
}
@@@ -1183,7 -1159,7 +1185,7 @@@ dirserv_dump_directory_to_string(char *
int
directory_fetches_from_authorities(or_options_t *options)
{
- routerinfo_t *me;
+ const routerinfo_t *me;
uint32_t addr;
int refuseunknown;
if (options->FetchDirInfoEarly)
@@@ -1295,8 -1271,7 +1297,8 @@@ static cached_dir_t cached_runningroute
* cached_dir_t. */
static digestmap_t *cached_v2_networkstatus = NULL;
-/** Map from flavor name to the v3 consensuses that we're currently serving. */
+/** Map from flavor name to the cached_dir_t for the v3 consensuses that we're
+ * currently serving. */
static strmap_t *cached_consensuses = NULL;
/** Possibly replace the contents of <b>d</b> with the value of
@@@ -1749,7 -1724,7 +1751,7 @@@ static uint64_t total_exit_bandwidth =
/** Helper: estimate the uptime of a router given its stated uptime and the
* amount of time since it last stated its stated uptime. */
static INLINE long
-real_uptime(routerinfo_t *router, time_t now)
+real_uptime(const routerinfo_t *router, time_t now)
{
if (now < router->cache_info.published_on)
return router->uptime;
@@@ -1800,10 -1775,24 +1802,25 @@@ dirserv_thinks_router_is_unreliable(tim
* been set.
*/
static int
-dirserv_thinks_router_is_hs_dir(routerinfo_t *router, time_t now)
+dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
+ const node_t *node, time_t now)
{
- long uptime = real_uptime(router, now);
+
+ long uptime;
+
+ /* If we haven't been running for at least
+ * get_options()->MinUptimeHidServDirectoryV2 seconds, we can't
+ * have accurate data telling us a relay has been up for at least
+ * that long. We also want to allow a bit of slack: Reachability
+ * tests aren't instant. If we haven't been running long enough,
+ * trust the relay. */
+
+ if (stats_n_seconds_working >
+ get_options()->MinUptimeHidServDirectoryV2 * 1.1)
+ uptime = MIN(rep_hist_get_uptime(router->cache_info.identity_digest, now),
+ real_uptime(router, now));
+ else
+ uptime = real_uptime(router, now);
/* XXX We shouldn't need to check dir_port, but we do because of
* bug 1693. In the future, once relays set wants_to_be_hs_dir
@@@ -1811,7 -1800,7 +1828,7 @@@
* version is too old. */
return (router->wants_to_be_hs_dir && router->dir_port &&
uptime > get_options()->MinUptimeHidServDirectoryV2 &&
- router->is_running);
+ node->is_running);
}
/** Look through the routerlist, the Mean Time Between Failure history, and
@@@ -1859,22 -1848,19 +1876,22 @@@ dirserv_compute_performance_thresholds(
/* Weighted fractional uptime for each active router. */
wfus = tor_malloc(sizeof(double)*smartlist_len(rl->routers));
+ nodelist_assert_ok();
+
/* Now, fill in the arrays. */
- SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
- if (router_is_active(ri, now)) {
+ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) {
+ routerinfo_t *ri = node->ri;
+ if (ri && router_is_active(ri, node, now)) {
const char *id = ri->cache_info.identity_digest;
uint32_t bw;
- ri->is_exit = (!router_exit_policy_rejects_all(ri) &&
- exit_policy_is_general_exit(ri->exit_policy));
+ node->is_exit = (!router_exit_policy_rejects_all(ri) &&
+ exit_policy_is_general_exit(ri->exit_policy));
uptimes[n_active] = (uint32_t)real_uptime(ri, now);
mtbfs[n_active] = rep_hist_get_stability(id, now);
tks [n_active] = rep_hist_get_weighted_time_known(id, now);
bandwidths[n_active] = bw = router_get_advertised_bandwidth(ri);
total_bandwidth += bw;
- if (ri->is_exit && !ri->is_bad_exit) {
+ if (node->is_exit && !node->is_bad_exit) {
total_exit_bandwidth += bw;
} else {
bandwidths_excluding_exits[n_active_nonexit] = bw;
@@@ -1882,7 -1868,7 +1899,7 @@@
}
++n_active;
}
- });
+ } SMARTLIST_FOREACH_END(node);
/* Now, compute thresholds. */
if (n_active) {
@@@ -1908,17 -1894,15 +1925,17 @@@
/* Now that we have a time-known that 7/8 routers are known longer than,
* fill wfus with the wfu of every such "familiar" router. */
n_familiar = 0;
- SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
- if (router_is_active(ri, now)) {
+
+ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) {
+ routerinfo_t *ri = node->ri;
+ if (ri && router_is_active(ri, node, now)) {
const char *id = ri->cache_info.identity_digest;
long tk = rep_hist_get_weighted_time_known(id, now);
if (tk < guard_tk)
continue;
wfus[n_familiar++] = rep_hist_get_weighted_fractional_uptime(id, now);
}
- });
+ } SMARTLIST_FOREACH_END(node);
if (n_familiar)
guard_wfu = median_double(wfus, n_familiar);
if (guard_wfu > WFU_TO_GUARANTEE_GUARD)
@@@ -1989,20 -1973,24 +2006,20 @@@ version_from_platform(const char *platf
*/
int
routerstatus_format_entry(char *buf, size_t buf_len,
- routerstatus_t *rs, const char *version,
+ const routerstatus_t *rs, const char *version,
routerstatus_format_type_t format)
{
int r;
- struct in_addr in;
char *cp;
char *summary;
char published[ISO_TIME_LEN+1];
- char ipaddr[INET_NTOA_BUF_LEN];
char identity64[BASE64_DIGEST_LEN+1];
char digest64[BASE64_DIGEST_LEN+1];
format_iso_time(published, rs->published_on);
digest_to_base64(identity64, rs->identity_digest);
digest_to_base64(digest64, rs->descriptor_digest);
- in.s_addr = htonl(rs->addr);
- tor_inet_ntoa(&in, ipaddr, sizeof(ipaddr));
r = tor_snprintf(buf, buf_len,
"r %s %s %s%s%s %s %d %d\n",
@@@ -2011,7 -1999,7 +2028,7 @@@
(format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
(format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
published,
- ipaddr,
+ fmt_addr32(rs->addr),
(int)rs->or_port,
(int)rs->dir_port);
if (r<0) {
@@@ -2039,7 -2027,7 +2056,7 @@@
rs->is_possible_guard?" Guard":"",
rs->is_hs_dir?" HSDir":"",
rs->is_named?" Named":"",
- rs->is_running?" Running":"",
+ rs->is_flagged_running?" Running":"",
rs->is_stable?" Stable":"",
rs->is_unnamed?" Unnamed":"",
rs->is_v2_dir?" V2Dir":"",
@@@ -2061,7 -2049,7 +2078,7 @@@
}
if (format != NS_V2) {
- routerinfo_t* desc = router_get_by_digest(rs->identity_digest);
+ const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
uint32_t bw;
if (format != NS_CONTROL_PORT) {
@@@ -2157,8 -2145,6 +2174,8 @@@ _compare_routerinfo_by_ip_and_bw(const
routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b;
int first_is_auth, second_is_auth;
uint32_t bw_first, bw_second;
+ const node_t *node_first, *node_second;
+ int first_is_running, second_is_running;
/* we return -1 if first should appear before second... that is,
* if first is a better router. */
@@@ -2181,14 -2167,9 +2198,14 @@@
else if (!first_is_auth && second_is_auth)
return 1;
- else if (first->is_running && !second->is_running)
+ node_first = node_get_by_id(first->cache_info.identity_digest);
+ node_second = node_get_by_id(second->cache_info.identity_digest);
+ first_is_running = node_first && node_first->is_running;
+ second_is_running = node_second && node_second->is_running;
+
+ if (first_is_running && !second_is_running)
return -1;
- else if (!first->is_running && second->is_running)
+ else if (!first_is_running && second_is_running)
return 1;
bw_first = router_get_advertised_bandwidth(first);
@@@ -2257,9 -2238,7 +2274,9 @@@ get_possible_sybil_list(const smartlist
*/
void
set_routerstatus_from_routerinfo(routerstatus_t *rs,
- routerinfo_t *ri, time_t now,
+ node_t *node,
+ routerinfo_t *ri,
+ time_t now,
int naming, int listbadexits,
int listbaddirs)
{
@@@ -2271,46 -2250,48 +2288,46 @@@
router_digest_is_trusted_dir(ri->cache_info.identity_digest);
/* Already set by compute_performance_thresholds. */
- rs->is_exit = ri->is_exit;
- rs->is_stable = ri->is_stable =
- router_is_active(ri, now) &&
+ rs->is_exit = node->is_exit;
+ rs->is_stable = node->is_stable =
+ router_is_active(ri, node, now) &&
!dirserv_thinks_router_is_unreliable(now, ri, 1, 0) &&
!unstable_version;
- rs->is_fast = ri->is_fast =
- router_is_active(ri, now) &&
+ rs->is_fast = node->is_fast =
+ router_is_active(ri, node, now) &&
!dirserv_thinks_router_is_unreliable(now, ri, 0, 1);
- rs->is_running = ri->is_running; /* computed above */
+ rs->is_flagged_running = node->is_running; /* computed above */
if (naming) {
uint32_t name_status = dirserv_get_name_status(
- ri->cache_info.identity_digest, ri->nickname);
+ node->identity, ri->nickname);
rs->is_named = (naming && (name_status & FP_NAMED)) ? 1 : 0;
rs->is_unnamed = (naming && (name_status & FP_UNNAMED)) ? 1 : 0;
}
- rs->is_valid = ri->is_valid;
+ rs->is_valid = node->is_valid;
- if (rs->is_fast &&
+ if (node->is_fast &&
(router_get_advertised_bandwidth(ri) >= BANDWIDTH_TO_GUARANTEE_GUARD ||
router_get_advertised_bandwidth(ri) >=
MIN(guard_bandwidth_including_exits,
guard_bandwidth_excluding_exits))) {
- long tk = rep_hist_get_weighted_time_known(
- ri->cache_info.identity_digest, now);
- double wfu = rep_hist_get_weighted_fractional_uptime(
- ri->cache_info.identity_digest, now);
+ long tk = rep_hist_get_weighted_time_known(node->identity, now);
+ double wfu = rep_hist_get_weighted_fractional_uptime(node->identity, now);
rs->is_possible_guard = (wfu >= guard_wfu && tk >= guard_tk) ? 1 : 0;
} else {
rs->is_possible_guard = 0;
}
- rs->is_bad_directory = listbaddirs && ri->is_bad_directory;
- rs->is_bad_exit = listbadexits && ri->is_bad_exit;
- ri->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, now);
- rs->is_hs_dir = ri->is_hs_dir;
+ rs->is_bad_directory = listbaddirs && node->is_bad_directory;
+ rs->is_bad_exit = listbadexits && node->is_bad_exit;
+ node->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, node, now);
+ rs->is_hs_dir = node->is_hs_dir;
rs->is_v2_dir = ri->dir_port != 0;
if (!strcasecmp(ri->nickname, UNNAMED_ROUTER_NICKNAME))
rs->is_named = rs->is_unnamed = 0;
rs->published_on = ri->cache_info.published_on;
- memcpy(rs->identity_digest, ri->cache_info.identity_digest, DIGEST_LEN);
+ memcpy(rs->identity_digest, node->identity, DIGEST_LEN);
memcpy(rs->descriptor_digest, ri->cache_info.signed_descriptor_digest,
DIGEST_LEN);
rs->addr = ri->addr;
@@@ -2327,7 -2308,7 +2344,7 @@@ static voi
clear_status_flags_on_sybil(routerstatus_t *rs)
{
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
- rs->is_running = rs->is_named = rs->is_valid = rs->is_v2_dir =
+ rs->is_flagged_running = rs->is_named = rs->is_valid = rs->is_v2_dir =
rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit =
rs->is_bad_directory = 0;
/* FFFF we might want some mechanism to check later on if we
@@@ -2335,6 -2316,18 +2352,6 @@@
* forget to add it to this clause. */
}
-/** Clear all the status flags in routerinfo <b>router</b>. We put this
- * function here because it's eerily similar to
- * clear_status_flags_on_sybil() above. One day we should merge them. */
-void
-router_clear_status_flags(routerinfo_t *router)
-{
- router->is_valid = router->is_running = router->is_hs_dir =
- router->is_fast = router->is_stable =
- router->is_possible_guard = router->is_exit =
- router->is_bad_exit = router->is_bad_directory = 0;
-}
-
/**
* Helper function to parse out a line in the measured bandwidth file
* into a measured_bw_line_t output structure. Returns -1 on failure
@@@ -2452,7 -2445,7 +2469,7 @@@ dirserv_read_measured_bandwidths(const
smartlist_t *routerstatuses)
{
char line[256];
- FILE *fp = fopen(from_file, "r");
+ FILE *fp = tor_fopen_cloexec(from_file, "r");
int applied_lines = 0;
time_t file_time;
int ok;
@@@ -2582,20 -2575,17 +2599,20 @@@ dirserv_generate_networkstatus_vote_obj
routerstatus_t *rs;
vote_routerstatus_t *vrs;
microdesc_t *md;
+ node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
+ if (!node)
+ continue;
vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
rs = &vrs->status;
- set_routerstatus_from_routerinfo(rs, ri, now,
+ set_routerstatus_from_routerinfo(rs, node, ri, now,
naming, listbadexits, listbaddirs);
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
clear_status_flags_on_sybil(rs);
if (!vote_on_reachability)
- rs->is_running = 0;
+ rs->is_flagged_running = 0;
vrs->version = version_from_platform(ri->platform);
md = dirvote_create_microdescriptor(ri);
@@@ -2726,8 -2716,10 +2743,8 @@@ generate_v2_networkstatus_opinion(void
char *outp, *endp;
or_options_t *options = get_options();
char fingerprint[FINGERPRINT_LEN+1];
- char ipaddr[INET_NTOA_BUF_LEN];
char published[ISO_TIME_LEN+1];
char digest[DIGEST_LEN];
- struct in_addr in;
uint32_t addr;
crypto_pk_env_t *private_key;
routerlist_t *rl = router_get_routerlist();
@@@ -2748,6 -2740,8 +2765,6 @@@
log_warn(LD_NET, "Couldn't resolve my hostname");
goto done;
}
- in.s_addr = htonl(addr);
- tor_inet_ntoa(&in, ipaddr, sizeof(ipaddr));
format_iso_time(published, now);
@@@ -2793,7 -2787,7 +2810,7 @@@
"dir-options%s%s%s%s\n"
"%s" /* client version line, server version line. */
"dir-signing-key\n%s",
- hostname, ipaddr, (int)options->DirPort,
+ hostname, fmt_addr32(addr), (int)options->DirPort,
fingerprint,
contact,
published,
@@@ -2824,12 -2818,8 +2841,12 @@@
if (ri->cache_info.published_on >= cutoff) {
routerstatus_t rs;
char *version = version_from_platform(ri->platform);
-
- set_routerstatus_from_routerinfo(&rs, ri, now,
+ node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
+ if (!node) {
+ tor_free(version);
+ continue;
+ }
+ set_routerstatus_from_routerinfo(&rs, node, ri, now,
naming, listbadexits, listbaddirs);
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
@@@ -2912,7 -2902,7 +2929,7 @@@ dirserv_get_networkstatus_v2_fingerprin
if (!strcmp(key,"authority")) {
if (authdir_mode_v2(get_options())) {
- routerinfo_t *me = router_get_my_routerinfo();
+ const routerinfo_t *me = router_get_my_routerinfo();
if (me)
smartlist_add(result,
tor_memdup(me->cache_info.identity_digest, DIGEST_LEN));
@@@ -3000,7 -2990,7 +3017,7 @@@ dirserv_get_routerdesc_fingerprints(sma
/* Treat "all" requests as if they were unencrypted */
for_unencrypted_conn = 1;
} else if (!strcmp(key, "authority")) {
- routerinfo_t *ri = router_get_my_routerinfo();
+ const routerinfo_t *ri = router_get_my_routerinfo();
if (ri)
smartlist_add(fps_out,
tor_memdup(ri->cache_info.identity_digest, DIGEST_LEN));
@@@ -3020,8 -3010,8 +3037,8 @@@
if (for_unencrypted_conn) {
/* Remove anything that insists it not be sent unencrypted. */
- SMARTLIST_FOREACH(fps_out, char *, cp, {
- signed_descriptor_t *sd;
+ SMARTLIST_FOREACH_BEGIN(fps_out, char *, cp) {
+ const signed_descriptor_t *sd;
if (by_id)
sd = get_signed_descriptor_by_fp(cp,is_extrainfo,0);
else if (is_extrainfo)
@@@ -3032,7 -3022,7 +3049,7 @@@
tor_free(cp);
SMARTLIST_DEL_CURRENT(fps_out, cp);
}
- });
+ } SMARTLIST_FOREACH_END(cp);
}
if (!smartlist_len(fps_out)) {
@@@ -3071,9 -3061,9 +3088,9 @@@ dirserv_get_routerdescs(smartlist_t *de
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
smartlist_add(descs_out, &(r->cache_info)));
} else if (!strcmp(key, "/tor/server/authority")) {
- routerinfo_t *ri = router_get_my_routerinfo();
+ const routerinfo_t *ri = router_get_my_routerinfo();
if (ri)
- smartlist_add(descs_out, &(ri->cache_info));
+ smartlist_add(descs_out, (void*) &(ri->cache_info));
} else if (!strcmpstart(key, "/tor/server/d/")) {
smartlist_t *digests = smartlist_create();
key += strlen("/tor/server/d/");
@@@ -3097,17 -3087,17 +3114,17 @@@
{
if (router_digest_is_me(d)) {
/* make sure desc_routerinfo exists */
- routerinfo_t *ri = router_get_my_routerinfo();
+ const routerinfo_t *ri = router_get_my_routerinfo();
if (ri)
- smartlist_add(descs_out, &(ri->cache_info));
+ smartlist_add(descs_out, (void*) &(ri->cache_info));
} else {
- routerinfo_t *ri = router_get_by_digest(d);
+ const routerinfo_t *ri = router_get_by_id_digest(d);
/* Don't actually serve a descriptor that everyone will think is
* expired. This is an (ugly) workaround to keep buggy 0.1.1.10
* Tors from downloading descriptors that they will throw away.
*/
if (ri && ri->cache_info.published_on > cutoff)
- smartlist_add(descs_out, &(ri->cache_info));
+ smartlist_add(descs_out, (void*) &(ri->cache_info));
}
});
SMARTLIST_FOREACH(digests, char *, d, tor_free(d));
@@@ -3173,8 -3163,7 +3190,8 @@@ dirserv_orconn_tls_done(const char *add
* an upload or a download. Used to decide whether to relaunch reachability
* testing for the server. */
int
-dirserv_should_launch_reachability_test(routerinfo_t *ri, routerinfo_t *ri_old)
+dirserv_should_launch_reachability_test(const routerinfo_t *ri,
+ const routerinfo_t *ri_old)
{
if (!authdir_mode_handles_descs(get_options(), ri->purpose))
return 0;
@@@ -3298,7 -3287,7 +3315,7 @@@ dirserv_remove_old_statuses(smartlist_
* its extra-info document if <b>extrainfo</b> is true. Return
* NULL if not found or if the descriptor is older than
* <b>publish_cutoff</b>. */
-static signed_descriptor_t *
+static const signed_descriptor_t *
get_signed_descriptor_by_fp(const char *fp, int extrainfo,
time_t publish_cutoff)
{
@@@ -3308,7 -3297,7 +3325,7 @@@
else
return &(router_get_my_routerinfo()->cache_info);
} else {
- routerinfo_t *ri = router_get_by_digest(fp);
+ const routerinfo_t *ri = router_get_by_id_digest(fp);
if (ri &&
ri->cache_info.published_on > publish_cutoff) {
if (extrainfo)
@@@ -3376,7 -3365,7 +3393,7 @@@ dirserv_estimate_data_size(smartlist_t
tor_assert(fps);
if (is_serverdescs) {
int n = smartlist_len(fps);
- routerinfo_t *me = router_get_my_routerinfo();
+ const routerinfo_t *me = router_get_my_routerinfo();
result = (me?me->cache_info.signed_descriptor_len:2048) * n;
if (compressed)
result /= 2; /* observed compressibility is between 35 and 55%. */
@@@ -3440,10 -3429,10 +3457,10 @@@ connection_dirserv_add_servers_to_outbu
time_t publish_cutoff = time(NULL)-ROUTER_MAX_AGE_TO_PUBLISH;
while (smartlist_len(conn->fingerprint_stack) &&
- buf_datalen(conn->_base.outbuf) < DIRSERV_BUFFER_MIN) {
+ connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) {
const char *body;
char *fp = smartlist_pop_last(conn->fingerprint_stack);
- signed_descriptor_t *sd = NULL;
+ const signed_descriptor_t *sd = NULL;
if (by_fp) {
sd = get_signed_descriptor_by_fp(fp, extra, publish_cutoff);
} else {
@@@ -3501,7 -3490,7 +3518,7 @@@ connection_dirserv_add_microdescs_to_ou
{
microdesc_cache_t *cache = get_microdesc_cache();
while (smartlist_len(conn->fingerprint_stack) &&
- buf_datalen(conn->_base.outbuf) < DIRSERV_BUFFER_MIN) {
+ connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) {
char *fp256 = smartlist_pop_last(conn->fingerprint_stack);
microdesc_t *md = microdesc_cache_lookup_by_digest256(cache, fp256);
tor_free(fp256);
@@@ -3540,7 -3529,7 +3557,7 @@@ connection_dirserv_add_dir_bytes_to_out
ssize_t bytes;
int64_t remaining;
- bytes = DIRSERV_BUFFER_MIN - buf_datalen(conn->_base.outbuf);
+ bytes = DIRSERV_BUFFER_MIN - connection_get_outbuf_len(TO_CONN(conn));
tor_assert(bytes > 0);
tor_assert(conn->cached_dir);
if (bytes < 8192)
@@@ -3579,7 -3568,7 +3596,7 @@@ static in
connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn)
{
- while (buf_datalen(conn->_base.outbuf) < DIRSERV_BUFFER_MIN) {
+ while (connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) {
if (conn->cached_dir) {
int uncompressing = (conn->zlib_state != NULL);
int r = connection_dirserv_add_dir_bytes_to_outbuf(conn);
@@@ -3625,7 -3614,7 +3642,7 @@@ connection_dirserv_flushed_some(dir_con
{
tor_assert(conn->_base.state == DIR_CONN_STATE_SERVER_WRITING);
- if (buf_datalen(conn->_base.outbuf) >= DIRSERV_BUFFER_MIN)
+ if (connection_get_outbuf_len(TO_CONN(conn)) >= DIRSERV_BUFFER_MIN)
return 0;
switch (conn->dir_spool_src) {
diff --combined src/or/dirvote.c
index 1052da9,9273dbc..7ba6cca
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@@ -83,7 -83,9 +83,7 @@@ format_networkstatus_vote(crypto_pk_env
const char *client_versions = NULL, *server_versions = NULL;
char *outp, *endp;
char fingerprint[FINGERPRINT_LEN+1];
- char ipaddr[INET_NTOA_BUF_LEN];
char digest[DIGEST_LEN];
- struct in_addr in;
uint32_t addr;
routerlist_t *rl = router_get_routerlist();
char *version_lines = NULL;
@@@ -96,6 -98,8 +96,6 @@@
voter = smartlist_get(v3_ns->voters, 0);
addr = voter->addr;
- in.s_addr = htonl(addr);
- tor_inet_ntoa(&in, ipaddr, sizeof(ipaddr));
base16_encode(fingerprint, sizeof(fingerprint),
v3_ns->cert->cache_info.identity_digest, DIGEST_LEN);
@@@ -182,8 -186,7 +182,8 @@@
flags,
params,
voter->nickname, fingerprint, voter->address,
- ipaddr, voter->dir_port, voter->or_port, voter->contact);
+ fmt_addr32(addr), voter->dir_port, voter->or_port,
+ voter->contact);
if (r < 0) {
log_err(LD_BUG, "Insufficient memory for network status line");
@@@ -1526,6 -1529,8 +1526,6 @@@ networkstatus_compute_consensus(smartli
smartlist_sort(dir_sources, _compare_dir_src_ents_by_authority_id);
SMARTLIST_FOREACH_BEGIN(dir_sources, const dir_src_ent_t *, e) {
- struct in_addr in;
- char ip[INET_NTOA_BUF_LEN];
char fingerprint[HEX_DIGEST_LEN+1];
char votedigest[HEX_DIGEST_LEN+1];
networkstatus_t *v = e->v;
@@@ -1535,6 -1540,8 +1535,6 @@@
if (e->is_legacy)
tor_assert(consensus_method >= 2);
- in.s_addr = htonl(voter->addr);
- tor_inet_ntoa(&in, ip, sizeof(ip));
base16_encode(fingerprint, sizeof(fingerprint), e->digest, DIGEST_LEN);
base16_encode(votedigest, sizeof(votedigest), voter->vote_digest,
DIGEST_LEN);
@@@ -1542,7 -1549,7 +1542,7 @@@
tor_asprintf(&buf,
"dir-source %s%s %s %s %s %d %d\n",
voter->nickname, e->is_legacy ? "-legacy" : "",
- fingerprint, voter->address, ip,
+ fingerprint, voter->address, fmt_addr32(voter->addr),
voter->dir_port,
voter->or_port);
smartlist_add(chunks, buf);
@@@ -3073,7 -3080,7 +3073,7 @@@ dirvote_compute_consensuses(void
n_votes = smartlist_len(pending_vote_list);
if (n_votes <= n_voters/2) {
log_warn(LD_DIR, "We don't have enough votes to generate a consensus: "
- "%d of %d", n_votes, n_voters/2);
+ "%d of %d", n_votes, n_voters/2+1);
goto err;
}
tor_assert(pending_vote_list);
diff --combined src/or/rephist.c
index be91422,e4afe62..2b804b1
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@@ -7,7 -7,7 +7,7 @@@
* \brief Basic history and "reputation" functionality to remember
* which servers have worked in the past, how much bandwidth we've
* been using, which ports we tend to want, and so on; further,
- * exit port statistics and cell statistics.
+ * exit port statistics, cell statistics, and connection statistics.
**/
#include "or.h"
@@@ -15,7 -15,6 +15,7 @@@
#include "circuituse.h"
#include "config.h"
#include "networkstatus.h"
+#include "nodelist.h"
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
@@@ -529,6 -528,20 +529,20 @@@ get_weighted_fractional_uptime(or_histo
return ((double) up) / total;
}
+ /** Return how long the router whose identity digest is <b>id</b> has
+ * been reachable. Return 0 if the router is unknown or currently deemed
+ * unreachable. */
+ long
+ rep_hist_get_uptime(const char *id, time_t when)
+ {
+ or_history_t *hist = get_or_history(id);
+ if (!hist)
+ return 0;
+ if (!hist->start_of_run || when < hist->start_of_run)
+ return 0;
+ return when - hist->start_of_run;
+ }
+
/** Return an estimated MTBF for the router whose identity digest is
* <b>id</b>. Return 0 if the router is unknown. */
double
@@@ -629,7 -642,7 +643,7 @@@ rep_hist_dump_stats(time_t now, int sev
size_t len;
int ret;
unsigned long upt, downt;
- routerinfo_t *r;
+ const node_t *node;
rep_history_clean(now - get_options()->RephistTrackTime);
@@@ -643,8 -656,8 +657,8 @@@
digestmap_iter_get(orhist_it, &digest1, &or_history_p);
or_history = (or_history_t*) or_history_p;
- if ((r = router_get_by_digest(digest1)))
- name1 = r->nickname;
+ if ((node = node_get_by_id(digest1)) && node_get_nickname(node))
+ name1 = node_get_nickname(node);
else
name1 = "(unknown)";
base16_encode(hexdigest1, sizeof(hexdigest1), digest1, DIGEST_LEN);
@@@ -674,8 -687,8 +688,8 @@@
lhist_it = digestmap_iter_next(or_history->link_history_map,
lhist_it)) {
digestmap_iter_get(lhist_it, &digest2, &link_history_p);
- if ((r = router_get_by_digest(digest2)))
- name2 = r->nickname;
+ if ((node = node_get_by_id(digest2)) && node_get_nickname(node))
+ name2 = node_get_nickname(node);
else
name2 = "(unknown)";
@@@ -806,7 -819,7 +820,7 @@@ rep_hist_record_mtbf_data(time_t now, i
base16_encode(dbuf, sizeof(dbuf), digest, DIGEST_LEN);
if (missing_means_down && hist->start_of_run &&
- !router_get_by_digest(digest)) {
+ !router_get_by_id_digest(digest)) {
/* We think this relay is running, but it's not listed in our
* routerlist. Somehow it fell out without telling us it went
* down. Complain and also correct it. */
@@@ -921,32 -934,28 +935,32 @@@ rep_hist_get_router_stability_doc(time_
}
DIGESTMAP_FOREACH(history_map, id, or_history_t *, hist) {
- routerinfo_t *ri;
+ const node_t *node;
char dbuf[BASE64_DIGEST_LEN+1];
char header_buf[512];
char *info;
digest_to_base64(dbuf, id);
- ri = router_get_by_digest(id);
- if (ri) {
- char *ip = tor_dup_ip(ri->addr);
+ node = node_get_by_id(id);
+ if (node) {
+ char ip[INET_NTOA_BUF_LEN+1];
char tbuf[ISO_TIME_LEN+1];
- format_iso_time(tbuf, ri->cache_info.published_on);
+ time_t published = node_get_published_on(node);
+ node_get_address_string(node,ip,sizeof(ip));
+ if (published > 0)
+ format_iso_time(tbuf, published);
+ else
+ strlcpy(tbuf, "???", sizeof(tbuf));
tor_snprintf(header_buf, sizeof(header_buf),
"router %s %s %s\n"
"published %s\n"
"relevant-flags %s%s%s\n"
"declared-uptime %ld\n",
- dbuf, ri->nickname, ip,
+ dbuf, node_get_nickname(node), ip,
tbuf,
- ri->is_running ? "Running " : "",
- ri->is_valid ? "Valid " : "",
- ri->is_hibernating ? "Hibernating " : "",
- ri->uptime);
- tor_free(ip);
+ node->is_running ? "Running " : "",
+ node->is_valid ? "Valid " : "",
+ node->ri && node->ri->is_hibernating ? "Hibernating " : "",
+ node_get_declared_uptime(node));
} else {
tor_snprintf(header_buf, sizeof(header_buf),
"router %s {no descriptor}\n", dbuf);
@@@ -1731,13 -1740,10 +1745,13 @@@ rep_hist_load_state(or_state_t *state,
/*********************************************************************/
+typedef struct predicted_port_t {
+ uint16_t port;
+ time_t time;
+} predicted_port_t;
+
/** A list of port numbers that have been used recently. */
static smartlist_t *predicted_ports_list=NULL;
-/** The corresponding most recently used time for each port. */
-static smartlist_t *predicted_ports_times=NULL;
/** We just got an application request for a connection with
* port <b>port</b>. Remember it for the future, so we can keep
@@@ -1746,11 -1752,14 +1760,11 @@@
static void
add_predicted_port(time_t now, uint16_t port)
{
- /* XXXX we could just use uintptr_t here, I think. */
- uint16_t *tmp_port = tor_malloc(sizeof(uint16_t));
- time_t *tmp_time = tor_malloc(sizeof(time_t));
- *tmp_port = port;
- *tmp_time = now;
- rephist_total_alloc += sizeof(uint16_t) + sizeof(time_t);
- smartlist_add(predicted_ports_list, tmp_port);
- smartlist_add(predicted_ports_times, tmp_time);
+ predicted_port_t *pp = tor_malloc(sizeof(predicted_port_t));
+ pp->port = port;
+ pp->time = now;
+ rephist_total_alloc += sizeof(*pp);
+ smartlist_add(predicted_ports_list, pp);
}
/** Initialize whatever memory and structs are needed for predicting
@@@ -1761,6 -1770,7 +1775,6 @@@ static voi
predicted_ports_init(void)
{
predicted_ports_list = smartlist_create();
- predicted_ports_times = smartlist_create();
add_predicted_port(time(NULL), 80); /* add one to kickstart us */
}
@@@ -1770,11 -1780,12 +1784,11 @@@
static void
predicted_ports_free(void)
{
- rephist_total_alloc -= smartlist_len(predicted_ports_list)*sizeof(uint16_t);
- SMARTLIST_FOREACH(predicted_ports_list, char *, cp, tor_free(cp));
+ rephist_total_alloc -=
+ smartlist_len(predicted_ports_list)*sizeof(predicted_port_t);
+ SMARTLIST_FOREACH(predicted_ports_list, predicted_port_t *,
+ pp, tor_free(pp));
smartlist_free(predicted_ports_list);
- rephist_total_alloc -= smartlist_len(predicted_ports_times)*sizeof(time_t);
- SMARTLIST_FOREACH(predicted_ports_times, char *, cp, tor_free(cp));
- smartlist_free(predicted_ports_times);
}
/** Remember that <b>port</b> has been asked for as of time <b>now</b>.
@@@ -1784,17 -1795,24 +1798,17 @@@
void
rep_hist_note_used_port(time_t now, uint16_t port)
{
- int i;
- uint16_t *tmp_port;
- time_t *tmp_time;
-
tor_assert(predicted_ports_list);
- tor_assert(predicted_ports_times);
if (!port) /* record nothing */
return;
- for (i = 0; i < smartlist_len(predicted_ports_list); ++i) {
- tmp_port = smartlist_get(predicted_ports_list, i);
- tmp_time = smartlist_get(predicted_ports_times, i);
- if (*tmp_port == port) {
- *tmp_time = now;
+ SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
+ if (pp->port == port) {
+ pp->time = now;
return;
}
- }
+ } SMARTLIST_FOREACH_END(pp);
/* it's not there yet; we need to add it */
add_predicted_port(now, port);
}
@@@ -1803,28 -1821,36 +1817,28 @@@
* we'll want to make connections to the same port in the future. */
#define PREDICTED_CIRCS_RELEVANCE_TIME (60*60)
-/** Return a pointer to the list of port numbers that
+/** Return a newly allocated pointer to a list of uint16_t * for ports that
* are likely to be asked for in the near future.
- *
- * The caller promises not to mess with it.
*/
smartlist_t *
rep_hist_get_predicted_ports(time_t now)
{
- int i;
- uint16_t *tmp_port;
- time_t *tmp_time;
-
+ smartlist_t *out = smartlist_create();
tor_assert(predicted_ports_list);
- tor_assert(predicted_ports_times);
/* clean out obsolete entries */
- for (i = 0; i < smartlist_len(predicted_ports_list); ++i) {
- tmp_time = smartlist_get(predicted_ports_times, i);
- if (*tmp_time + PREDICTED_CIRCS_RELEVANCE_TIME < now) {
- tmp_port = smartlist_get(predicted_ports_list, i);
- log_debug(LD_CIRC, "Expiring predicted port %d", *tmp_port);
- smartlist_del(predicted_ports_list, i);
- smartlist_del(predicted_ports_times, i);
- rephist_total_alloc -= sizeof(uint16_t)+sizeof(time_t);
- tor_free(tmp_port);
- tor_free(tmp_time);
- i--;
+ SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
+ if (pp->time + PREDICTED_CIRCS_RELEVANCE_TIME < now) {
+ log_debug(LD_CIRC, "Expiring predicted port %d", pp->port);
+
+ rephist_total_alloc -= sizeof(predicted_port_t);
+ tor_free(pp);
+ SMARTLIST_DEL_CURRENT(predicted_ports_list, pp);
+ } else {
+ smartlist_add(out, tor_memdup(&pp->port, sizeof(uint16_t)));
}
- }
- return predicted_ports_list;
+ } SMARTLIST_FOREACH_END(pp);
+ return out;
}
/** The user asked us to do a resolve. Rather than keeping track of
@@@ -2060,9 -2086,7 +2074,9 @@@ rep_hist_exit_stats_term(void
tor_free(exit_streams);
}
-/** Helper for qsort: compare two ints. */
+/** Helper for qsort: compare two ints. Does not handle overflow properly,
+ * but works fine for sorting an array of port numbers, which is what we use
+ * it for. */
static int
_compare_int(const void *x, const void *y)
{
@@@ -2310,6 -2334,7 +2324,6 @@@ typedef struct circ_buffer_stats_t
uint32_t processed_cells;
double mean_num_cells_in_queue;
double mean_time_cells_in_queue;
- uint32_t local_circ_id;
} circ_buffer_stats_t;
/** Holds stats. */
@@@ -2332,9 -2357,9 +2346,9 @@@ rep_hist_buffer_stats_add_circ(circuit_
return;
if (!circuits_for_buffer_stats)
circuits_for_buffer_stats = smartlist_create();
- start_of_interval = circ->timestamp_created >
- start_of_buffer_stats_interval ?
- circ->timestamp_created :
+ start_of_interval = (circ->timestamp_created.tv_sec >
+ start_of_buffer_stats_interval) ?
+ circ->timestamp_created.tv_sec :
start_of_buffer_stats_interval;
interval_length = (int) (end_of_interval - start_of_interval);
stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
@@@ -2500,227 -2525,6 +2514,227 @@@ rep_hist_buffer_stats_write(time_t now
return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL;
}
+/*** Connection statistics ***/
+
+/** Start of the current connection stats interval or 0 if we're not
+ * collecting connection statistics. */
+static time_t start_of_conn_stats_interval;
+
+/** Initialize connection stats. */
+void
+rep_hist_conn_stats_init(time_t now)
+{
+ start_of_conn_stats_interval = now;
+}
+
+/* Count connections that we read and wrote less than these many bytes
+ * from/to as below threshold. */
+#define BIDI_THRESHOLD 20480
+
+/* Count connections that we read or wrote at least this factor as many
+ * bytes from/to than we wrote or read to/from as mostly reading or
+ * writing. */
+#define BIDI_FACTOR 10
+
+/* Interval length in seconds for considering read and written bytes for
+ * connection stats. */
+#define BIDI_INTERVAL 10
+
+/* Start of next BIDI_INTERVAL second interval. */
+static time_t bidi_next_interval = 0;
+
+/* Number of connections that we read and wrote less than BIDI_THRESHOLD
+ * bytes from/to in BIDI_INTERVAL seconds. */
+static uint32_t below_threshold = 0;
+
+/* Number of connections that we read at least BIDI_FACTOR times more
+ * bytes from than we wrote to in BIDI_INTERVAL seconds. */
+static uint32_t mostly_read = 0;
+
+/* Number of connections that we wrote at least BIDI_FACTOR times more
+ * bytes to than we read from in BIDI_INTERVAL seconds. */
+static uint32_t mostly_written = 0;
+
+/* Number of connections that we read and wrote at least BIDI_THRESHOLD
+ * bytes from/to, but not BIDI_FACTOR times more in either direction in
+ * BIDI_INTERVAL seconds. */
+static uint32_t both_read_and_written = 0;
+
+/* Entry in a map from connection ID to the number of read and written
+ * bytes on this connection in a BIDI_INTERVAL second interval. */
+typedef struct bidi_map_entry_t {
+ HT_ENTRY(bidi_map_entry_t) node;
+ uint64_t conn_id; /**< Connection ID */
+ size_t read; /**< Number of read bytes */
+ size_t written; /**< Number of written bytes */
+} bidi_map_entry_t;
+
+/** Map of OR connections together with the number of read and written
+ * bytes in the current BIDI_INTERVAL second interval. */
+static HT_HEAD(bidimap, bidi_map_entry_t) bidi_map =
+ HT_INITIALIZER();
+
+static int
+bidi_map_ent_eq(const bidi_map_entry_t *a, const bidi_map_entry_t *b)
+{
+ return a->conn_id == b->conn_id;
+}
+
+static unsigned
+bidi_map_ent_hash(const bidi_map_entry_t *entry)
+{
+ return (unsigned) entry->conn_id;
+}
+
+HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
+ bidi_map_ent_eq);
+HT_GENERATE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
+ bidi_map_ent_eq, 0.6, malloc, realloc, free);
+
+static void
+bidi_map_free(void)
+{
+ bidi_map_entry_t **ptr, **next, *ent;
+ for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
+ ent = *ptr;
+ next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
+ tor_free(ent);
+ }
+ HT_CLEAR(bidimap, &bidi_map);
+}
+
+/** Reset counters for conn statistics. */
+void
+rep_hist_reset_conn_stats(time_t now)
+{
+ start_of_conn_stats_interval = now;
+ below_threshold = 0;
+ mostly_read = 0;
+ mostly_written = 0;
+ both_read_and_written = 0;
+ bidi_map_free();
+}
+
+/** Stop collecting connection stats in a way that we can re-start doing
+ * so in rep_hist_conn_stats_init(). */
+void
+rep_hist_conn_stats_term(void)
+{
+ rep_hist_reset_conn_stats(0);
+}
+
+/** We read <b>num_read</b> bytes and wrote <b>num_written</b> from/to OR
+ * connection <b>conn_id</b> in second <b>when</b>. If this is the first
+ * observation in a new interval, sum up the last observations. Add bytes
+ * for this connection. */
+void
+rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
+ size_t num_written, time_t when)
+{
+ if (!start_of_conn_stats_interval)
+ return;
+ /* Initialize */
+ if (bidi_next_interval == 0)
+ bidi_next_interval = when + BIDI_INTERVAL;
+ /* Sum up last period's statistics */
+ if (when >= bidi_next_interval) {
+ bidi_map_entry_t **ptr, **next, *ent;
+ for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
+ ent = *ptr;
+ if (ent->read + ent->written < BIDI_THRESHOLD)
+ below_threshold++;
+ else if (ent->read >= ent->written * BIDI_FACTOR)
+ mostly_read++;
+ else if (ent->written >= ent->read * BIDI_FACTOR)
+ mostly_written++;
+ else
+ both_read_and_written++;
+ next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
+ tor_free(ent);
+ }
+ while (when >= bidi_next_interval)
+ bidi_next_interval += BIDI_INTERVAL;
+ log_info(LD_GENERAL, "%d below threshold, %d mostly read, "
+ "%d mostly written, %d both read and written.",
+ below_threshold, mostly_read, mostly_written,
+ both_read_and_written);
+ }
+ /* Add this connection's bytes. */
+ if (num_read > 0 || num_written > 0) {
+ bidi_map_entry_t *entry, lookup;
+ lookup.conn_id = conn_id;
+ entry = HT_FIND(bidimap, &bidi_map, &lookup);
+ if (entry) {
+ entry->written += num_written;
+ entry->read += num_read;
+ } else {
+ entry = tor_malloc_zero(sizeof(bidi_map_entry_t));
+ entry->conn_id = conn_id;
+ entry->written = num_written;
+ entry->read = num_read;
+ HT_INSERT(bidimap, &bidi_map, entry);
+ }
+ }
+}
+
+/** Return a newly allocated string containing the connection statistics
+ * until <b>now</b>, or NULL if we're not collecting conn stats. */
+char *
+rep_hist_format_conn_stats(time_t now)
+{
+ char *result, written[ISO_TIME_LEN+1];
+
+ if (!start_of_conn_stats_interval)
+ return NULL; /* Not initialized. */
+
+ format_iso_time(written, now);
+ tor_asprintf(&result, "conn-bi-direct %s (%d s) %d,%d,%d,%d\n",
+ written,
+ (unsigned) (now - start_of_conn_stats_interval),
+ below_threshold,
+ mostly_read,
+ mostly_written,
+ both_read_and_written);
+ return result;
+}
+
+/** If 24 hours have passed since the beginning of the current conn stats
+ * period, write conn stats to $DATADIR/stats/conn-stats (possibly
+ * overwriting an existing file) and reset counters. Return when we would
+ * next want to write conn stats or 0 if we never want to write. */
+time_t
+rep_hist_conn_stats_write(time_t now)
+{
+ char *statsdir = NULL, *filename = NULL, *str = NULL;
+
+ if (!start_of_conn_stats_interval)
+ return 0; /* Not initialized. */
+ if (start_of_conn_stats_interval + WRITE_STATS_INTERVAL > now)
+ goto done; /* Not ready to write */
+
+ /* Generate history string. */
+ str = rep_hist_format_conn_stats(now);
+
+ /* Reset counters. */
+ rep_hist_reset_conn_stats(now);
+
+ /* Try to write to disk. */
+ statsdir = get_datadir_fname("stats");
+ if (check_private_dir(statsdir, CPD_CREATE) < 0) {
+ log_warn(LD_HIST, "Unable to create stats/ directory!");
+ goto done;
+ }
+ filename = get_datadir_fname2("stats", "conn-stats");
+ if (write_str_to_file(filename, str, 0) < 0)
+ log_warn(LD_HIST, "Unable to write conn stats to disk!");
+
+ done:
+ tor_free(str);
+ tor_free(filename);
+ tor_free(statsdir);
+ return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
+}
+
/** Free all storage held by the OR/link history caches, by the
* bandwidth history arrays, by the port history, or by statistics . */
void
@@@ -2735,6 -2539,5 +2749,6 @@@ rep_hist_free_all(void
tor_free(exit_streams);
built_last_stability_doc_at = 0;
predicted_ports_free();
+ bidi_map_free();
}
diff --combined src/or/rephist.h
index cb70e15,b06a39e..5748748
--- a/src/or/rephist.h
+++ b/src/or/rephist.h
@@@ -40,6 -40,7 +40,7 @@@ int rep_hist_record_mtbf_data(time_t no
int rep_hist_load_mtbf_data(time_t now);
time_t rep_hist_downrate_old_runs(time_t now);
+ long rep_hist_get_uptime(const char *id, time_t when);
double rep_hist_get_stability(const char *id, time_t when);
double rep_hist_get_weighted_fractional_uptime(const char *id, time_t when);
long rep_hist_get_weighted_time_known(const char *id, time_t when);
@@@ -77,13 -78,5 +78,13 @@@ void rep_hist_buffer_stats_add_circ(cir
time_t rep_hist_buffer_stats_write(time_t now);
void rep_hist_buffer_stats_term(void);
+void rep_hist_conn_stats_init(time_t now);
+void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
+ size_t num_written, time_t when);
+void rep_hist_reset_conn_stats(time_t now);
+char *rep_hist_format_conn_stats(time_t now);
+time_t rep_hist_conn_stats_write(time_t now);
+void rep_hist_conn_stats_term(void);
+
#endif
1
0

12 Mar '11
commit 2f8e96b5535481e157486944c8d7637f31e1a197
Author: Sebastian Hahn <sebastian(a)torproject.org>
Date: Mon Mar 7 00:03:09 2011 +0100
Fix log message when we have too few dirauths
The calculation of when to send the logmessage was correct, but we
didn't give the correct number of relays required: We want more than
half of all authorities we know about. Fixes bug 2663.
---
src/or/dirvote.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 529b45c..9273dbc 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -3080,7 +3080,7 @@ dirvote_compute_consensuses(void)
n_votes = smartlist_len(pending_vote_list);
if (n_votes <= n_voters/2) {
log_warn(LD_DIR, "We don't have enough votes to generate a consensus: "
- "%d of %d", n_votes, n_voters/2);
+ "%d of %d", n_votes, n_voters/2+1);
goto err;
}
tor_assert(pending_vote_list);
1
0