6 releases (stable)

2.0.1 Oct 24, 2024
2.0.0 Sep 9, 2024
1.1.1 Apr 8, 2024
1.0.1 Nov 24, 2023
0.0.0 Mar 3, 2023

#414 in Network programming

Download history 113/week @ 2024-09-06 37/week @ 2024-09-13 21/week @ 2024-09-20 9/week @ 2024-09-27 2/week @ 2024-10-04 2/week @ 2024-10-11 46/week @ 2024-10-18 74/week @ 2024-10-25 8/week @ 2024-11-01 3/week @ 2024-11-08 55/week @ 2024-12-06

55 downloads per month

MIT/Apache

340KB
5.5K SLoC

The Maybenot Simulator

A simulator for the Maybenot framework.

Crates.io Documentation Build Status MIT OR Apache-2.0

Example Usage

See cargo docs for details on the API. The following is a simple example of how to use the simulator:

use maybenot::{event::TriggerEvent, Machine};
use maybenot_simulator::{network::Network, parse_trace, sim};
use std::{str::FromStr, time::Duration};
// The first ten packets of a network trace from the client's perspective
// when visiting google.com. The format is: "time,direction\n". The
// direction is either "s" (sent) or "r" (received). The time is in
// nanoseconds since the start of the trace.
let raw_trace = "0,s
19714282,r
183976147,s
243699564,r
1696037773,s
2047985926,s
2055955094,r
9401039609,s
9401094589,s
9420892765,r";
// The network model for simulating the network between the client and the
// server. Currently just a delay.
let network = Network::new(Duration::from_millis(10), None);
// Parse the raw trace into a queue of events for the simulator. This uses
// the delay to generate a queue of events at the client and server in such
// a way that the client is ensured to get the packets in the same order and
// at the same time as in the raw trace.
let mut input_trace = parse_trace(raw_trace, &network);
// A simple machine that sends one padding packet 20 milliseconds after the
// first normal packet is sent.
let m = "02eNp1ibEJAEAIA5Nf7B3N0v1cSESwEL0m5A6YvBqSgP7WeXfM5UoBW7ICYg==";
let m = Machine::from_str(m).unwrap();
// Run the simulator with the machine at the client. Run the simulation up
// until 100 packets have been recorded (total, client and server).
let trace = sim(&[m], &[], &mut input_trace, network.delay, 100, true);
// print packets from the client's perspective
let starting_time = trace[0].time;
trace
    .into_iter()
    .filter(|p| p.client)
    .for_each(|p| match p.event {
        TriggerEvent::TunnelSent => {
            if p.contains_padding {
                println!(
                    "sent a padding packet at {} ms",
                    (p.time - starting_time).as_millis()
                );
            } else {
                println!(
                    "sent a normal packet at {} ms",
                    (p.time - starting_time).as_millis()
                );
            }
        }
        TriggerEvent::TunnelRecv => {
            if p.contains_padding {
                println!(
                    "received a padding packet at {} ms",
                    (p.time - starting_time).as_millis()
                );
            } else {
                println!(
                    "received a normal packet at {} ms",
                    (p.time - starting_time).as_millis()
                );
            }
        }
        _ => {}
    });

Produces the following output:

sent a normal packet at 0 ms
received a normal packet at 19 ms
sent a padding packet at 20 ms
sent a normal packet at 183 ms
received a normal packet at 243 ms
sent a normal packet at 1696 ms
sent a normal packet at 2047 ms
received a normal packet at 2055 ms
sent a normal packet at 9401 ms
sent a normal packet at 9401 ms
received a normal packet at 9420 ms

Key Limitations

This is a prototype simulator, and as such, it has a number of limitations. For one, it is a simulator! We are simulating the integration with the application/destination using the framework and the network between the client and server. We have a sim2real problem.

In terms of networking, the relevant code for the simulator is in src/network.rs. It is very crude: we use a fixed static delay. This should be improved and evaluated against real-world network experiments. The goal of the simulator is not necessarily to be a perfect simulator, but a useful simulator for making different kinds of traffic analysis defenses.

There are also fundamental issues with simulating blocking actions of machines. Because the simulator takes as input a base network trace of encrypted network traffic, we do not know any semantics or inter-dependencies between the packets in the encrypted trace. As a result, we cannot properly simulate blocking actions. For example, if a machine blocks a packet, we cannot know if the blocked packet contains a request for a resource that leads to a response contained in the following received packets. The simulator will happily still receive the resource in the encrypted network trace. Here be dragons.

Rich Debug Output

The simulator can be run with the RUST_LOG=debug environment variable set to get rich debug output. For example, to run the integration test test_bypass_machine with debug output, run the following command:

RUST_LOG=debug cargo test test_bypass_machine

Contributing

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as MIT or Apache-2.0, without any additional terms or conditions.

Sponsorship

Made possible with support from Mullvad VPN, the Swedish Internet Foundation, and the Knowledge Foundation of Sweden.

Dependencies

~10–20MB
~300K SLoC