webnetstack is a browser-to-localhost networking bridge for Linux that uses existing OS socket APIs while keeping the exposed surface narrow, permissioned, and auditable.
It is inspired by the repository style and capability posture used by WebGPU, WebGL, and WebUSB work: explainer material, protocol/spec notes, examples, tests, and a constrained API surface instead of direct kernel or hardware exposure.
Prototype host bridge plus browser SDK.
Implemented:
- TCP connect/send/receive/close
- UDP connect/send/receive/close
- Real DNS resolution through the host OS resolver
- Real HTTP client requests over
httpandhttps - Real outbound WebSocket client channels over
wsandwss - Permission-descriptor helpers similar in spirit to browser capability requests
- Origin allow-list enforcement
- Secure-origin style restriction:
https://or loopbackhttp:// - Required WebSocket subprotocol:
webnetstack.v1 - Explicit destination allow-list with protocol scope
- Token gate for session establishment
- Payload limits, channel limits, idle timeout, and session timeout
- User-space simulation knobs: latency, jitter, loss, duplication, rate limiting
- Rust integration tests and Jest SDK tests
Not implemented:
- Inbound listeners
- QUIC
- Raw packets
- Interface enumeration
- Kernel stats
- Hardware identifiers
- Browser-native permission prompts
explainer/: rationale and API shape notesspec/: host protocol documentationexamples/: demo page and manifestsdk/: browser-facing JavaScript APIsrc/: Rust host bridgetests/: Rust integration teststools/: local development helpers.github/workflows/: CI
webnetstack is intentionally narrower than native sockets.
Constraints:
- No
/sysreads - No kernel telemetry
- No interface enumeration
- No MAC addresses or host hardware identifiers
- No raw packet or privileged socket features
- Opaque channel handles only
- Explicit origin and destination policy checks
- Session and resource limits enforced by the host
WebNetStack methods:
connect()openTcp()openUdp()openWebSocket()resolveDns()fetchHttp()requestTcpAccess()requestUdpAccess()requestAccess()ping()closeAll()close()getPolicy()getOrigins()getDestinations()getLimits()supportsDestination()
WebNetChannel methods:
send()sendText()sendJson()sendHex()setSimulation()resetSimulation()setLatency()setLoss()setDuplication()setRateLimit()readOnce()waitForClose()close()onMessage()onClose()decode()
Start the host:
cargo run -- --manifest examples/manifest.jsonServe the demo from an allowed loopback origin:
python3 tools/serve_localhost.pyOpen:
http://127.0.0.1:8080/examples/demo.html
Rust:
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo testJavaScript:
npm run test:js{
"token": "dev-token",
"allowOrigins": ["http://127.0.0.1:8080"],
"destinations": [
{ "host": "example.com", "port": 80, "protocols": ["tcp"] },
{ "host": "127.0.0.1", "port": 18080, "protocols": ["tcp", "udp"] }
],
"maxPayloadBytes": 1048576,
"maxChannelsPerSession": 8,
"idleTimeoutMs": 30000,
"sessionTimeoutMs": 300000
}Before pushing to GitHub:
npm ci
cargo test
npm run test:jsIf you want the repository to be fully publishable, the next practical addition is a LICENSE file and any release/versioning policy you want to use.