ExoneraTor
        or: a script that tells you whether some IP address was a Tor relay

---------------------------------------------------------------------------

Introduction:

Some people have expressed the desire to learn whether a given IP address
has been a Tor relay at a certain time. In addition to that, these people
might want to know whether the IP address permitted exit to a given address
and port.

Answering these questions can be important for Tor relay operators to show
to the authorities that an anonymous user might have conducted bad things
with their IP address. Likewise, police investigators might be interested
in the answer to these questions, too, in order to decide whether to
proceed with their investigations or not.

We can answer the above questions from looking at the descriptor archives
that are available since late 2007 (or even beyond, but this script only
works with the data format that was produced starting in October 2007).
This script parses the directory archives to print out the answer whether
a certain IP address was a Tor relay at a given time. The script further
prints out all intermediate steps in answering this, so that users can
confirm the correctness of the result themselves.

This script is available in two versions written in Python and in Java with
equivalent functionality.

---------------------------------------------------------------------------

Python Quick Start:

In order to run the Python version of this script, you need to install and
download the following software and data (please note that all instructions
are written for Linux; commands for Windows or Mac OS X may vary):

- Install Python 2.6.2 or higher. (Previous Python versions might work,
  too, but have not been tested.)

- Install the Python module IPy 0.62 or higher either from
  http://pypi.python.org/pypi/IPy/ or using "apt-get install python-ipy" on
  Debian-based systems.

- Download the v3 consensuses and server descriptors of the relevant time
  from http://metrics.torproject.org/data.html and extract them to a
  directory in your working directory, e.g. /home/you/exonerator/data/ .
  Don't rename the extracted directories or any of the contained files, or
  the script won't find the contained descriptors.

  Note that you only need the server descriptors if you want to learn
  whether a given IP address permits exiting to a given target. If you
  only want to learn whether that IP address was a Tor relay, you don't
  need them.

- Run the script, providing it with the parameters it needs:

  python exonerator.py [--archive=<descriptor archive directory>]
           <IP address in question>
           <timestamp, in UTC, formatted as YYYY-MM-DD hh:mm:ss>
           [<target address>[:<target port>]]

  The --archive option defaults to data/ . In the following examples, it is
  assumed that this default applies.

  Make sure that the timestamp is provided in UTC, which is equivalent to
  GMT, and not in your local timezone! Otherwise, results will very likely
  be wrong.

  A sample invocation might be:

  $ python exonerator.py 209.17.171.104 2009-08-15 16:05:00
        209.85.129.104:80

---------------------------------------------------------------------------

Java Quick Start:

In order to run the Java version of this script, you need to install and
download the following software and data (please note that all instructions
are written for Linux; commands for Windows or Mac OS X may vary):

- Install Java 6 or higher.

- Download the BouncyCastle provider that includes Base 64 decoding from
  http://www.bouncycastle.org/download/bcprov-jdk16-143.jar and put it in
  your working directory, e.g. /home/you/exonerator/ .

- Download the v3 consensuses and server descriptors of the relevant time
  from http://metrics.torproject.org/data.html and extract them to a
  directory in your working directory, e.g. /home/you/exonerator/data/ .
  Don't rename the extracted directories or any of the contained files, or
  the script won't find the contained descriptors.

  Note that you only need the server descriptors if you want to learn
  whether a given IP address permits exiting to a given target. If you
  only want to learn whether that IP address was a Tor relay, you don't
  need them.

- Compile the (single) Java class using this command:

  $ javac -cp bcprov-jdk16-143.jar ExoneraTor.java

- Run the script, providing it with the parameters it needs:

  java -cp .:bcprov-jdk16-143.jar ExoneraTor
           <descriptor archive directory>
           <IP address in question>
           <timestamp, in UTC, formatted as YYYY-MM-DD hh:mm:ss>
           [<target address>[:<target port>]]

  Make sure that the timestamp is provided in UTC, which is equivalent to
  GMT, and not in your local timezone! Otherwise, results will very likely
  be wrong.

  A sample invocation might be:

  $ java -cp .:bcprov-jdk16-143.jar ExoneraTor data/ 209.17.171.104 \
        2009-08-15 16:05:00 209.85.129.104:80

---------------------------------------------------------------------------

Test cases:

The following test cases work with the August 2009 archives and can be used
to check whether this script works correctly:

- Positive result of echelon1+2 being a relay:

  $ python exonerator.py 209.17.171.104 2009-08-15 16:05:00
  $ java -cp .:bcprov-jdk16-143.jar ExoneraTor data/ 209.17.171.104 \
        2009-08-15 16:05:00

- Positive result of echelon1+2 exiting to google.com on any port

  $ python exonerator.py 209.17.171.104 2009-08-15 16:05:00 209.85.129.104
  $ java -cp .:bcprov-jdk16-143.jar ExoneraTor data/ 209.17.171.104 \
        2009-08-15 16:05:00 209.85.129.104

- Positive result of echelon1+2 exiting to google.com on port 80

  $ python exonerator.py 209.17.171.104 2009-08-15 16:05:00 \
        209.85.129.104:80
  $ java -cp .:bcprov-jdk16-143.jar ExoneraTor data/ 209.17.171.104 \
        2009-08-15 16:05:00 209.85.129.104:80

- Negative result of echelon1+2 exiting to google.com, but not on port 25

  $ python exonerator.py 209.17.171.104 2009-08-15 16:05:00 \
        209.85.129.104:25
  $ java -cp .:bcprov-jdk16-143.jar ExoneraTor data/ 209.17.171.104 \
        2009-08-15 16:05:00 209.85.129.104:25

- Negative result with IP address of echelon1+2 changed in the last octet

  $ python exonerator.py 209.17.171.50 2009-08-15 16:05:00
  $ java -cp .:bcprov-jdk16-143.jar ExoneraTor data/ 209.17.171.50 \
        2009-08-15 16:05:00

