Toolbox networking

TCP proxy, encryption, packet processing and the tera-network-proxy API.

Purpose

tera-network-proxy forwards TCP traffic between a TERA client and game server, allowing packets to be read, modified, blocked and generated. Ordinary module authors use mod.hook and mod.send. The classes below are for integrating the networking layer itself.

Packet pipeline

Server → TCP → decryption → complete packet assembly → Dispatch
                                                         ↓ hooks
Client ← TCP ← encryption ← processed packet ←────────────┘

The reverse stream goes from RealClient through decryption and buffering to Dispatch.handle(data, false), then to the server. TCP is a byte stream: one socket data event need not equal one game packet. PacketBuffer assembles complete messages using the header length. The handshake and key exchange precede ordinary packet processing; modules see decrypted messages.

Each connection has its own Dispatch, opcode map, protocol definitions and encryption state. Slow synchronous handlers delay further traffic processing in the event loop. Avoid long computations and file I/O inside them.

Dispatch

Dispatch merges packet-specific and '*' hooks by order, checks filters and parses the message using the required definition version. Modifications invalidate cached parsed events. handle returns false if the packet remains silenced, or the resulting Buffer otherwise.

Current implementation API Purpose
hook(moduleName, name, version, options, callback) Low-level registration with an explicit module name
unhook(handle), unhookModule(name) Remove a hook or module hooks
write(outgoing, buffer) Send a complete packet
write(outgoing, name, version, data) Serialize and send an object
handle(data, incoming, fake = false) Run the hook chain
fromRaw(name, version, data) Parse a Buffer using a definition
toRaw(name, version, data) Serialize an object
resolve(name, version = '*') Resolve a definition
destructor() Clear hooks

For write, outgoing: true means server; for handle, incoming: true means client. Generated packets also pass through handle, with fake: true. Raw sending copies the buffer because encryption changes bytes in place.

Connection

const { Connection, RealClient, FakeClient } = require('tera-network-proxy');

The current signature is new Connection(metadata, clientInterfaceConnection, noIntegrity = false). metadata needs consistent client information: protocolVersion, majorPatchVersion, minorPatchVersion, platform, maps.protocol, maps.sysmsg and dataFolder. Toolbox normally supplies these. This is not a standalone connection example: arbitrary empty metadata cannot initialize a working protocol.

connection.connect(client, options) forwards options to net.connect and returns the server socket. It enables setNoDelay(true) on that socket. connection.dispatch exposes packet dispatching. close() closes both sides, destroys Dispatch and releases connection state. Infrastructure handles encryption and packet integrity according to the client version.

RealClient

new RealClient(connection, socket) attaches an actual game TCP client. It has its own buffer and traffic processing state toward the server. Use socket.setNoDelay(true) on the accepted socket, as Toolbox integration does. Connection manages this client; ordinary modules do not need to create one.

FakeClient

new FakeClient(connection, keys) represents a connection without an incoming game client socket. Optional keys is an array of two 128-byte buffers; omitted keys are randomly generated. The class extends EventEmitter.

Event Meaning
connect Initial handshake and key exchange completed
timeout Forwarded server socket event
error Forwarded server socket error
close FakeClient is closing

FakeClient does not implement account login or game logic. A successful TCP/cryptographic connection does not mean the game has authenticated the client.

Differences from the historical README

The shipped README describes an older TERA Proxy API. In this distribution, module management lives in bin/mod-manager.js/bin/mod.js: Dispatch has no documented legacy load() or reset(). The example calling new Connection() without metadata is also outdated. Use exact names such as S_LOGIN instead of relying on the historical sLogin conversion. Raw hooks receive a copy: return the modified Buffer.

Sources: node_modules/tera-network-proxy/README.md, lib/connection/{index,dispatch}.js, lib/clients/{RealClient,FakeClient}.js, lib/packetBuffer.js.