Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

tls: native bidirectional TLS bridge for kernel-adjacent forwarding (TUN/VPN/proxy workloads)

Aperta
#63,953 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
30/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Tranquilla
Stack tecnologico
javascript, node.js

Direzione di ricerca

Inizia leggendo src/crypto/crypto_tls.cc intorno a TLSWrap::ClearOut(), EncOut() e DoWrite(), quindi esamina test-tls-onread-static-buffer.js. Questa proposta richiede l’accordo dei maintainer sull’API, sulla proprietà di fd, sul threading e sul comportamento del ciclo di vita. Il lavoro è completo quando test e benchmark concordati dimostrano il forwarding TLS bidirezionale senza la gestione del payload JavaScript per ogni chunk.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

feature request
What is the problem this feature will solve?

Node’s TLSSocket is designed for application-level stream I/O: cleartext is delivered to JavaScript via the streams API ('data', read(), backpressure via pause()/drain). For high-throughput, full-duplex, kernel-adjacent forwarding (TUN/TAP tunnels, VPN bridges, L3 proxies), users must implement a JS pump between a native fd and a TLSSocket.

That pattern degrades badly in practice:

  • Per-chunk V8 boundary — TLSWrap::ClearOut() reads via SSL_read, copies into an allocated buffer, and EmitRead() into JS (src/crypto/crypto_tls.cc, kClearOutChunkSize = 16384).
  • Extra event-loop turns — sync underlying writes are deferred with SetImmediate before WriteWrap::Done() (EncOut() / empty DoWrite() paths).
  • Dual backpressure — the app must coordinate pause/resume between two independent stream endpoints (e.g. TUN poll + TLS socket) in JavaScript.
  • No framing help — TLS is a byte stream; L3 frames (e.g. IPv6 packets) often require reassembly across multiple reads in userland.
  • Real-world impact: projects doing iOS CoreDevice / CDTunnel-style forwarding (e.g. Appium appium-ios-tuntap) had to leave Node TLS entirely and implement OpenSSL forwarding in a native addon with dedicated blocking I/O threads — duplicating logic that conceptually belongs next to TLSWrap.

The stream API remains correct for HTTP, RPC, etc.; this gap is specifically for payload forwarding where JS should never see the bytes.

What is the feature you are proposing to solve the problem?

Add a first-class native TLS bridge API that pumps cleartext between an encrypted TCP (or pipe) stream and another native I/O endpoint without surfacing payload data to JavaScript.

Proposed API (sketch):

import tls from 'node:tls';
import net from 'node:net';
const tcp = net.connect({ port });
const bridge = tls.createBridge({
  socket: tcp,              // existing net.Socket / fd
  sink: tunFd,              // numeric fd or native handle (TUN, pipe, etc.)
  credentials: { cert, key }, // or secureContext / PSK options
  direction: 'duplex',      // 'duplex' | 'encrypt-only' | 'decrypt-only'
  onError(err) { /* lifecycle */ },
  onClose() { /* cleanup */ },
});
await bridge.handshake();   // or auto on first I/O
bridge.start();
bridge.stop();

Implementation outline (in core, built on existing TLSWrap):

  • Reuse TLSWrap + OpenSSL session setup (lockdown cert, TLS-PSK, etc.) — same crypto as tls.connect().
  • Run the hot loop in native code (dedicated per-connection thread or integrated read/write cycle in TLSWrap), analogous to ClearIn → ClearOut → EncOut but wired directly to the sink fd instead of EmitRead/DoWrite.
  • JavaScript receives only: handshake result, errors, close — not per-packet callbacks.
  • Support dup()/fd ownership semantics documented clearly (who closes what).

Success criteria:

  1. Sustained bidirectional TLS 1.2 forwarding at path-MTU record sizes without per-chunk JS allocation.
    p99 latency and CPU use materially better than an equivalent socket.on('data') ↔ tun.write() pump.
  2. Add-on authors (TUN, userspace VPN, transparent proxies) can delete custom OpenSSL pthread forwarders.
What alternatives have you considered?
  • Stay on TLSSocket + streams — Correct for apps, insufficient for tunnel workloads; requires JS pump and suffers the costs above. This is what forced native-addon workarounds today.
  • socket.on('data') + onread static buffer — Helps TCP; TLSWrap::ClearOut() still copies before JS (test-tls-onread-static-buffer.js covers TCP onread, not a TLS zero-copy path). Does not remove the V8 boundary for cleartext payload.
  • Third-party native addons (custom OpenSSL in N-API) — Works (proven in production) but duplicates TLSWrap session management, cert/PSK handling, and security updates. Every VPN/tunnel project reinvents the same forwarder.
  • node:quic patterns — QUIC has native stream handling oriented toward protocol I/O; CDTunnel / lockdown TLS 1.2 over TCP is a different stack and not a drop-in substitute.
  • Document “don’t use TLS for this” only — Honest but pushes ecosystem fragmentation; a small, targeted tls.createBridge() (or similar) keeps advanced use cases on supported Node APIs.
Lingua principale
JavaScript
Stelle
122k
Fork
37.4k
Merge medio
4g 3h
PR unite (30g)
279

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di nodejs/node

Tutte le issue di nodejs/node

Issue simili

Altre issue su JavaScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.