Skip to content

Commit d3949d5

Browse files
committed
WIP 3
1 parent 58334c7 commit d3949d5

4 files changed

Lines changed: 31 additions & 15 deletions

File tree

.github/workflows/test.yml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -259,22 +259,27 @@ jobs:
259259
260260
./awl.exe cli gateway client use --name awl-tester
261261
./awl.exe cli gateway status
262-
ROUTES_ON=$(powershell -NoProfile -Command '(Get-NetRoute -DestinationPrefix 0.0.0.0/1,128.0.0.0/1 -ErrorAction SilentlyContinue | Measure-Object).Count')
263-
NRPT_ON=$(powershell -NoProfile -Command '(Get-DnsClientNrptPolicy | Where-Object { $_.Namespace -eq "." } | Measure-Object).Count')
262+
ROUTES_ON=$(powershell -NoProfile -Command '(Get-NetRoute -DestinationPrefix 0.0.0.0/1,128.0.0.0/1 -ErrorAction SilentlyContinue | Measure-Object).Count' | tr -d '\r')
263+
NRPT_ON=$(powershell -NoProfile -Command '(Get-DnsClientNrptPolicy | Where-Object { $_.Namespace -eq "." } | Measure-Object).Count' | tr -d '\r')
264264
powershell -NoProfile -Command 'Get-DnsClientNrptPolicy | Format-List Namespace,NameServers'
265-
powershell -NoProfile -Command 'Get-NetRoute -DestinationPrefix ::/1,8000::/1 -ErrorAction SilentlyContinue | Format-List DestinationPrefix,InterfaceAlias' # v6 fence diagnostics
265+
# Route diagnostics incl. lifetimes/protocol: a route created without
266+
# InitializeIpForwardEntry shows zero lifetimes and is ignored by the
267+
# forwarding path while still being listed here.
268+
powershell -NoProfile -Command 'Get-NetRoute -DestinationPrefix 0.0.0.0/1,128.0.0.0/1,::/1,8000::/1 -ErrorAction SilentlyContinue | Format-List DestinationPrefix,InterfaceAlias,RouteMetric,Protocol,ValidLifetime,PreferredLifetime'
266269
# Tolerate a failed curl here so we always reach `client stop` below
267270
# (a broken tunnel must not leave the runner black-holed); the
268271
# `test -n "$IP_GW"` assertion after teardown turns it into a clean failure.
269272
IP_GW=$(curl4 || true); echo "egress IP (via gateway): $IP_GW"
270273
271274
./awl.exe cli gateway client stop
272-
ROUTES_OFF=$(powershell -NoProfile -Command '(Get-NetRoute -DestinationPrefix 0.0.0.0/1,128.0.0.0/1 -ErrorAction SilentlyContinue | Measure-Object).Count')
273-
NRPT_OFF=$(powershell -NoProfile -Command '(Get-DnsClientNrptPolicy | Where-Object { $_.Namespace -eq "." } | Measure-Object).Count')
275+
ROUTES_OFF=$(powershell -NoProfile -Command '(Get-NetRoute -DestinationPrefix 0.0.0.0/1,128.0.0.0/1 -ErrorAction SilentlyContinue | Measure-Object).Count' | tr -d '\r')
276+
NRPT_OFF=$(powershell -NoProfile -Command '(Get-DnsClientNrptPolicy | Where-Object { $_.Namespace -eq "." } | Measure-Object).Count' | tr -d '\r')
274277
IP_REVERTED=$(curl4); echo "egress IP (reverted): $IP_REVERTED"
275278
276279
# Assertions run with the gateway already disabled, so a failure here
277-
# can't leave the runner's egress black-holed.
280+
# can't leave the runner's egress black-holed. Values are echoed
281+
# first so a failed assertion is attributable from the log alone.
282+
echo "ROUTES_ON=$ROUTES_ON NRPT_ON=$NRPT_ON ROUTES_OFF=$ROUTES_OFF NRPT_OFF=$NRPT_OFF"
278283
test "$ROUTES_ON" -eq 2 # /1 pair installed while gateway is on
279284
test "$NRPT_ON" -ge 1 # full-capture NRPT rule while gateway is on
280285
test -n "$IP_GW" # traffic really flowed through the exit node
@@ -293,12 +298,14 @@ jobs:
293298
# awl is gone. Route absence can't distinguish a clean teardown from a
294299
# crash here — the /1 routes are bound to the Wintun LUID and die with
295300
# the adapter either way — so this only re-verifies crash semantics.
296-
DANGLING=$(powershell -NoProfile -Command '(Get-NetRoute -DestinationPrefix 0.0.0.0/1,128.0.0.0/1,::/1,8000::/1 -ErrorAction SilentlyContinue | Measure-Object).Count')
301+
DANGLING=$(powershell -NoProfile -Command '(Get-NetRoute -DestinationPrefix 0.0.0.0/1,128.0.0.0/1,::/1,8000::/1 -ErrorAction SilentlyContinue | Measure-Object).Count' | tr -d '\r')
302+
echo "DANGLING=$DANGLING"
297303
test "$DANGLING" -eq 0
298304
# The NRPT catch-all rule CAN distinguish them: it lives in the
299305
# registry and survives a killed process, but the graceful shutdown
300306
# path removes it — its absence proves the shutdown teardown ran
301307
# (the Windows analogue of the interface-independent fwmark ip rule
302308
# asserted on Linux).
303-
NRPT_SHUTDOWN=$(powershell -NoProfile -Command '(Get-DnsClientNrptPolicy | Where-Object { $_.Namespace -eq "." } | Measure-Object).Count')
309+
NRPT_SHUTDOWN=$(powershell -NoProfile -Command '(Get-DnsClientNrptPolicy | Where-Object { $_.Namespace -eq "." } | Measure-Object).Count' | tr -d '\r')
310+
echo "NRPT_SHUTDOWN=$NRPT_SHUTDOWN"
304311
test "$NRPT_SHUTDOWN" -eq 0

service/vpn_gateway.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,8 @@ func (g *VPNGateway) applyClient() error {
390390
return nil
391391
}
392392

393-
// Temporary exception rather than a restructure: this branching moves into
394-
// the netstate manager in the next MR (plans/windows-vpn-gateway.md §8.2)
395-
// and flattens there.
393+
// TODO: Temporary exception rather than a restructure: this branching moves into
394+
// the netstate manager in the next MR and flattens there.
396395
//nolint:nestif
397396
if g.disableOSSetup {
398397
g.clientRouteState = &routes.RouteState{}

vpn/routes/routes_windows.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ func SetupGatewayRoutes(tunIfName string, fwmark uint32) (*RouteState, error) {
8787
// and records it for teardown.
8888
func (state *RouteState) addTunRoute(prefix netip.Prefix, nextHop netip.Addr) error {
8989
row := winipcfg.MibIPforwardRow2{}
90+
// InitializeIpForwardEntry is mandatory before CreateIpForwardEntry2
91+
// it sets ValidLifetime/PreferredLifetime to infinite and Protocol to NetMgmt.
92+
// Without it the route lands in the table with zero lifetimes and is
93+
// ignored by the forwarding path — visible in Get-NetRoute, yet traffic
94+
// keeps flowing past it.
95+
row.Init()
9096
row.InterfaceLUID = state.tunLUID
9197
row.DestinationPrefix.PrefixLength = uint8(prefix.Bits())
9298
if err := row.DestinationPrefix.RawPrefix.SetAddr(prefix.Addr()); err != nil {

vpn/routes/vpn_hostnet_windows_integration_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,21 +227,25 @@ func TestGatewayHostNetNATRollback(t *testing.T) {
227227
forwardingBefore := forwardingEnabled(t, nicLUID)
228228

229229
// Provoke a New-NetNat failure at the last setup step by occupying WinNAT
230-
// with a conflicting instance (WinNAT is effectively single-instance).
230+
// with a conflicting instance whose internal prefix CONTAINS the awl one
231+
// (10.66.0.0/15 ⊃ 10.66.0.0/16). Windows Server images tolerate multiple
232+
// instances with disjoint prefixes (observed on the GitHub runner), but
233+
// overlapping prefixes are rejected — which is exactly the failure we
234+
// need at the last step.
231235
const conflictName = "awl-hostnet-conflict"
232236
_, err := runPowerShell(fmt.Sprintf(
233-
"New-NetNat -Name %s -InternalIPInterfaceAddressPrefix 10.77.0.0/16 | Out-Null", conflictName))
237+
"New-NetNat -Name %s -InternalIPInterfaceAddressPrefix 10.66.0.0/15 | Out-Null", conflictName))
234238
require.NoError(t, err, "creating the conflicting NetNat must succeed on a clean host")
235239
t.Cleanup(func() {
236240
_, _ = runPowerShell(fmt.Sprintf("Remove-NetNat -Name %s -Confirm:$false", conflictName))
237241
})
238242

239243
state, err := SetupNAT(testAwlSubnet, nicGUID)
240244
if err == nil {
241-
// Some builds tolerate multiple WinNAT instances — then there is no
245+
// If even overlapping-prefix instances are tolerated, there is no
242246
// failure to roll back from. Clean up and skip rather than fail.
243247
require.NoError(t, TeardownNAT(state))
244-
t.Skip("this host allows multiple WinNAT instances; rollback path not reachable here")
248+
t.Skip("this host allows overlapping WinNAT instances; rollback path not reachable here")
245249
}
246250
require.Contains(t, err.Error(), "WinNAT", "failure must come from the WinNAT step")
247251

0 commit comments

Comments
 (0)