Skip to main content

ObfuscatorServer

ObfuscatorServer is the server-side peer for ObfuscatorClient. It uses the same reversible payload transform and must be configured with the same method, key, and header options.

In the current implementation, the only supported method is XOR. This node is a traffic-shaping and obfuscation layer, not an encryption layer.

ObfuscatorServer is created with WaterWall's packet-tunnel API and has no per-line tunnel state. Payload bytes are transformed in place, except when the optional TLS-like header mode needs to clone a buffer to get enough left padding.

Typical Placement

Simple TCP path:

client side: TcpListener -> ObfuscatorClient -> TcpConnector
server side: TcpListener -> ObfuscatorServer -> TcpConnector

UDP path:

client side: UdpListener -> ObfuscatorClient -> UdpConnector
server side: UdpListener -> ObfuscatorServer -> UdpConnector

Raw packet path:

packet transport -> ObfuscatorServer -> RawSocket

Use the same skip and tls_record_header settings as the client side.

What It Does

  • Requires settings.method: "xor".
  • Requires settings.xor_key.
  • Applies XOR to upstream payload bytes before forwarding to next.
  • Optionally prepends a 5-byte TLS-like record header after upstream XOR.
  • Optionally strips the 5-byte TLS-like header before downstream XOR.
  • Applies XOR to downstream payload bytes before forwarding to the previous node.
  • Can leave the IPv4 header, or IPv4 plus TCP/UDP header, unobfuscated.
  • Marks packet-line payloads for checksum recalculation after changing bytes.
  • Does not buffer payloads and does not keep per-line state.

The server implementation mirrors the client implementation. The client/server names describe deployment role; the transform itself is symmetric.

Configuration Example

{
"name": "obfuscator-server",
"type": "ObfuscatorServer",
"settings": {
"method": "xor",
"xor_key": 90,
"skip": "transport",
"tls_record_header": true
},
"next": "service-node"
}

Matching client:

{
"name": "obfuscator-client",
"type": "ObfuscatorClient",
"settings": {
"method": "xor",
"xor_key": 90,
"skip": "transport",
"tls_record_header": true
},
"next": "transport-node"
}

Required Fields

Top-level fields:

FieldTypeDescription
namestringUser-chosen node name. Must be unique inside the config file.
typestringMust be exactly "ObfuscatorServer".
settingsobjectRequired. Must contain method and xor_key.
nextstringRequired in normal use. The next node receives transformed upstream payloads.

Required settings fields:

FieldTypeDescription
methodstringMust be "xor" in the current implementation.
xor_keyintegerXOR key. The value is stored as one byte, so values outside 0..255 are converted to uint8_t.

Optional Settings

SettingTypeDefaultDescription
skipstring"none"Leading packet headers to leave clear before XOR. Accepted values are "none", "ipv4", and "transport".
tls_record_headerbooleanfalseAdds/removes a 5-byte TLS-like application-data record header on the transport-facing payload.
tls_headerbooleanunsetDeprecated compatibility alias for tls_record_header. If present, it is accepted and a warning is logged.

Skip Modes

skip controls how many leading bytes are not XORed:

ValueBehavior
"none"XOR the whole payload.
"ipv4"If the payload starts with a valid IPv4 packet, leave the IPv4 header clear and XOR bytes after it.
"transport"If the payload starts with a valid IPv4 TCP/UDP packet, leave the IPv4 header and TCP/UDP header clear. For other IPv4 protocols, leave only the IPv4 header clear.

If the payload is too short or not a valid IPv4 packet, the skip length becomes 0 and the whole payload is XORed.

For malformed or incomplete TCP/UDP headers under skip: "transport", the implementation falls back to leaving only the IPv4 header clear.

TLS-Like Record Header

When tls_record_header is enabled, transport-facing payloads are sent as:

17 03 03 + length(2 bytes, big-endian) + obfuscated payload

The bytes imitate a TLS application-data record header:

FieldValue
content type23 / 0x17
legacy version0x0303
lengthobfuscated payload length, 16-bit big-endian

On the receive path, the header is validated and stripped before XOR runs.

warning

This is not TLS. It has no handshake, no certificates, no SNI, no ALPN, no encryption, and no authentication. It only imitates the shape of a post-handshake TLS application-data record.

Important limits:

  • payloads larger than 65535 bytes are dropped when wrapping
  • truncated headers are dropped when stripping
  • records whose declared length does not exactly match the current payload buffer length are dropped
  • there is no record reassembly buffer, so receive-side payload callbacks should contain exactly one complete TLS-like record

Direction Behavior

Incoming callbackBehavior
upstream PayloadXORs according to skip, optionally prepends the TLS-like header, marks packet-line checksum recalculation, then forwards to next.
downstream PayloadOptionally validates and strips the TLS-like header, XORs according to skip, marks packet-line checksum recalculation, then forwards to the previous node.
downstream InitForwards to the previous node.
other lifecycle callbacksUses packet-tunnel default behavior. Payload transformation is the meaningful behavior of this node.

The source also contains ordinary pass-through lifecycle callback files, but the current create path installs only the downstream Init override plus upstream and downstream payload overrides on top of packet-tunnel defaults.

Buffer And Padding Notes

Node metadata advertises:

required_padding_left = 5
layer_group = kNodeLayerAnything

The 5 bytes are for the optional TLS-like header. If a buffer does not have enough left padding when tls_record_header is enabled, the node clones the payload into a new buffer with enough padding, recycles the original buffer, and then prepends the header.

When the current line is the worker packet line, the node sets recalculate_checksum = true after transforming payload bytes.

Implementation Notes

The XOR helper has optimized paths:

  • AVX2 when available
  • aligned 64-bit chunk processing on 64-bit builds
  • aligned 32-bit or byte-wise fallback otherwise

These paths change performance only; visible behavior is still byte-wise XOR with the configured one-byte key.

Practical Notes

  • ObfuscatorServer and ObfuscatorClient must use the same method, xor_key, skip, and tls_record_header settings.
  • This is obfuscation, not cryptographic security.
  • skip: "none" is simplest for ordinary byte streams.
  • skip: "transport" is useful for raw IPv4 TCP/UDP packets whose IP and transport headers need to remain readable.
  • If you only need secure encryption, use EncryptionClient and EncryptionServer instead.