Skip to main content

Part 2: Networking Basics

WaterWall is easier to configure when you separate three ideas:

  • where traffic enters WaterWall
  • what WaterWall does to the traffic
  • where WaterWall sends it next

Most examples use simple arrows:

TcpListener -> MuxClient -> VlessClient -> TlsClient -> TcpConnector

Traffic enters from the left, moves upstream through the chain, and responses come back downstream in the opposite direction.

IP Addresses

An IP address identifies a host or interface on a network.

Common examples:

127.0.0.1       local machine only
0.0.0.0 bind on all IPv4 interfaces
192.168.1.10 private LAN address
203.0.113.10 public IPv4 documentation address
::1 IPv6 loopback
:: bind on all IPv6 interfaces

For listener nodes, address is usually the local address to bind.

For connector nodes, address is usually the remote destination to connect to.

Ports

A port identifies a service on an IP address. For example:

22    SSH
53 DNS
80 HTTP
443 HTTPS
8080 common test HTTP port

Only one process can usually listen on the same address, protocol, and port at the same time. If WaterWall cannot bind a listener, another process may already be using that port.

On Linux, check listening TCP sockets with:

ss -ltnp

For UDP:

ss -lunp

TCP

TCP is connection-oriented. It creates a stream between two endpoints.

In WaterWall, TCP traffic usually starts with TcpListener and ends with TcpConnector:

client -> TcpListener -> ... -> TcpConnector -> remote server

TcpListener accepts incoming TCP connections and creates one WaterWall line for each accepted connection. TcpConnector opens the outbound TCP connection on the other side of the chain.

Use TCP for protocols such as HTTP, HTTPS, SSH, SOCKS, and most proxy-style tunnel traffic.

UDP

UDP is message-oriented. It sends datagrams instead of a continuous stream.

WaterWall has UDP nodes for stateful and stateless cases:

UdpListener -> ... -> UdpConnector
UdpStatelessSocket -> packet-oriented chain

UDP is commonly used for DNS, QUIC, WireGuard, game traffic, and real-time media. Because UDP does not create a stream by itself, the surrounding WaterWall nodes must decide how peer identity and packet routing are handled.

Localhost, Private IP, and Public IP

127.0.0.1 only accepts connections from the same machine. Use it for local testing.

Private addresses such as 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 are used inside private networks. They are not directly reachable from the public internet.

A public VPS address is reachable from the internet if the provider firewall and the server firewall allow the port.

For a public WaterWall listener on a VPS, a common bind address is:

{
"address": "0.0.0.0",
"port": 443
}

For a local-only test listener:

{
"address": "127.0.0.1",
"port": 8080
}

DNS and Domain Names

Connector nodes can use domain names:

{
"address": "example.com",
"port": 443
}

WaterWall resolves the domain through its shared DNS resolver. The default selection policy is controlled by dns.domain-strategy in core.json.

If a domain returns both IPv4 and IPv6 records, domain-strategy decides which one WaterWall should prefer.

NAT and Port Forwarding

Many machines are behind NAT. A private machine can usually connect outward, but outside clients cannot connect inward unless the router or cloud firewall forwards the port.

A simple TCP forward looks like this:

client -> VPS:8080 -> WaterWall -> example.com:80

WaterWall chain:

TcpListener(0.0.0.0:8080) -> TcpConnector(example.com:80)

This forwards TCP streams. It does not automatically change the HTTP Host header or make the remote server behave as if the client connected directly.

Streams and Packets

WaterWall supports both stream-style and packet-style traffic.

Stream-style traffic behaves like a byte stream:

TcpListener -> EncryptionClient -> TcpConnector

Packet-style traffic carries IP packets or packet-like datagrams:

TunDevice -> WireGuardDevice -> UdpStatelessSocket

Some nodes bridge between the two worlds. For example, PacketsToStream wraps packets into a stream format, and StreamToPackets unwraps that stream back into packets on the other side.

Do not treat packet chains exactly like TCP chains. A packet chain may use worker-level packet lines that stay alive across many unrelated packets.

Reading Chain Arrows

This chain:

TcpListener -> MuxClient -> VlessClient -> TlsClient -> TcpConnector

means:

  1. TcpListener accepts a TCP client.
  2. MuxClient multiplexes logical connections over the transport path.
  3. VlessClient wraps the payload in VLESS client framing.
  4. TlsClient carries the result inside a TLS connection.
  5. TcpConnector connects to the configured remote server.

The reverse traffic returns through the same nodes in the opposite direction.

When designing a chain, first write the plain arrow diagram. Then turn each arrow node into JSON in the config file.