Linuxでは、/proc/net/*
やNetlinkソケットを通じて、TCP/UDPのコネクション情報を取得できる。
しかし、ここで取得したコネクション情報は、コネクションを保有するプロセスに関する情報(pidなど)を含んでいない。
ssコマンドの--extended
オプションは、inode番号を表示することから、inode番号からプロセス情報を辿ることを考える。
当該プロセスのpidがわかっていれば、/proc/<pid>/fd
以下から、次のようにsocket inode番号を知ることができる。
ubuntu@yuukidev01:~$ sudo readlink /proc/21326/fd/6 socket:[16801]
しかし、inode番号からそのinodeを保持しているpidを直接知ることはおそらくできない。 そこで、次のようなTCP/UDPのコネクションリストとプロセスリストの2つのリストを突き合わせ、socket inodeをキーとして、結合する必要がある。(RDB風に表現するとNested Loop Joinする。)
TCP/UDP connections (netlink diag messages | /proc/net/*) ---------------------------------------------------------- | State | Local Address:Port | Peer Address:Port | Inode | |--------------------------------------------------------| | ESTAB | 10.0.0.10:80 | 10.0.0.11: 46021 | 16801 | | ESTAB | 10.0.0.10:80 | 10.0.0.11: 48010 | 16829 | | ... | ----------------------------------------------------------
Processes (/proc/<pid>/*) ------------------------------------------------| | Pid | Process Name | File Discriptor | Inode | | 543 | nginx | 3 | 16801 | | 543 | nginx | 3 | 16802 | | ... | -------------------------------------------------
iproute2ユーティリティのssコマンドの実装でもこれと同じようになっており、具体的には次の通りである。
--processes
オプションが指定されると、user_ent_hash_build
が呼ばれる https://github.com/shemminger/iproute2/blob/afa588490b7e87c5adfb05d5163074e20b6ff14a/misc/ss.c#L5073 .user_ent_hash_build
では、/proc/
以下をスキャンして、inodeをキーとしたプロセス情報の連想配列を作成している、 https://github.com/shemminger/iproute2/blob/afa588490b7e87c5adfb05d5163074e20b6ff14a/misc/ss.c#L573-L674- コネクションの各行を表示するときに、コネクションのinodeをキーとして2.の連想配列からプロセス情報を取得する。tcp_show_line -> inet_stats_print -> proc_ctx_print -> find_entry
ただし、TCPコネクションのステートがTIME_WAITなど、ソケットをcloseした後のステートでは、ssコマンドでinodeが0となり、プロセス情報を取得できない。 また、まれにステートがESTABであっても、inodeが0となっていることがある。