Simple Tor Network Example

We recommend getting started with the basic file transfer and traffic generation examples to orient yourself with Shadow before running this slightly more complex Tor simulation.

This example requires that you have installed:

  • tor; can typically be installed via your system package manager.
  • tgen; will most likely need to be built from source.

Configuring Shadow

This simulation again uses tgen as both client and server. In addition to a tor-oblivious client and server, we add a tor network and a client that uses tor to connect to the server.

shadow.yaml:

general:
  stop_time: 30 min
network:
  graph:
    type: gml
    inline: |
      graph [
        directed 0
        node [
          id 0
          host_bandwidth_down "1 Gbit"
          host_bandwidth_up "1 Gbit"
        ]
        edge [
          source 0
          target 0
          latency "50 ms"
          jitter "0 ms"
          packet_loss 0.0
        ]
      ]
hosts:
  fileserver:
    network_node_id: 0
    processes:
    - path: tgen
      # See https://shadow.github.io/docs/guide/compatibility_notes.html#libopenblas
      environment: { OPENBLAS_NUM_THREADS: "1" }
      args: ../../../conf/tgen.server.graphml.xml
      start_time: 1
      expected_final_state: running
  4uthority:
    network_node_id: 0
    ip_addr: 100.0.0.1
    processes:
    - path: tor
      args: --Address 4uthority --Nickname 4uthority
            --defaults-torrc torrc-defaults -f torrc
      start_time: 1
      expected_final_state: running
  exit1:
    network_node_id: 0
    processes:
    - path: tor
      args: --Address exit1 --Nickname exit1
            --defaults-torrc torrc-defaults -f torrc
      start_time: 60
      expected_final_state: running
  exit2:
    network_node_id: 0
    processes:
    - path: tor
      args: --Address exit2 --Nickname exit2
            --defaults-torrc torrc-defaults -f torrc
      start_time: 60
      expected_final_state: running
  relay1:
    network_node_id: 0
    processes:
    - path: tor
      args: --Address relay1 --Nickname relay1
            --defaults-torrc torrc-defaults -f torrc
      start_time: 60
      expected_final_state: running
  relay2:
    network_node_id: 0
    processes:
    - path: tor
      args: --Address relay2 --Nickname relay2
            --defaults-torrc torrc-defaults -f torrc
      start_time: 60
      expected_final_state: running
  relay3:
    network_node_id: 0
    processes:
    - path: tor
      args: --Address relay3 --Nickname relay3
            --defaults-torrc torrc-defaults -f torrc
      start_time: 60
      expected_final_state: running
  relay4:
    network_node_id: 0
    processes:
    - path: tor
      args: --Address relay4 --Nickname relay4
            --defaults-torrc torrc-defaults -f torrc
      start_time: 60
      expected_final_state: running
  client:
    network_node_id: 0
    processes:
    - path: tgen
      # See https://shadow.github.io/docs/guide/compatibility_notes.html#libopenblas
      environment: { OPENBLAS_NUM_THREADS: "1" }
      args: ../../../conf/tgen.client.graphml.xml
      start_time: 600
  torclient:
    network_node_id: 0
    processes:
    - path: tor
      args: --Address torclient --Nickname torclient
            --defaults-torrc torrc-defaults -f torrc
      start_time: 900
      expected_final_state: running
    - path: tgen
      # See https://shadow.github.io/docs/guide/compatibility_notes.html#libopenblas
      environment: { OPENBLAS_NUM_THREADS: "1" }
      args: ../../../conf/tgen.torclient.graphml.xml
      start_time: 1500

Running the Simulation

We run this example similarly as before. Here we use an additional command-line flag --template-directory to copy a template directory layout containing each host's tor configuraton files into its host directory before the simulation begins.

For brevity we omit the contents of our template directory, and configuration files that are referenced from it, but you can find them at examples/docs/tor/shadow.data.template/ and examples/docs/tor/conf/.

# delete any existing simulation data
rm -rf shadow.data/
shadow --template-directory shadow.data.template shadow.yaml > shadow.log

Simulation Output

As before, Shadow will write simulation output to the data directory shadow.data/. Each host has its own directory under shadow.data/hosts/.

In the TGen process output, lines containing stream-success represent completed downloads and contain useful timing statistics. From these lines we should see that clients have completed a total of 20 streams:

$ for d in shadow.data/hosts/*client*; do grep "stream-success" "${d}"/*.stdout ; done | wc -l
50

We can also look at the transfers from the servers' perspective:

$ for d in shadow.data/hosts/fileserver*; do grep "stream-success" "${d}"/*.stdout ; done | wc -l
50

You can also parse the TGen output logged to the stdout files using the tgentools program from the TGen repo, and plot the data in graphical format to visualize the performance characteristics of the transfers. This page describes how to get started.

More Realistic Simulations

You can use the tornettools toolkit to run larger, more complex Tor networks that are meant to more accurately resemble the characteristics and state of the public Tor network.

Determinism

To improve determinism for your simulation, Shadow preloads an auxiliary library, libshadow_openssl_rng, which override's some of openssl's RNG routines. This is enabled by default, but can be controlled using the experimental use_openssl_rng_preload option.