readme.md for @push.rocks/smartvpn
A high-performance VPNΒ solution with a TypeScript control plane and a Rust data plane daemon. ManageEnterprise-ready VPNclient connectionsauthentication, withtriple clean,transport fully-support (WebSocket + QUIC + WireGuard), and a typed APIshub whileAPI allfor networkingmanaging heavyclients liftingfrom β encryption, tunneling, QoS, rate limiting β runs at native speed in Rust.code.
ππ Noise NKIK handshakemutual +authentication XChaCha20-Poly1305β encryptionper-client X25519 keypairs, server-side registry
π Triple transport: WebSocket (Cloudflare-friendly), raw QUIC (datagrams), and WireGuard (standard protocol)
π‘οΈ ACL engineΒ β deny-overrides-allow IP filtering, aligned with SmartProxy conventions
π Adaptive QoS: packetper-client classification,rate limiting, priority queues, per-clientconnection ratequality limitingtracking
π Auto-transportHub API: triesone QUICcreateClient() first,call fallsgenerates backkeys, toassigns WebSocketIP, seamlesslyreturns both SmartVPN + WireGuard configs
π‘ Real-time telemetry: RTT, jitter, loss,loss ratio, link health β all exposed via typed APIs
π‘οΈ WireGuard mode: full userspace WireGuard via boringtunΒ β generate .confΒ files, manage peers live
Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.
InstallΒ π¦
pnpm install @push.rocks/smartvpn
# or
npm install @push.rocks/smartvpn
The package ships with pre-compiled Rust binaries for linux/amd64Β and linux/arm64. No Rust toolchain required at runtime.
Architecture ποΈΒ Architecture
TypeScript (control plane) Rust (data plane)
ββββββββββββββββββββββββββββββββ JSON-lines IPC ββββββββββββββββββββββββββββββββββββββ
β VpnClientTypeScript /Control VpnServerPlane β β smartvpn_daemonβββββββββββββββββββββββΊ β βRust ββData VpnBridgePlane βββstdio/βββΆ β ββ management (JSON IPC) β
β ββ RustBridge β socket β ββ transport_trait (abstraction) β
β (smartrust)Daemon β
β β ββstdio transportor (WebSocket/TLS)Unix sock β β
β βVpnServer β/ ββ quic_transport (QUIC/UDP)VpnClient β β WgConfigGeneratorNoise IK handshake β
β ββTyped wireguardIPC (boringtun WG)commands β β ββ .conf file outputXChaCha20-Poly1305 β
β ββConfig cryptovalidation (Noiseβ NKβ WS + XCha20)QUIC + WireGuard β
β Hub: client management β β TUN device, IP pool, NAT β
β WireGuard .conf generation β β Rate limiting, ACLs, QoS β
ββββββββββββββββββββββββββββ β ββ codec (binary framing) β
β ββ keepalive (adaptive state FSM) β
β ββ telemetry (RTT/jitter/loss) β
β ββ qos (classify + priority Q) β
β ββ ratelimit (token bucket) β
β ββ mtu (overhead calc + ICMP) β
β ββ tunnel (TUN device) β
β ββ network (NAT/IP pool) β
β ββ reconnect (exp. backoff) β
βββββββ βββββββββββββββββββββββββββββββββ
KeySplit-plane design decisions:β TypeScript handles orchestration, config, and DX; Rust handles every hot-path byte with zero-copy async I/O (tokio, mimalloc).
Quick Start π
Decision
1. ChoiceStart Whya
VPN Server (Hub)
import Transport{ VpnServer } from '@push.rocks/smartvpn';
const server = new VpnServer({ transport: { transport: 'stdio' } });
await server.start({
listenAddr: '0.0.0.0:443',
privateKey: '<server-noise-private-key-base64>',
publicKey: '<server-noise-public-key-base64>',
subnet: '10.8.0.0/24',
transportMode: 'both', // WebSocket + QUIC +simultaneously
WireGuardenableNat: WStrue,
worksdns: through['1.1.1.1', Cloudflare;'8.8.8.8'],
QUIC});
gives
low2. latencyCreate +a datagrams;Client WG(One forCall = Everything)
const bundle = await server.createClient({
clientId: 'alice-laptop',
tags: ['engineering'],
security: {
destinationAllowList: ['10.0.0.0/8'], // can only reach internal network
destinationBlockList: ['10.0.0.99'], // except this host
rateLimit: { bytesPerSec: 10_000_000, burstBytes: 20_000_000 },
},
});
// bundle.smartvpnConfig β typed IVpnClientConfig, ready to use
// bundle.wireguardConfig β standard protocolWireGuard interop.conf string
// boringtunstdiosocket[type:1B][length:4B][payload:NB]π Quick Start
VPN3. Connect a Client
import { VpnClient } from '@push.rocks/smartvpn';
const client = new VpnClient({ transport: { transport: 'stdio' }, });
await client.start();
const { assignedIp } = await client.connect({
serverUrl: 'wss://vpn.example.com/tunnel',
serverPublicKey: 'BASE64_SERVER_PUBLIC_KEY',
dns: ['1.1.1.1', '8.8.8.8'],
mtu: 1420,
keepaliveIntervalSecs: 30,
})bundle.smartvpnConfig);
console.log(`Connected! AssignedVPN IP: ${assignedIp}`);
Features β¨
π Enterprise Authentication (Noise IK)
Every client authenticates with a Noise IK handshakeΒ (Noise_IK_25519_ChaChaPoly_BLAKE2s). The server verifies the client's static public key against its registry β unauthorized clients are rejected before any data flows.
rotateClientKey()Β β generates new keys, returns fresh config bundle, disconnects old session
π Triple Transport
The server can run all three simultaneouslyΒ with transportMode: 'both'Β (WS + QUIC) or 'wireguard'. Clients auto-negotiate with transport: 'auto'Β (tries QUIC first, falls back to WS).
π‘οΈ ACL Engine (SmartProxy-Aligned)
Security policies per client, using the same ipAllowListΒ / ipBlockListΒ naming convention as @push.rocks/smartproxy:
security: {
ipAllowList: ['192.168.1.0/24'], // source IPs allowed to connect
ipBlockList: ['192.168.1.100'], // deny overrides allow
destinationAllowList: ['10.0.0.0/8'], // VPN destinations permitted
destinationBlockList: ['10.0.0.99'], // deny overrides allow
maxConnections: 5,
rateLimit: { bytesPerSec: 1_000_000, burstBytes: 2_000_000 },
}
Supports exact IPs, CIDR, wildcards (192.168.1.*), and ranges (1.1.1.1-1.1.1.100).
π Telemetry & QoS
healthy degraded critical)
Adaptive keepalives: Interval adjusts based on link health (60s β 30s β 10s)
Per-client rate limiting: Token bucket with configurable bytes/sec and burst
Dead-peer detection: 180s inactivity timeout
MTU management: Automatic overhead calculation (IP+TCP+WS+Noise = 79 bytes)
π Hub Client Management
The server acts as a hubΒ β one API to manage all clients:
// Create (generates keys, assigns IP, returns config bundle)
const qualitybundle = await client.getConnectionQuality();
console.log(quality);
// server.createClient({ // srttMs: 42.5, jitterMs: 3.2, minRttMs: 38.0, maxRttMs: 67.0,
// lossRatio: 0.0, consecutiveTimeouts: 0,
// linkHealth:clientId: 'healthy', currentKeepaliveIntervalSecs: 60
// }
// MTU info
const mtu = await client.getMtuInfo();
console.log(mtu);
// { tunMtu: 1420, effectiveMtu: 1421, linkMtu: 1500, overheadBytes: 79, ... }
// Traffic stats (includes quality snapshot)
const stats = await client.getStatistics();
await client.disconnect();
client.stop();
VPN Client with QUIC
import { VpnClient } from '@push.rocks/smartvpn';
// Explicit QUIC β serverUrl is host:port, pinned by cert hash
const quicClient = new VpnClient({
transport: { transport: 'stdio' },
});
await quicClient.start();
const { assignedIp } = await quicClient.connect({
serverUrl: 'vpn.example.com:443',
serverPublicKey: 'BASE64_SERVER_PUBLIC_KEY',
transport: 'quic',
serverCertHash: 'BASE64_SHA256_CERT_HASH', // printed by server on startupbob-phone' });
// Or use auto-transport: tries QUIC first (3s timeout), falls back to WSRead
const autoCliententry = new VpnClient({
transport: { transport: 'stdio' },
});
await autoClient.start();
await autoClient.connect({
serverUrl: server.getClient('wss://vpn.example.com/tunnel', // WS URL β host:port extracted for QUIC attempt
serverPublicKey: 'BASE64_SERVER_PUBLIC_KEY',
transport: 'auto', // default β QUIC first, then WS
});
VPN Client with WireGuard
import { VpnClient } from '@push.rocks/smartvpn';
const wgClient = new VpnClient({
transport: { transport: 'stdio' },
});
await wgClient.start(bob-phone');
const { assignedIp }all = await wgClient.connect({
serverPublicKey: 'BASE64_SERVER_WG_PUBLIC_KEY',
serverUrl: '',server.listRegisteredClients();
// notUpdate used(ACLs, fortags, WireGuarddescription, transport:rate limits...)
await server.updateClient('wireguard'bob-phone', wgPrivateKey:{
'BASE64_CLIENT_PRIVATE_KEY',security: wgAddress:{ '10.8.0.2',
wgAddressPrefix: 24,
wgEndpoint: 'vpn.example.com:51820',
wgAllowedIps:destinationAllowList: ['0.0.0.0/0']Β },
// route all traffic
wgPersistentKeepalive: 25,
wgPresharedKey: 'OPTIONAL_PSK', // optional extra layer
dns:tags: ['1.1.1.1']mobile', mtu: 1420,
});
console.log(`WireGuard connected! IP: ${assignedIp}`);
await wgClient.disconnect();
wgClient.stop();
VPN Server
import { VpnServer } from '@push.rocks/smartvpn';
const server = new VpnServer({
transport: { transport: 'stdio' }field-ops'],
});
// GenerateEnable a/ Noise keypair firstDisable
await server.start(disableClient('bob-phone'); // disconnects + blocks reconnection
await server.enableClient('bob-phone');
// Key rotation
const keypairnewBundle = await server.generateKeypair(rotateClientKey('bob-phone');
// StartExport theconfig VPN(without listenersecrets)
const wgConf = await server.start({
listenAddr: exportClientConfig('0.0.0.0:443',
privateKey: keypair.privateKey,
publicKey: keypair.publicKey,
subnet: '10.8.0.0/24',
dns: ['1.1.1.1'],
mtu: 1420,
enableNat: true,
// Transport mode: 'websocket'bob-phone', 'quic', 'both', or 'wireguard'
transportMode: 'both',
// Optional: separate QUIC listen address
quicListenAddr: '0.0.0.0:4433',
// Optional: QUIC idle timeout
quicIdleTimeoutSecs: 30,
// Optional: default rate limit for all new clients
defaultRateLimitBytesPerSec: 10_000_000, // 10 MB/s
defaultBurstBytes: 20_000_000, // 20 MB burst
});
// List connected clients
const clients =Remove
await server.listClients();
// Per-client rate limiting (live, no reconnect needed)
await server.setClientRateLimit(removeClient('client-id', 5_000_000, 10_000_000);
await server.removeClientRateLimit('client-id'); // unlimited
// Per-client telemetry
const telemetry = await server.getClientTelemetry('client-id');
console.log(telemetry);
// {
// clientId, assignedIp, lastKeepaliveAt, keepalivesReceived,
// packetsDropped, bytesDropped, bytesReceived, bytesSent,
// rateLimitBytesPerSec, burstBytes
// }
// Kick a client
await server.disconnectClient('client-id');
await server.stopServer();
server.stop(bob-phone');
WireGuard Server Mode
import { VpnServer } from '@push.rocks/smartvpn';
const wgServer = new VpnServer({
transport: { transport: 'stdio' },
});
// Generate aπ WireGuard X25519Config keypair
await wgServer.start();
const keypair = await wgServer.generateWgKeypair();
console.log(`Server public key: ${keypair.publicKey}`);
// Start in WireGuard mode
await wgServer.start({
listenAddr: '0.0.0.0:51820',
privateKey: keypair.privateKey,
publicKey: keypair.publicKey,
subnet: '10.8.0.0/24',
transportMode: 'wireguard',
wgListenPort: 51820,
wgPeers: [
{
publicKey: 'CLIENT_PUBLIC_KEY_BASE64',
allowedIps: ['10.8.0.2/32'],
persistentKeepalive: 25,
},
],
enableNat: true,
dns: ['1.1.1.1'],
mtu: 1420,
});
// Live peer management β add/remove peers without restart
await wgServer.addWgPeer({
publicKey: 'NEW_CLIENT_PUBLIC_KEY',
allowedIps: ['10.8.0.3/32'],
persistentKeepalive: 25,
});
// List peers with live stats
const peers = await wgServer.listWgPeers();
for (const peer of peers) {
console.log(`${peer.publicKey}: β${peer.bytesSent} β${peer.bytesReceived}`);
}
// Remove a peer by public key
await wgServer.removeWgPeer('CLIENT_PUBLIC_KEY_BASE64');
await wgServer.stopServer();
wgServer.stop();
Generating WireGuard .conf FilesGeneration
The WgConfigGeneratorΒ createsGenerate standardΒ WireGuard .conf files compatiblefor with wg-quick, iOS/Android apps, and all standardany WireGuard clients:client:
import { WgConfigGenerator } from '@push.rocks/smartvpn';
// Client config (for wg-quick or mobile apps)
const clientConfconf = WgConfigGenerator.generateClientConfig({
privateKey: 'CLIENT_PRIVATE_KEY_BASE64'<client-wg-private-key>',
address: '10.8.0.2/24',
dns: ['1.1.1.1', '8.8.8.8'],
mtu: 1420,
peer: {
publicKey: 'SERVER_PUBLIC_KEY_BASE64'<server-wg-public-key>',
endpoint: 'vpn.example.com:51820',
allowedIps: ['0.0.0.0/0', '::/0'],
persistentKeepalive: 25,
presharedKey: 'OPTIONAL_PSK_BASE64',
},
});
// Serverβ configstandard (forWireGuard .conf compatible with wg-quick)quick, iOS, Android
π₯οΈ System Service Installation
import { VpnInstaller } from '@push.rocks/smartvpn';
const serverConfunit = WgConfigGenerator.generateServerConfig(VpnInstaller.generateServiceUnit({
privateKey:mode: 'SERVER_PRIVATE_KEY_BASE64'server',
address:configPath: '10.8.0.1/24',
listenPort: 51820,
dns: ['1.1.1.1'],
mtu: 1420,
enableNat: true,
natInterface: 'eth0', // auto-detected if omitted
peers: [
{
publicKey: 'CLIENT_PUBLIC_KEY_BASE64',
allowedIps: ['10.8.0.2/32'],
persistentKeepalive: 25,
},
]etc/smartvpn/server.json',
});
// Writeunit.platform to disk
import * as fs fromβ 'fs';linux' fs.writeFileSync(| 'macos'
// unit.content β systemd unit file or launchd plist
// unit.installPath β /etc/wireguard/wg0.conf', serverConf);systemd/system/smartvpn-server.service
Example output: client .conf
[Interface]
PrivateKey = CLIENT_PRIVATE_KEY_BASE64
Address = 10.8.0.2/24
DNS = 1.1.1.1, 8.8.8.8
MTU = 1420
[Peer]
PublicKey = SERVER_PUBLIC_KEY_BASE64
PresharedKey = OPTIONAL_PSK_BASE64
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
Production: Socket Transport
In production, the daemon runs as a system service and you connect over a Unix socket:
const client = new VpnClient({
transport: {
transport: 'socket',
socketPath: '/var/run/smartvpn.sock',
autoReconnect: true,
reconnectBaseDelayMs: 100,
reconnectMaxDelayMs: 30000,
maxReconnectAttempts: 10,
},
});
await client.start(); // connects to existing daemon (does not spawn)
When using socket transport, client.stop()Β closes the socket but does not kill the daemonΒ β exactly what you want in production.
π API ReferenceΒ π
VpnClientClasses
start()VpnServer
Promise<boolean>connect(config?)VpnClient
Promise<{Manages assignedIpthe }>Rust disconnect()PromiseVpnBridge<voidT>
getStatus(VpnConfig
Static config validation and file I/O.
VpnInstaller
Generates systemd/launchd service files.
WgConfigGenerator
Generates standard WireGuard .confΒ files.
Key Interfaces
IVpnServerConfig
Server configuration (listen addr, keys, subnet, transport mode, clients)
IVpnClientConfig
Client configuration (server URL, keys, transport, WG options)
IClientEntry
Server-side client definition (ID, keys, security, priority, tags, expiry)
IClientSecurity
Per-client ACLs and rate limits (SmartProxy-aligned naming)
IClientRateLimit
Rate limiting config (bytesPerSec, burstBytes)
IClientConfigBundle
Full config bundle returned by createClient()
Promise<IVpnStatus>IVpnClientInfo
IVpnConnectionQuality
RTT, jitter, loss ratio, link health
IVpnKeypair
Base64-encoded public/private key pair
Server IPC Commands
startΒ / stop
Start/stop the VPN listener
createClient
Generate keys, assign IP, return config bundle
removeClientΒ / getClientΒ / listRegisteredClients
Client registry CRUD
updateClientΒ / enableClientΒ / disableClient
Modify client state
getStatistics()rotateClientKey
Promise<IVpnStatistics>Fresh getConnectionQuality()exportClientConfig
Re-export as SmartVPN config or WireGuard Promise<IVpnConnectionQuality>.conf
listClientsΒ / disconnectClient
Manage live connections
setClientRateLimitΒ / removeClientRateLimit
Runtime rate limit adjustments
getStatusΒ / getStatisticsΒ / getClientTelemetry
Monitoring
generateKeypairΒ / generateWgKeypairΒ / generateClientKeypair
Key generation
addWgPeerΒ / removeWgPeerΒ / listWgPeers
WireGuard peer management
Client IPC Commands
connectΒ / disconnect
Manage the tunnel
getStatusΒ / getStatistics
Connection state and traffic stats
getConnectionQuality
RTT, jitter, loss, link health
getMtuInfo()Promise<IVpnMtuInfo>getMtuInfo
MTU stop()voidrunningbooleanTransport Modes π
Server Configuration
VpnServer// WebSocket only
{ transportMode: 'websocket', listenAddr: '0.0.0.0:443' }
// QUIC only
{ transportMode: 'quic', listenAddr: '0.0.0.0:443' }
// Both (WS + QUIC on same or different ports)
{ transportMode: 'both', listenAddr: '0.0.0.0:443', quicListenAddr: '0.0.0.0:4433' }
// WireGuard
{ transportMode: 'wireguard', wgListenPort: 51820, wgPeers: [...] }
Client Configuration
// Auto (tries QUIC first, falls back to WS)
{ transport: 'auto', serverUrl: 'wss://vpn.example.com' }
// Explicit QUIC with certificate pinning
{ transport: 'quic', serverUrl: '1.2.3.4:4433', serverCertHash: '<sha256-base64>' }
// WireGuard
{ transport: 'wireguard', wgPrivateKey: '...', wgEndpoint: 'vpn.example.com:51820', ... }
Cryptography π
Binary Protocol π‘
All frames use [type:1B][length:4B][payload:NB]Β with a 64KB max payload:
start(config?)Promise<void>stopServer()Promise<void>getStatus()Promise<IVpnStatus>getStatistics()Promise<IVpnServerStatistics>listClients()Promise<IVpnClientInfo[]>disconnectClient(id)Promise<void>generateKeypair()Promise<IVpnKeypair>setClientRateLimit(id, rate, burst)Promise<void>removeClientRateLimit(id)Promise<void>getClientTelemetry(id)Promise<IVpnClientTelemetry>generateWgKeypair()Promise<IVpnKeypair>addWgPeer(peer)Promise<void>removeWgPeer(publicKey)Promise<void>listWgPeers()Promise<IWgPeerInfo[]>stop()voidVpnConfig
Static utility class for config validation and file I/O:
import { VpnConfig } from '@push.rocks/smartvpn';
// Validate (throws on invalid)
VpnConfig.validateClientConfig(config);
VpnConfig.validateServerConfig(config);
// Load/save JSON configs
const config = await VpnConfig.loadFromFile<IVpnClientConfig>('/etc/smartvpn/client.json');
await VpnConfig.saveToFile('/etc/smartvpn/client.json', config);
Validation covers both smartvpn-native configs and WireGuard configs β base64 key format, CIDR ranges, port ranges, and required fields are all checked.
WgConfigGenerator
Static generator for standard WireGuard .confΒ files:
generateClientConfig(opts)stringwg-quick.confgenerateServerConfig(opts)stringwg-quick.confOutput is compatible with wg-quick, WireGuard iOS/Android apps, and any standard WireGuard implementation.
VpnInstaller
Generate system service units for the daemon:
import { VpnInstaller } from '@push.rocks/smartvpn';
const platform = VpnInstaller.detectPlatform(); // 'linux' | 'macos' | 'windows' | 'unknown'
// Linux (systemd)
const unit = VpnInstaller.generateSystemdUnit({
binaryPath: '/usr/local/bin/smartvpn_daemon',
socketPath: '/var/run/smartvpn.sock',
mode: 'server',
});
// macOS (launchd)
const plist = VpnInstaller.generateLaunchdPlist({
binaryPath: '/usr/local/bin/smartvpn_daemon',
socketPath: '/var/run/smartvpn.sock',
mode: 'client',
});
// Auto-detect platform
const serviceUnit = VpnInstaller.generateServiceUnit({
binaryPath: '/usr/local/bin/smartvpn_daemon',
socketPath: '/var/run/smartvpn.sock',
mode: 'server',
});
Events
Both VpnClientΒ and VpnServerΒ extend EventEmitter:
client.on('exit', ({ code, signal }) => { /* daemon exited */ });
client.on('reconnected', () => { /* socket reconnected */ });
client.on('status', (status) => { /* IVpnStatus update */ });
client.on('error', (error) => { /* error from daemon */ });
server.on('client-connected', (info) => { /* IVpnClientInfo */ });
server.on('client-disconnected', ({ clientId, reason }) => { /* ... */ });
server.on('started', () => { /* server listener started */ });
server.on('stopped', () => { /* server listener stopped */ });
π Transport Modes
smartvpn supports three transport protocols. The smartvpn-native transports (WebSocket + QUIC) share the same encryption, framing, and QoS pipeline. WireGuard mode uses the standard WireGuard protocol for broad interoperability.
WebSocket (default for smartvpn-native)
wss://host/pathws://host:port/pathQUIC
host:portsmartvpnWireGuard
boringtun.confWgConfigGenerator51820/UDPAuto-Transport (Recommended for smartvpn-native)
The default transport: 'auto'Β mode gives you the best of both worlds:
host:portawait client.connect({
serverUrl: 'wss://vpn.example.com/tunnel',
serverPublicKey: '...',
transport: 'auto', // default β QUIC first, WS fallback
});
Server Dual-Mode / Multi-Mode
The server can listen on multiple transports simultaneously:
// WebSocket + QUIC (dual mode)
await server.start({
listenAddr: '0.0.0.0:443', // WebSocket listener
quicListenAddr: '0.0.0.0:4433', // QUIC listener (optional, defaults to listenAddr)
transportMode: 'both', // 'websocket' | 'quic' | 'both' | 'wireguard'
quicIdleTimeoutSecs: 30,
// ... other config
});
// WireGuard standalone
await server.start({
listenAddr: '0.0.0.0:51820',
transportMode: 'wireguard',
wgListenPort: 51820,
wgPeers: [{ publicKey: '...', allowedIps: ['10.8.0.2/32'] }],
// ... other config
});
When using 'both'Β mode, the server logs the QUIC certificate hash on startup β share this with clients for cert pinning.
π QoS System
The Rust daemon includes a full QoS stack that operates on decrypted IP packets:
Adaptive Keepalive
The keepalive system automatically adjusts its interval based on connection quality:
State transitions include hysteresis (3 consecutive good checks to upgrade, 2 to recover) to prevent flapping. Dead peer detection fires after 3 consecutive timeouts in Critical state.
Packet Classification
IP packets are classified into three priority levels by inspecting headers (no deep packet inspection):
Priority channels drain with biased tokio::select!Β β high-priority packets always go first.
Smart Packet Dropping
Under backpressure, packets are dropped intelligently:
Drop statistics are tracked per priority level and exposed via telemetry.
Per-Client Rate Limiting
Token bucket algorithm with byte granularity:
// Set: 10 MB/s sustained, 20 MB burst
await server.setClientRateLimit('client-id', 10_000_000, 20_000_000);
// Check drops via telemetry
const t = await server.getClientTelemetry('client-id');
console.log(`Dropped: ${t.packetsDropped} packets, ${t.bytesDropped} bytes`);
// Remove limit
await server.removeClientRateLimit('client-id');
Rate limits can be changed live without disconnecting the client.
Path MTU
Tunnel overhead is calculated precisely:
For a standard 1500-byte Ethernet link, effective TUN MTU = 1421 bytes. The default TUN MTU of 1420 is conservative and correct. Oversized packets get an ICMP "Fragmentation Needed" (Type 3, Code 4) written back into the TUN, so the source TCP adjusts its MSS automatically.
π Security Model
smartvpn-native (WebSocket / QUIC)
The VPN uses a Noise NKΒ handshake pattern:
e, ese, eePost-handshake, all IP packets are encrypted with XChaCha20-Poly1305:
[nonce:24B][ciphertext:var][tag:16B]WireGuard Mode
Uses the standard Noise IKpsk2Β handshake:
boringtunQUIC Certificate Pinning
When using QUIC transport, the server generates a self-signed TLS certificate (or uses a configured PEM). Instead of relying on a CA chain, clients pin the server's certificate by its SHA-256 hashΒ (base64-encoded) β a WireGuard-inspired trust model:
// Server logs the cert hash on startup:
// "QUIC cert hash: <BASE64_HASH>"
// Client pins it:
await client.connect({
serverUrl: 'vpn.example.com:443',
transport: 'quic',
serverCertHash: '<BASE64_HASH>',
serverPublicKey: '...',
});
π¦ Binary Protocol
Inside the tunnel (both WebSocket and QUIC reliable channels), packets use a simple binary framing:
ββββββββββββ¬βββββββββββ¬βββββββββββββββββββββ
β Type (1B)β Len (4B) β Payload (variable) β
ββββββββββββ΄βββββββββββ΄βββββββββββββββββββββ
HandshakeInit
0x01
Client β Server
HandshakeResp
0x02
Server β Client
IpPacket
0x10
Bidirectional
Encrypted Keepalive
0x20
Client β Server
App-level KeepaliveAck
0x21
SessionResume0x30SessionResumeOk0x31SessionResumeErr0x32Disconnect
0x3F
Bidirectional
Graceful disconnect
When
Development QUIC datagrams are available, IP packets can optionally be sent via the unreliable datagram channel for lower latency. Packets that exceed the max datagram size automatically fall back to the reliable stream.
Note:Β WireGuard mode uses the standard WireGuard wire protocol, not this binary framing.
π οΈΒ Rust Daemon CLI
# Development: stdio management (JSON lines on stdin/stdout)
smartvpn_daemon --management --mode client
smartvpn_daemon --management --mode server
# Production: Unix socket management
smartvpn_daemon --management-socket /var/run/smartvpn.sock --mode server
# Generate a Noise keypair
smartvpn_daemon --generate-keypair
π§ Building from Source
# Install dependencies
pnpm install
# Build (TypeScript + cross-compile Rust (amd64 + arm64)cross-compile)
pnpmΒ build
# Build Rust only (debug)
cd rust && cargo build
# Run all tests (9379 TS + 121 Rust += 77200 TypeScript)tests)
pnpm test
# Run Rust tests directly
cd rust && cargo test
pnpm# Run a specific TS test
tstest test/test.flowcontrol.node.ts --verbose
π
Project Structure
smartvpn/
βββ ts/ # TypeScript Interfacescontrol Clickβ toβββ expandindex.ts full# typeAll definitions
plane
exports
//β Transportβββ optionssmartvpn.interfaces.ts type# TVpnTransportOptionsInterfaces, =types, |IPC {command transport:maps
'stdio'β }βββ |smartvpn.classes.vpnserver.ts
{β transport:βββ 'socket';smartvpn.classes.vpnclient.ts
socketPath:β string;βββ autoReconnect?:smartvpn.classes.vpnbridge.ts
boolean;β reconnectBaseDelayMs?:βββ number;smartvpn.classes.vpnconfig.ts
reconnectMaxDelayMs?:β number;βββ maxReconnectAttempts?:smartvpn.classes.vpninstaller.ts
number;β };βββ //smartvpn.classes.wgconfig.ts
βββ rust/ # Rust data plane daemon
β βββ src/
β βββ main.rs # CLI entry point
β βββ server.rs # VPN server + hub methods
β βββ client.rs # VPN client
β βββ crypto.rs # Noise IK + XChaCha20
β βββ client_registry.rs # Client configdatabase
interfaceβ IVpnClientConfigβββ {acl.rs serverUrl:# string;ACL //engine
WS:β 'wss://host/path'βββ |management.rs QUIC:# 'host:port'JSON-lines serverPublicKey:IPC
string;β //βββ Base64-encodedtransport.rs Noise# staticWebSocket keytransport
(orβ WGβββ publicquic_transport.rs key)
transport?: 'auto' | 'websocket' | 'quic' | 'wireguard'; // Default: 'auto'
serverCertHash?: string; // SHA-256 cert hash (base64) for# QUIC pinningtransport
dns?:β string[];βββ mtu?:wireguard.rs number;
keepaliveIntervalSecs?: number;
// WireGuard-specific
wgPrivateKey?: string; // Client private key (base64, X25519)
wgAddress?: string; // Client TUN address (e.g. 10.8.0.2)
wgAddressPrefix?: number; // Address prefix length (default: 24)
wgPresharedKey?: string; // Optional preshared key (base64)
wgPersistentKeepalive?: number; // Persistent keepalive interval (seconds)
wgEndpoint?: string; // Server endpoint (host:port)
wgAllowedIps?: string[]; // Allowed IPs (CIDR strings)
}
// Server config
interface IVpnServerConfig {
listenAddr: string;
privateKey: string;
publicKey: string;
subnet: string;
tlsCert?: string;
tlsKey?: string;
dns?: string[];
mtu?: number;
keepaliveIntervalSecs?: number;
enableNat?: boolean;
transportMode?: 'websocket' | 'quic' | 'both' | 'wireguard';
quicListenAddr?: string;
quicIdleTimeoutSecs?: number;
defaultRateLimitBytesPerSec?: number;
defaultBurstBytes?: number;
// WireGuard-specific
wgListenPort?: number; // UDP port (default: 51820)
wgPeers?: IWgPeerConfig[]; // Initial peers
}
//# WireGuard peer(boringtun)
configβ interfaceβββ IWgPeerConfigcodec.rs {# publicKey:Binary string;frame //protocol
Peer'sβ X25519βββ publickeepalive.rs key# Adaptive keepalives
β βββ ratelimit.rs # Token bucket
β βββ ... # tunnel, network, telemetry, qos, mtu, reconnect
βββ test/ # 9 test files (base64)79 presharedKey?:tests)
string;βββ //dist_ts/ Optional# presharedCompiled keyTypeScript
βββ dist_rust/ # Cross-compiled binaries (base64)linux allowedIps:amd64 string[];+ // Allowed IP ranges (CIDR)
endpoint?: string; // Peer endpoint (host:port)
persistentKeepalive?: number; // Keepalive interval (seconds)
}
// WireGuard peer info (with live stats)
interface IWgPeerInfo {
publicKey: string;
allowedIps: string[];
endpoint?: string;
persistentKeepalive?: number;
bytesSent: number;
bytesReceived: number;
packetsSent: number;
packetsReceived: number;
lastHandshakeTime?: string;
}
// Status
type TVpnConnectionState = 'disconnected' | 'connecting' | 'handshaking'
| 'connected' | 'reconnecting' | 'error';
interface IVpnStatus {
state: TVpnConnectionState;
assignedIp?: string;
serverAddr?: string;
connectedSince?: string;
lastError?: string;
}
// Statistics
interface IVpnStatistics {
bytesSent: number;
bytesReceived: number;
packetsSent: number;
packetsReceived: number;
keepalivesSent: number;
keepalivesReceived: number;
uptimeSeconds: number;
quality?: IVpnConnectionQuality;
}
interface IVpnServerStatistics extends IVpnStatistics {
activeClients: number;
totalConnections: number;
}
// Connection quality (QoS)
type TVpnLinkHealth = 'healthy' | 'degraded' | 'critical';
interface IVpnConnectionQuality {
srttMs: number;
jitterMs: number;
minRttMs: number;
maxRttMs: number;
lossRatio: number;
consecutiveTimeouts: number;
linkHealth: TVpnLinkHealth;
currentKeepaliveIntervalSecs: number;
}
// MTU info
interface IVpnMtuInfo {
tunMtu: number;
effectiveMtu: number;
linkMtu: number;
overheadBytes: number;
oversizedPacketsDropped: number;
icmpTooBigSent: number;
}
// Client info (with QoS fields)
interface IVpnClientInfo {
clientId: string;
assignedIp: string;
connectedSince: string;
bytesSent: number;
bytesReceived: number;
packetsDropped: number;
bytesDropped: number;
lastKeepaliveAt?: string;
keepalivesReceived: number;
rateLimitBytesPerSec?: number;
burstBytes?: number;
}
// Per-client telemetry
interface IVpnClientTelemetry {
clientId: string;
assignedIp: string;
lastKeepaliveAt?: string;
keepalivesReceived: number;
packetsDropped: number;
bytesDropped: number;
bytesReceived: number;
bytesSent: number;
rateLimitBytesPerSec?: number;
burstBytes?: number;
}
interface IVpnKeypair {
publicKey: string;
privateKey: string;
}arm64)
License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the LICENSElicense file.
Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.