Skip to main content

JunkDatagramSender

JunkDatagramSender is a composable middle tunnel that injects generated UDP-like datagram payloads before early upstream payloads on each line.

It is meant for camouflage and protocol-noise experiments around UDP-style paths. The node does not modify the real payload. Instead, when an upstream payload arrives, it may first send a random batch of generated junk payloads to next, then forward the real payload unchanged.

JunkDatagramSender is a normal tunnel with per-line state. It is not a socket adapter, does not create or destroy line_t objects, and is not a raw IPv4 packet tunnel.

Typical Placement​

UDP-style path:

UdpListener -> JunkDatagramSender -> UdpConnector

With other datagram-preserving nodes:

UdpListener -> JunkDatagramSender -> EncryptionClient -> UdpConnector

Use it where one WaterWall payload is expected to behave like one datagram. In ordinary TCP stream paths, the junk payloads become extra stream bytes, which is usually not what an application protocol expects.

What It Does​

  • Initializes a per-line remaining trigger counter from resend-again-times.
  • Sends junk only when upstream payload callbacks arrive.
  • Sends junk before the real upstream payload.
  • Sends a random number of junk payloads between packet-count-perline-min and packet-count-perline-max.
  • Picks each junk payload's protocol generator randomly from selected-protocols.
  • Can schedule one delayed duplicate of each generated junk payload.
  • Forwards the real upstream payload unchanged after the junk batch.
  • Forwards downstream payloads unchanged.
  • Passes Est, Pause, and Resume in the same direction unchanged.
  • Destroys its local line state before forwarding directional Finish.

If junk generation or forwarding closes the line before the real payload is forwarded, the node recycles the real payload buffer and returns.

Configuration Example​

{
"name": "junk",
"type": "JunkDatagramSender",
"settings": {
"packet-count-perline-min": 2,
"packet-count-perline-max": 5,
"resend-again-times": 2,
"selected-protocols": [
"dns",
"ntp",
"quic-http3",
"rtp-rtcp-srtp"
],
"keep-sending-max-ms": 1500
},
"next": "udp-out"
}

With default settings, the first upstream payload on each line triggers one generated junk payload, then the real payload is forwarded.

Required Fields​

Top-level fields:

FieldTypeDescription
namestringUser-chosen node name. Must be unique inside the config file.
typestringMust be exactly "JunkDatagramSender".
settingsobjectOptional settings object. Empty settings use defaults.
nextstringOptional in node metadata, but normally set to the next tunnel that receives upstream payloads.

Settings​

SettingTypeDefaultDescription
packet-count-perline-mininteger1Minimum number of junk payloads generated for each trigger. Negative values are clamped to 0.
packet-count-perline-maxinteger1Maximum number of junk payloads generated for each trigger. Negative values are clamped to 0; values above 256 are clamped to 256. If lower than the minimum, it is clamped up to the minimum.
resend-again-timesinteger1Number of upstream payload callbacks that trigger junk sending on each line. 0 disables junk sending. Negative values are clamped to 0; values above 256 are clamped to 256.
selected-protocolsarray of stringsall implemented protocolsProtocol generators eligible for random selection. If omitted, all implemented generators are used. An empty array is accepted but makes the node pass traffic through without junk.
keep-sending-max-msinteger00 disables delayed duplicate sends. When greater than 0, each generated junk payload is duplicated once and scheduled with a random delay from 1 to this value in milliseconds. Negative values disable delayed sends.

Trigger Behavior​

resend-again-times counts upstream payload callbacks, not individual bytes and not connection attempts.

For example:

{
"packet-count-perline-min": 2,
"packet-count-perline-max": 4,
"resend-again-times": 3
}

On each line, the first three upstream payload callbacks each trigger a random batch of 2 to 4 junk payloads. The fourth and later upstream payloads are forwarded without adding more junk.

No junk is sent during Init by itself. The node waits until a real upstream payload arrives.

Protocol Selection​

Accepted canonical protocol names:

Canonical nameAccepted aliases
dnsnone
dhcpnone
ntpnone
quic-http3quic, http3, http/3, quic/http3
rtp-rtcp-srtprtp, rtcp, srtp
stun-turn-icestun, turn, ice
mdnsnone
snmpnone
syslognone
ipsec-nat-tipsec-natt, natt
sipnone

Use "all" inside selected-protocols to explicitly enable every implemented generator:

{
"selected-protocols": ["all"]
}

Protocol names are matched case-insensitively by the current implementation, even though lowercase names are the documented form.

Disabled Protocol Names​

The following names exist only as disabled placeholders. If any of them are listed in selected-protocols, startup fails:

Disabled nameNotes
tftpgenerator placeholder only
ssdpgenerator placeholder only
radiusgenerator placeholder only
gtp-u / gtpugenerator placeholder only
game-udp-protocols / game-udp / gamegenerator placeholder only
coapgenerator placeholder only

Generated Payload Types​

The implemented modules generate valid-looking UDP application payloads, not UDP/IP headers:

ProtocolGenerated shape
dnsDNS query payloads, sometimes with EDNS(0)-style data.
dhcpDHCPv4 client-message payloads.
ntpNTP client request payloads.
quic-http3QUIC Initial-like payloads with HTTP/3 ALPN data.
rtp-rtcp-srtpRTP media, RTCP control, and SRTP-shaped payloads.
stun-turn-iceSTUN, TURN, and ICE connectivity or relay-control payloads.
mdnsMulticast DNS query and announcement payloads.
snmpSNMP v1/v2c manager request payloads.
syslogRFC3164/RFC5424-style syslog messages.
ipsec-nat-tNAT-T keepalive, IKEv2, and ESP-in-UDP-shaped payloads.
sipSIP request and response payloads.

The node passes generator arguments with a default target range of 12 to 1200 bytes. Individual generators may still choose fixed sizes where the protocol shape requires it.

Direction Behavior​

Incoming callbackBehavior
upstream InitInitializes line state, then forwards Init to next.
upstream PayloadSends configured junk batch if triggers remain, then forwards the real payload to next.
upstream Est / Pause / ResumeForwards to next.
upstream FinishDestroys local line state, then forwards Finish to next.
downstream InitInitializes line state, then forwards Init to the previous node.
downstream PayloadForwards unchanged to the previous node.
downstream Est / Pause / ResumeForwards to the previous node.
downstream FinishDestroys local line state, then forwards Finish to the previous node.

The source contains a downstream junk direction helper, but the active payload path only triggers junk on upstream payload callbacks.

Line Safety​

JunkDatagramSender stores a trigger count plus directional Finish gates:

remaining_resend_again_times
upstream_finished / downstream_finished

During upstream payload handling, the node holds a temporary line reference with lineRef() while sending the junk batch, checks lineIsAlive() afterward, then releases that reference with lineUnref(). The reference preserves allocation memory, not line contents or worker access. Delayed duplicate payloads are best effort and transfer their buffer to lineScheduleDelayedTaskWithBuf() on every submission result. The scheduler releases it if a normal line is already closed when the timer runs. Packet lines remain allocated until chain destruction, so either packet-direction Finish closes both gates; an armed duplicate is then recycled instead of being published after the terminal callback.

The node does not call lineDestroy(). It destroys normal-line state before forwarding Finish; packet-line state remains present with both gates closed.

Buffer And Padding Notes​

JunkDatagramSender does not prepend bytes to the real payload and does not modify the real payload buffer. It allocates separate large buffers for generated junk payloads.

Node metadata sets:

required_padding_left = 0
layer_group = kNodeLayerAnything

Although the layer metadata is permissive, the generated data is UDP-like application payload data. Do not treat this node as an IPv4 packet mutator. For raw packet changes, use packet-oriented nodes such as IpManipulator or IpOverrider.

Practical Notes​

  • resend-again-times: 0 makes the node pass traffic through.
  • packet-count-perline-max: 0 makes the node pass traffic through.
  • selected-protocols: [] makes the node pass traffic through and logs a warning.
  • keep-sending-max-ms schedules one delayed duplicate per generated junk payload; it does not keep generating forever.
  • Delayed duplicate ordering is not guaranteed by the line scheduler.
  • The node does not rewrite addresses, ports, checksums, or packet headers.
  • The generated payloads are camouflage noise, not encryption or authentication.

Node Metadata​

Source-backed metadata:

PropertyValue
node flagskNodeFlagSupportsSplice
can_have_prevtrue
can_have_nexttrue
layer_groupkNodeLayerAnything
layer_group_prev_nodekNodeLayerSameAsNext
layer_group_next_nodekNodeLayerSameAsPrev
required_padding_left0 bytes

Splice support​

Generated junk and its delayed duplicates remain ordinary buffers. Incoming application payloads pass through opaquely, preserving their private-pipe bodies and existing ordering relative to immediate junk. Terminal directions discard input; if sending junk closes the line, the still-owned application buffer is recycled.

Ordinary fallback buffers remain accepted. Splice requires a supported Linux build, misc.splice enabled, no packet nodes, and support from every node in the finalized expanded/merged chain. The capability flag does not bypass these checks. No performance improvement is promised without measurement.

Packet configurations of this dual-layer node still do not enable splice.