Linux API to determine sockets owned by a process
To determine sockets owned by a process you can just use netstat
. Here's an example w/output (shortened) of netstat
with options that will do what you want.
$ sudo netstat -apeen
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
tcp 0 0 127.0.0.1:8118 0.0.0.0:* LISTEN 138 744850 13248/privoxy
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 117 9612 2019/postgres
udp 0 0 127.0.0.1:51960 127.0.0.1:51960 ESTABLISHED 117 7957 2019/postgres
udp 0 0 0.0.0.0:68 0.0.0.0:* 0 7740 1989/dhclient
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node PID/Program name Path
unix 2 [ ACC ] STREAM LISTENING 7937 2019/postgres /var/run/postgresql/.s.PGSQL.5432
unix 2 [ ACC ] STREAM LISTENING 958058 8080/emacs /tmp/emacs1000/server
unix 2 [ ACC ] STREAM LISTENING 6969 1625/Xorg /tmp/.X11-unix/X0
unix 2 [ ] DGRAM 9325 1989/dhclient
unix 3 [ ] STREAM CONNECTED 7720 1625/Xorg @/tmp/.X11-unix/X0
Make sure you run netstat as root otherwise you'll get this message:
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
An explanation of the -apeen
options from the netstat manpage:
-a, --all
Show both listening and non-listening sockets. With the
--interfaces option, show interfaces that are not up
-p, --program
Show the PID and name of the program to which each socket
belongs.
-e, --extend
Display additional information. Use this option twice for
maximum detail.
--numeric , -n
Show numerical addresses instead of trying to determine symbolic host, port or user names.
--numeric-hosts
shows numerical host addresses but does not affect the resolution of port or user names.
--numeric-ports
shows numerical port numbers but does not affect the resolution of host or user names.
--numeric-users
shows numerical user IDs but does not affect the resolution of host or port names.
I think you first have to look through the open fds in /proc/*/fd, e.g.
4 -> socket:[11147]
and then look for the referenced sockets (by the inode) in /proc/net/tcp (or /proc/net/udp), e.g.
12: B382595D:8B40 D5C43B45:0050 01 00000000:00000000 00:00000000 00000000 1000 0 11065 1 ffff88008bd35480 69 4 12 4 -1
The /proc
filesystem provides details on each process, including networking information. Open socket information is listed in /proc/net/tcp
. The IPv6 sockets are listed separately in the tcp6
file. The socket information includes information such as the local and remote ports, and the socket inode number, which can be mapped back to the process by parsing the /proc/{pid}/fd/*
information.
If you aren't familiar with the /proc
filesystem, it is basically a virtual filesystem that allows the kernel to publish all sorts of useful information to user-space. The files are normally simple structured text files that are easy to parse.
For example, on my Ubuntu system I used netcat
for testing, and ran nc -l -p 8321
to listen on port 8321. Looking at the tcp
socket information:
$ cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:2081 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 26442 1 de0c8e40 300 0 0 2 -1
1: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 7019 1 de0c84c0 300 0 0 2 -1
The first line shows it is listening on all addresses to point 8321 (0x2081). The inode number is 26442, which we can use to look up the matching pid in /proc/{pid}/fd/*
, which consists of a bunch of symlinks from the file handle number to the device. So if we look up the pid for netcat
, and check its fd
mapping:
$ ls -l /proc/7266/fd
total 0
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 0 -> /dev/pts/1
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 1 -> /dev/pts/1
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 2 -> /dev/pts/1
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 3 -> socket:[26442]
And there we see that file descriptor 3 in this process is mapped to the socket with inode 26442, just as we expect.
So obviously to build a complete map of sockets, you will need to first enumerate all the /proc/**/fd/*
files, look up the socket symlinks, then match the socket inode against the tables from /proc/net/tcp
which has the endpoint information.
This is the way the lsof
tool works (see lsof/dialects/linux/dsocket.c
for the implementation).
- Wikipedia on procfs
- The Linux /proc filesystem as a Programmer's Tool