Linux Sockets Presentation and Manually Closing

From a generic point of view, sockets are just the binding of an IP address and a port number. In GNU/Linux operating systems sockets are represented through file descriptors which in this case are called socket descriptors. These socket descriptors are managed by the kernel but opening or closing of these descritptors is requested by the application which wants to send or receive data. You can see all states a socket goes through below:

There are multiple ways to view sockets on GNU/Linux but in this tutorial I shall focus on lsof command:

╰─ lsof -i -P -n | grep ESTAB COMMAND PID TID TASKCMD USER FD TYPE DEVICE SIZE/OFF NODE NAME firefox 2188 tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED)

Lsof stands for list open files and meaning of options is:

The meaning of each parameter is pretty straight forward but what I would like to focus on is FD(file descriptor) column. In this case 126 is FD number and "u" means read & write permissions. For more details please check lsof command.

We see that PID is 2188 but there is no TID (thread ID) because open files for threads of this socket have been filtered out. To display all open files together with their corresponding threads which are involved in communication on this socket we can filter lsof command by FD number and remove -i option

╰─ lsof -n -P | grep 126u COMMAND PID TID TASKCMD USER FD TYPE DEVICE SIZE/OFF NODE NAME firefox 2188 tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED) firefox 2188 2198 firefox:d tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED) firefox 2188 2199 firefox:s tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED) firefox 2188 2200 firefox:s tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED) firefox 2188 2201 firefox:s tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED) firefox 2188 2202 IPC\x20I/ tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED) firefox 2188 2203 Timer tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED) firefox 2188 2204 Netlink tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED) firefox 2188 2205 Socket tony 126u IPv4 34643 0t0 TCP 192.168.0.227:59842->54.187.71.185:443 (ESTABLISHED) ...etc

I have displayed the first 10 open files from a total of 163 and what I want to emphasize is that all these threads working together such as "Netlink", "Timer", etc. are shared by multiple PIDs. We can see that all these files share the same "NODE" which is part of the inode table aka kernel vnode table in which all open files are managed. Kernel allocates files to a node usually taking into account functionality as a whole of those files, in our case there are 163 open files working together to ensure functionality of socket.

Each process and thread has its own file descriptor table in which we can see all files used by that process/thread and this table contains actual links between file descritpors number and the operating system resource(in our case socket). To better understand tables and open files I strongly recommend to check file descriptors

To list all these links for a PID navigate to /proc/$PID/fd:

╭─░▒▓    /proc/2188/fd  ───────────────────────────────────────────────────────────── ✔  15:11:08  ▓▒░─╮ ╰─ ls -l ─╯ total 0 lr-x------ 1 tony tony 64 sep 11 15:08 0 -> 'pipe:[34371]' l-wx------ 1 tony tony 64 sep 11 15:08 1 -> /dev/null lrwx------ 1 tony tony 64 sep 11 15:08 10 -> 'anon_inode:[eventfd]' lr-x------ 1 tony tony 64 sep 11 10:25 100 -> '/memfd:mozilla-ipc (deleted)' lr-x------ 1 tony tony 64 sep 11 10:25 101 -> '/memfd:mozilla-ipc (deleted)' lr-x------ 1 tony tony 64 sep 11 10:25 102 -> '/memfd:mozilla-ipc (deleted)' lr-x------ 1 tony tony 64 sep 11 10:25 103 -> '/memfd:mozilla-ipc (deleted)' lr-x------ 1 tony tony 64 sep 11 10:25 104 -> '/memfd:mozilla-ipc (deleted)' lr-x------ 1 tony tony 64 sep 11 10:25 105 -> '/memfd:mozilla-ipc (deleted)' lr-x------ 1 tony tony 64 sep 11 10:25 106 -> '/memfd:mozilla-ipc (deleted)' lrwx------ 1 tony tony 64 sep 11 15:08 107 -> /home/tony/.mozilla/firefox/ldycq77w.default-release/cert9.db lrwx------ 1 tony tony 64 sep 11 15:08 108 -> /home/tony/.mozilla/firefox/ldycq77w.default-release/key4.db lrwx------ 1 tony tony 64 sep 11 15:08 109 -> 'socket:[36991]' lrwx------ 1 tony tony 64 sep 11 15:08 11 -> /home/tony/.mozilla/firefox/ldycq77w.default-release/cookies.sqlite ...etc

Some FDs are linked with files that have an actual path on the OS while the others point most of the times towards a pipe or socket followed by expression ":[nodeID]" where nodeID is the same "NODE" which was discussed above.

FD number which is responsible for the ESTABLISHED socket mentioned above is 126 and its socket is bound to kernel node ID 34643. Knowing that these IDs are unique and each nodeID is bound to only one file descriptor ID we can list and filter by nodeID (34643) and the only displayed FD should be 126

╰─ ls -l | grep 34643 lrwx------ 1 tony tony 64 sep 11 15:08 126 -> socket:[34643]

Indeed! Notice that if this link is removed the kernel will close this socket immediately.

╰─whoami & rm 126 root rm: cannot remove '126': Operation not permitted

Of course some protection is implemented and not even root can manually remove this link. One way to get rid of that socket is to use GNU Debugger, if you don't have it installed just use your OS package manager to install it.

Then issue gdb attach PID

And finally use "call close(FD)" and the issue "exit"

╰─ gdb attach 2188 [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1". 0x00007f0a2aaabe9f in poll () from /usr/lib/libc.so.6 (gdb) call close(126) 'close' has unknown return type; cast the call to its declared return type (gdb) exit

Even if you see that message which seems as an error, you will notice that the link was indeed removed and socket was closed.

╰─ rm 126 rm: cannot remove '126': No such file or directory

We can see that FD number 126 is no longer present. So far we have seen how to view and close sockets but their primary functionality is to send and receive data which you can see in socket I/O