Setting Up a TCP Listener and Connecting to It with Netcat
This can be handy to test connecting to a specific port.
The nc
command (Netcat) lets us start a TCP listener and connect to it. If
you’re developing a tool or testing something that connects to a TCP port, nc
lets you quickly do that. It can do a lot more than that, but that’s the use
case we’re going to cover in this post.
Before we get into the examples it’s worth pointing out there’s 3 variants of
nc
such as “traditional”, “GNU” and “OpenBSD”. They all act a little
different, some variants are more maintained than others.
Typically most folks choose between traditional or OpenBSD because it’s available in most package managers. Both versions are available on Linux and macOS.
Ubuntu installs the OpenBSD version by default. Debian requires that you pick
which version to install, such as sudo apt-get install netcat-openbsd
.
Generally speaking, the OpenBSD version is considered to be more common.
All of the examples below are using the OpenBSD version. If you notice the
outputs look different or certain flags don’t work you probably have a
different variant of Netcat. If nc -e
fails with “invalid option” then you
have the OpenBSD version (a good thing IMO).
# Listening and Connecting
Listening:
$ nc -v -l 4299
Listening on 0.0.0.0 4299
-v
provides more verbose log output (such as showing “Listening on…” above)-l
listens for an incoming connection4299
is the port to listen on, feel free to change it to any other available port- You can also do
localhost 4299
or another IP address or hostname before the port- As seen above, if you omit that it defaults to
0.0.0.0
- As seen above, if you omit that it defaults to
Connecting:
$ nc -v localhost 4299
Connection to localhost (127.0.0.1) 4299 port [tcp/*] succeeded!
The connection will remain open until you kill it, such as hitting CTRL+c
.
- By omitting
-l
we’re saying we want to connect not listen -v
provides more verbose log output (such as “Connection to…” above)- We need to supply a host to connect to, in this case
localhost
4299
is the port to connect to, in our example it should match the listener port
Our listener will also log Connection received on localhost 54658
. That port
number on the end will be different since it’s a randomly assigned port.
# Experimenting
You’re not limited to connecting to TCP listeners that nc
created.
For example, I typically run web apps locally on port 8000. If I start one of
those projects and run nc -v localhost 8000
then it will make a successful connection. That’s because HTTP
is based off TCP.
Also, if you run nc -v localhost 50001
or pick a port with no active TCP
listener then you’ll get a connection refused error. That’s normal.
Lastly, here’s a fun one. If you run nc -v -l 4299
twice you will be able to
listen on the same port. Then if you connect with nc -v localhost 4299
one
of them will receive the connection.
If you have a socket analysis tool installed such as ss
you can verify that:
$ ss -ntpl | grep 4299
LISTEN 0 1 0.0.0.0:4299 0.0.0.0:* users:(("nc",pid=32725,fd=3))
LISTEN 0 1 0.0.0.0:4299 0.0.0.0:* users:(("nc",pid=32720,fd=3))
That likely breaks your mental model of how ports work right? You can’t listen on the same port twice. That’s what I thought too but it’s more detailed than that. The rule is really you can’t bind to the same combination of a few different values that are included as part of the TCP connection.
This starts to get a bit below my understanding of how sockets work but this StackOverflow answer has a complete breakdown if you want to know the gory details.
# Demo Video
Timestamps
- 0:21 – Traditional vs GNU vs OpenBSD
- 1:36 – Creating a listener
- 2:32 – Connecting to our listener
- 3:46 – Connecting to an existing port such as an HTTP port
- 4:42 – Accessing an unused port
- 4:53 – Listening on the same port twice?
- 6:29 – Checking out port usage with ss
When did you last use Netcat? Let us know below!