Lab

Lab is the fault kit every tunnel in VPN Works must pass before it ships. It breaks the path on purpose, in the project’s tests, and checks four things each time: the program hears about the fault, nothing goes around the tunnel, every connection ends up in the record with an outcome, and vpnw never hangs.

Lab came back in 0.6.0, for the WireGuard path. It isn’t a feature you run. It lives in the test suite, runs on every push, and its results are recorded with the rest of the figures on this site.

Lab in 0.6.0: a sealed program, vpnw with its WireGuard tunnel, a relay that injects faults on demand, and a real WireGuard peer; a fault is handled when the program learns of it, nothing goes around the tunnel, every connection has an outcome, and vpnw ends with the program

How It Works

A relay sits on the path the tunnel’s UDP packets take, between vpnw and a real WireGuard peer that runs inside the tests. On command it drops everything, drops handshakes, delays every packet, or sends the tunnel to a different peer. The peer’s own DNS server can be told to lie. The program under test is sealed, so the tunnel is its only way out.

The Faults

Fault What must happen
The peer goes silent mid-run requests fail in time, nothing reaches the peer, every connection has an outcome, vpnw ends with the program
The peer goes silent, then comes back requests fail while it’s gone and work again after, with no restart
The peer goes silent in the middle of a download the program’s read times out, and the record closes the connection with the bytes that arrived
The first handshake is lost WireGuard tries again and the run starts
Every handshake is lost the program never starts, and vpnw exits 123
The tunnel is sent to an impostor peer, from the start or mid-run the impostor gets only packets it can’t read; the program never starts, or its requests fail
The tunnel’s DNS points a name at loopback, cloud metadata, a LAN address or an outside one refused with the reason, or carried only into the tunnel; nothing on this machine is reached
Every packet is delayed 300 ms each way it works, only slower

The DNS cases run three ways: with a tunnel that covers only the peer’s network, with a full tunnel (AllowedIPs = 0.0.0.0/0), and with deny_private. That makes 18 cases. Since 0.8.0 each one runs twice, with --wireguard and with the same config handed over by the rotate plugin, so 36 in all. The full results, case by case, are in test/results/lab.md.

What It Found

Four things, all fixed in 0.6.0:

  • Lookups and dials still waiting when a run ended had no outcome in the record. They’re now cut off at the end and recorded that way.
  • Connections still open at the end weren’t closed in the record. Now they are, with their bytes.
  • A connection could wait on a silent destination until the run ended, after the program had already given up on it. Now, once the program stops sending, 2 minutes with nothing arriving closes it. A destination that keeps sending, however slowly, keeps it open.
  • On a full tunnel, a lying DNS answer could send a program to 127.0.0.1 or 169.254.169.254 through the tunnel, which reaches the peer’s own machine or its cloud metadata. Loopback, link-local and multicast addresses are now refused through any tunnel, whatever AllowedIPs says.

What It Doesn’t Cover

A route pushed by a hostile network can’t pull a sealed program out of the tunnel: the tunnel runs inside vpnw, which doesn’t use the machine’s routing table, and the sealed program has no route of its own. So Lab tests the other half of that fault, a network that reroutes the tunnel’s packets, which the impostor cases cover.

Tunnel plugins, out in 0.8.0, hand configs to the same WireGuard path, and Lab runs every case through one of them as well. Tunnel plugins in 0.8.0

Where It Came From

Lab first ran as a separate engine in VPN Works 0.2.0, a test bench that broke networks around stand-in VPN clients built for the bench, one correct and three with a planted fault each. In its recorded case, a stand-in client sent 81 DNS queries to the home router while it reconnected. The case study

Lab’s first test bench, in 0.2.0: four private networks on one Linux machine

That code is in the repository’s history at the v0.2.0 tag. The 0.6.0 kit is new, built for the tunnel vpnw runs itself.