tor-commits
Threads by month
- ----- 2025 -----
- 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
March 2011
- 18 participants
- 683 discussions

[metrics-web/master] Add bridge pool assignments to metrics website.
by karsten@torproject.org 14 Mar '11
by karsten@torproject.org 14 Mar '11
14 Mar '11
commit 117a75e2ccc2f4a7215619367a8ab154e47788d1
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Mon Mar 14 12:25:48 2011 +0100
Add bridge pool assignments to metrics website.
---
.../torproject/ernie/web/ResearchDataServlet.java | 19 +++++++++++++++++
web/WEB-INF/data.jsp | 22 ++++++++++++++++++++
web/WEB-INF/index.jsp | 15 +++++--------
3 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/src/org/torproject/ernie/web/ResearchDataServlet.java b/src/org/torproject/ernie/web/ResearchDataServlet.java
index 2d45c0f..ca6bf7b 100644
--- a/src/org/torproject/ernie/web/ResearchDataServlet.java
+++ b/src/org/torproject/ernie/web/ResearchDataServlet.java
@@ -75,6 +75,8 @@ public class ResearchDataServlet extends HttpServlet {
SortedMap<String, Map<String, String[]>> torperfData =
new TreeMap<String, Map<String, String[]>>();
SortedMap<Date, String[]> exitLists = new TreeMap<Date, String[]>();
+ SortedMap<Date, String[]> bridgePoolAssignments =
+ new TreeMap<Date, String[]>();
/* Prepare rewriting Torperf sources. */
Map<String, String> torperfSources = new HashMap<String, String>();
@@ -207,6 +209,22 @@ public class ResearchDataServlet extends HttpServlet {
exitLists.put(month, new String[2]);
}
exitLists.get(month)[0] = url;
+
+ /* URL contains bridge pool assignments. */
+ } else if (filename.startsWith("bridge-pool-assignments-20")) {
+ String yearMonth = filename.substring(filename.indexOf("20"));
+ yearMonth = yearMonth.substring(0, 7);
+ Date month = null;
+ try {
+ month = monthFormat.parse(yearMonth);
+ } catch (ParseException e) {
+ /* Ignore this URL. */
+ continue;
+ }
+ if (!bridgePoolAssignments.containsKey(month)) {
+ bridgePoolAssignments.put(month, new String[2]);
+ }
+ bridgePoolAssignments.get(month)[0] = url;
}
}
@@ -217,6 +235,7 @@ public class ResearchDataServlet extends HttpServlet {
request.setAttribute("relayStatistics", relayStatistics);
request.setAttribute("torperfData", torperfData);
request.setAttribute("exitLists", exitLists);
+ request.setAttribute("bridgePoolAssignments", bridgePoolAssignments);
request.getRequestDispatcher("WEB-INF/data.jsp").forward(request,
response);
}
diff --git a/web/WEB-INF/data.jsp b/web/WEB-INF/data.jsp
index 86028c2..30d42f6 100644
--- a/web/WEB-INF/data.jsp
+++ b/web/WEB-INF/data.jsp
@@ -1,5 +1,6 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<fmt:setLocale value="en_US"/>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
@@ -26,6 +27,7 @@
<ul>
<li><a href="#relaydesc">Relay descriptor archives</a></li>
<li><a href="#bridgedesc">Bridge descriptor archives</a></li>
+ <li><a href="#bridgeassignments">Bridge pool assignments</a></li>
<li><a href="#stats">Statistics produced by relays</a></li>
<li><a href="#performance">Performance data</a></li>
<li><a href="#exitlist">Exit lists</a></li>
@@ -124,6 +126,26 @@
</table>
<p></p>
<br>
+ <a name="bridgeassignments"></a>
+ <h3>Bridge pool assignments</h3>
+ <br>
+ <p>BridgeDB periodically dumps the list of running bridges with
+ information about the rings, subrings, and file buckets to which
+ they are assigned to a local file. We are archiving sanitized
+ versions of these files here to analyze how the pool assignment
+ affects a bridge's usage.</p>
+ <table width="100%" border="0" cellpadding="5" cellspacing="0" summary="">
+ <c:forEach var="item" items="${bridgePoolAssignments}" >
+ <fmt:formatDate var="longDate" pattern="MMMM yyyy"
+ value="${item.key}"/>
+ <tr>
+ <td>
+ <a href="${item.value[0]}">${longDate}</a>
+ </td>
+ </tr>
+ </c:forEach>
+ </table>
+ <br>
<a name="stats"></a>
<h3>Statistics produced by relays</h3>
<br>
diff --git a/web/WEB-INF/index.jsp b/web/WEB-INF/index.jsp
index f82a7b3..0da160b 100644
--- a/web/WEB-INF/index.jsp
+++ b/web/WEB-INF/index.jsp
@@ -32,6 +32,11 @@
<br>
<h3>News</h3>
<ul>
+ <li>March 14, 2011:
+ <a href="data.html#bridgeassignments">Sanitized bridge pool
+ assignments</a> containing lists of running bridges with
+ information about the rings, subrings, and file buckets to which
+ they are assigned are now available.</li>
<li>January 27, 2011: New <a href="performance.html">Torperf</a>
graphs combining the download times of all sources and showing
the fraction of timeouts and failures are now available.</li>
@@ -45,15 +50,7 @@
<li>November 30, 2010: Tech report on
<a href="papers/countingusers-2010-11-30.pdf">Privacy-preserving
Ways to Estimate the Number of Tor Users</a> is available for
- download on the <a href="papers.html">Papers</a> page.
- <li>October 7, 2010: Custom graphs are now available for all
- <a href="graphs.html">graphs</a>. Based on work by Kevin
- Berry.</li>
- <li>September 9, 2010: Custom
- graphs on network size, relay platforms, versions, and
- observed bandwidth available. Implemented by Kevin Berry.</li>
- <li>September 2, 2010: New <a href="relay-search.html">relay
- search</a> feature available.</li>
+ download on the <a href="papers.html">Papers</a> page.</li>
</ul>
</div>
</div>
1
0

14 Mar '11
commit 01d8d919512d8dfe3df3440e5dec0bccb2942baa
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Mon Mar 14 10:54:59 2011 +0100
Sanitize bridge pool assignments.
---
config.template | 11 ++
.../ernie/db/BridgePoolAssignmentsProcessor.java | 128 ++++++++++++++++++++
src/org/torproject/ernie/db/Configuration.java | 23 +++-
src/org/torproject/ernie/db/Main.java | 7 +
4 files changed, 167 insertions(+), 2 deletions(-)
diff --git a/config.template b/config.template
index 0d6743e..47a8c8d 100644
--- a/config.template
+++ b/config.template
@@ -44,6 +44,13 @@
## Download exit list and store it to disk
#DownloadExitList 0
#
+## Process bridge pool assignment files by sanitizing bridge fingerprints
+## and sorting sanitized files into subdirectories
+#ProcessBridgePoolAssignments 0
+#
+## Relative path to directory to read bridge pool assignment files from
+#AssignmentsDirectory assignments/
+#
#### Data sinks ####
#
## Write directory archives to disk
@@ -66,4 +73,8 @@
#
## Relative path to directory to write sanitized bridges to
#SanitizedBridgesWriteDirectory sanitized-bridges/
+#
+## Relative path to directory to write sanitized bridge pool assignment
+## files to
+#SanitizedAssignmentsDirectory sanitized-assignments/
diff --git a/src/org/torproject/ernie/db/BridgePoolAssignmentsProcessor.java b/src/org/torproject/ernie/db/BridgePoolAssignmentsProcessor.java
new file mode 100644
index 0000000..583d36e
--- /dev/null
+++ b/src/org/torproject/ernie/db/BridgePoolAssignmentsProcessor.java
@@ -0,0 +1,128 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.ernie.db;
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import java.util.logging.*;
+import org.apache.commons.codec.*;
+import org.apache.commons.codec.binary.*;
+import org.apache.commons.codec.digest.*;
+
+public class BridgePoolAssignmentsProcessor {
+
+ public BridgePoolAssignmentsProcessor(File assignmentsDirectory,
+ File sanitizedAssignmentsDirectory) {
+
+ Logger logger =
+ Logger.getLogger(BridgePoolAssignmentsProcessor.class.getName());
+ if (assignmentsDirectory == null ||
+ sanitizedAssignmentsDirectory == null) {
+ IllegalArgumentException e = new IllegalArgumentException("Neither "
+ + "assignmentsDirectory nor sanitizedAssignmentsDirectory may "
+ + "be null!");
+ throw e;
+ }
+
+ List<File> assignmentFiles = new ArrayList<File>();
+ Stack<File> files = new Stack<File>();
+ files.add(assignmentsDirectory);
+ while (!files.isEmpty()) {
+ File file = files.pop();
+ if (file.isDirectory()) {
+ files.addAll(Arrays.asList(file.listFiles()));
+ } else {
+ assignmentFiles.add(file);
+ }
+ }
+
+ SimpleDateFormat assignmentFormat =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ assignmentFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ SimpleDateFormat filenameFormat =
+ new SimpleDateFormat("yyyy/MM/dd/yyyy-MM-dd-HH-mm-ss");
+ filenameFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ for (File assignmentFile : assignmentFiles) {
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(
+ assignmentFile));
+ String line, bridgePoolAssignmentLine = null;
+ SortedSet<String> sanitizedAssignments = new TreeSet<String>();
+ boolean wroteLastLine = false;
+ while ((line = br.readLine()) != null || !wroteLastLine) {
+ if (line == null ||
+ line.startsWith("bridge-pool-assignment ")) {
+ if (bridgePoolAssignmentLine != null) {
+ try {
+ long bridgePoolAssignmentTime = assignmentFormat.parse(
+ bridgePoolAssignmentLine.substring(
+ "bridge-pool-assignment ".length())).getTime();
+ File sanitizedAssignmentsFile = new File(
+ sanitizedAssignmentsDirectory, filenameFormat.format(
+ bridgePoolAssignmentTime));
+ if (!sanitizedAssignmentsFile.exists()) {
+ sanitizedAssignmentsFile.getParentFile().mkdirs();
+ BufferedWriter bw = new BufferedWriter(new FileWriter(
+ sanitizedAssignmentsFile));
+ bw.write(bridgePoolAssignmentLine + "\n");
+ for (String assignmentLine : sanitizedAssignments) {
+ bw.write(assignmentLine + "\n");
+ }
+ bw.close();
+ }
+ } catch (IOException e) {
+ logger.log(Level.WARNING, "Could not write sanitized "
+ + "bridge pool assignment file for line '"
+ + bridgePoolAssignmentLine + "' to disk. Skipping "
+ + "bridge pool assignment file '"
+ + assignmentFile.getAbsolutePath() + "'.", e);
+ break;
+ } catch (ParseException e) {
+ logger.log(Level.WARNING, "Could not write sanitized "
+ + "bridge pool assignment file for line '"
+ + bridgePoolAssignmentLine + "' to disk. Skipping "
+ + "bridge pool assignment file '"
+ + assignmentFile.getAbsolutePath() + "'.", e);
+ break;
+ }
+ sanitizedAssignments.clear();
+ }
+ if (line == null) {
+ wroteLastLine = true;
+ } else {
+ bridgePoolAssignmentLine = line;
+ }
+ } else {
+ String[] parts = line.split(" ");
+ if (parts.length < 2 || parts[0].length() < 40) {
+ logger.warning("Unrecognized line '" + line
+ + "'. Skipping.");
+ continue;
+ }
+ String hashedFingerprint = null;
+ try {
+ hashedFingerprint = DigestUtils.shaHex(Hex.decodeHex(
+ line.split(" ")[0].toCharArray())).toLowerCase();
+ } catch (DecoderException e) {
+ logger.warning("Unable to decode hex fingerprint in line '"
+ + line + "'. Skipping.");
+ continue;
+ }
+ String assignmentDetails = line.substring(40);
+ sanitizedAssignments.add(hashedFingerprint
+ + assignmentDetails);
+ }
+ }
+ br.close();
+ } catch (IOException e) {
+ logger.log(Level.WARNING, "Could not read bridge pool assignment "
+ + "file '" + assignmentFile.getAbsolutePath()
+ + "'. Skipping.", e);
+ }
+ }
+
+ logger.info("Finished processing bridge pool assignment file(s).");
+ }
+}
+
diff --git a/src/org/torproject/ernie/db/Configuration.java b/src/org/torproject/ernie/db/Configuration.java
index c1cdbea..ae24175 100644
--- a/src/org/torproject/ernie/db/Configuration.java
+++ b/src/org/torproject/ernie/db/Configuration.java
@@ -37,6 +37,9 @@ public class Configuration {
+ "~gettor/gettor_stats.txt";
private String getTorDirectory = "gettor/";
private boolean downloadExitList = false;
+ private boolean processBridgePoolAssignments = false;
+ private String assignmentsDirectory = "assignments/";
+ private String sanitizedAssignmentsDirectory = "sanitized-assignments/";
public Configuration() {
/* Initialize logger. */
@@ -127,6 +130,13 @@ public class Configuration {
} else if (line.startsWith("DownloadExitList")) {
this.downloadExitList = Integer.parseInt(
line.split(" ")[1]) != 0;
+ } else if (line.startsWith("ProcessBridgePoolAssignments")) {
+ this.processBridgePoolAssignments = Integer.parseInt(
+ line.split(" ")[1]) != 0;
+ } else if (line.startsWith("AssignmentsDirectory")) {
+ this.assignmentsDirectory = line.split(" ")[1];
+ } else if (line.startsWith("SanitizedAssignmentsDirectory")) {
+ this.sanitizedAssignmentsDirectory = line.split(" ")[1];
} else {
logger.severe("Configuration file contains unrecognized "
+ "configuration key in line '" + line + "'! Exiting!");
@@ -156,8 +166,8 @@ public class Configuration {
if (!this.importCachedRelayDescriptors &&
!this.importDirectoryArchives && !this.downloadRelayDescriptors &&
!this.importBridgeSnapshots && !this.downloadGetTorStats &&
- !this.downloadExitList && !this.writeDirectoryArchives &&
- !this.writeSanitizedBridges) {
+ !this.downloadExitList && !this.processBridgePoolAssignments &&
+ !this.writeDirectoryArchives && !this.writeSanitizedBridges) {
logger.warning("We have not been configured to read data from any "
+ "data source or write data to any data sink. You need to "
+ "edit your config file (" + configFile.getAbsolutePath()
@@ -246,5 +256,14 @@ public class Configuration {
public boolean getDownloadExitList() {
return this.downloadExitList;
}
+ public boolean getProcessBridgePoolAssignments() {
+ return processBridgePoolAssignments;
+ }
+ public String getAssignmentsDirectory() {
+ return assignmentsDirectory;
+ }
+ public String getSanitizedAssignmentsDirectory() {
+ return sanitizedAssignmentsDirectory;
+ }
}
diff --git a/src/org/torproject/ernie/db/Main.java b/src/org/torproject/ernie/db/Main.java
index 657cdfc..50c06bb 100644
--- a/src/org/torproject/ernie/db/Main.java
+++ b/src/org/torproject/ernie/db/Main.java
@@ -128,6 +128,13 @@ public class Main {
new ExitListDownloader();
}
+ // Process bridge pool assignments
+ if (config.getProcessBridgePoolAssignments()) {
+ new BridgePoolAssignmentsProcessor(
+ new File(config.getAssignmentsDirectory()),
+ new File(config.getSanitizedAssignmentsDirectory()));
+ }
+
// Remove lock file
lf.releaseLock();
1
0

r24351: {arm} Inbound connections are only private if it doesn't match any (arm/trunk/src/interface/connections)
by Damian Johnson 13 Mar '11
by Damian Johnson 13 Mar '11
13 Mar '11
Author: atagar
Date: 2011-03-13 21:24:23 +0000 (Sun, 13 Mar 2011)
New Revision: 24351
Modified:
arm/trunk/src/interface/connections/connEntry.py
Log:
Inbound connections are only private if it doesn't match any relays (not if it can't be resolved due to duplicates)
Modified: arm/trunk/src/interface/connections/connEntry.py
===================================================================
--- arm/trunk/src/interface/connections/connEntry.py 2011-03-13 19:11:09 UTC (rev 24350)
+++ arm/trunk/src/interface/connections/connEntry.py 2011-03-13 21:24:23 UTC (rev 24351)
@@ -299,7 +299,9 @@
# if the connection doesn't belong to a known relay then it might be
# client traffic
- return self.foreign.getFingerprint() == "UNKNOWN"
+ conn = torTools.getConn()
+ allMatches = conn.getRelayFingerprint(self.foreign.getIpAddr(), getAllMatches = True)
+ return allMatches == []
elif myType == Category.EXIT:
# DNS connections exiting us aren't private (since they're hitting our
# resolvers). Everything else, however, is.
1
0

r24350: {website} make (broken) arabic pages, so when phobos repushes the webs (website/trunk)
by Roger Dingledine 13 Mar '11
by Roger Dingledine 13 Mar '11
13 Mar '11
Author: arma
Date: 2011-03-13 19:11:09 +0000 (Sun, 13 Mar 2011)
New Revision: 24350
Modified:
website/trunk/Makefile.common
Log:
make (broken) arabic pages, so when phobos repushes the website
he won't erase about/overview.html.ar
Modified: website/trunk/Makefile.common
===================================================================
--- website/trunk/Makefile.common 2011-03-13 04:58:18 UTC (rev 24349)
+++ website/trunk/Makefile.common 2011-03-13 19:11:09 UTC (rev 24350)
@@ -18,7 +18,7 @@
-D STABLETAG=$(STABLETAG)
#LANGS=ar bms de en es et fa it fi fr ja ko nl no pl pt ru se tr zh-cn
-LANGS=en es fr ru
+LANGS=en ar es fr ru
WMLFILES=$(wildcard $(patsubst %, %/*.wml, $(LANGS)))
WMIFILES=$(wildcard $(patsubst %, %/*.wmi, $(LANGS)) $(WMLBASE)/include/*.wmi )
1
0

[metrics-tasks/master] Add code to turn BridgeDB logs into assignment.log files.
by karsten@torproject.org 13 Mar '11
by karsten@torproject.org 13 Mar '11
13 Mar '11
commit e1ece10fe3629d9a7268780f77ff4b0653ff72a6
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Sun Mar 13 18:43:24 2011 +0100
Add code to turn BridgeDB logs into assignment.log files.
---
task-2537/.gitignore | 4 +
task-2537/BridgeDBLogConverter.java | 136 +++++++++++++++++++++++++++++++++++
task-2537/README | 15 ++++
3 files changed, 155 insertions(+), 0 deletions(-)
diff --git a/task-2537/.gitignore b/task-2537/.gitignore
new file mode 100644
index 0000000..d169b51
--- /dev/null
+++ b/task-2537/.gitignore
@@ -0,0 +1,4 @@
+*.log
+*.class
+*.swp
+
diff --git a/task-2537/BridgeDBLogConverter.java b/task-2537/BridgeDBLogConverter.java
new file mode 100644
index 0000000..5a8d69c
--- /dev/null
+++ b/task-2537/BridgeDBLogConverter.java
@@ -0,0 +1,136 @@
+import java.io.*;
+import java.text.*;
+import java.util.*;
+
+public class BridgeDBLogConverter {
+ public static void main(String[] args) throws Exception {
+ if (args.length != 3) {
+ System.out.println("Usage: java BridgeDBLogConverter logfile year "
+ + "outfile");
+ System.exit(1);
+ }
+ File logfile = new File(args[0]), outfile = new File(args[2]);
+ String year = args[1];
+ SimpleDateFormat logFormat = new SimpleDateFormat(
+ "yyyy MMM dd HH:mm:ss");
+ SimpleDateFormat isoFormat = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");
+ SimpleDateFormat fileFormat = new SimpleDateFormat(
+ "yyyy/MM/dd/yyyy-MM-dd-HH-mm-ss");
+ logFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ fileFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ BufferedReader br = new BufferedReader(new FileReader(logfile));
+ BufferedWriter bw = new BufferedWriter(new FileWriter(outfile));
+ String line;
+ SortedMap<String, String> entries = new TreeMap<String, String>();
+ long lastTimestamp = -1L;
+ String fingerprint = null, lastFingerprint = null, type = null,
+ port = "", flag = "";
+ while ((line = br.readLine()) != null) {
+ long timestamp = logFormat.parse(year + " "
+ + line.substring(0, 15)).getTime();
+ if (timestamp > lastTimestamp + 10L * 60L * 1000L) {
+ if (lastTimestamp > 0L) {
+ bw.write("bridge-pool-assignment "
+ + isoFormat.format(lastTimestamp) + "\n");
+ for (String entry : entries.values()) {
+ bw.write(entry + "\n");
+ }
+ entries.clear();
+ }
+ }
+ lastTimestamp = timestamp;
+ String[] parts = line.split(" ");
+ fingerprint = parts[7];
+ String assignment = line.substring(line.indexOf(parts[7]) + 41);
+ if (!fingerprint.equals(lastFingerprint)) {
+ if (lastFingerprint != null) {
+ entries.put(lastFingerprint, lastFingerprint + " " + type
+ + port + flag);
+ }
+ type = null;
+ port = "";
+ flag = "";
+ }
+ if (assignment.startsWith("to IP ")) {
+ int ring = -1;
+ if (assignment.startsWith("to IP category ring")) {
+ ring = 4; // TODO This is fragile!
+ } else {
+ ring = Integer.parseInt(assignment.split(" ")[3]) - 1;
+ }
+ String newType = "https ring=" + ring;
+ if (type != null && !type.equals(newType)) {
+ System.out.println("type inconsistency in line '" + line + "'");
+ System.exit(1);
+ }
+ type = newType;
+ if (assignment.endsWith(" (port-443 subring)")) {
+ String newPort = " port=443";
+ if (port.length() > 0 && !port.equals(newPort)) {
+ System.out.println("port inconsistency in line '" + line
+ + "'");
+ System.exit(1);
+ }
+ port = newPort;
+ } else if (assignment.endsWith(" (stable subring)")) {
+ String newFlag = " flag=stable";
+ if (flag.length() > 0 && !flag.equals(newFlag)) {
+ System.out.println("flag inconsistency in line '" + line
+ + "'");
+ System.exit(1);
+ }
+ flag = newFlag;
+ }
+ } else if (assignment.equals("to email ring")) {
+ String newType = "email";
+ if (type != null && !type.equals(newType)) {
+ System.out.println("type inconsistency in line '" + line + "'");
+ System.exit(1);
+ }
+ type = newType;
+ } else if (assignment.startsWith("to Ring ")) {
+ String newType = "email";
+ if (type != null && !type.equals(newType)) {
+ System.out.println("type inconsistency in line '" + line + "'");
+ System.exit(1);
+ }
+ type = newType;
+ if (assignment.equals("to Ring (port-443 subring)")) {
+ String newPort = " port=443";
+ if (port.length() > 0 && !port.equals(newPort)) {
+ System.out.println("port inconsistency in line '" + line
+ + "'");
+ System.exit(1);
+ }
+ port = newPort;
+ } else if (assignment.equals("to Ring (stable subring)")) {
+ String newFlag = " flag=stable";
+ if (flag.length() > 0 && !flag.equals(newFlag)) {
+ System.out.println("flag inconsistency in line '" + line
+ + "'");
+ System.exit(1);
+ }
+ flag = newFlag;
+ } else {
+ System.out.println("type inconsistency in line '" + line
+ + "'");
+ System.exit(1);
+ }
+ } else {
+ type = "unallocated";
+ }
+ lastFingerprint = fingerprint;
+ }
+ if (lastTimestamp > 0L) {
+ bw.write("bridge-pool-assignment "
+ + isoFormat.format(lastTimestamp) + "\n");
+ for (String entry : entries.values()) {
+ bw.write(entry + "\n");
+ }
+ }
+ bw.close();
+ }
+}
+
diff --git a/task-2537/README b/task-2537/README
new file mode 100644
index 0000000..1d5375f
--- /dev/null
+++ b/task-2537/README
@@ -0,0 +1,15 @@
+BridgeDBLogConverter.java
+
+The BridgeDBLogConverter takes BridgeDB's logs as input and writes
+(non-sanitized) bridge pool assignments to disk as output.
+
+ - Compile the Java class, e.g.,
+ $ javac BridgeDBLogConverter.java
+
+ - If your bridgedb.log file contains log lines from more than one
+ calendar year, split it into as many log files as necessary to ensure
+ that each file only contains log lines from a single calendar year!
+
+ - Run the Java class, e.g.,
+ $ java BridgeDBLogConverter bridgedb.log 2011 assignments.log
+
1
0

[bridgedb/master] Dump bridge pool assignments to a file for statistics.
by karsten@torproject.org 13 Mar '11
by karsten@torproject.org 13 Mar '11
13 Mar '11
commit 4d00328af81cfe6606c57cf01241c770bd5559d5
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Wed Mar 9 15:17:45 2011 +0100
Dump bridge pool assignments to a file for statistics.
With this patch we dump the list of currently running bridges with
information about their assigned rings, subrings, and file buckets to a
local file. The idea is to publish sanitized versions of these assignment
files and analyze how the assignment affects a bridge's usage.
The assignment file is written on startup and after receiving a HUP signal
and parsing new bridge descriptors. Note that the assignments file is not
updated when bridges are dumped to file buckets; in that case the changed
assignments to file buckets will be reflected in the assignments file
after the next HUP.
Also note that the assignment file only contains bridges that are believed
to be running from parsing the last network status. As a result, bridges
that are contained in file buckets, but that are not believed to be
running, won't be contained in the assignment file.
---
bridgedb.conf | 3 +++
lib/bridgedb/Bridges.py | 43 ++++++++++++++++++++++++++++++++++++++++++-
lib/bridgedb/Dist.py | 6 ++++++
lib/bridgedb/Main.py | 18 ++++++++++++++++--
4 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/bridgedb.conf b/bridgedb.conf
index 44422a7..e486e0a 100644
--- a/bridgedb.conf
+++ b/bridgedb.conf
@@ -30,6 +30,9 @@ DB_LOG_FILE = "./bridgedist.log"
# File in which we store our secret HMAC root key.
MASTER_KEY_FILE = "./secret_key"
+# File to which we dump bridge pool assignments for statistics.
+ASSIGNMENTS_FILE = "assignments.log"
+
# How many clusters do we group IPs in when distributing bridges based on IP?
# Note that if PROXY_LIST_FILES is set (below), what we actually do here
# is use one higher than the number here, and the extra cluster is used
diff --git a/lib/bridgedb/Bridges.py b/lib/bridgedb/Bridges.py
index 67db9af..eca6db5 100644
--- a/lib/bridgedb/Bridges.py
+++ b/lib/bridgedb/Bridges.py
@@ -211,6 +211,9 @@ class BridgeHolder:
def assignmentsArePersistent(self):
return True
+ def dumpAssignments(self, f, description=""):
+ pass
+
class BridgeRingParameters:
"""DOCDOC"""
def __init__(self, needPorts=(), needFlags=()):
@@ -349,6 +352,15 @@ class BridgeRing(BridgeHolder):
return self.bridgesByID.get(fp)
+ def dumpAssignments(self, f, description=""):
+ for b in self.bridges.itervalues():
+ desc = [ description ]
+ ident = b.getID()
+ for tp,val,_,subring in self.subrings:
+ if subring.getBridgeByID(ident):
+ desc.append("%s=%s"%(tp,val))
+ f.write("%s %s\n"%( toHex(ident), " ".join(desc).strip()))
+
class FixedBridgeSplitter(BridgeHolder):
"""A bridgeholder that splits bridges up based on an hmac and assigns
them to several sub-bridgeholders with equal probability.
@@ -376,19 +388,45 @@ class FixedBridgeSplitter(BridgeHolder):
n += len(r)
return n
+ def dumpAssignments(self, f, description=""):
+ for i,r in zip(xrange(len(self.rings)), self.rings):
+ r.dumpAssignments(f, "%s ring=%s" % (description, i))
class UnallocatedHolder(BridgeHolder):
"""A pseudo-bridgeholder that ignores its bridges and leaves them
unassigned.
"""
+ def __init__(self):
+ self.fingerprints = []
+
def insert(self, bridge):
logging.debug("Leaving %s unallocated", bridge.getConfigLine(True))
+ if not bridge.fingerprint in self.fingerprints:
+ self.fingerprints.append(bridge.fingerprint)
def assignmentsArePersistent(self):
return False
def __len__(self):
- return 0
+ return len(self.fingerprints)
+
+ def clear(self):
+ self.fingerprints = []
+
+ def dumpAssignments(self, f, description=""):
+ db = bridgedb.Storage.getDB()
+ allBridges = db.getAllBridges()
+ for bridge in allBridges:
+ if bridge.hex_key not in self.fingerprints:
+ continue
+ dist = bridge.distributor
+ desc = [ description ]
+ if dist.startswith(bridgedb.Bucket.PSEUDO_DISTRI_PREFIX):
+ dist = dist.replace(bridgedb.Bucket.PSEUDO_DISTRI_PREFIX, "")
+ desc.append("bucket=%s" % dist)
+ elif dist != "unallocated":
+ continue
+ f.write("%s %s\n" % (bridge.hex_key, " ".join(desc).strip()))
class BridgeSplitter(BridgeHolder):
"""A BridgeHolder that splits incoming bridges up based on an hmac,
@@ -470,3 +508,6 @@ class BridgeSplitter(BridgeHolder):
ring = self.ringsByName.get(ringname)
ring.insert(bridge)
+ def dumpAssignments(self, f, description=""):
+ for name,ring in self.ringsByName.iteritems():
+ ring.dumpAssignments(f, "%s %s" % (description, name))
diff --git a/lib/bridgedb/Dist.py b/lib/bridgedb/Dist.py
index 53fdda0..e11d21e 100644
--- a/lib/bridgedb/Dist.py
+++ b/lib/bridgedb/Dist.py
@@ -112,6 +112,9 @@ class IPBasedDistributor(bridgedb.Bridges.BridgeHolder):
def __len__(self):
return sum(len(r) for r in self.rings)
+ def dumpAssignments(self, f, description=""):
+ self.splitter.dumpAssignments(f, description)
+
# These characters are the ones that RFC2822 allows.
#ASPECIAL = '!#$%&*+-/=?^_`{|}~'
#ASPECIAL += "\\\'"
@@ -282,3 +285,6 @@ class EmailBasedDistributor(bridgedb.Bridges.BridgeHolder):
else:
db.commit()
+ def dumpAssignments(self, f, description=""):
+ self.ring.dumpAssignments(f, description)
+
diff --git a/lib/bridgedb/Main.py b/lib/bridgedb/Main.py
index 82181b8..99d43b6 100644
--- a/lib/bridgedb/Main.py
+++ b/lib/bridgedb/Main.py
@@ -9,6 +9,7 @@ This module sets up a bridgedb and starts the servers running.
import os
import signal
import sys
+import time
import logging
import gettext
@@ -57,6 +58,8 @@ CONFIG = Conf(
N_IP_CLUSTERS = 4,
MASTER_KEY_FILE = "./secret_key",
+ ASSIGNMENTS_FILE = "assignments.log",
+
FORCE_PORTS = [(443, 1)],
FORCE_FLAGS = [("Stable", 1)],
PROXY_LIST_FILES = [ ],
@@ -197,8 +200,9 @@ def startup(cfg):
# Expand any ~ characters in paths in the configuration.
cfg.BRIDGE_FILES = [ os.path.expanduser(fn) for fn in cfg.BRIDGE_FILES ]
for key in ("RUN_IN_DIR", "DB_FILE", "DB_LOG_FILE", "MASTER_KEY_FILE",
- "HTTPS_CERT_FILE", "HTTPS_KEY_FILE", "PIDFILE", "LOGFILE",
- "STATUS_FILE"):
+ "ASSIGNMENTS_FILE", "HTTPS_CERT_FILE", "HTTPS_KEY_FILE",
+ "PIDFILE", "LOGFILE", "STATUS_FILE"):
+
v = getattr(cfg, key, None)
if v:
setattr(cfg, key, os.path.expanduser(v))
@@ -299,6 +303,16 @@ def startup(cfg):
for name, b in r.bridges.items():
logging.info("%s" % b.getConfigLine(True))
+ # Dump bridge pool assignments to disk.
+ try:
+ f = open(cfg.ASSIGNMENTS_FILE, 'a')
+ f.write("bridge-pool-assignment %s\n" %
+ time.strftime("%Y-%m-%d %H:%M:%S"))
+ splitter.dumpAssignments(f)
+ f.close()
+ except IOError:
+ logging.info("I/O error while writing assignments")
+
global _reloadFn
_reloadFn = reload
signal.signal(signal.SIGHUP, _handleSIGHUP)
1
0
commit 128063053f21ddde0f8c3dbc61a4890bef06618e
Merge: daa394e 4d00328
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Sun Mar 13 11:35:55 2011 +0100
Merge branch 'dump-rebased'
bridgedb.conf | 3 +++
lib/bridgedb/Bridges.py | 43 ++++++++++++++++++++++++++++++++++++++++++-
lib/bridgedb/Dist.py | 6 ++++++
lib/bridgedb/Main.py | 18 ++++++++++++++++--
4 files changed, 67 insertions(+), 3 deletions(-)
1
0

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