Linux API to determine sockets owned by a process

34,885

Solution 1

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

Solution 2

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.

Solution 3

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).

Solution 4

/proc/<pid>/net is equivalent to /proc/net for all processes in the same network namespace as you – in other words, it's "global" information.

You can do what lsof and fuser do, which is to iterate through both /proc/<pid>/fd/* and /proc/net/* looking for matching inodes. Quick demonstration:

#!/bin/sh
pgrep "$@" | while read pid; do
    for fd in /proc/$pid/fd/*; do
        name=$(readlink $fd)
        case $name in
            socket:\[*\])
                ino=${name#*:}
                for proto in tcp:10 tcp6:10 udp:10 udp6:10 unix:7; do
                    [[ ! -e /proc/net/${proto%:*} ]] ||
                    awk "
                        \$${proto##*:} == ${ino:1:${#ino}-2} {
                            print \"${proto%:*}:\", \$0
                            exit 1
                        }
                    " /proc/net/${proto%:*} || break
                done
                ;;
        esac
    done
done

You can extend this to other protocols (I see ax25, ipx, packet, raw, raw6, udplite, udp6lite in /proc/net/ too) or rewrite in a language of your choosing.

Solution 5

You can read them from proc filesystem. The 'files' you probably want to look at are found in /proc/<pid>/net (namely tcp, udp, unix)

Here's some examples on using the proc filesystem

Share:
34,885
Rob H
Author by

Rob H

I'm a Java EE developer at my day job. At home, I work on projects in Java and C++ and dabble in Scala and Python.

Updated on July 09, 2022

Comments

  • Rob H
    Rob H almost 2 years

    Is there a Linux library that will enable me to tell what IP sockets are owned by what processes? I guess I'm looking for the programmatic equivalent of lsof -i. Ultimately, I want to correlate packets seen through libpcap to processes.

    UPDATE: A couple of people have suggested using /proc/<pid>/net/tcp and udp, but on my system, the same data is shown for every process, so it doesn't help.

    • Matt Joiner
      Matt Joiner about 14 years
      oh wow. i'm writing a program to do just this right now, what a coincidence
    • Rob H
      Rob H about 14 years
      I have code now if you're interested in comparing notes. I've seen a couple rare quirks in the /proc data, but overall the approach works.
  • Rob H
    Rob H over 14 years
    Perhaps I'm missing something, but /proc/*/net/tcp shows the same data for different pids. Must be showing all connections. How can I map each one back to the source pid?
  • Rob H
    Rob H over 14 years
    Same question as I had for Kimvais: The /proc/*/net/tcp directories show the same data for different pids. How can I map each one back to the source pid?
  • Rob H
    Rob H over 14 years
    This is the missing link. Thanks! (Won't let me upvote for some reason.)
  • gavinb
    gavinb over 14 years
    I have updated the answer to include a full description of how to map sockets to pids. I hope this is clearer now - it basically involves building a table of pids to socket inodes, and looking up these inodes in the tcp socket table. Let me know if there's anything that needs clarifying.
  • ephemient
    ephemient over 14 years
    You answered this while I was writing, and I didn't notice... good job :) +1 since OP apparently can't.
  • gred
    gred over 11 years
    you can get the pid if you sudo to the owner of that process (if you can't get root). +1 on this solution! Thanks!
  • Samveen
    Samveen almost 11 years
    This answer could be even better if the inodes in the 2 examples matched each other.
  • Fish Monitor
    Fish Monitor over 10 years
    Look at /proc/XXX/net/tcp, it only contains sockets opened by the process whose pid is XXX.
  • Remember Monica
    Remember Monica about 10 years
    fossilet, /proc/<pid>/net/tcp contains all (tcp) sockets in the network namespace of the process, not just the ones opened by the process.
  • duvduv
    duvduv over 9 years
    netstat will actually parse /proc/net/tcp et al. see, for example, here (parse code for /proc/net/tcp). Paths in use by netstat defined in lib/pathnames.h.