Finding a Process Id Given a Socket and Inode in Python 3

Finding a process ID given a socket and inode in Python 3

The following code accomplishes the original goal:

def find_pid(inode):

# get a list of all files and directories in /proc
procFiles = os.listdir("/proc/")

# remove the pid of the current python process
procFiles.remove(str(os.getpid()))

# set up a list object to store valid pids
pids = []

for f in procFiles:
try:
# convert the filename to an integer and back, saving the result to a list
integer = int(f)
pids.append(str(integer))
except ValueError:
# if the filename doesn't convert to an integer, it's not a pid, and we don't care about it
pass

for pid in pids:
# check the fd directory for socket information
fds = os.listdir("/proc/%s/fd/" % pid)
for fd in fds:
# save the pid for sockets matching our inode
if ('socket:[%d]' % inode) == os.readlink("/proc/%s/fd/%s" % (pid, fd)):
return pid

How to find more information about the file descriptor?

Since you are using strace I assume you are on Linux and you know the process id. In that case you can find a lot of info in /proc. Here is an example of what to do.

Do ls -l /proc/<pid>/fd. There will be an entry corresponding to the fd you are interested in and that fd should be a socket as such:

$ ls -l /proc/3311/fd
total 0
lrwx------ 1 alanau alanau 64 Sep 24 20:37 0 -> /dev/pts/0
lrwx------ 1 alanau alanau 64 Sep 24 20:37 1 -> /dev/pts/0
lrwx------ 1 alanau alanau 64 Sep 24 20:37 2 -> /dev/pts/0
lrwx------ 1 alanau alanau 64 Sep 24 20:37 3 -> socket:[23182]

In the above example, 3 is the socket of interest. The number after socket is the inode number, 23182 in this case.

Now look in the file /proc/net/tcp to find that inode:

$ cat /proc/net/tcp | grep 23182
2: 0F02000A:C43B 8EDC3AD8:0050 01 00000000:00000000 00:00000000 00000000 1000 0 **23182** 1 0000000000000000 23 0 0 10 -1

The first line of /proc/net/tcp tells you what each field represents:

 sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode

So in this example, the remote address is 8EDC3AD8:0050. That's the ip_addres:port_number in hex and network byte ordering. If you convert that to decimal it is 216.58.220.142:80.

Which tells you it is in fact a TCP connection to port 80 of google.com!

If you don't find the inode number in /proc/net/tcp then try the other protocols in the directory, probably /proc/net/udp.

with root, open other process socket and get tcp_info with python?

There's no python tool that I know of which does what you're asking for, nor is there an easy way I can think of involving parsing the proc directory yourself. As such, you could either implement a pure python version of the ss command yourself (or at least figure out how it calculates RTT from information in /proc/<pid>/net/*), or parse its' output. I'm more of a bash person so this is what I threw together to get a list of (RTT,PID) pairs:

#!/usr/bin/python
from subprocess import check_output as co

co("ss -tp > ss.out", shell=True)
rtts = co("cat ss.out | grep ESTAB | awk '{print $4}' | xargs -I {} ss -i 'src {}' | grep \"rtt:\" | awk '{print $4}' | cut -d : -f 2 | cut -d / -f 1", shell=True)
pids = co("cat ss.out | grep ESTAB | awk '{print $6}' | cut -d , -f 2", shell=True)

print zip(rtts.split('\n'), pids.split('\n'))

In the ss command the -t means show TCP connections and the -p means print process (PID) info. Using the -e option you could also get the inode number, which you can use to determine the file descriptor numbers in /proc/XXXX/fd/. For instance I have process 31117 running on my machine with file descriptor number 11 corresponding to a socket with inode number 31159:

# ls -lah /proc/31117/fd/11
lrwx------ 1 root root 64 Dec 10 19:08 /proc/31117/fd/11 -> socket:[31159]

The reason you cannot "open" a socket file like /proc/pid/fd/4 is because these are all links which point to non-existent files. The only information you can get from them is the name (inode number) of the socket.

with root, open other process socket and get tcp_info with python?

There's no python tool that I know of which does what you're asking for, nor is there an easy way I can think of involving parsing the proc directory yourself. As such, you could either implement a pure python version of the ss command yourself (or at least figure out how it calculates RTT from information in /proc/<pid>/net/*), or parse its' output. I'm more of a bash person so this is what I threw together to get a list of (RTT,PID) pairs:

#!/usr/bin/python
from subprocess import check_output as co

co("ss -tp > ss.out", shell=True)
rtts = co("cat ss.out | grep ESTAB | awk '{print $4}' | xargs -I {} ss -i 'src {}' | grep \"rtt:\" | awk '{print $4}' | cut -d : -f 2 | cut -d / -f 1", shell=True)
pids = co("cat ss.out | grep ESTAB | awk '{print $6}' | cut -d , -f 2", shell=True)

print zip(rtts.split('\n'), pids.split('\n'))

In the ss command the -t means show TCP connections and the -p means print process (PID) info. Using the -e option you could also get the inode number, which you can use to determine the file descriptor numbers in /proc/XXXX/fd/. For instance I have process 31117 running on my machine with file descriptor number 11 corresponding to a socket with inode number 31159:

# ls -lah /proc/31117/fd/11
lrwx------ 1 root root 64 Dec 10 19:08 /proc/31117/fd/11 -> socket:[31159]

The reason you cannot "open" a socket file like /proc/pid/fd/4 is because these are all links which point to non-existent files. The only information you can get from them is the name (inode number) of the socket.

Using /proc/ pid , how can I identify a network port number's application?

NOTE: Added another answers as lsof was not satisfactory.

This should work:

#! /bin/bash
port=56474
hex_port=$(echo "obase=16; $port" | bc )

inode=$(cat /proc/net/tcp | grep ":$hex_port" | awk '{print $10}')

for i in $(ps axo pid); do
ls -l /proc/$i/fd 2> /dev/null | grep -q ":\[$inode\]" && echo $i
done

Explanation:

Once we have the port number converted to Hexadecimal, we can get the inode number from /proc/net/tcp (10th field), then we loop through /proc/pids/fd and find a symlink pointing to the inode.



Related Topics



Leave a reply



Submit