Skip to content

Latest commit

 

History

History
76 lines (66 loc) · 3.46 KB

ARCHITECTURE.md

File metadata and controls

76 lines (66 loc) · 3.46 KB

Netem architecture

The most important struct in this library is UNetStack. It wraps a Gvisor-based TCP/IP stack in userspace and it defines the boundary between the application and the emulated network stack.

Seen from above a UNetStack is an UnderlyingNetwork, the interface on which networking code depends in ooni/probe-cli. On top of the UnderlyingNetwork, we define abstractions that simplify using this library. For example, the Net struct uses an UnderlyingNetwork and provides replacements for functions commonly found in Go codebases (e.g., the Dialer and the [Resolver(https://pkg.go.dev/net#Resolver)]).

Seen from below, instead, a UNetStack is a NIC, the Go interface used by code connecting userspace TCP/IP stacks together. In particular, we should mention:

  1. the Link, which sends IP packets between two NICs, emulates latency, packets losses, and censorship attempts. Using a Link, one can create point-to-point topologies connecting NICs.

  2. the Router, which allows to create more complex network topologies.

The following diagram illustrates the relationship between important structs and interfaces in netem.

classDiagram
NIC <|-- UNetStack : implements
UnderlyingNetwork <|-- UNetStack : implements
Net ..> UnderlyingNetwork : uses
Link ..> DPIEngine : uses
Link ..> NIC : uses
Router ..> RouterPort : uses
RouterPort --|> NIC: implements
DNSClient ..> UnderlyingNetwork : uses
UNetStack ..> gvisorStack : uses
UnderlyingNetwork <|-- Stdlib : implements
PCAPDumper --|> NIC : decorates
ApplicationCode ..> Net : uses
ApplicationCode ..> DNSClient : uses
OONIProbe ..> UnderlyingNetwork : uses
ApplicationCode ..> UnderlyingNetwork : uses
Stdlib ..> GolangStdlib : uses
Loading

The DNSClient is an example of high-level code using an UnderlyingNetwork to perform DNS lookups. The PCAPDumper instead decorates an existing NIC to collect PCAP traces.

The Stdlib struct implements the UnderlyingNetwork model using the Go standard library rather than Gvisor. Therefore, code depending on UnderlyingNetwork can use both the Internet and TCP/IP stacks in userspace.

The most complex bit of this implementation is Link because we need to emulate network behavior reasonably enough for Gvisor TCP/IP implementation to behave like it does in normal networks.