nrpt-audit.ps1 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. # winnet-ops :: nrpt-audit.ps1
  2. # Dump every NRPT rule with full forensics. Use when probe.ps1 shows
  3. # layer 4 (nslookup) PASS but layer 5 (Resolve-DnsName) FAIL — that's the
  4. # textbook signature of a rogue NRPT entry.
  5. Write-Output "=== NRPT RULES (PowerShell view) ==="
  6. $rules = Get-DnsClientNrptRule
  7. if (!$rules) {
  8. Write-Output "No NRPT rules configured."
  9. return
  10. }
  11. $rules | Format-Table Name, Namespace, NameServers, Comment -AutoSize -Wrap | Out-String | Write-Output
  12. Write-Output ""
  13. Write-Output "=== SUSPICIOUS RULES (catch-all or non-Tailscale) ==="
  14. $bad = $rules | Where-Object {
  15. $_.Namespace -eq "." -or
  16. ($_.NameServers -and ($_.NameServers | Where-Object { $_ -notmatch "^100\.100\.100\.100$|^fd7a:115c:a1e0::53$" }))
  17. }
  18. if ($bad) {
  19. $bad | Format-List Name, Namespace, NameServers, Comment, DohTemplate
  20. } else {
  21. Write-Output "None — only Tailscale MagicDNS rules present (normal)."
  22. }
  23. Write-Output ""
  24. Write-Output "=== REGISTRY FORENSICS (creation source, timestamps) ==="
  25. # NRPT lives in two possible locations:
  26. # 1. HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\DnsPolicyConfig (Group Policy)
  27. # 2. HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters\DnsPolicyConfig (local, set by apps)
  28. $paths = @(
  29. @{Path="HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\DnsPolicyConfig"; Source="Group Policy"},
  30. @{Path="HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters\DnsPolicyConfig"; Source="Local (app-set)"}
  31. )
  32. foreach ($p in $paths) {
  33. if (!(Test-Path $p.Path)) { continue }
  34. Write-Output ("--- " + $p.Source + " :: " + $p.Path + " ---")
  35. Get-ChildItem $p.Path -ErrorAction SilentlyContinue | ForEach-Object {
  36. $values = Get-ItemProperty $_.PSPath
  37. # LastWriteTime via reg.exe (.NET doesn't expose it for subkeys in older PS)
  38. $regOut = reg query $($_.Name -replace "HKEY_LOCAL_MACHINE","HKLM") 2>&1
  39. Write-Output ("Rule: " + $_.PSChildName)
  40. Write-Output (" Comment: " + $values.Comment)
  41. Write-Output (" DNSServers:" + ($values.GenericDNSServers -join "; "))
  42. Write-Output (" Namespaces:" + (($values.Name | Select-Object -First 3) -join "; ") + $(if ($values.Name.Count -gt 3) { " ... (+" + ($values.Name.Count - 3) + " more)" } else { "" }))
  43. Write-Output ""
  44. }
  45. }
  46. Write-Output "=== ATTRIBUTION HINTS ==="
  47. # Match comments / DNS IPs to known VPN clients
  48. $rules | ForEach-Object {
  49. $hint = switch -Regex ($_.Comment + " " + ($_.NameServers -join " ")) {
  50. "Proton" { "Proton VPN" }
  51. "Mullvad" { "Mullvad" }
  52. "AnyConnect|Cisco" { "Cisco AnyConnect" }
  53. "Nord" { "NordVPN" }
  54. "DirectAccess" { "Windows DirectAccess (corporate)" }
  55. "10\.2\.0\." { "Proton VPN (default DNS gateway)" }
  56. "10\.64\.0\." { "Mullvad (default DNS gateway)" }
  57. "100\.100\.100\.100" { "Tailscale MagicDNS (expected)" }
  58. default { "" }
  59. }
  60. if ($hint) {
  61. Write-Output (" " + $_.Name + " :: likely " + $hint)
  62. }
  63. }