tcp_tunnel 2.1.0
tcp_tunnel: ^2.1.0 copied to clipboard
A minimalistic TCP tunnel library, entirely written in Dart, and equipped with a user-friendly Command Line Interface (CLI) for seamless usage across diverse platforms.
2.1.0 #
- Security layer for hub-mode connections (opt-in, two independent layers):
- TLS on the agent↔hub links. The hub can serve its control port over TLS
(
hub --tls-cert <pem> --tls-key <pem>/TunnelHub.securityContext); each accepted connection is upgraded withSecureSocket.secureServerbefore its handshake. Agents connect over TLS withpublish/connect --tls, trusting a custom CA with--tls-ca <pem>or accepting any certificate (dev only) with--tls-insecure(TunnelServerAgent/TunnelClientAgent.securityContextandonBadCertificate). Encrypts both the control frames and the raw-piped payload as it crosses the network. No new dependency —dart:ioTLS. - Shared-secret authentication. Agents present a token in their
HELLO, constant-time compared by the hub (TunnelHub.authToken,TunnelServerAgent/TunnelClientAgent.authToken); a mismatch is rejected with aREJECTframe. The token is resolved (in priority order) from--token-file <path>(keeps it out of shell history and the process arg list), theTCP_TUNNEL_TOKENenv var, or--token <secret>. TheHELLOframe now carries an optionaltokenfield; addsconstantTimeEquals. - Both layers are optional and independent; existing plaintext deployments are unaffected. The hub's control-accept loop now runs in the guarded zone so a stray socket error during a TLS handshake or rejection teardown is logged rather than left unhandled.
- TLS on the agent↔hub links. The hub can serve its control port over TLS
(
2.0.1 #
publishcan request a public port from the hub (default off):--public-port <n>(fixed),--public-port any/--public-port .(dynamic), or--public(alias for--public-port any). Exposed asTunnelServerAgent.requestPublicPort. If the request cannot be satisfied — the port is already in use by another service/process, it is unallocatable, or a dynamic request reaches a hub started without--map-dynamic— the hub sends aREJECTcontrol frame andpublishexits non-zero with the reason (TunnelServerAgent.onPublicPortRejected). AddsFrameType.reject; theHELLOframe now carries the agent's public-port request.- Changed
--map-dynamicsemantics: it no longer auto-allocates a public port for every published service. It now only permits publishers to request a dynamic public port via--public-port any; without the flag such requests are rejected with a reason. Operator-configured dynamic ports (--map svc=.) are unaffected, and a service whose agent requests no port stays in local port mode (TunnelHub.dynamicPublicPorts).
2.0.0 #
- Hub mode: a single public hub that routes named services
from private LANs (NAT-friendly on both ends) to remote consumers, using a
pre-warmed pool of parked connections. Two consumer modes share the same hub:
- Mode 1 — public port mode: the hub binds a public TCP port per service
(
--map svc=port); plain TCP clients connect directly. The port may be dynamically allocated with--map svc=.(per service) or--map-dynamic(auto-allocate a port for any published service); the chosen port is logged. Dynamic allocation can be constrained to a firewall-friendly range via--port-range start-end(TunnelHub.dynamicPortRange/PortRange). - Mode 2 — local port mode: a client agent opens a local listen port and uses the hub purely as a rendezvous (no public per-service port needed).
- Mode 1 — public port mode: the hub binds a public TCP port per service
(
- Every CLI command prints a "How to use" block on startup explaining how to publish to / consume from it (the hub block lists allocated public ports).
- The hub now tells each connecting server agent its service's public port (a
WELCOMEcontrol frame);publishlogs where the service is publicly mapped (or that it is local port mode only). Exposed asTunnelServerAgent.publicPort. - New library APIs:
lib/src/tcp_tunnel_protocol.dart: length-prefixed control frames (HELLO/ACTIVATE/PING/PONG/READY),encodeFrame/decodeFrame, andFramedConnection(reads frames across fragmented/coalesced TCP reads).lib/src/tcp_tunnel_hub.dart:TunnelHub.lib/src/tcp_tunnel_agent.dart:TunnelServerAgent(publish) andTunnelClientAgent(connect).
lib/src/tcp_tunnel_base.dart: addedSocketAsync.adopt(FramedConnection)to hand a connection off from the framed handshake to raw piping by reusing the existing single subscription (no re-listen) and replaying leftover bytes.- CLI: new
hub,publish, andconnectmodes. Existinglocal,bridge, andclientmodes are unchanged. - Activation uses an explicit
ACTIVATE/READYbarrier so server-speaks-first protocols (MySQL/SSH/SMTP banners) work and in-flight keepalive frames never leak into the raw stream. - Not included (same posture as before): encryption/TLS, authentication, dynamic public-port allocation, client-specified target addressing.
1.0.2 #
-
lib/src/tcp_tunnel_base.dart:- Added end-to-end backpressure:
SocketAsyncnow owns its stream subscription and pauses reading until the destination's flush completes, preventing unbounded memory growth when one peer is slower than the other. - Connection failures no longer hang:
SocketAsync.unresolvedcloses on a failed connect, andclose()now always notifiesonCloseeven when the socket was never resolved. Tunnel.connectAsync: a failed target connection now closes the tunnel (and firesonClose) instead of hanging forever.- Removed a dead
Socket.handleError(...)handler whose result was discarded; error handling lives in the subscription'sonError. - Added
Tunnel.pair(SocketAsync, SocketAsync)factory;withSocketsandtargetPortnow delegate to it. Tunnel.targetPortnow returnsFuture<Tunnel?>and destroys the inbound socket when the target connection fails.- Verbose data logging now logs byte counts instead of
latin1-decoding payloads; removed the now-unuseddart:convertimport.
- Added end-to-end backpressure:
-
bin/tcp_tunnel.dart:- Fixed
_withFlagto correctly detect single-dash flags. _parseMaxTunnels: added lower bound check to ensure minimum value of 1.- Added graceful shutdown:
SIGINT/SIGTERMnow close active servers and tunnels before exiting (SIGTERMskipped on Windows).
- Fixed
-
lib/src/tcp_tunnel_bridge.dart:- Changed
_server1and_server2fields to nullableServerSocket?. - Added null-aware calls to
_server1?.close()and_server2?.close()inclose(). - Queues now hold
SocketAsyncinstances; a queued socket that closes before being paired is evicted viaonCloseand skipped during pairing, so it is never paired into a dead tunnel.
- Changed
-
lib/src/tcp_tunnel_server.dart:- Changed
_serverfield to nullableServerSocket?. - Added null-aware call to
_server?.close()inclose(). - Updated to the nullable
Tunnel.targetPortresult (logs only on success).
- Changed
-
pubspec.yaml:- Updated
testdependency from^1.31.0to^1.31.1.
- Updated
-
test/tcp_tunnel_test.dart:- Rewrote tests extensively:
- Added utility functions
freePort(),_wait(). - Added
RecordingServerhelper class to record socket data. - Added
echoServerhelper for echoing data. - Added comprehensive tests for:
TunnelLocalServerforwarding data one and both directions.- Multiple concurrent clients support.
TunnelBridgeconnecting queued sockets, FIFO pairing, and close idempotency.Tunnel.withSocketsrelaying data and close notification.- Full chain integration test with bridge, client tunnel, and local server.
- Connection failures firing
onCloseforconnectandconnectAsync. connectAsynclazy connect (target connects only after first remote data).- Backpressure: large payload (4 MiB) transferred byte-for-byte.
TunnelBridgeeviction of a queued socket closed before pairing.- CLI usage smoke test.
connectAsyncforwarding the first (triggering) data to the target and bidirectional round-trip withonReadycompleting.TunnelBridgebuffering data sent while a socket is queued, isolating many concurrent pairs, and tearing down a peer when one side closes.TunnelLocalServerdropping the client when the target is unreachable.onStartcallback,verbosedata path, and customtargetHost.- Edge cases: half-close drain, zero-length writes, reverse-direction
relay, large bidirectional transfer, and
SocketAsyncstate getters.
- Removed old
redirectLocalPort,bridgePorts, andclientTunnelhelper functions. - Improved test reliability with explicit waits and socket flushes.
- Added utility functions
- Rewrote tests extensively:
1.0.2+ #
-
bin/tcp_tunnel.dart:- Added support for
verboseflag in CLI. - Added support for
loopflag and--max-tunnelsoption in client mode. - Added structured logging using
package:logging. - Updated
_configureLoggingto always configure logging with levelALLif verbose, otherwiseINFO. - Changed default logging level in
_configureLoggingfromALLtoINFO. - Refactored main logic to
_runwith verbose and loop parameters. - Added
_withFlaghelper to parse boolean flags.
- Added support for
-
Client mode:
- Added support for parallel connections with a new
_parseParallelsmethod. - Run multiple client tunnels in parallel based on the parsed parallel count.
- Managed multiple tunnels with
_tunnelslist and recursive connection logic in client mode.
- Added support for parallel connections with a new
-
Argument parsing:
- Added
_parseParallelsto parse concurrency-related flags (--concurrency,--parallel,--parallels) with clamping between 2 and max tunnels. - Refactored argument parsing into
_parseArgInthelper method used by_parseMaxTunnelsand_parseParallels.
- Added
-
lib/src/tcp_tunnel_base.dart:- Added guarded zone support with
Tunnel.zoneGuardedandTunnel.runGuarded. - Added
onReadyfuture toTunnelto notify when tunnel is fully established. - Added
connectAsyncfactory for two-phase lazy connection (remote connect → first data → target connect). - Updated
connectfactory to completeonReadyafter both sockets connect. - Updated
targetPortandwithSocketsfactories to completeonReady. - Added
verboseparameter toTunnelconstructors and logging on close. - Improved internal connection and ready notification logic.
- Added guarded zone support with
-
lib/src/tcp_tunnel_bridge.dart:- Added
verboseparameter toTunnelBridge. - Tunnel creation now passes
verboseflag. - Added logging on tunnel connection when verbose enabled.
- Added
-
lib/src/tcp_tunnel_server.dart:- Added
verboseparameter toTunnelLocalServer. - Tunnel creation now passes
verboseflag. - Added logging on new tunnel connection when verbose enabled.
- Added
1.0.1 #
- Updated SDK constraint to
>=3.10.0 <4.0.0. - Updated dependencies:
loggingto ^1.3.0lintsto ^6.1.0dependency_validatorto ^5.0.5testto ^1.31.0
- Added executable entry for
tcp_tunnelinpubspec.yaml. - Changed module type in
tcp_tunnel.imlfromJAVA_MODULEtoWEB_MODULE. bin/tcp_tunnel.dart:- Fixed trailing comma in
_runModeClientparameters.
- Fixed trailing comma in
lib/src/tcp_tunnel_base.dart:- Improved code style in
SocketAsyncandTunnelclasses.
- Improved code style in
lib/tcp_tunnel.dart:- Removed library name declaration (
library tcp_tunnel;) to default unnamed library.
- Removed library name declaration (
1.0.0 #
- Initial version.