Some usage notes for the Linux ss
program
Today I tweeted:
The Linux ss command is one of those things that I should learn one of these days but I keep just using lsof unless lsof is going to be really inconvenient (or slow).
In the way of these things, this prompted me to go poke at ss
again. It turns
out that something important has happened in the world of ss
since I last looked at it in late 2018, namely
ss
's very useful filtering language is now actually documented
in its manual page.
(This development is from early 2021 and may not be in your Linux distribution's manpage collection yet. But it's in the online manpage at man7.org.)
There are still some things that aren't obvious in the manpage, especially about filters. In no particular order:
- The filter expression can be split up over multiple command line
arguments, but doesn't have to be. My old example
used a single command line argument for the filter expression but I
also have other ones that use a mixture, including:
[...] 'dport = :8025' dst $SPECIALIP
This splits the filter expression across three command line arguments without
ss
choking. - When the
ss
manpage talks about 'source' and 'destination' hosts or ports, it really means 'local' and 'remote' respectively. Because I normally deal with firewalls, 'source' and 'destination' generally have packet or connection specific meanings to me, and I have to reset my assumptions when dealing withss
. - State filters can be written in a sequence, eg '
state established state listening
' will list established and listening sockets. - As documented at the end of the manual page's HOST SYNTAX, the 'host' for IP addresses can also be a CIDR network address such as '192.168.1.0/24'.
My traditional use of lsof
in this context is 'lsof -n -i
',
perhaps with some filtering to look at only listening sockets.
Unfortunately there's no exact analog of this command, so the
arguments you want to use depend on what you're trying to do. First,
by default ss
doesn't show listening sockets; if you give -l
you get only listening sockets, and if you really want all sockets,
both listening and non-listening, you need to use -a
.
Although it is not documented, you can combine -t
and -u
to get
both TCP and UDP sockets. However, you cannot combine -4
and -6
to get both IPv4 and IPv6 sockets; you must pick one. To get just
IPv4 and IPv6 together, I think that '-A inet
' works, but I'm not
sure I understand socket tables correctly here. You can also use
'-tu
', which is usually close enough to what you want.
Lsof will show you the PID, the program name of the PID, and the
login name of the owner of the process. There is no convenient
direct equivalent of this in ss
; you can show the process with
-p
, and sometimes show the UID (along with varying other things)
with -e
, but there's no option to turn the UID into a login name
even when it's shown. In addition, lsof
and ss
give you somewhat
different information, technically. Lsof is working forward from
what file descriptors a process has open and what UID those processes
are running as; as it says, ss
is working backward from who the
kernel considers to own a socket. It's possible for ss
to list
multiple processes for a given socket. Based on my experimentation,
ss
is not a useful and reliable way of easily showing who 'owns'
a particular socket, especially a listening one; if you need this,
use lsof
.
(According to ss
's manpage, the -e
option shows 'the user id
the socket belongs to', implicitly as the kernel sees it. Evidently
the kernel sometimes doesn't consider the socket to belong to anyone.
People who understand Linux socket internals can probably tell you
all about when and why this happens, but I know is that -e
has
highly variable and not entirely useful output for my purposes. The
-p
option appears to be reliable.)
I think this means that 'ss -tupa
' the closes equivalent to
'lsof -n -i
', but usually I actually want only listening sockets,
which makes that 'ss -tupl
'. If I want to know what the active
connections are and don't care about listening things, I want 'ss
-tup
' instead.
(Credit goes to @bitprophet, who
gave me starting arguments. I skip the '-d
' argument because I
rather doubt we ever have any DCCP
sockets on our systems.)
For sysadmin purposes, where I often care 'what is listening to the world instead of just localhost', what I want is:
ss -tulp '! ( src 127.0.0.0/8 or src [::1] )'
Some of the time, I will want '-n
' as well so that ss
stops
decoding high port numbers to whatever is listed in /etc/services
as once upon a time being vaguely associated with that port. For
some purposes, you can add 'sport gt 1024
' to ignore ports that
require root's involvement to listen on.
(This is where I wish all tools had an option that used names only for ports under 1024, which really are solidly assigned, and listed all others numerically.)
PS: ss
may not show a process associated with (listening) ports
under some circumstances, such as if you have the kernel Wireguard
implementation listening on some port. As I do. You can also see
this for some ports on a NFS server, for
the same reason.
Comments on this page:
|
|