# ============================================================ # Hotspot IPv6 readiness test (pure ASCII -- safe to copy/paste) # # Purpose: # 1) After connecting this laptop to a PHONE HOTSPOT, # check whether the laptop receives a global IPv6 address. # 2) Check whether the HOME host can be reached directly over IPv6. # # Output: Desktop\hotspot-ipv6-result.txt # ============================================================ # --- change these two lines if the home IPv6 address changes --- $HOME_V6 = '240e:338:263:3600:29f1:e63f:d476:597e' $HOME_PORT = 38443 # --------------------------------------------------------------- $desk = [Environment]::GetFolderPath('Desktop') if (-not $desk) { $desk = $env:TEMP } $o = Join-Path $desk 'hotspot-ipv6-result.txt' $L = New-Object System.Collections.Generic.List[string] function A($s) { $L.Add([string]$s) } function Flush() { $L -join "`r`n" | Set-Content -Path $o -Encoding UTF8 } $okOut = $false $okHome = $false A ('TIME ' + (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')) A ('HOST ' + [System.Net.Dns]::GetHostName()) A ('RESULT FILE: ' + $o) A '' A '[1] Global IPv6 addresses on this machine' $ga = @(Get-NetIPAddress -AddressFamily IPv6 -ErrorAction SilentlyContinue | Where-Object { $_.IPAddress -notlike 'fe80*' -and $_.IPAddress -ne '::1' }) if ($ga.Count -eq 0) { A ' NONE <-- this network gives NO global IPv6' } else { foreach ($a in $ga) { A (" {0} :: {1}/{2} :: Pref={3} Suffix={4} State={5}" -f ` $a.InterfaceAlias, $a.IPAddress, $a.PrefixLength, ` $a.PrefixOrigin, $a.SuffixOrigin, $a.AddressState) } } Flush A '' A '[2] IPv6 default route' $r = @(Get-NetRoute -AddressFamily IPv6 -DestinationPrefix '::/0' -ErrorAction SilentlyContinue) if ($r.Count -eq 0) { A ' NONE' } else { foreach ($x in $r) { A (" {0} -> {1}" -f $x.InterfaceAlias, $x.NextHop) } } Flush function Tcp6([string]$h, [int]$port, [int]$ms) { try { $a = @([System.Net.Dns]::GetHostAddresses($h) | Where-Object { $_.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetworkV6 }) if ($a.Count -eq 0) { return 'NO-AAAA' } $ad = $a[0] $c = New-Object System.Net.Sockets.TcpClient($ad.AddressFamily) $iar = $c.BeginConnect($ad, $port, $null, $null) if (-not $iar.AsyncWaitHandle.WaitOne($ms, $false)) { $c.Close(); return 'TIMEOUT' } try { $c.EndConnect($iar); $c.Close(); return ('OK ' + $ad.IPAddressToString) } catch { $c.Close(); return ('FAIL ' + $_.Exception.Message) } } catch { return ('ERR ' + $_.Exception.Message) } } A '' A '[3] Outbound IPv6 test (decisive for the whole route)' foreach ($h in @('ipv6.icanhazip.com', 'www.taobao.com')) { $res = Tcp6 $h 443 4000 A (" {0}:443 -> {1}" -f $h, $res) if ($res -like 'OK*') { $okOut = $true } } Flush A '' A '[4] Direct reach to HOME host over IPv6 (the real goal)' $u = 'http://[' + $HOME_V6 + ']:' + $HOME_PORT + '/' A (' target = ' + $u) try { $r2 = Invoke-WebRequest -Uri $u -UseBasicParsing -TimeoutSec 6 A (' HTTP status = ' + $r2.StatusCode) A (' body line 1 = ' + (($r2.Content -split '\r?\n')[0])) if ($r2.StatusCode -eq 200) { $okHome = $true } } catch { A (' FAILED: ' + $_.Exception.Message) } Flush A '' A '===== SUMMARY =====' if ($okOut -and $okHome) { A ' PASS: hotspot gives IPv6 AND home host is reachable.' A ' -> The IPv6 direct route is viable from this laptop.' } elseif ($okOut -and -not $okHome) { A ' PARTIAL: IPv6 outbound OK, but home host unreachable.' A ' -> Most likely the home gateway blocks inbound IPv6,' A ' or the home IPv6 address/prefix has changed.' } else { A ' FAIL: no usable IPv6 outbound on this network.' A ' -> The hotspot handed out no IPv6 (IPv6 sharing may be off).' } Flush