The ss
program is using a sock_diag(7)
netlink socket to retrieve information about sockets. But the sock_diag
interface doesn't support a "monitor"/watching/listening mode, as rtnetlink(7)
does. You can only do queries via a sock_diag
socket.
You can however capture the tcp syn (=connect) packets via pcap/tcpdump and use to sock_diag
interface to find process info about them.
But there are at least three serious problems with this:
all the command line utilities able to query and display that info (ss
, lsof
) are very rigid, and it's hard to impossible to configure their output format or let them act as a filter. From the command line all you can possibly do is run a separate ss
instance for each packet.
it's racy; the process may have already finished in the time between capturing the packet and querying information about the process.
tcpdump
itself is as easy to use from a script as ss
or lsof
.
Keeping all this in mind, something like this may do, or at least may be a start:
socmon(){
script /dev/null -qc "tcpdump -qn -iany '
((tcp[tcpflags] & tcp-syn) != 0 or (ip6 and (ip6[13 + 40] & 2) == 2)) and ($*)
' 2>/dev/null" </dev/null |
perl -ne 'print; next unless /(\S+)\.(\d+) >/; print qx(ss -Hp src "[$1]:$2") =~ s/.*users:/\t/r'
}
Usage:
>>> socmon dst port 9999
07:14:59.700995 IP6 fe80::89c8:7f7c:29f5:78df.50720 > fe80::89c8:7f7c:29f5:78df.9999: tcp 0
(("xxx",pid=15805,fd=1),("xxx",pid=15804,fd=0))
07:15:08.868555 IP 127.0.0.1.42784 > 127.0.0.1.9999: tcp 0
(("xxx",pid=15851,fd=1),("xxx",pid=15850,fd=0))
07:15:17.055518 IP 172.31.255.1.39700 > 172.31.255.1.9999: tcp 0
(("xxx",pid=15856,fd=1),("xxx",pid=15855,fd=0))
The script /dev/null ... </dev/null
forces tcpdump
to use line buffering; tcpdump -l
will NOT do without an artificial delay between capturing the packet and printing it.
The (ip6 and (ip6[13 + 40] & 2) == 2)
checks if it's a SYN packet BY HAND because tcp[tcpflags] & tcp-syn
doesn't work with IPv6.
The perl thing extracts the source address and port from the tcpdump output, calls ss
with them as a filter argument, and trims the ss
output to show only the process info.
A better idea, not developed here
You could redirect the ports with iptables or nftables to another port, where a listening program could retrieve info about its peer before accepting the connection, and then will forward the connection to the destination. This would fix both the race, and won't be confused by processes which connect somewhere, then either pass or leak the socket file descriptor to other processes.
pid
-s after collecting all of them? – lainatnavi Mar 11 '20 at 15:03