Open-Source Wikis

/

Node.js

/

Systems

/

Net, TCP, UDP, TLS, and DNS

nodejs/node

Net, TCP, UDP, TLS, and DNS

Owners: @nodejs/net (most paths), @nodejs/crypto (TLS).

Purpose

Expose the BSD-socket-style networking surface that everything else builds on: net.Socket, net.Server, tls.TLSSocket, dgram.Socket, dns.lookup / dns.resolve*. Each of these is a JS class wrapping a libuv handle wrapped by a *Wrap C++ object.

Directory layout

lib/
  net.js
  tls.js
  dns.js
  dgram.js
  _tls_common.js  / _tls_wrap.js   // legacy export shells
  internal/
    net.js
    js_stream_socket.js              // Duplex-over-Duplex helper used by mock TLS
    socketaddress.js
    socket_list.js
    blocklist.js                     // SocketAddress block list
    dns/                             // resolver, promises, utils
    tls/                             // TLSSocket internals: secure-context, parent, etc.
src/
  tcp_wrap.{cc,h}                    // TCP handle wrap
  udp_wrap.{cc,h}                    // UDP handle wrap
  pipe_wrap.{cc,h}                   // named pipe (uv_pipe_t)
  tty_wrap.{cc,h}                    // TTY (uv_tty_t)
  cares_wrap.{cc,h}                  // c-ares DNS resolver glue
  connect_wrap.{cc,h}                // ConnectWrap : ReqWrap
  connection_wrap.{cc,h}             // shared base for TCP + Pipe
  node_sockaddr.{cc,h}               // SocketAddress / Block list
  node_blob.{cc,h}                   // Blob (used by some net APIs)
  crypto/crypto_tls.{cc,h}           // TLSWrap : StreamBase
deps/
  cares/                             // c-ares

Key abstractions

Type / file Role
net.Socket (lib/net.js) Duplex stream over TCPWrap or PipeWrap.
net.Server (lib/net.js) Listening server; uses TCPWrap.listen + accept.
TCPWrap (src/tcp_wrap.cc) Wraps uv_tcp_t, inherits ConnectionWrap : LibuvStreamWrap : StreamBase.
UDPWrap (src/udp_wrap.cc) Wraps uv_udp_t with recv/send.
PipeWrap (src/pipe_wrap.cc) Wraps uv_pipe_t for IPC and named pipes.
TTYWrap (src/tty_wrap.cc) TTY-aware variant of pipe (uv_tty_t).
tls.TLSSocket (lib/_tls_wrap.jslib/tls.js) Duplex layered over TLSWrap and a parent Socket.
TLSWrap (src/crypto/crypto_tls.cc) Streams plaintext into OpenSSL and ciphertext out.
ChannelWrap (src/cares_wrap.cc) c-ares DNS channel; dns.resolve* lives here.
dns.lookup (lib/dns.js) Uses libuv getaddrinfo from the threadpool.
SocketAddress / BlockList (src/node_sockaddr.cc) Address parsing + block-list filter for connection acceptance.

How a TCP request flows

sequenceDiagram
    participant JS as net.Socket
    participant TCPWrap as TCPWrap (C++)
    participant uv as libuv uv_tcp_*
    participant K as kernel

    JS->>TCPWrap: connect(host, port)
    TCPWrap->>uv: uv_tcp_connect
    uv->>K: connect(2)
    K-->>uv: EPOLLOUT / IOCP
    uv-->>TCPWrap: OnConnect
    TCPWrap-->>JS: emit 'connect'
    JS->>TCPWrap: write(buffer)
    TCPWrap->>uv: uv_write
    uv->>K: write(2)
    K-->>uv: completion
    uv-->>TCPWrap: OnAfterWrite
    TCPWrap-->>JS: 'drain' if buffer crosses HWM
    K->>uv: data ready (EPOLLIN)
    uv-->>TCPWrap: OnAlloc + OnRead
    TCPWrap-->>JS: emit 'data'

TLS layering

graph LR
    Plain["TLSSocket (Duplex)"] --> Wrap[TLSWrap]
    Wrap --> SSL[OpenSSL BIOs]
    Wrap --> Parent[parent net.Socket]
    Parent --> TCP[TCPWrap]
    SSL --> Wrap

TLSWrap is itself a StreamBase, so the parent socket can read encrypted bytes from one StreamBase and feed them to OpenSSL via two BIOs (crypto_bio.cc). TLSWrap then exposes the decrypted stream to JS as another StreamBase. The wrap-of-wrap structure is what lets tls.TLSSocket chain over both raw net.Socket and over Duplex user streams (used by tls.connect({ socket })).

OpenSSL access goes through deps/ncrypto/, the project's wrapper library; src/crypto/crypto_tls.cc is built on top.

DNS

Two layers:

  • dns.lookup — libuv's getaddrinfo; runs in the threadpool. JS in lib/dns.js (lookup); C++ in src/cares_wrap.cc (the GetAddrInfoReqWrap).
  • dns.resolve* and dns.Resolver — c-ares (deps/cares/). The Resolver JS class wraps a ChannelWrap that owns a c-ares ares_channel. Each resolve* call posts a QueryWrap ReqWrap; completion fires JS callbacks.

dns.promises exposes the same surface returning Promises (lib/internal/dns/promises.js).

UDP / dgram

dgram.Socket is a EventEmitter (not a stream) over UDPWrap. The C++ side handles receive via uv_udp_recv_start; sends are queued through SendWrap. Multicast / membership is exposed JS-side.

SocketAddress and BlockList

net.SocketAddress / net.BlockList (and the dgram BlockList integration) live in src/node_sockaddr.cc. BlockList allows servers to reject inbound IPs at accept time without ever surfacing them to JS.

Integration points

  • HTTP: http.Server and http.ClientRequest ride on net.Socket. HTTP/2 uses TLS sockets directly; see systems › http-and-quic.
  • undici fetch: vendored at deps/undici/; uses Node's net/tls and an HTTP/1+2 implementation.
  • Permission model: the net permission domain (src/permission/net_permission.cc) gates outbound connect / inbound listen.
  • Inspector: opens a listening TCP socket using TCPWrap directly from C++.

Entry points for modification

  • New TCP feature? lib/net.js for the JS surface, src/tcp_wrap.cc for handle ops, libuv handle for syscall plumbing.
  • New TLS option? Threading new options through is awkward — there are three layers: lib/_tls_wrap.js, the secureContext (lib/internal/tls/), and src/crypto/crypto_context.cc / crypto_tls.cc. Look at any recent --tls-keylog-style PR for the pattern.
  • New DNS resolver? See src/cares_wrap.cc Query<> template; tests at test/parallel/test-dns-*.js and (for network) test/internet/test-dns-*.js.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Net, TCP, UDP, TLS, and DNS – Node.js wiki | Factory