# Lab notes: setting up a torperf to a hidden service (#1944)

These notes describe the process of setting up a torperf instance to measure performance of a Tor hidden service.  These notes may later lead to code changes to automate more of these steps and/or make this process more user friendly.  But the current focus is to get performance results quickly.

## Preparing the test system

The following steps will be run on a Debian Wheezy 64 bit system, created by Vagrant/VirtualBox using the following `Vagrantfile`:

```
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "wheezy64"
  config.vm.box_url = "http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-puppet.box"
  config.vm.boot_timeout = 60
end
```

Run the following commands to initialize the test system:

```
vagrant up
vagrant ssh
sudo apt-get update
sudo apt-get upgrade
```

## Building a custom tor binary

We need a tor binary that provides an easy way to clean its hidden service descriptor caches and forget about rendezvous connections.

```
mkdir ~/src
cd ~/src/
git clone https://git.torproject.org/tor.git
cd tor/
```

The patch is based on arma's bug1944 branch but rebased to current master (4c8b809).  It's pretty simple:

```
diff --git a/src/or/main.c b/src/or/main.c
index 094120f..585de80 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -2102,9 +2102,12 @@ process_signal(uintptr_t sig)
       control_event_signal(sig);
       break;
     case SIGUSR2:
-      switch_logs_debug();
-      log_debug(LD_GENERAL,"Caught USR2, going to loglevel debug. "
-                "Send HUP to change back.");
+      /* Replace the USR2 functionality with bug1944-specific plans.
+       * Ugly hack, but it'll do. */
+      log_info(LD_GENERAL, "Forgetting about rendezvous connections...");
+      rend_cache_clean(10000000);
+      rend_cache_clean_v2_descs_as_dir(10000000);
+      circuit_mark_all_dirty_circs_as_unusable();
       control_event_signal(sig);
       break;
     case SIGHUP:
```

Once this patch is applied, build tor and run its unit tests:

```
sudo apt-get install libevent-dev libssl-dev automake
./autogen.sh
./configure --disable-asciidoc
make
make test
```

## Configuring the hidden service

Create a new tor data directory for the tor instance hosting the hidden service.

```
mkdir -p ~/run/torhs
cd ~/run/torhs/
```

Use the following `torrc` file for this tor process:

```
DataDirectory /home/vagrant/run/torhs/
SocksPort 9019
UseEntryGuards 0
RunAsDaemon 1
Log info file /home/vagrant/run/torhs/info.log
ControlPort 10019
CookieAuthentication 1
HiddenServiceDir /home/vagrant/run/torhs/hidserv/
HiddenServicePort 80
```

Start the tor process:

```
~/src/tor/src/or/tor -f ~/run/torhs/torrc &
```

Print out the hidden service hostname:

```
cat ~/run/torhs/hidserv/hostname
```

In this case it's `7rpph4wsx4eosqi3.onion`.

Install nginx to serve some files and auto-generate these files using random data:

```
sudo apt-get install nginx
sudo service nginx start
sudo dd if=/dev/urandom of=/usr/share/nginx/www/.50kbfile count=1 bs=50K
sudo dd if=/dev/urandom of=/usr/share/nginx/www/.1mbfile count=1 bs=1M
sudo dd if=/dev/urandom of=/usr/share/nginx/www/.5mbfile count=1 bs=5M
```

Test that files are available via the hidden service using tor2web by visiting `https://7rpph4wsx4eosqi3.tor2web.org/.50kbfile` in a browser.

## Configuring three tor clients

Create three tor data directories for tor clients:

```
cd ~/run/
mkdir torclient50kb torclient1mb torclient5mb
```

Create `torrc` files for all three tor instances:

```
cat <<EOF >> torclient50kb/torrc
DataDirectory /home/vagrant/run/torclient50kb/
SocksPort 9020
MaxCircuitDirtiness 1 minute
UseEntryGuards 0
RunAsDaemon 1
Log info file /home/vagrant/run/torclient50kb/info.log
ControlPort 10020
CookieAuthentication 1
PidFile /home/vagrant/run/torclient50kb/tor.pid
EOF

cat <<EOF >> torclient1mb/torrc
DataDirectory /home/vagrant/run/torclient1mb/
SocksPort 9021
UseEntryGuards 0
RunAsDaemon 1
Log info file /home/vagrant/run/torclient1mb/info.log
ControlPort 10021
CookieAuthentication 1
PidFile /home/vagrant/run/torclient1mb/tor.pid
EOF

cat <<EOF >> torclient5mb/torrc
DataDirectory /home/vagrant/run/torclient5mb/
SocksPort 9022
UseEntryGuards 0
RunAsDaemon 1
Log info file /home/vagrant/run/torclient5mb/info.log
ControlPort 10022
CookieAuthentication 1
PidFile /home/vagrant/run/torclient5mb/tor.pid
EOF
```

Start the tor processes by creating the following script to `~/run/start-tors` (which also contains the tor process hosting the hidden service), making it executable, and executing it:

```
#!/bin/bash
~/src/tor/src/or/tor -f ~/run/torhs/torrc &
~/src/tor/src/or/tor -f ~/run/torclient50kb/torrc &
~/src/tor/src/or/tor -f ~/run/torclient1mb/torrc &
~/src/tor/src/or/tor -f ~/run/torclient5mb/torrc &
```

Ideally, put it into crontab:

```
@reboot cd ~/run/ && ./start-tors
```

## Building and testing torperf

Clone and build the torperf tool:

```
cd ~/src/
git clone https://git.torproject.org/torperf.git
cd torperf/
make
```

Make a first test run to fetch the 50 KiB file over Tor:

```
~/src/torperf/trivsocks-client 7rpph4wsx4eosqi3.onion 127.0.0.1:9020 /.50kbfile 51200 2>/dev/null
```

This command produces output like the following:

```
1411379100 454458 1411379100 454467 1411379100 455031 1411379100 455143 1411379100 455738 1411379106 922 1411379106 945 1411379106 502107 1411379107 130422 75 51427 0 1411379106 700760 1411379106 710348 1411379106 824048 1411379106 827450 1411379106 830742 1411379106 909961 1411379107 4770 1411379107 12142 1411379107 49708 
```

In this case, the time between starting the request (columns 1 and 2) and completing it (colums 17 and 18) was 6.7 seconds.

Let's also try out tor's patched behavior to clean its hidden service descriptor caches and forget about rendezvous connections.  First, we need to find out the process ID of the tor client we just used.  Then we can send the process a USR2 signal:

```
ps x     # shows PID 27598 for torclient50kb
kill -USR2 27598
grep "Forgetting about rendezvous connections" ~/run/torclient50kb/info.log
```

## Setting up torperf cronjobs

Put the following three lines into the crontab:

```
*/5 * * * * cd ~/run/torclient50kb/ && timeout -s2 295 ~/src/torperf/trivsocks-client 7rpph4wsx4eosqi3.onion 127.0.0.1:9020 /.50kbfile 51200 >> torperf.log 2>/dev/null; kill -USR2 `cat tor.pid`
2,32 * * * * cd ~/run/torclient1mb/ && timeout -s2 1795 ~/src/torperf/trivsocks-client 7rpph4wsx4eosqi3.onion 127.0.0.1:9021 /.1mbfile 1048576 >> torperf.log 2>/dev/null; kill -USR2 `cat tor.pid`
8 * * * * cd ~/run/torclient5mb/ && timeout -s2 3595 ~/src/torperf/trivsocks-client 7rpph4wsx4eosqi3.onion 127.0.0.1:9022 /.5mbfile 5242880 >> torperf.log 2>/dev/null; kill -USR2 `cat tor.pid`
```

## Plotting simple performance metrics

The torperf output contains some performance data as observed by the SOCKS client that we can plot.

Install `R` and the `ggplot2` library:

```
sudo apt-get install r-base r-cran-ggplot2
```

Create a script with the plotting code and write it to `~/src/plot-torperf.R`:

```
require(ggplot2)
data <- rbind(
  data.frame(read.table("/home/vagrant/run/torclient50kb/torperf.log",
                        header = FALSE), size = 51200),
  data.frame(read.table("/home/vagrant/run/torclient1mb/torperf.log",
                        header = FALSE), size = 1048576),
  data.frame(read.table("/home/vagrant/run/torclient5mb/torperf.log",
                        header = FALSE), size = 5242880))
ggplot(data, aes(x = as.POSIXct(V1, origin = "1970-01-01 00:00:00"),
                 y = V17 + V18 / 1e6 - V1 - V2 / 1e6,
                 colour = as.factor(size))) +
geom_point() +
geom_line() +
scale_x_datetime("") +
scale_y_continuous("") +
scale_colour_hue("Request size\nin bytes") +
opts(title = "Time in seconds to complete request to hidden service\n") +
ggsave("/vagrant/torperf-2014-09-22.png", width = 8, height = 5, dpi = 100)
```
