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
| Difference | Consequence |
|---|---|
| No handshake | A "connection" never fails, so success proves nothing |
| No ordering | Datagrams can arrive out of order or not at all |
| Message boundaries | Each write is one datagram, not a byte stream |
| No close | The listener cannot tell that the sender is done |
| Refusal is out-of-band | You 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:
| Signal | Conclusion |
|---|---|
| A protocol reply arrives | Open, and identified |
| ICMP port unreachable | Closed, if the ICMP is not rate-limited |
| Silence | Open, 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
| Option | OpenBSD / macOS nc | Ncat |
|---|---|---|
| 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
| Task | Command |
|---|---|
| UDP listener | nc -u -l 5514 |
| UDP listener, many senders | ncat -u -lk 5514 |
| Send one datagram | echo x | nc -u -w 1 host 5514 |
| Real UDP scan | sudo nmap -sU -p 53,161 host |
| TCP forward, one shot | ncat -lk 8080 --sh-exec "ncat backend 80" |
| TCP forward, persistent | socat TCP-LISTEN:8080,fork,reuseaddr TCP:backend:80 |
| UDP forward | socat UDP-LISTEN:5514,fork UDP:backend:514 |
| Through SOCKS5 | nc -x 127.0.0.1:1080 -X 5 host 80 |
| Through HTTP CONNECT | nc -x proxy:3128 -X connect host 443 |
| Relay two firewalled hosts | ncat --broker -lk 9000 |