Skip to main content

UdpListener

UdpListener is a UDP server adapter. It binds a local UDP address and port, receives inbound datagrams, groups them by remote peer, creates one WaterWall line for each peer, and sends payloads upstream to the next node.

Typical placement:

client -> UdpListener -> ... -> UdpConnector -> remote UDP service

This node is normally used as the beginning of a UDP stream-style chain.

What It Does

  • Listens on one UDP port, several explicit UDP ports, or a contiguous UDP port range.
  • Receives inbound UDP datagrams through WaterWall's socket manager.
  • Applies optional listener filters such as whitelist, blacklist, and balance groups.
  • Creates one WaterWall line per remote peer address and port.
  • Sends inbound datagrams upstream as payloads to the next node.
  • Sends downstream payloads back to the remembered peer address.
  • Tracks peer lines with UDP idle timeouts.

UDP itself is connectionless, but UdpListener gives the rest of the chain a stable line abstraction per peer.

Configuration Example

{
"name": "udp-listener",
"type": "UdpListener",
"settings": {
"address": "0.0.0.0",
"port": [
5353,
853,
123
],
"large-send-buffer": true,
"large-recv-buffer": true,
"interface": "eth0",
"fwmark": 10,
"balance-group": "udp-public",
"balance-interval": 30000,
"multiport-backend": "socket",
"whitelist": [
"192.168.1.0/24",
"2001:db8::/64"
],
"blacklist": [
"192.168.1.50/32"
]
},
"next": "next-node-name"
}

Required Fields

Top-level fields:

FieldTypeDescription
namestringUser-chosen node name. Must be unique inside the config file.
typestringMust be exactly "UdpListener".
nextstringNode that receives UDP peer lines and payloads.

Required settings fields:

FieldTypeDescription
addressstringLocal bind address, such as "0.0.0.0", "::", or a specific local IP.
port or port-rangenumber, array, or range arrayListening port definition. Exactly one of these fields is required.

settings must be a non-empty object.

Port Configuration

UdpListener supports three port modes.

Single Port

{
"settings": {
"address": "0.0.0.0",
"port": 5353
}
}

Explicit Port List

{
"settings": {
"address": "0.0.0.0",
"port": [
5353,
853,
123
]
}
}

This listens only on the listed ports. It does not mean the range from 123 to 5353.

Contiguous Port Range

{
"settings": {
"address": "0.0.0.0",
"port-range": [
20000,
20100
]
}
}

port-range must be an array with exactly two positive integer ports: [min, max]. The minimum must be lower than or equal to the maximum.

Rules:

RuleBehavior
Use both port and port-rangeStartup fails.
port numberListens on one UDP port.
port arrayListens on the explicit ports in the array.
port-range arrayListens on every UDP port from minimum to maximum.
Invalid, zero, negative, or above 65535 portStartup fails.
warning

Do not use old string-style ranges such as "20000-20100". The current parser expects port-range as a two-item array.

Optional Settings

SettingTypeDefaultDescription
large-send-bufferboolean or positive integertrueSets SO_SNDBUF on UDP listener sockets.
large-recv-bufferboolean or positive integertrueSets SO_RCVBUF on UDP listener sockets.
interfacestringnot setRestricts the listener to a local network interface.
fwmarkintegernot setApplies a Linux-style socket mark where supported.
balance-groupstringnot setGroups compatible same-port listeners for sticky distribution.
balance-intervalinteger, millisecondssocket-manager defaultSticky interval for repeated peers in a balance group.
multiport-backendstringruntime default for port-rangeBackend for contiguous port ranges: "iptables" or "socket".
whitelistarray of stringsnot setAllowed peer IPs or CIDR ranges.
blacklistarray of stringsnot setBlocked peer IPs or CIDR ranges.

Socket Buffer Options

large-send-buffer and large-recv-buffer accept:

ValueMeaning
trueUse WaterWall's default large socket buffer size, currently 4194304 bytes.
falseDo not explicitly set this socket buffer; use the kernel default.
positive integerRequest that many bytes directly.

Both options default to WaterWall's large socket buffer size for UDP listeners.

Interface and fwmark

interface restricts the listener to a local network device.

On Linux, WaterWall uses SO_BINDTODEVICE. On platforms without device binding, WaterWall falls back to binding by the interface's IPv4 address when possible.

fwmark uses SO_MARK on platforms that provide it. It is platform-dependent and is not available on Windows.

Filtering and Balancing

Filtering and balancing happen in the shared socket manager before the datagram is delivered to UdpListener.

SettingBehavior
whitelistIf configured, only matching peer IPs are accepted.
blacklistMatching peer IPs are rejected.
balance-groupEnables sticky peer distribution between compatible listeners on the same port.
balance-intervalControls how long a peer remains sticky to the chosen listener.
multiport-backendControls how a contiguous port-range listener is implemented.

When both ACL lists are configured, a peer must match the whitelist, if any, and must not match the blacklist.

Example:

{
"settings": {
"address": "0.0.0.0",
"port": 5353,
"whitelist": [
"10.0.0.0/8",
"203.0.113.10/32",
"2001:db8::/64"
],
"blacklist": [
"10.0.0.99/32"
]
}
}

Per-Peer Line Model

UDP has no transport connection, so UdpListener builds a pseudo-connection model for the chain.

For each unique remote peer address and port on a listening socket:

  1. A new WaterWall line is created on the first accepted datagram.
  2. The peer address is stored in listener line state.
  3. Later datagrams from the same peer reuse the same line until it expires.
  4. Downstream payloads on that line are sent back to the remembered peer.

This lets later stream-style nodes work with UDP traffic using normal WaterWall line callbacks.

Data Flow

Peer to chain:

UDP datagram -> UdpListener -> upstream payload -> next node

Chain to peer:

previous downstream payload -> UdpListener -> UDP send to remembered peer

The line source context is filled from the peer socket address and marked as UDP.

Establishment Semantics

A new peer line is created on the first accepted datagram. The line becomes established only when a downstream est callback reaches UdpListener from the next node.

Pause Behavior

UdpListener does not queue inbound datagrams while a peer line is paused.

If a datagram arrives from a paused peer line:

  • the datagram is dropped
  • the line remains alive
  • once resumed, new datagrams from that peer can be forwarded again

This is different from TCP-style backpressure. For this node, pause means drop, not buffer.

Idle Timeout

Each peer line is tracked in an idle table.

Current timeouts:

StateTimeout
Newly created peer lineabout 30 seconds
Active peer after traffic continuesabout 300 seconds

If the peer line expires, UdpListener sends upstream finish and destroys the line it created.

Notes and Caveats

  • UdpListener is a UDP chain-head node and requires next.
  • port arrays are explicit lists, not ranges.
  • Use port-range for contiguous ranges.
  • whitelist and blacklist support IPv4 and IPv6 CIDR strings.
  • fwmark and device binding are platform-dependent.
  • Paused peer lines drop inbound datagrams instead of buffering them.
  • For packet-level, stateless UDP behavior, UdpStatelessSocket may be a better fit than UdpListener.