hypothesisphp/tunnels

PHP socket transport library — AES-256-GCM encryption, ephemeral key exchange with forward secrecy, non-blocking I/O via PHP Fibers, session key rotation, heartbeat keep-alive, replay attack protection, and extensible middleware pipeline.

Maintainers

Package info

github.com/HypothesisPHP/Tunnels

pkg:composer/hypothesisphp/tunnels

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.0 2026-07-17 02:50 UTC

This package is not auto-updated.

Last update: 2026-07-18 01:06:33 UTC


README

PHP socket transport library — secure, non-blocking, and extensible.

Built on native stream_socket with PHP 8.2 Fibers, AES-256-GCM encryption, ephemeral key exchange with forward secrecy, replay-attack-resistant handshake, session key rotation, heartbeat keep-alive, and a fluent API designed for long-running CLI processes.

Features

  • Non-blocking I/O via PHP 8.2 Fibers — no event loop dependency required
  • AES-256-GCM encryption on every frame — authenticated, tamper-proof
  • Ephemeral key exchange — fresh random contributions per session → forward secrecy
  • Secure handshake with HMAC-SHA256, timestamp window ±30s, and nonce tracking (replay protection)
  • Persistent nonce storeInMemoryNonceStore, FileNonceStore, or custom NonceStoreInterface
  • Session key rotation — time-based, volume-based, or composite policies
  • Heartbeat / keep-alive — automatic PING/PONG, idle detection, manual ping() with RTT measurement
  • Receive-side frame guard — 16 MB hard limit on incoming frames
  • Middleware pipelineCompressionMiddleware, PayloadSizeMiddleware, LoggingMiddleware, RateLimitMiddleware (token bucket), HeartbeatMiddleware
  • Observer/Event system — lifecycle events including KEY_ROTATED
  • Fluent builder API — zero boilerplate for common cases
  • TLS transport — configurable cert/key/CA via ->withTls()
  • Zero mandatory dependencies — pure PHP 8.2, no external packages required
  • Extensible by design — swap encryption, handshake, logger, nonce store, or middleware via interfaces
  • Resilient connections — automatic reconnect with exponential backoff
  • Connection pool — multi-peer server management with broadcast support
  • Session statistics — bytes/messages sent/received, uptime, last ping

Requirements

  • PHP 8.2 or higher
  • openssl extension (enabled by default in most PHP distributions)
  • zlib extension (only if using CompressionMiddleware)

Installation

composer require hypothesisphp/tunnels

Quick Start

Server

<?php

use HypothesisPHP\Tunnels\TunnelBuilder;
use HypothesisPHP\Tunnels\Logging\ConsoleLogger;

$tunnel = TunnelBuilder::server('0.0.0.0', 9000)
    ->withSecret('my-super-secret-key-32bytes!!!!!')
    ->withLogger(new ConsoleLogger())
    ->build();

$tunnel->open();

$message = $tunnel->receive();
echo "Received: {$message}" . PHP_EOL;

$tunnel->send('pong');
$tunnel->close();

Client

<?php

use HypothesisPHP\Tunnels\TunnelBuilder;
use HypothesisPHP\Tunnels\Logging\ConsoleLogger;
use HypothesisPHP\Tunnels\Middleware\CompressionMiddleware;
use HypothesisPHP\Tunnels\Middleware\PayloadSizeMiddleware;
use HypothesisPHP\Tunnels\Middleware\RateLimitMiddleware;
use HypothesisPHP\Tunnels\Rotation\CompositeRotationPolicy;
use HypothesisPHP\Tunnels\Rotation\TimeBasedRotationPolicy;
use HypothesisPHP\Tunnels\Rotation\VolumeBasedRotationPolicy;
use HypothesisPHP\Tunnels\Nonce\FileNonceStore;

$tunnel = TunnelBuilder::client('127.0.0.1', 9000)
    ->withSecret('my-super-secret-key-32bytes!!!!!')
    ->withLogger(new ConsoleLogger())
    ->withNonceStore(new FileNonceStore('/var/lib/tunnels'))
    ->withMiddleware(new PayloadSizeMiddleware(512_000))
    ->withMiddleware(new CompressionMiddleware())
    ->withMiddleware(new RateLimitMiddleware(capacity: 100, refillPerSecond: 50))
    ->withKeyRotation(new CompositeRotationPolicy(
        new TimeBasedRotationPolicy(3600),
        new VolumeBasedRotationPolicy(104_857_600),
    ))
    ->withHeartbeat(30)
    ->build();

$tunnel->open();
$tunnel->send('ping');

$response = $tunnel->receive();
echo "Response: {$response}" . PHP_EOL;

print_r($tunnel->stats());

$tunnel->close();

One-shot request/reply

$response = TunnelBuilder::client('127.0.0.1', 9000)
    ->withSecret('my-super-secret-key-32bytes!!!!!')
    ->build()
    ->request('hello');

With TLS

$tunnel = TunnelBuilder::client('secure.example.com', 9000)
    ->withSecret('...')
    ->withTls(
        certFile:   '/etc/ssl/client.crt',
        keyFile:    '/etc/ssl/client.key',
        caFile:     '/etc/ssl/ca-bundle.crt',
        verifyPeer: true,
    )
    ->build();

Middleware

$tunnel = TunnelBuilder::client('127.0.0.1', 9000)
    ->withSecret('...')
    ->withMiddleware(new PayloadSizeMiddleware(1_048_576))
    ->withMiddleware(new CompressionMiddleware(level: 6))
    ->withMiddleware(new RateLimitMiddleware(capacity: 100, refillPerSecond: 50))
    ->withMiddleware(new LoggingMiddleware($logger))
    ->build();

Built-in middleware

Class Purpose
CompressionMiddleware gzip compress/decompress payloads
PayloadSizeMiddleware reject oversized frames (send side)
LoggingMiddleware log payload byte counts
RateLimitMiddleware token bucket rate limiter
HeartbeatMiddleware idle PING/PONG keep-alive (auto via ->withHeartbeat())

Session Key Rotation

use HypothesisPHP\Tunnels\Rotation\TimeBasedRotationPolicy;

$tunnel = TunnelBuilder::client('127.0.0.1', 9000)
    ->withSecret('...')
    ->withKeyRotation(new TimeBasedRotationPolicy(3600)) // rotate every hour
    ->build();

See docs/key-rotation.md for all policies and custom policy guide.

Heartbeat

->withHeartbeat(30)  // PING after 30s idle

// Manual ping with RTT
$rtt = $tunnel->ping();
echo "RTT: {$rtt}ms";

// Liveness check
if (!$tunnel->isAlive()) { /* reconnect */ }

Replay Attack Protection

use HypothesisPHP\Tunnels\Nonce\FileNonceStore;

// Persistent across restarts — prevents replay after server restart
->withNonceStore(new FileNonceStore('/var/lib/tunnels/nonces'))

Events

use HypothesisPHP\Tunnels\Events\TunnelEvents;

$tunnel = TunnelBuilder::client('127.0.0.1', 9000)
    ->withSecret('...')
    ->on(TunnelEvents::CONNECTED,    new ConnectionLogger())
    ->on(TunnelEvents::KEY_ROTATED,  new RotationAuditLogger())
    ->on(TunnelEvents::ERROR,        new AlertNotifier())
    ->build();

All events

Constant Fired when
TunnelEvents::CONNECTING Before connect attempt
TunnelEvents::CONNECTED Connection + handshake successful
TunnelEvents::DISCONNECTED Transport disconnected (includes stats)
TunnelEvents::HANDSHAKE_START Handshake begins
TunnelEvents::HANDSHAKE_SUCCESS Handshake completed
TunnelEvents::HANDSHAKE_FAILED Handshake rejected
TunnelEvents::DATA_SENT Frame sent
TunnelEvents::DATA_RECEIVED Frame received
TunnelEvents::KEY_ROTATED Session key rotated
TunnelEvents::ERROR Any transport/middleware error

Security

  • AES-256-GCM: authenticated encryption — tampering detected on every frame
  • Ephemeral key exchange: fresh random contributions per session → forward secrecy
  • HKDF-SHA256: session key derived from ephemeral values + shared secret — never transmitted
  • HMAC-SHA256: handshake authentication proves knowledge of shared secret
  • Timestamp window ±30s + nonce store: two-layer replay attack prevention
  • Receive-side frame guard: 16 MB hard limit prevents memory exhaustion
  • Rate limiting: token bucket middleware protects against frame flooding
  • TLS: optional transport-layer encryption for public network deployment

Docs

Document Topic
architecture.md Design patterns, data flow, Fiber model
encryption.md AES-256-GCM, key derivation, custom drivers
handshake.md Ephemeral key exchange, replay protection
security.md TLS, nonce stores, frame guard, rate limiting
middleware.md Pipeline, built-in middleware, custom middleware
events.md Observer system, all events, async listeners
heartbeat.md Keep-alive, manual ping, session stats
key-rotation.md Rotation policies, custom policy, KEY_ROTATED event
connection-pool.md Multi-peer management, broadcast
extending.md All extension points with examples

License

MIT — see LICENSE.