When a net.Server is configured with a `blockList`, the peer address is
looked up with getpeername() and checked before the connection is
accepted. If the peer address cannot be obtained (for example, the
connection was reset before getpeername(), causing
uv_tcp_getpeername() to return ENOTCONN), the access-control check was
silently skipped and the connection proceeded, allowing a blocked peer
to reach the application's 'connection' handler (fail open).
Fail closed: when a BlockList is configured but the peer address cannot
be determined, close the connection instead of bypassing the check. A
connection whose peer address cannot be obtained cannot be proven to be
allowed, so it must be refused.
Ref: https://github.com/nodejs/node/issues/66422
Ref: https://github.com/libuv/libuv/pull/5337
Signed-off-by: Matteo Collina <hello@matteocollina.com>
Assisted-by: pi
PR-URL: https://github.com/nodejs/node/pull/66640
Refs: https://github.com/nodejs/node/issues/66422
Refs: https://github.com/libuv/libuv/pull/5337
Reviewed-By: Tim Perry <pimterry@gmail.com>
This adds support for transferring net.BoundSocket instances to other
threads via the worker_threads postMessage() transfer list, and for
sending them to child processes as the sendHandle argument of
subprocess.send(), following on from the BoundSocket introduction.
A BoundSocket reserves a port synchronously at construction time.
Making it transferable means a port can be reserved on one thread or
process and the bound (but not yet listening or connected) TCP handle
handed off to another to listen or connect on, without racing on the
bind.
For threads, BoundSocket implements kTransfer/kTransferList/
kDeserialize, moving the underlying TCP handle with the same mechanism
used for net.Socket and net.Server transfer. For child processes, the
handleConversion entry reuses the same transfer protocol on the
sending side and the same _TransferredBoundSocket deserialization path
on the receiving side; the underlying transport is that of cluster's
shared-handle scheduling: SCM_RIGHTS on Unix and WSADuplicateSocket on
Windows, both of which carry bind state.
In both cases the source instance is left in the adopted state:
address(), fd() and close() throw ERR_SOCKET_HANDLE_ADOPTED. Transfer
requires an un-adopted, open TCP handle, otherwise
ERR_WORKER_HANDLE_NOT_TRANSFERABLE is thrown; pipe (path) binds are
not transferable and throw ERR_INVALID_HANDLE_TYPE when sent over IPC.
On the receiving side the local address is re-derived from the handle
rather than trusted from serialized state.
Signed-off-by: Guy Bedford <guybedford@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/64725
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
The fix and approach are from #64491 by Shivay-98; this reopens it to
get it landed, since the original stalled awaiting requested changes.
`Socket.prototype._unrefTimer` and `Socket.prototype._destroy` both walk
the `_parent` chain with a strict `!== null` check. During connection
teardown a socket's `_parent` can be left `undefined` (for example a TLS
socket layered over another stream), so the loop steps onto `undefined`
and reads a property off it, throwing a TypeError:
Cannot read properties of undefined (reading 'Symbol(timeout)')
from an uncaught I/O callback and crashing the process.
Using a nullish (`!= null`) check terminates the walk on both `null` and
`undefined`.
[petter@hightouch.io: apply the same fix to the identical loop in
`_destroy`, which the original regression test already exercised via
`destroy()`; add direct unit coverage for both paths.]
Fixes: https://github.com/nodejs/node/issues/64490
Refs: https://github.com/nodejs/node/pull/64491
Signed-off-by: Petter Häggholm <petter@hightouch.io>
PR-URL: https://github.com/nodejs/node/pull/64644
Fixes: https://github.com/nodejs/node/issues/64490
Refs: https://github.com/nodejs/node/pull/64491
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Add an experimental `net/promises` namespace, accessible via
`require('node:net/promises')` or `net.promises`, mirroring the existing
`fs/promises` and `dns/promises` modules.
It provides promise-based variants of net's one-shot lifecycle
operations:
- `connect()` returns a promise that fulfills with a connected Socket
once the 'connect' event fires, and rejects on connection failure or
when an optional AbortSignal is aborted, destroying the socket.
- `listen()` creates a server, begins listening, and returns a promise
that fulfills with the listening Server once the 'listening' event
fires. It rejects if the server fails to bind or an optional
AbortSignal is aborted, closing the server.
The functions are named for the actions they await, forming a parallel
`connect()`/`listen()` pair. This is intentionally not the callback
API's factory taxonomy: there `createConnection()` is canonical because
it both creates a socket and initiates connecting, whereas
`createServer()` is a pure factory that does not listen. A
`createConnection`/`createServer` pairing would be inconsistent here
because `createServer` has no completion to await, so no
`createConnection` alias is provided.
Refs: https://github.com/nodejs/node/issues/21482
Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ethan Arrowood <ethan@arrowood.dev>
PR-URL: https://github.com/nodejs/node/pull/63965
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
`tls.connect()` silently ignores `keepAlive`, `keepAliveInitialDelay`,
and `noDelay` options. The documentation states it accepts any
`socket.connect()` option, and `net.createConnection()` with the same
options works correctly.
Forward the options through both code paths so `net.Socket`'s
constructor stores them on the internal symbols (`kSetNoDelay`,
`kSetKeepAlive`, `kSetKeepAliveInitialDelay`), which `afterConnect()`
then applies to the handle.
Fixes: https://github.com/nodejs/node/issues/62003
PR-URL: https://github.com/nodejs/node/pull/62004
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Defer socket.destroy() calls in internalConnect and
internalConnectMultiple to the next tick. This ensures that error
handlers have a chance to be set up before errors are emitted,
particularly important when using http.request with a custom
lookup function that returns synchronously.
Previously, if a synchronous lookup function returned an IP that
triggered an immediate error (e.g., via blockList), the error would
be emitted before the HTTP client had set up its error handler
(which happens via process.nextTick in onSocket). This caused
unhandled 'error' events.
Fixes: https://github.com/nodejs/node/issues/48771
PR-URL: https://github.com/nodejs/node/pull/61658
Refs: https://github.com/nodejs/node/pull/51038
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Jason Zhang <xzha4350@gmail.com>
Previously, the 'net.client.socket' diagnostics channel was only
published to when `net.connect()` was called. This change ensures the
message is also published for the following calls:
- net.createConnection()
- net.Socket#connect()
- tls.connect()
Signed-off-by: Darshan Sen <raisinten@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/58349
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: theanarkh <theratliter@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>