私は関数の1つとしてprocfsを繰り返して開いているソケットを見つけ、ターゲット/ソースポート/アドレスなどを決定するプログラム(C)を作成しようとしています(netstatとlsofが実行するものと似ています)。しかし、ソケットファイルを見つけたら、どのシステムコールを使うべきかわかりません。たとえば、私が電話をかけて戻ってきreadlink
た/proc/123/fd/4
としましょうsocket:[56789]
。この情報で何ができますか?システムAPIを使用してソケットの詳細を取得します。
私は走り続けようとしましたが、strace
何netstat
が起こっているのか全く知りませんでした。一つ見ましたが、それがどういう意味なのか理解できませんでしたread
。/proc/123/fdinfo/4
たとえば、fdinfo
開いている接続(127.0.0.1:5000へのTCP接続)のファイルは次のとおりです。
pos: 0
flags: 04002
mnt_id: 9
答え1
/proc/pid/fdinfo/fd
ファイル記述子の属性と、その後に記録された開かれたファイル記述に関する情報を提供します。工程(5)マンページ。
ソケット固有の情報はありません。
/proc/net
歴史的に、Linuxでは、ソケットに関する情報を各アドレスファミリとプロトコル(たとえば/proc/net/unix
...)ごとに1つずつテキストファイルから取得できました/proc/net/udp6
。
しかし今、代替案ができました。インターネット接続プログラムの使用に適しており、より信頼性が高く(特に/proc/net/unix
改行文字でソケットファイルを分割するため、安定して解析できません)、機能が豊富です。
この内容は次のように記録されます。ウェブリンク(7)マニュアルページ、特にソケット診断情報ソックス診断(7)(inet_diag
2011年 他のファミリーから名称変更及び他のファミリーに拡大それ自体tcpdiag
2005年から名称変更・拡張独自に追加2.5.2.12002年)。 kernel.orgの情報も参照してください。
これは、アプリケーションがカーネルと通信するために使用するソケットベースのAPIです。他のソケットと同様に、socket()
システムコールを使用してソケットを作成し(AF_NETLINK
アドレスファミリとして)、一部をsetsockopt()
使用してソケットを調整しsendmsg()
たりrecvmsg()
情報を送受信したりできます。
これがss
(from iproute2
)が使用されることです。netstat
(from net-tools
)、lsfd
(from)はまだファイルインタフェースをutil-linux
使用しているようです。 Linuxでもオプションとして使用できます。/proc/net/...
lsof
+E
最新バージョンでは、strace
これらのソケットで送受信されたメッセージをデコードできるため、次のように実際の動作を確認できますss
。
$ strace -qqe network ss -lt
socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_SOCK_DIAG) = 3
setsockopt(3, SOL_SOCKET, SO_SNDBUF, [32768], 4) = 0
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [1048576], 4) = 0
setsockopt(3, SOL_NETLINK, NETLINK_EXT_ACK, [1], 4) = 0
bind(3, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 12) = 0
getsockname(3, {sa_family=AF_NETLINK, nl_pid=9352, nl_groups=00000000}, [12]) = 0
sendmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=72, nlmsg_type=SOCK_DIAG_BY_FAMILY, nlmsg_flags=NLM_F_REQUEST|NLM_F_DUMP, nlmsg_seq=123456, nlmsg_pid=0}, {sdiag_family=AF_INET, sdiag_protocol=IPPROTO_TCP, idiag_ext=0, idiag_states=1<<TCP_CLOSE|1<<TCP_LISTEN, id={idiag_sport=htons(0), idiag_dport=htons(0), idiag_src=inet_addr("0.0.0.0"), idiag_dst=inet_addr("0.0.0.0"), idiag_if=0, idiag_cookie=[0, 0]}}], iov_len=72}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 72
recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 812
recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[[{nlmsg_len=116, nlmsg_type=SOCK_DIAG_BY_FAMILY, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=123456, nlmsg_pid=9352}, {idiag_family=AF_INET, idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0, id={idiag_sport=htons(4330), idiag_dport=htons(0), idiag_src=inet_addr("0.0.0.0"), idiag_dst=inet_addr("0.0.0.0"), idiag_if=0, idiag_cookie=[8331, 0]}, idiag_expires=0, idiag_rqueue=0, idiag_wqueue=5, idiag_uid=997, idiag_inode=18774}, [[{nla_len=5, nla_type=INET_DIAG_SHUTDOWN}, 0], [{nla_len=12, nla_type=INET_DIAG_CGROUP_ID}, 5094], [{nla_len=6, nla_type=INET_DIAG_SOCKOPT}, {is_icsk=1, mc_loop=1, mc_all=1}]]], [{nlmsg_len=116, nlmsg_type=SOCK_DIAG_BY_FAMILY, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=123456, nlmsg_pid=9352}, {idiag_family=AF_INET, idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0, id={idiag_sport=htons(3306), idiag_dport=htons(0), idiag_src=inet_addr("127.0.0.1"), idiag_dst=inet_addr("0.0.0.0"), idiag_if=0, idiag_cookie=[8332, 0]}, idiag_expires=0, idiag_rqueue=0, idiag_wqueue=80, idiag_uid=121, idiag_inode=4823}, [[{nla_len=5, nla_type=INET_DIAG_SHUTDOWN}, 0], [{nla_len=12, nla_type=INET_DIAG_CGROUP_ID}, 3733], [{nla_len=6, nla_type=INET_DIAG_SOCKOPT}, {is_icsk=1, freebind=1, mc_loop=1, mc_all=1}]]], [{nlmsg_len=116, nlmsg_type=SOCK_DIAG_BY_FAMILY, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=123456, nlmsg_pid=9352}, {idiag_family=AF_INET, idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0, id={idiag_sport=htons(22), idiag_dport=htons(0), idiag_src=inet_addr("0.0.0.0"), idiag_dst=inet_addr("0.0.0.0"), idiag_if=0, idiag_cookie=[8333, 0]}, idiag_expires=0, idiag_rqueue=0, idiag_wqueue=128, idiag_uid=0, idiag_inode=2707}, [[{nla_len=5, nla_type=INET_DIAG_SHUTDOWN}, 0], [{nla_len=12, nla_type=INET_DIAG_CGROUP_ID}, 3774], [{nla_len=6, nla_type=INET_DIAG_SOCKOPT}, {is_icsk=1, mc_loop=1, mc_all=1}]]], [{nlmsg_len=116, nlmsg_type=SOCK_DIAG_BY_FAMILY, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=123456, nlmsg_pid=9352}, {idiag_family=AF_INET, idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0, id={idiag_sport=htons(44321), idiag_dport=htons(0), idiag_src=inet_addr("0.0.0.0"), idiag_dst=inet_addr("0.0.0.0"), idiag_if=0, idiag_cookie=[8334, 0]}, idiag_expires=0, idiag_rqueue=0, idiag_wqueue=5, idiag_uid=0, idiag_inode=18553}, [[{nla_len=5, nla_type=INET_DIAG_SHUTDOWN}, 0], [{nla_len=12, nla_type=INET_DIAG_CGROUP_ID}, 5012], [{nla_len=6, nla_type=INET_DIAG_SOCKOPT}, {is_icsk=1, mc_loop=1, mc_all=1}]]], [{nlmsg_len=116, nlmsg_type=SOCK_DIAG_BY_FAMILY, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=123456, nlmsg_pid=9352}, {idiag_family=AF_INET, idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0, id={idiag_sport=htons(44322), idiag_dport=htons(0), idiag_src=inet_addr("0.0.0.0"), idiag_dst=inet_addr("0.0.0.0"), idiag_if=0, idiag_cookie=[8335, 0]}, idiag_expires=0, idiag_rqueue=0, idiag_wqueue=128, idiag_uid=0, idiag_inode=18613}, [[{nla_len=5, nla_type=INET_DIAG_SHUTDOWN}, 0], [{nla_len=12, nla_type=INET_DIAG_CGROUP_ID}, 5135], [{nla_len=6, nla_type=INET_DIAG_SOCKOPT}, {is_icsk=1, mc_loop=1, mc_all=1}]]], [{nlmsg_len=116, nlmsg_type=SOCK_DIAG_BY_FAMILY, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=123456, nlmsg_pid=9352}, {idiag_family=AF_INET, idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0, id={idiag_sport=htons(44323), idiag_dport=htons(0), idiag_src=inet_addr("0.0.0.0"), idiag_dst=inet_addr("0.0.0.0"), idiag_if=0, idiag_cookie=[8336, 0]}, idiag_expires=0, idiag_rqueue=0, idiag_wqueue=128, idiag_uid=0, idiag_inode=18614}, [[{nla_len=5, nla_type=INET_DIAG_SHUTDOWN}, 0], [{nla_len=12, nla_type=INET_DIAG_CGROUP_ID}, 5135], [{nla_len=6, nla_type=INET_DIAG_SOCKOPT}, {is_icsk=1, mc_loop=1, mc_all=1}]]], [{nlmsg_len=116, nlmsg_type=SOCK_DIAG_BY_FAMILY, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=123456, nlmsg_pid=9352}, {idiag_family=AF_INET, idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0, id={idiag_sport=htons(631), idiag_dport=htons(0), idiag_src=inet_addr("127.0.0.1"), idiag_dst=inet_addr("0.0.0.0"), idiag_if=0, idiag_cookie=[8337, 0]}, idiag_expires=0, idiag_rqueue=0, idiag_wqueue=4096, idiag_uid=0, idiag_inode=3811}, [[{nla_len=5, nla_type=INET_DIAG_SHUTDOWN}, 0], [{nla_len=12, nla_type=INET_DIAG_CGROUP_ID}, 3610], [{nla_len=6, nla_type=INET_DIAG_SOCKOPT}, {is_icsk=1, mc_loop=1, mc_all=1}]]]], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 812
答え2
最初に読む必要があるのは、/proc/net/tcp
ネットワーク名前空間に対して開いているすべてのTCP / IP接続の詳細のリストです(/proc/net/tcp6
TCP / IPv6接続を参照)。この情報には関連する inode 番号が含まれます。このファイルの例行は次のとおりです。
2: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 19691 1 0000000000000000 100 0 0 10 0
これは00000000:0016
、ソケットが0.0.0.0
ポート22でリッスンしていることを意味します。ピアアドレス(00000000:0000
)がすべて0であるため、これがリスニングソケットであることがわかります。このソケットのインデックスノードは19691であることがわかります。
これらの番号があれば、のリストと一致させることができます/proc/<pid>/fd
。たとえば、socket:[12345]
ソケットが inode 12345 にあることを意味します。より良いことは、オブジェクトからinode番号を呼び出してstat
抽出できることです。/proc/<pid>/fd/4
struct stat