Private/Test-GSAILAProbeIdentification.ps1
|
# # Function: Test-GSAILAProbeIdentification # Validates a single Intelligent Local Access (ILA) DNS-based network identification: checks that the # probe FQDN isn't publicly resolvable (via DNS-over-HTTPS) and that its DNS server/expected IP # addresses are private (RFC1918). Shared by Test-GSAIntelligentLocalAccessConfiguration for both # Graph-retrieved Private Networks and ad-hoc manual checks. # Example: Test-GSAILAProbeIdentification -ContextLabel "Private Network 'Home sweet home'" -FQDN unifi.home.contoso.com -PublicDnsServer https://dns.google/resolve # function Test-GSAILAProbeIdentification { param ( [string]$ContextLabel, [Parameter(Mandatory)] [string]$FQDN, [string[]]$ServerAddresses, [string[]]$ExpectedIPs, [Parameter(Mandatory)] [string]$PublicDnsServer ) $passed = $true # 1. The probe FQDN must NOT be resolvable via a public DNS resolver - if it is, corporate-network # detection can be satisfied from anywhere, causing GSA to falsely bypass traffic locally. # Uses DNS-over-HTTPS rather than a classic port-53 query, since the latter can be silently # intercepted/answered by the local GSA client or a router's own local DNS records. $publiclyResolvable = $false $publicIPs = @() try { $dohUri = "$PublicDnsServer`?name=$([uri]::EscapeDataString($FQDN))&type=A" $dohResponse = Invoke-RestMethod -Uri $dohUri -Headers @{ Accept = 'application/dns-json' } -ErrorAction Stop if ($dohResponse.Status -eq 0) { # Status 0 (NOERROR) alone doesn't guarantee an A record exists - a NODATA response # (e.g. only an Authority/SOA section, no Answer) means the zone exists but this # name doesn't resolve publicly, so only a non-empty Answer counts as resolvable. $publicIPs = @($dohResponse.Answer | Where-Object { $_.type -eq 1 } | Select-Object -ExpandProperty data -ErrorAction SilentlyContinue) $publiclyResolvable = $publicIPs.Count -gt 0 } elseif ($dohResponse.Status -ne 3) { # Status 3 (NXDOMAIN) simply means "not resolvable" - anything else is inconclusive Write-Log "Could not determine public resolvability of '$FQDN' via DNS-over-HTTPS ($PublicDnsServer): DNS status code $($dohResponse.Status)." "WARNING" } } catch { Write-Log "Could not determine public resolvability of '$FQDN' via DNS-over-HTTPS ($PublicDnsServer): $($_.Exception.Message)" "WARNING" } if ($publiclyResolvable) { # A GSA-only device could still return its own synthetic 6.6.x.x address if the DoH provider # itself happened to be covered by a Private Access rule - vanishingly unlikely, but checked # anyway as defense-in-depth so this never produces a false failure. $syntheticIPs = @($publicIPs | Where-Object { $_ -like '6.6.*' }) if ($syntheticIPs.Count -gt 0 -and $syntheticIPs.Count -eq $publicIPs.Count) { Write-Log "$ContextLabel probe FQDN '$FQDN' resolved to a GSA synthetic address ($($syntheticIPs -join ', ')) - the local GSA client is intercepting this query, so public resolvability can't be verified from this device." "WARNING" Write-Log "Recommended action: Re-run this check from a device without the GSA client active for '$FQDN' (e.g. temporarily disable Private Access, or use a machine that doesn't have it installed) to get a trustworthy result." "WARNING" } else { $ipInfo = if ($publicIPs.Count -gt 0) { " (resolves to $($publicIPs -join ', '))" } else { "" } Write-Log "$ContextLabel probe FQDN '$FQDN' is PUBLICLY resolvable via DNS-over-HTTPS$ipInfo." "ERROR" Write-Log "Recommended action: Use an FQDN that only resolves on your internal/corporate DNS servers (no public DNS record). A publicly resolvable probe FQDN defeats corporate-network detection and can cause GSA to incorrectly bypass Private Access traffic locally for users who are NOT on the corporate network (a confirmed real-world root cause of client connectivity failures on hotel/home networks)." "WARNING" $passed = $false } } else { Write-Log "$ContextLabel probe FQDN '$FQDN' is not publicly resolvable - OK." "SUCCESS" } # 2. The DNS server(s) used for the probe should be private/internal addresses only. foreach ($serverAddress in @($ServerAddresses | Where-Object { $_ })) { if (-not (Test-GSAIsPrivateIPv4 -IPAddress $serverAddress)) { Write-Log "$ContextLabel uses a public/non-RFC1918 DNS server address ($serverAddress) for corporate-network detection." "ERROR" Write-Log "Recommended action: Configure an internal DNS server address that is only reachable from inside the corporate network." "WARNING" $passed = $false } } # 3. The expected IP resolution(s) should be private/internal addresses. foreach ($expectedIP in @($ExpectedIPs | Where-Object { $_ })) { if (-not (Test-GSAIsPrivateIPv4 -IPAddress $expectedIP)) { Write-Log "$ContextLabel expects the probe to resolve to a public/non-RFC1918 address ($expectedIP)." "WARNING" Write-Log "Recommended action: Verify this is intentionally using a public IP as its corporate-network indicator; this is unusual for Intelligent Local Access." "WARNING" } } return $passed } |