Motivation
In this post, I’m going to go over two tools for inspecting the socket states (netstat
and ss
), and why to choose one over the other (spoiler: you can really choose either). This is not going to be a 12 ways to inspect socket states article, there are lots of those.
What is a socket?
A socket is a Linux file descriptor for communicating with the network. In Linux, they say everything is a file. In this case, you can treat a socket like a file that writes to the network instead of writing to a disk. Sockets come in different flavors for TCP vs. UDP. For more on sockets, checkout these links:
- The Linux Programming Interface (this is really great)
- Beej’s Network Programming Guide (not quite TLPI, but available for free)
Why would I care about sockets?
Sockets can be in a bunch of different states (listed in this snippet of ss) which can be useful to answer questions like:
- Is my server process actually listening on the port I think it is?
- Is it listening on the loopback interface (
127.0.0.1
), or could someone on my network connect to it (*
or0.0.0.0
)? (This can be bad if you’re developing something and running a database that anyone in the coffee shop can make requests to) - What processes are listening on what ports in general?
These questions pertain to sockets that are listening on a host, but there are also various connected states a socket can be in. High Performance Browser Networking’s TCP overview if great for some explanation of the other states (or again TLPI is excellent)
How do I inspect the state of sockets on my machine?
The two tools I’ll cover are the command line tools netstat
and ss
. I’ll start with where they get their information.
Procfs
The Procfs is a file system that Linux exposes that is like a peek into kernel memory. It lives in /proc
and it exposes information about TCP and UDP sockets at /proc/net/tcp
and /proc/net/udp
. If I cat
either of those I’ll get some inscrutable output.
Netlink
The other source of information is called the netlink
protocol. In this case you open a socket (a SOCK_RAW
with AF_NETLINK
as seen here). I can then send requests on that socket for information about other sockets (pretty meta). I have a lot to learn still about netlink
, but here are some things I found:
libnl
documentation which is a library for interacting withnetlink
sockets.- RFC 3594 – Linux Netlink as an IP Services Protocol
Netstat vs. ss
netstat
gets its information from /proc/net
directly. It parses the file and prints out information based on it.
ss
was written more recently to use the netlink
API (it will fall back to proc/net
if netlink is unavailable). The information in both systems is essentially the same (from what I’ve seen), but here are some arguments for why to use ss
- It’s faster (I just read that a lot, I don’t find
netstat
to be noticeably slower) - Netlink exposes more TCP states (again I mostly look for
LISTEN
so that’s not a huge selling point) - It has better default argument
None of these are a huge homerun, which is why I expect a lot of people still use netstat
. It’s also likely that netstat
is installed more places. For instance my Macbook has netstat
but not ss
.
The default arguments is a little more compelling. netstat
by default will try to resolve IP addresses through DNS which really slows it down. It also opens a bunch of new UDP sockets, which might clutter the picture if you’re investigating something. netstat -n
stops this behavior, but ss
has that on by default (you can use ss -r
if you do want the resolution).
One other nice thing about ss
is that its source code is much nicer to read!
Open Questions
Here are some things I am still wondering
- What are the states that netlink supports that
netstat
won’t show? Are they states I actually care about? - Where does
lsof -i
fit in with all of this? Why would I choose that overss
? - What other users are there for netlink?
- Can I use netlink to poll for any new UDP connection? (I’ve been wanting to do this to figure out what process is sending UDP packets to a particular IP address, which is easy with TCP but hard with UDP)