Platform connectivity¶
Platform connectivity problems¶
If you think Enclave is having trouble reaching the Enclave platform, please work through the following checklist to identify the problem.
-
Check https://status.enclave.io/ for any disruptions or service outages
-
Check your systems are enrolled and showing as both connected and approved in the portal
-
Check you're running on the latest version of Enclave with
enclave version -
Check the output of
enclave statusdoesn't contain any warnings or errors -
Check the output of
enclave statuslists at least onePeerand the state shows asUp -
Check network traffic is allowed out to
tcp/*:443 -
Check network traffic is allowed out to
udp/*:1024-65355 -
Check network traffic isn't forced through a SOCKS proxy, which is currently unsupported
-
Check local anti-virus software is not interfering with Enclave by temporarily disabling it
-
Run the platform reachability test script below to systematically verify connectivity to all Enclave platform services
-
Check whether the system in question may have been cloned, duplicating its private key material
Platform reachability test script¶
If you need to systematically verify connectivity to all Enclave platform services, the following scripts resolve DNS for each hostname and test TCP port 443 (and ICMP where applicable) against every resolved address. They report latency and pass/fail status for each check.
The scripts test connectivity to the following hosts:
| Host | Checks | Purpose |
|---|---|---|
api.enclave.io |
TCP 443 | Enclave API |
install.enclave.io |
TCP 443 | Installer and update downloads |
discover.enclave.io |
TCP 443 | Peer discovery service |
relays.enclave.io |
TCP 443, ICMP | Traffic relay servers |
google.com |
TCP 443, ICMP | General internet connectivity |
management.azure.com |
TCP 443, ICMP | Azure management plane |
go.microsoft.com |
TCP 443, ICMP | Microsoft update services |
Save the script below as platform-reachability-report.ps1 and run it on Windows:
.\platform-reachability-report.ps1
# Define the list of domains with their respective checks
$domains = @(
@{
Name = "api.enclave.io"
Checks = @("tcp/443")
},
@{
Name = "install.enclave.io"
Checks = @("tcp/443")
},
@{
Name = "discover.enclave.io"
Checks = @("tcp/443")
},
@{
Name = "relays.enclave.io"
Checks = @("tcp/443", "icmp")
},
@{
Name = "google.com"
Checks = @("tcp/443", "icmp")
},
@{
Name = "management.azure.com"
Checks = @("tcp/443", "icmp")
},
@{
Name = "go.microsoft.com"
Checks = @("tcp/443", "icmp")
}
)
# Execute diagnostic commands
$psCmdlets = @(
"Get-NetAdapter | Format-Table -AutoSize",
"Get-NetIPConfiguration | Format-Table -AutoSize",
"Get-DnsClientServerAddress | Format-Table -AutoSize",
"Get-DnsClient | Format-Table -AutoSize",
"Get-DnsClientGlobalSetting",
"Get-NetIPInterface | Sort-Object InterfaceIndex | Format-Table -AutoSize"
)
$commands = @(
"enclave status",
"enclave self-test",
"route print",
"ipconfig /all",
"nslookup discover.enclave.io",
"nslookup discover.enclave.io 8.8.8.8",
"nslookup google.com",
"nslookup google.com 1.1.1.1",
"nslookup google.com 8.8.8.8",
"ping 8.8.8.8",
"ping 1.1.1.1"
)
function Get-NameserversWithInterfaceNames {
Write-Host "Nameservers"
$onlineAdapters = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' }
$dnsInfo = @()
foreach ($adapter in $onlineAdapters) {
$nameserversIPv4 = Get-DnsClientServerAddress -InterfaceIndex $adapter.InterfaceIndex -AddressFamily IPv4
$nameserversIPv6 = Get-DnsClientServerAddress -InterfaceIndex $adapter.InterfaceIndex -AddressFamily IPv6
$nameservers = @($nameserversIPv4) + @($nameserversIPv6)
foreach ($nameserver in $nameservers) {
foreach ($address in $nameserver.ServerAddresses) {
$dnsInfo += [PSCustomObject]@{
AddressFamily = if ($server -match ":") { "IPv6" } else { "IPv4" }
State = "Up"
InterfaceIndex = $nameserver.InterfaceIndex
InterfaceAlias = $nameserver.InterfaceAlias
Nameserver = $address
}
}
}
}
# Sort the information by AddressFamily (IPv4 first, then IPv6), then InterfaceIndex and InterfaceAlias
$dnsInfo = $dnsInfo | Sort-Object -Property @{Expression="AddressFamily"; Ascending=$true}, InterfaceIndex, InterfaceAlias
# Display the information
$dnsInfo | Format-Table -AutoSize
}
# Function to resolve DNS
function Resolve-Dns {
param (
[string]$Domain
)
$addresses = Resolve-DnsName -Name $Domain -ErrorAction SilentlyContinue
$results = @()
$addresses | ForEach-Object {
$result = [PSCustomObject]@{
Name = $Domain
Address = $_.IPAddress
Type = $_.QueryType
}
# If the result is a CNAME, resolve the CNAME target recursively
if ($_.QueryType -eq 'CNAME') {
$cnameTarget = $_.NameHost
$ip = Resolve-Dns -Domain $cnameTarget
$results += $ip
} else {
$results += $result
}
}
# Deduplicate the results
$uniqueResults = $results | Sort-Object Address, Type -Unique
return $uniqueResults
}
# Function to format output
function Format-Output {
param (
[string]$protocol,
[string]$address,
[string]$status,
[int]$totalLength = 50
)
$line = "$protocol/$address"
$dots = "." * ($totalLength - $line.Length - 4) # Subtract 4 for the brackets and spaces
return " $line $dots [$status]"
}
# Main script logic
Get-NameserversWithInterfaceNames
foreach ($domain in $domains) {
Write-Host "$($domain.Name)"
$resolvedAddresses = Resolve-Dns -Domain $domain.Name
$jobs = @()
foreach ($address in $resolvedAddresses) {
foreach ($check in $domain.Checks) {
if ($check -eq "icmp") {
$jobs += @{
Job = Start-Job -ScriptBlock {
param ($addr)
function Test-IcmpPing {
param (
[string]$Address
)
try {
$pingResult = Test-Connection -ComputerName $Address -Count 1 -WarningAction SilentlyContinue -ErrorAction Stop
if ($pingResult.StatusCode -eq 0) {
return "ok $($pingResult.ResponseTime)ms"
} else {
return "failure $($pingResult.ResponseTime)ms (timeout waiting for a response)"
}
} catch {
if ($Address -match ":") {
return "failure (A socket operation was attempted to an unreachable network [$Address])"
} else {
return "failure ($($_.Exception.Message))"
}
}
}
$status = Test-IcmpPing -Address $addr
return @{ Protocol = "icmp"; Address = $addr; Status = $status }
} -ArgumentList $address.Address
}
} elseif ($check -match "tcp/(\d+)") {
$port = [int]$matches[1]
$jobs += @{
Job = Start-Job -ScriptBlock {
param ($addr, $prt)
function Test-TcpPort {
param (
[string]$ComputerName,
[int]$Port,
[int]$Timeout = 10000
)
try {
$address = [System.Net.IPAddress]::Parse($ComputerName)
$addressFamily = $address.AddressFamily
$tcpClient = New-Object System.Net.Sockets.TcpClient($addressFamily)
$asyncResult = $tcpClient.BeginConnect($address, $Port, $null, $null)
$waitHandle = $asyncResult.AsyncWaitHandle
if ($waitHandle.WaitOne($Timeout, $false)) {
$tcpClient.EndConnect($asyncResult)
$tcpClient.Close()
return "ok"
} else {
$tcpClient.Close()
return "failure (no response)"
}
} catch [System.Net.Sockets.SocketException] {
return "failure $($stopwatch.ElapsedMilliseconds)ms ($($_.Exception.Message))"
} catch {
return "failure $($stopwatch.ElapsedMilliseconds)ms ($($_.Exception.Message))"
}
}
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$tcpResult = Test-TcpPort -ComputerName $addr -Port $prt
$stopwatch.Stop()
$status = if ($tcpResult -match "ok") { "ok $($stopwatch.ElapsedMilliseconds)ms" } else { $tcpResult }
return @{ Protocol = "tcp"; Address = "$addr`:$prt"; Status = $status }
} -ArgumentList $address.Address, $port
}
}
}
}
# Collect job results
foreach ($job in $jobs) {
$result = Receive-Job -Job $job.Job -Wait -AutoRemoveJob
$formattedResult = Format-Output -protocol $result.Protocol -address $result.Address -status $result.Status
Write-Host $formattedResult
}
}
Write-Host "`nExecuting diagnostic commands..."
foreach ($cmd in $psCmdlets) {
Write-Host "`nRunning: $cmd"
Invoke-Expression $cmd
}
foreach ($cmd in $commands) {
Write-Host "`nRunning: $cmd"
Start-Process -FilePath "cmd.exe" -ArgumentList "/c $cmd" -NoNewWindow -Wait
}
Save the script below as platform-reachability-report.sh and run it on Linux or macOS. The script requires dig, ping, and timeout to be installed.
chmod +x platform-reachability-report.sh
./platform-reachability-report.sh
#!/bin/bash
# Define the list of domains with their respective checks
declare -A domains
domains=(
["api.enclave.io"]="tcp/443"
["install.enclave.io"]="tcp/443"
["discover.enclave.io"]="tcp/443"
["relays.enclave.io"]="tcp/443 icmp"
["google.com"]="tcp/443 icmp"
["management.azure.com"]="tcp/443 icmp"
["go.microsoft.com"]="tcp/443 icmp"
)
# Check if required commands are installed
for cmd in dig ping timeout; do
if ! command -v $cmd &> /dev/null; then
echo "Error: $cmd command not found. Please install it to proceed."
exit 1
fi
done
# Function to resolve DNS for both IPv4 and IPv6, including full CNAME resolution to IP addresses
resolve_dns() {
local domain=$1
local addresses=""
local cname=$domain
# Keep resolving CNAMEs until we reach the final A or AAAA records
while :; do
local new_cname=$(dig +short CNAME $cname)
if [[ -z "$new_cname" ]]; then
break
fi
cname=$new_cname
done
# Resolve A and AAAA records for the final resolved domain
local ipv4_addresses=$(dig +short A $cname)
local ipv6_addresses=$(dig +short AAAA $cname)
addresses+="$ipv4_addresses $ipv6_addresses"
if [[ -z "$addresses" || "$addresses" == " " ]]; then
echo "No addresses found for $domain"
else
echo "$addresses"
fi
}
# Function to test ICMP ping
test_icmp_ping() {
local address=$1
local start_time=$(date +%s%3N)
ping -c 1 -W 1 $address &> /dev/null
local end_time=$(date +%s%3N)
local elapsed_time=$((end_time - start_time))
if [ $? -eq 0 ]; then
echo "ok ${elapsed_time}ms"
else
echo "failure (timeout waiting for a response)"
fi
}
# Function to test TCP port
test_tcp_port() {
local address=$1
local port=$2
local start_time=$(date +%s%3N)
timeout 1 bash -c "</dev/tcp/$address/$port" &> /dev/null
local end_time=$(date +%s%3N)
local elapsed_time=$((end_time - start_time))
if [ $? -eq 0 ]; then
echo "ok ${elapsed_time}ms"
else
echo "failure (no response)"
fi
}
# Function to format output
format_output() {
local protocol=$1
local address=$2
local status=$3
local total_length=50
local line="$protocol/$address"
local dots=$(printf '.%.0s' $(seq 1 $((total_length - ${#line} - 4))))
echo " $line $dots [$status]"
}
# Function to display nameserver information
show_nameservers() {
echo -e "\nNameservers\n"
echo -e "AddressFamily Nameserver"
echo -e "------------- ----------"
if command -v nmcli &> /dev/null; then
if nmcli dev show &> /dev/null; then
nmcli dev show | awk '/DNS/ {print $2}' | while read -r ns; do
echo -e "IPv4 $ns\n"
done
return
fi
fi
if command -v resolvectl &> /dev/null; then
if resolvectl status &> /dev/null; then
resolvectl status | awk '/DNS Servers/ {print $3}' | while read -r ns; do
echo -e "IPv4 $ns\n"
done
return
fi
fi
if [ -f /etc/resolv.conf ]; then
if grep "^nameserver" /etc/resolv.conf &> /dev/null; then
grep "^nameserver" /etc/resolv.conf | awk '{print $2}' | while read -r ns; do
echo -e "IPv4 $ns\n"
done
return
fi
fi
echo "Nameserver information not available (requires nmcli, resolvectl, or /etc/resolv.conf)\n"
}
# Main script logic
show_nameservers
for domain in "${!domains[@]}"; do
echo "$domain"
addresses=$(resolve_dns $domain)
if [[ "$addresses" == "No addresses found for $domain" ]]; then
format_output "dns" "$domain" "failure (could not resolve)"
continue
fi
for address in $addresses; do
for check in ${domains[$domain]}; do
if [[ $check == "icmp" ]]; then
status=$(test_icmp_ping $address)
format_output "icmp" "$address" "$status"
elif [[ $check == tcp/* ]]; then
port=$(echo $check | cut -d'/' -f2)
status=$(test_tcp_port $address $port)
format_output "tcp" "$address:$port" "$status"
fi
done
done
done
Results show [ok <latency>] for successful connections and [failure ...] for problems. If all Enclave platform hosts show as ok, the machine has the connectivity it needs. Failures indicate a firewall rule, DNS resolution problem, or network configuration that needs attention. The PowerShell version also runs additional diagnostic commands including enclave status, enclave self-test, routing table, and DNS lookups.
If you're still experiencing connectivity problems after working through this checklist, see collecting logs and contact support.