VPN Works 0.6.0: Lab Breaks the Tunnel on Purpose, and Four Fixes Come Out of It
VPN Works 0.6.0 brings Lab back as the fault kit every tunnel must pass before it ships. It broke the WireGuard path 18 ways. The path now handles all 18, and four fixes came out of the cases it didn’t handle at first.
A tunnel that works on a good network proves little. The cases that matter are the bad ones: a VPN server that stops answering, a handshake lost on the way, a network that sends your packets somewhere else, a DNS server that lies. When one of those happens, the program has to find out and nothing may slip around the tunnel. Afterwards, the record has to say what happened.
Lab checks exactly that. It lives in the project’s tests and runs on every push. It doesn’t ship as a feature.

How It Breaks Things
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 by 300 ms, or sends the tunnel to an impostor peer that doesn’t have the right key. The peer’s own DNS server can be told to point names at loopback, at cloud metadata, at a LAN address or at one outside the tunnel.
A case passes when the program hears about the fault in time, nothing goes around the tunnel, every connection in the record has an outcome, and vpnw ends when the program does. Each row of the results says what was measured, case by case.
What It Found
Connections left without an outcome. When a run ended while a lookup or a dial was still waiting on a silent peer, the record showed the attempt and nothing after it. Those are now cut off at the end and recorded that way. Connections still open at the end weren’t closed in the record either; now they are, with their bytes.
A connection kept open for nothing. When a program gave up on a silent destination and closed its side, vpnw held the other side open until the run ended. Now, once the program has stopped sending, 2 minutes with nothing arriving closes it. A destination that keeps sending, however slowly, keeps it open.
Cloud metadata through a full tunnel. Most VPN providers hand out configs with AllowedIPs = 0.0.0.0/0. With one of those, a lying DNS answer from the tunnel could send a program to 127.0.0.1 or 169.254.169.254 through the tunnel, which reaches the VPN server’s own machine or its cloud metadata. Loopback, link-local and multicast addresses are now refused through any tunnel, whatever AllowedIPs says. With deny_private, the policy refuses them as well, before anything but the lookup is sent.
Before release, an independent review went through the kit and found cases that would have passed without proving anything: a check for a denial that matched a header line on every run, and an impostor case that tested nothing a lost handshake didn’t. Both were rewritten. It also caught the quiet limit misreading the tunnel’s timeouts, which would have cut slow downloads on the WireGuard path. That’s fixed, with a test.
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 half of that fault that can happen: a network that sends the tunnel’s packets elsewhere.
Measured
| What | 0.6.0 |
|---|---|
| Faults thrown at the WireGuard path | 18, all handled |
| Test functions | 155 of 155 passed |
| Ways out of the sealed sandbox | 17 of 17 blocked, IPv6 included |
| Statements covered | 82.3% |
| Fuzz targets | 11, all clean |
| Data through a WireGuard tunnel | 99 MB/s |
How it was measured: test/results
Next is 0.7.0, Exit: the far end of a path, checking the client’s policy again. Lab · Roadmap · Download