|
28 | 28 | // (extracted wintun.dll from the embeds package), because /1 on-link routes |
29 | 29 | // need a point-to-point interface and their crash semantics — dying with the |
30 | 30 | // adapter — are exactly what we assert. |
| 31 | +// |
| 32 | +// Deliberately NOT covered here (vs the Linux suite): |
| 33 | +// - reaction to route changes (Linux R4/R5): on Windows that machinery is |
| 34 | +// the sockmark watcher (UNICAST_IF re-bind), not a routes-package |
| 35 | +// monitor — its integration test lands with the netstate refactoring, |
| 36 | +// see TODO(netstate) in vpn/sockmark/sockmark_windows.go |
| 37 | +// - client-route stale recovery / leftover collisions (Linux R2/R3): |
| 38 | +// impossible by design — the routes die with the adapter LUID |
| 39 | +// (TestGatewayHostNetClientRoutesDieWithAdapter proves exactly that), |
| 40 | +// and a fresh adapter is a fresh LUID. |
31 | 41 | package routes |
32 | 42 |
|
33 | 43 | import ( |
@@ -100,6 +110,14 @@ func forwardingEnabled(t *testing.T, luid winipcfg.LUID) bool { |
100 | 110 | return ipIface.ForwardingEnabled |
101 | 111 | } |
102 | 112 |
|
| 113 | +func setForwarding(t *testing.T, luid winipcfg.LUID, enabled bool) { |
| 114 | + t.Helper() |
| 115 | + ipIface, err := luid.IPInterface(windows.AF_INET) |
| 116 | + require.NoError(t, err) |
| 117 | + ipIface.ForwardingEnabled = enabled |
| 118 | + require.NoError(t, ipIface.Set()) |
| 119 | +} |
| 120 | + |
103 | 121 | // wfpRuleInstalled reports whether our BLOCK rule is currently visible in the |
104 | 122 | // filtering engine, via a fresh read-only session (rules created by a dynamic |
105 | 123 | // session are visible engine-wide for its lifetime). |
@@ -151,6 +169,34 @@ func TestGatewayHostNetNATLifecycle(t *testing.T) { |
151 | 169 | require.False(t, wfpRuleInstalled(t), "teardown must remove the WFP rule (dynamic session closed)") |
152 | 170 | } |
153 | 171 |
|
| 172 | +// ---- Server: teardown must not disable forwarding it did not enable ---- |
| 173 | + |
| 174 | +// TestGatewayHostNetNATPreservesExistingForwarding is the Windows counterpart |
| 175 | +// of the Linux "pre-existing ip_forward=1 stays on" test: interfaces that |
| 176 | +// already forward (other VPNs, containers, ICS — or a previous awl run that |
| 177 | +// was killed, leaving the flag set) must be left alone by TeardownNAT. |
| 178 | +// Unlike the Linux test (which skips unless the host happens to have |
| 179 | +// ip_forward pre-enabled), the per-interface flag lets us set up the |
| 180 | +// precondition deterministically. |
| 181 | +func TestGatewayHostNetNATPreservesExistingForwarding(t *testing.T) { |
| 182 | + verifyNoLeaks(t) |
| 183 | + requireAdmin(t) |
| 184 | + nicLUID, nicGUID := pickServerTestNIC(t) |
| 185 | + |
| 186 | + if !forwardingEnabled(t, nicLUID) { |
| 187 | + setForwarding(t, nicLUID, true) |
| 188 | + t.Cleanup(func() { setForwarding(t, nicLUID, false) }) |
| 189 | + } |
| 190 | + |
| 191 | + state, err := SetupNAT(testAwlSubnet, nicGUID) |
| 192 | + require.NoError(t, err) |
| 193 | + require.True(t, forwardingEnabled(t, nicLUID)) |
| 194 | + |
| 195 | + require.NoError(t, TeardownNAT(state)) |
| 196 | + require.True(t, forwardingEnabled(t, nicLUID), |
| 197 | + "forwarding was already on before setup; teardown must NOT disable it") |
| 198 | +} |
| 199 | + |
154 | 200 | // ---- Server: stale state recovery ---- |
155 | 201 |
|
156 | 202 | func TestGatewayHostNetNATStaleRecovery(t *testing.T) { |
|
0 commit comments