소켓 파일의 다양한 측면을 프로그래밍 방식으로 결정

소켓 파일의 다양한 측면을 프로그래밍 방식으로 결정

저는 기능 중 하나로 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: ...)에 대해 하나씩 텍스트 파일에서 얻을 수 있었습니다 /proc/net/udp6.

하지만 이제 대안이 생겼습니다인터넷 연결프로그래밍 방식 사용에 더 적합하고 더 안정적이며(특히 /proc/net/unix개행 문자로 소켓 파일을 나누기 때문에 안정적으로 구문 분석할 수 없음) 기능이 풍부합니다.

이 내용은 다음과 같이 기록됩니다.웹 링크(7)매뉴얼 페이지, 특히 소켓 진단 정보양말 진단(7)(inet_diag2011년 다른 패밀리에서 명칭 변경 및 다른 패밀리로 확대그 자체tcpdiag2005년부터 명칭 변경 및 확장자체적으로 추가됨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/tcp6TCP/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/4struct stat

관련 정보