Skip to content

SDK 1.1.1-beta.1 → main: WireGuard + IKEv2 hardening + GRDSGWServer + wifi-loss fix + CJ PR review (all-inclusive)#224

Merged
TimE4DNSF merged 18 commits into
mainfrom
fix-orphaned-dns-filters-unplanned-disconnect
Jun 29, 2026
Merged

SDK 1.1.1-beta.1 → main: WireGuard + IKEv2 hardening + GRDSGWServer + wifi-loss fix + CJ PR review (all-inclusive)#224
TimE4DNSF merged 18 commits into
mainfrom
fix-orphaned-dns-filters-unplanned-disconnect

Conversation

@TimE4DNSF

@TimE4DNSF TimE4DNSF commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

SDK 1.1.1-beta.1main. All-inclusive consolidation line: WireGuard transport consolidation, IKEv2 encryption hardening, GRDSGWServer parity, stability fixes, the wifi-loss DNS-filter fix, and CJ's PR-review changes. 18 commits; GRDVPNHelper.cs is the bulk of the diff.

WireGuard transport consolidation

  • Collapse the connect-flow negotiate into a single protocol path + VPNDeviceResponse DTO.
  • Consolidate the connect/disconnect entry points and collapse ActiveConnectionPossible into one protocol-aware path.

IKEv2 encryption hardening

  • Require maximum encryption and pin the AES-256-GCM / SHA-384 / ECP-384 IPsec suite.
  • Fix the CustomIPSecPolicies cipher blob: client GCM-256 = cipher 5 / auth 8 (was 8/5) — the real EAP-MSCHAPv2 fix.

GRDSGWServer parity (iOS / Android)

  • Rename RegionalHostRecordGRDSGWServer and thread it through the connect flow; add GRDSGWServer + source-gen JSON context, remove the old RegionalHostRecord*.

Stability fixes

  • Fix the stale _activeTransport lockout (IKEv2 power-suspend gap).
  • Remove orphaned DNS-leak WFP filters on an unplanned IKEv2 disconnect (the wifi-loss → "host unknown" → reboot bug).
  • Log device-registration non-2xx response bodies on the IKEv2 path.

CJ PR review

  • Replace ! null-deny on mainCredential / subCred with graceful null-checks that return an errorResponse instead of throwing.
  • Remove the string host-override mechanism entirely (Common.kGuardianPreferredHost, HostOverrideMismatchAgainst, and its ConnectVPNTunnel() teardown) — the SDK no longer reads any host override; that logic now lives in the app Dev window.
  • Add ConnectVpnWithNewUserCredentialsForProtocol(TransportProtocol, GRDSGWServer?) so a caller can drive a specific server explicitly.

Versioning

  • Adopt the 1.1.0 baseline + beta.N prerelease suffix; current cut 1.1.1-beta.1.

Notes

  • An EAP-MSCHAPv2 user-data prototype was added then fully removed within this branch (net no-op) — the cipher-blob fix above was the real solution.
  • On merge to main as GA, drop the beta.1 suffix → 1.1.1.

TimE4DNSF and others added 16 commits June 10, 2026 16:31
…Response DTO

Tier 1: collapse the negotiate dispatch in ConnectVpnWithConfiguredCredentials so BOTH protocols route through ConnectVpnWithNewUserCredentialsForProtocol(protocol). Delete NegotiateAndStartWireGuard (its host-pick was duplicate, its negotiate is the gateway dispatcher, its dial is StartWireGuardFromStoredCreds). Port the two WG-only host-pick behaviors (PreferredRegion region-snap + host-selection error check) into the now-shared CreateStandaloneCredentialsForTransportProtocol host-pick.

Tier 2: introduce VPNDeviceResponse, a nullable superset DTO for the POST /api/v1.3/device reply for both protocols. RegisterDeviceForTransportProtocol deserializes the reply into it for IKEv2 and WireGuard alike; retire WireGuardRegistrationResponse + its JSON context. A single GRDCredential.CreateFromDeviceResponse(protocol, ...) factory plucks per protocol (replaces the two inline build sites and the dead, stuffing InitWithTransportProtocol). The credential carries the DTO verbatim on GRDCredential.Device; usage points (WireGuardQuickConfigForCredential, StartIKEv2Connection, ActiveConnectionPossible) pluck from Device. The WG device keypair stays on the flat fields (client-side, not in the host reply).

Correctness: drop the UserName/Password field-stuffing on WG creds. ActiveConnectionPossible predicates now read disjoint subsets of Device by construction, so an IKEv2 check is false on a WG cred without any stuffing (removes the latent RasDial-645 coupling).

Persistence/migration: flat fields are kept and still serialized so existing DPAPI-encrypted keychain blobs load unchanged; GRDCredentialManager backfills Device from the flat fields on read (EnsureDeviceFromLegacyFields, protocol-scoped so legacy WG stuffing is not surfaced as EAP fields). VPNDeviceResponse added to the source-gen GRDCredentialJsonContext for AOT. Service IPC contract (VPNCallParameters) unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uild

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… suite

dwEncryptionType ET_Optional -> ET_RequireMax, and replace the CustomIPSecPolicies blob (ROUTER_CUSTOM_IKEv2_POLICY_0) with 3,4,8,5,5,5 = SHA-384 / AES-256 (IKE), AES-256-GCM ESP, ECP-384 PFS+DH. Prior blob's ESP cipher decoded to 3DES with an inconsistent/uncertain policy. Adds ET_RequireMax to the CsWin32 NativeMethods.txt request list. Gateway must offer this suite or the dial fails (by design) -- verify negotiated SA with Get-NetIPsecQuickModeSA before shipping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…8 (was 8/5)

wg-poc.1 used the MS-RRASM server enum (GCM-256 cipher=8/auth=5); the client phonebook is the opposite (5/8), so RasDial failed with FWP_E_INVALID_ENUMERATOR (0x8032001D). Corrected hex matches Set-VpnConnectionIPsecConfiguration output. Bump to wg-poc.2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Carries the i196 WireGuard negotiate-consolidation work forward onto a
fresh branch with main's 0.46.0->0.46.2 cleanup merged in. Conflicts
resolved keeping the consolidated single connect-flow path (HEAD) while
adopting main's key-exchange terminology, explicit VPNCallParameters
.Transport, GRDTransportProtocol move to Shared, and related cleanups.
Version: 0.46.2-wg-alpha.43.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… consolidation-and-cleanup

# Conflicts:
#	GuardianConnectSDK/Directory.Build.Props
Closes the EAP user-auth gap: the entry required EAP (RASEO_RequireEAP +
EAP type 26) but creds were only fed the legacy RasSetCredentials way, which
a non-interactive SYSTEM service can't use to answer the EAP-MSCHAPv2
challenge -> looked like an MSCHAPv2/server failure.

Two auto-chained paths in ConfigureEapMschapV2UserData:
 1. RasGetEapUserIdentity (NonInteractive) -> RasSetEapUserData
 2. fallback: EapHostConfig XML (type 26) -> EapHostPeerConfigXml2Blob ->
    RasSetCustomAuthData

Gateway-cert validation (iOS serverCertificateCommonName) is already handled
at the IKEv2 layer (dialed hostname + machine Trusted Root). UNTESTED against
a live gateway; verify eappcfg.dll export host + a Quick-Mode SA.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…6.3-alpha.2

RegisterDeviceForTransportProtocol discarded the server's error body on a non-success status (e.g. 400 'staff access restricted node'), surfacing only the HTTP reason phrase. Now logs status+body and returns it in the error message, mirroring the WireGuard branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…onPossible

- ActiveConnectionPossible: single method with optional TransportProtocol?
  defaulting to the user's preferred protocol (GetPreferred); removed the
  duplicate no-arg overload.
- Rename public entry points to clean parameterless API for app/partners:
  ConnectVpnWithConfiguredCredentials -> ConnectVPNTunnel,
  DisconnectVPN -> DisconnectVPNTunnel. Protocol resolved internally; both
  protocol paths stay merged from the entry down to the tunnel split.
- Bump to 0.46.3-alpha.3 (breaking rename; new version required to publish).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- SelectGuardianHostWithCompletion returns the RegionalHostRecord (the
  GRDSGWServer analog) instead of flattening to (hostname, display) strings;
  connect flow carries the server object and reads fields at point of use.
- RegionalHostRecord gains SmartProxyRoutingEnabled (wire key
  'smart-routing-enabled') and a Region back-ref. Region binds from the nested
  'region' object in servers/all-hostnames responses (GetAllHostnamesAsync);
  GetHostsForRegion stamps it (??=) for the per-region endpoint that omits it.
  Registered GRDRegion in RegionalHostRecordJsonContext (+ IncludeFields).
- Scrub SDK comments referencing the app's developer window/tab.
- Bump to 0.46.3-alpha.4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Server rename

IKEv2 power-suspend gap (CJ's connect-after-sleep lockout):
- StartVPNConnection guard is now OS-authoritative: decides 'is a tunnel up?'
  from IsAnyConnectionActive (IKEv2/RAS) rather than the static _activeTransport,
  which goes stale when the power-suspend path tears the tunnel down outside
  DisconnectVPNConnection (and is null-but-up after a resume reconnect). Stale
  references are reclaimed instead of blocking the next connect.
- New GuardianNPCommandDispatcher.NotifyTransportTornDownExternally(), called from
  ServicePowerEventsHandler after PowerSuspendVPNConnection, so the dispatcher's
  reference doesn't dangle across sleep.

Consolidation (since alpha.4):
- Rename RegionalHostRecord -> GRDSGWServer (cross-platform parity w/ iOS/Android),
  incl. GRDSGWServerJsonContext.
- CreateStandaloneCredentialsForTransportProtocol(..., GRDSGWServer server).
- Delete dead ConfigureFirstTimeUserPostCredential.
- Bump to 0.46.3-alpha.5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The prototype (ConfigureEapMschapV2UserData) fails in the AOT/SYSTEM service anyway
(RasGetEapUserIdentity -> ERROR_INTERACTIVE_MODE; XML fallback -> COM unsupported under
AOT). This build dials EAP-MSCHAPv2 purely from the RAS-entry config (RASEO_RequireEAP +
dwCustomAuthKey=26) + RasSetCredentials. Test: if IKEv2 EAP-MSCHAPv2 still authenticates
(no RasDial 645), the explicit EAP user-data is NOT needed; if it fails, the prototype is
needed and must be reworked to run in a service.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build A proved EAP-MSCHAPv2 authenticates from the RAS-entry config (RASEO_RequireEAP +
dwCustomAuthKey=26) + RasSetCredentials alone — the RasSetEapUserData prototype was never
needed and couldn't run in the AOT/SYSTEM service anyway. Removes
ConfigureEapMschapV2UserData / ConfigureEapViaXmlConfig / BuildEapMschapV2ConfigXml, the
eappcfg + RasGetEapUserIdentity/RasSetEapUserData/RasSetCustomAuthData P/Invokes, and
RASEAPUSERIDENTITYW. The IKEv2 entry config + cipher suite (df2de66) are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…alpha.8)

On an unplanned RAS drop (e.g. wifi deadspot), PollConnectionState only set suspend
state and never removed the DNS-leak WFP filters. Those PermitQueriesFromTAP filters
permit DNS only on the tunnel LUID and block all else; once the tunnel is dead the
machine can't resolve ANY hostname, so every reconnect's GetServerStatus fails
'host unknown' and reboot is the only recovery (confirmed in CJ's 06-22 logs).

Adds ConnectionRoutines.RemoveDnsFiltersAfterUnplannedDisconnect(), invoked from the
!WasDisconnectPlanned branch; reuses VpnDnsFilteringHandler.UpdateFiltersState which
removes filters when it sees the connection DISCONNECTED (same mechanism the planned
path uses). WireGuard unaffected. Reset Configuration intentionally unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@TimE4DNSF TimE4DNSF self-assigned this Jun 24, 2026
Move SDK to 1.1.0 with VersionSuffix beta.N. New policy: bump the PATCH digit per fix/build
so MSI/consumers can actually upgrade (MSI ProductVersion ignores the 4th .9999 field). No
code change — version/policy only. Carries the full consolidation + DNS-filter-fix line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@TimE4DNSF TimE4DNSF changed the title Fix: remove orphaned DNS-leak filters on unplanned IKEv2 disconnect SDK 1.1.0-beta.1: orphaned-DNS-filter (wifi-loss) fix + 1.1.x version baseline Jun 25, 2026
@TimE4DNSF TimE4DNSF changed the base branch from consolidation-and-cleanup to main June 25, 2026 20:44
@TimE4DNSF TimE4DNSF changed the title SDK 1.1.0-beta.1: orphaned-DNS-filter (wifi-loss) fix + 1.1.x version baseline SDK 1.1.0-beta.1 → main: WireGuard + IKEv2 hardening + wifi-loss fix (all-inclusive) Jun 25, 2026
@TimE4DNSF TimE4DNSF requested a review from tzeejay June 25, 2026 20:50
Comment thread GuardianConnectSDK/GuardianConnect/Credentials/VPNDeviceResponse.cs Outdated
Comment thread GuardianConnectSDK/GuardianConnect/Helpers/GRDVPNHelper.cs Outdated
Comment thread GuardianConnectSDK/GuardianConnect/Helpers/GRDVPNHelper.cs
Comment thread GuardianConnectSDK/GuardianConnect/Helpers/GRDVPNHelper.cs Outdated
Comment thread GuardianConnectSDK/GuardianConnect/Helpers/GRDVPNHelper.cs Outdated
Comment thread GuardianConnectSDK/GuardianConnect/Helpers/GRDVPNHelper.cs Outdated
Comment thread GuardianConnectSDK/Shared/Common.cs Outdated
…connect overload

- GRDVPNHelper: replace `!` null-deny on mainCredential/subCred with sanity
  null-checks that return a graceful errorResponse instead of NRE.
- Remove the string host-override mechanism entirely: drop
  Common.kGuardianPreferredHost, GRDVPNHelper.HostOverrideMismatchAgainst, and
  the host-override-mismatch teardown in ConnectVPNTunnel(). The SDK no longer
  reads any host override — that logic moves wholly to the app Dev window.
- Add overload ConnectVpnWithNewUserCredentialsForProtocol(TransportProtocol,
  GRDSGWServer?) so a caller can drive a specific server explicitly.
- VPNDeviceResponse: regroup client-id under the Shared fields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@TimE4DNSF TimE4DNSF requested a review from tzeejay June 26, 2026 20:46
@TimE4DNSF TimE4DNSF changed the title SDK 1.1.0-beta.1 → main: WireGuard + IKEv2 hardening + wifi-loss fix (all-inclusive) SDK 1.1.1-beta.1 → main: WireGuard + IKEv2 hardening + GRDSGWServer + wifi-loss fix + CJ PR review (all-inclusive) Jun 29, 2026
@TimE4DNSF TimE4DNSF merged commit 381ae28 into main Jun 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants