demo · v141
Network Topology Explorer
Local Network Access restrictions divide the web into three address spaces — public, private, and loopback — and block public websites from reaching the lower two without an explicit permission grant. Explore the address space taxonomy, classify any IP address, and understand which source→target combinations Chrome 141 allows, prompts for, or outright blocks.
The three address spaces
Any IP not in a reserved range. Normal web traffic. No restrictions imposed by LNA on requests within this space.
93.184.216.34 (example.com)
8.8.8.8 (Google DNS)
2606:2800::1 (IPv6)
RFC 1918 ranges and other local-network blocks. Routers, printers, smart TVs, NAS units live here. LNA gates public-to-private requests.
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
fc00::/7 (IPv6 ULA)
The host itself. Dev servers, local tooling. LNA treats this as even more sensitive than private — public-to-loopback is blocked in most cases.
127.0.0.0/8
::1/128 (IPv6)
IP address classifier
Source → target permission matrix
| Source \ Target | Public | Private | Loopback |
|---|---|---|---|
| Public origin | allowed | blocked* | blocked* |
| Private origin | allowed | allowed | blocked* |
| Loopback origin | allowed | allowed | allowed |
* "blocked" means Chrome sends a CORS preflight requesting Access-Control-Allow-Private-Network: true. Without it the request fails.
Simulate a blocked cross-space fetch
headers a compliant IoT device must serve
# The device at 192.168.1.100 must answer the LNA preflight:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Private-Network: true ← the key header
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
Vary: Origin
# Chrome sends the OPTIONS preflight with:
Access-Control-Request-Private-Network: true
# The device MUST echo back Access-Control-Allow-Private-Network: true
# or Chrome cancels the actual request before it leaves the browser.
a compliant Node.js / Deno device server
// Handles the LNA preflight then the actual request
Deno.serve({ port: 8080 }, (req) => {
const origin = req.headers.get("origin") ?? "";
const corsHeaders = {
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Private-Network": "true",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
"Vary": "Origin",
};
if (req.method === "OPTIONS") {
// respond to LNA preflight immediately
return new Response(null, { status: 204, headers: corsHeaders });
}
return new Response(
JSON.stringify({ device: "smart-plug-001", state: "on" }),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
});