Netcat Cheatsheet

UDP and Proxying

Use this Netcat reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

UDP mode

-u switches both client and listener to UDP. The semantics change more than the flag suggests.

# Listener
nc -u -l 5514

# Client
nc -u 10.0.0.5 5514

# Send one datagram and exit
echo "test message" | nc -u -w 1 10.0.0.5 5514
DifferenceConsequence
No handshakeA "connection" never fails, so success proves nothing
No orderingDatagrams can arrive out of order or not at all
Message boundariesEach write is one datagram, not a byte stream
No closeThe listener cannot tell that the sender is done
Refusal is out-of-bandYou learn about a closed port from an ICMP error, if at all

A UDP listener latches onto the first sender. OpenBSD nc records the source of the first datagram and ignores everything else, so a second client's traffic vanishes. Ncat behaves the same without -k.

# Ncat, accept datagrams from more than one source
ncat -u -lk 5514

Testing UDP services

# Syslog, which is UDP 514 and accepts a bare line
echo '<14>test message from netcat' | nc -u -w 1 10.0.0.5 514

# StatsD
echo 'test.counter:1|c' | nc -u -w 1 10.0.0.5 8125

# A raw DNS query is binary, so use dig instead
dig +short @10.0.0.5 example.com

# TFTP, SNMP, NTP all need real protocol bytes
snmpget -v2c -c public 10.0.0.5 1.3.6.1.2.1.1.1.0
ntpdate -q 10.0.0.5

For anything with a binary wire format, netcat is the wrong tool unless you pipe pre-built bytes into it:

# A real DNS query, captured once with tcpdump then replayed
xxd -r -p <<'EOF' | nc -u -w 2 10.0.0.5 53 | xxd | head
abcd0100000100000000000007657861...
EOF

Why nc -zu lies

nc -zvu 10.0.0.5 53
# Connection to 10.0.0.5 53 port [udp/domain] succeeded!

That message means the local sendto succeeded. Nothing was confirmed by the remote host. Every UDP port on an unreachable machine will "succeed".

The only real signals:

SignalConclusion
A protocol reply arrivesOpen, and identified
ICMP port unreachableClosed, if the ICMP is not rate-limited
SilenceOpen, closed, or filtered. No conclusion

Linux rate-limits ICMP destination-unreachable messages (roughly one per second by default), so even scanning a small range gives false "open" results. Use sudo nmap -sU if you actually need a UDP scan, and expect it to be slow.

Port forwarding with netcat

netcat forwards one stream, so a bidirectional relay needs two of them joined back to back.

# Ncat does it directly, this is the form to use
ncat -lk 8080 --sh-exec "ncat backend.internal 80"

# With a FIFO, when you only have plain nc
mkfifo /tmp/relay
nc -l 8080 < /tmp/relay | nc backend.internal 80 > /tmp/relay
rm /tmp/relay

# netcat-traditional and GNU netcat: -L / --tunnel
nc.traditional -l -p 8080 -c "nc backend.internal 80"

The FIFO trick works but is fragile. It handles one connection, leaks the named pipe if you forget to remove it, and deadlocks if either side half-closes. Use ncat --sh-exec or socat for anything that has to keep working.

# socat, the right tool for a persistent forward
socat TCP-LISTEN:8080,fork,reuseaddr TCP:backend.internal:80

# UDP forward, which the netcat FIFO trick cannot do reliably
socat UDP-LISTEN:5514,fork UDP:collector.internal:514

# UDP in, TCP out, a protocol bridge
socat UDP-LISTEN:5514,fork TCP:collector.internal:601

fork is what makes socat handle more than one client, and reuseaddr avoids the TIME_WAIT rebind failure.

Dialing through a proxy

nc -x 127.0.0.1:1080 -X 5 example.com 80        # SOCKS5
nc -x 127.0.0.1:9050 -X 5 example.com 80        # through Tor's SOCKS port
nc -x proxy.internal:3128 -X connect host 443   # HTTP CONNECT

ncat --proxy 127.0.0.1:1080 --proxy-type socks5 example.com 80
ncat --proxy proxy:3128 --proxy-type http \
  --proxy-auth user:pass example.com 443
OptionOpenBSD / macOS ncNcat
Proxy address-x host:port--proxy host:port
Type-X 4 / -X 5 / -X connect--proxy-type socks4|socks5|http
Credentials—--proxy-auth user:pass
DNS side—--proxy-dns local|remote|both

netcat-traditional and GNU netcat have no proxy support. --proxy-dns remote matters when resolving the target locally would leak what you are connecting to.

Broker mode as a relay

Ncat's --broker connects every client to every other, which is a zero-config relay between two hosts that cannot reach each other directly.

# On a host both sides CAN reach
ncat --broker -lk 9000

# Each side connects out
ncat relay.example.com 9000        # host A
ncat relay.example.com 9000        # host B

Everything A types reaches B and the reverse, without either host accepting an inbound connection. Add --ssl to encrypt each leg.

UDP and forwarding reference

TaskCommand
UDP listenernc -u -l 5514
UDP listener, many sendersncat -u -lk 5514
Send one datagramecho x | nc -u -w 1 host 5514
Real UDP scansudo nmap -sU -p 53,161 host
TCP forward, one shotncat -lk 8080 --sh-exec "ncat backend 80"
TCP forward, persistentsocat TCP-LISTEN:8080,fork,reuseaddr TCP:backend:80
UDP forwardsocat UDP-LISTEN:5514,fork UDP:backend:514
Through SOCKS5nc -x 127.0.0.1:1080 -X 5 host 80
Through HTTP CONNECTnc -x proxy:3128 -X connect host 443
Relay two firewalled hostsncat --broker -lk 9000