Where is the official documentation (Debian package iproute-doc)?

The documentation is available in the Debian 9 package but was removed in later releases because it was outdated. The manpage is supposed to be the complete documentation now. (But it doesn’t have much to say about the details of filters.)


       FILTER := [ state STATE-FILTER ] [ EXPRESSION ]
              Please take a look at the official documentation for details regarding filters.

STATE-FILTER
       STATE-FILTER allows to construct arbitrary set of states to match. Its syntax is sequence of keywords state and  exclude  fol‐
       lowed by identifier of state.

       Available identifiers are:

              All  standard TCP states: established, syn-sent, syn-recv, fin-wait-1, fin-wait-2, time-wait, closed, close-wait, last-
              ack, listening and closing.

              all - for all the states

              connected - all the states except for listening and closed

              synchronized - all the connected states except for syn-sent

              bucket - states, which are maintained as minisockets, i.e.  time-wait and syn-recv

              big - opposite to bucket
...

   ss -o state established '( dport = :ssh or sport = :ssh )'
          Display all established ssh connections.

   ss -o state fin-wait-1 '( sport = :http or sport = :https )' dst 193.233.7/24
          List all the tcp sockets in state FIN-WAIT-1 for our apache to network 193.233.7/24 and look at their timers.

So

ss [options] [ FILTER ]

can be expanded to

ss [options] [ state STATE-FILTER ] [ EXPRESSION ]

where options are

[-hVHnraloempiKsZNb460tudwxS] [-f FAMILY] [-A QUERY] [-D FILE] [-D FILE]

STATE-FILTER is one of

established, syn-sent, syn-recv, fin-wait-1, fin-wait-2, time-wait, closed, close-wait, last-ack, listening, closing, all, connected, synchronized, bucket, big

and we can deduce from the examples that EXPRESSION is a list of ip-rule SELECTORs.

SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ] [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ] [ uidrange NUMBER-NUMBER ] [ ipproto PROTOCOL ] [ sport [ NUMBER | NUMBER-NUMBER ] ] [ dport [ NUMBER | NUMBER-NUMBER ] ] [ tun_id TUN_ID ]

I was wondering this same thing and the other answers and comments providing a link to the source was incredibly helpful.

The overall FILTER syntax is still a bit confusing, but based on an example from Linode showing how to check for ports above the secure (root required) range and the source I was able to put together a "complex" filter to check for opened ports in a specific range.

All three of these examples are functionally equivalent:

ss -a -t '( dport geq :5900 and dport leq :5999 or sport geq :5900 and sport leq :5999 )'

ss -a -t '( dport >= :5900 and dport <= :5999 or sport >= :5900 and sport <= :5999 )'

ss -a -t '( dport >= :5900 & dport <= :5999 | sport >= :5900 & sport <= :5999 )'

In this case the port(s) I'm hunting for are related to VNC, because the Vagrant and Packer tools from Hashicorp (and the virtualization tools they interact with like Virtualbox/VMware/libvirt) will automatically allocate ports in this range for virtual machines launched "headless" so that you can interact with the VM console without just sending in raw keystrokes.

The part that tripped me up for a second was that in the source code it has GEQ and LEQ but the actual filter syntax requires them to be lowercase or the symbolic representation >= or <=, while in the source code you can see the eq is defined as lowercase.

The other sneaky/confusing thing is that = and eq and == all work for equality.