sock_diag(7) Miscellaneous Information Manual sock_diag(7) sock_diag - #include #include #include /* UNIX */ #include /* IPv4 IPv6 */ diag_socket = socket(AF_NETLINK, socket_type, NETLINK_SOCK_DIAG); sock_diag netlink . . , , , . , . , (, . .). , sock_diag ; , bind(2) (, connect(2)). /proc/net/unix, /proc/net/tcp, /proc/net/udp . . struct nlmsghdr, netlink(7), nlmsg_type SOCK_DIAG_BY_FAMILY. , , , : struct sock_diag_req { __u8 sdiag_family; __u8 sdiag_protocol; }; : sdiag_family . AF_*. sdiag_protocol sdiag_family. IPPROTO_* AF_INET AF_INET6, 0 . nlmsg_flags struct nlmsghdr NLM_F_DUMP, , ; . struct nlmsghdr, , . NLMSG_* netlink(3). NLA ( netlink), RTA_* rtnetlink(3). UNIX UNIX : struct unix_diag_req { __u8 sdiag_family; __u8 sdiag_protocol; __u16 pad; __u32 udiag_states; __u32 udiag_ino; __u32 udiag_show; __u32 udiag_cookie[2]; }; : sdiag_family ; AF_UNIX. sdiag_protocol pad 0. udiag_states , . . , . : 1 << TCP_ESTABLISHED 1 << TCP_LISTEN udiag_ino . , . udiag_show , . netlink, : UDIAG_SHOW_NAME , -- UNIX_DIAG_NAME. , -- , ( UNIX_PATH_MAX). UDIAG_SHOW_VFS , -- UNIX_DIAG_VFS. , : struct unix_diag_vfs { __u32 udiag_vfs_dev; __u32 udiag_vfs_ino; }; : udiag_vfs_dev , . udiag_vfs_ino , . UDIAG_SHOW_PEER , -- UNIX_DIAG_PEER. , -- __u32, . . UDIAG_SHOW_ICONS , -- UNIX_DIAG_ICONS. , -- __u32, , connect(2), accept(2). , . UDIAG_SHOW_RQLEN , -- UNIX_DIAG_RQLEN. , : struct unix_diag_rqlen { __u32 udiag_rqueue; __u32 udiag_wqueue; }; : udiag_rqueue : . , UNIX_DIAG_ICONS. : . udiag_wqueue : (backlog), , listen(2). : , . UDIAG_SHOW_MEMINFO , -- UNIX_DIAG_MEMINFO. , __u32, << >>. : UNIX_DIAG_SHUTDOWN , , __u8 shutdown(2). udiag_cookie , udiag_ino . , -1. UNIX struct unix_diag_msg { __u8 udiag_family; __u8 udiag_type; __u8 udiag_state; __u8 pad; __u32 udiag_ino; __u32 udiag_cookie[2]; }; netlink. : udiag_family struct unix_diag_req. udiag_type SOCK_PACKET, SOCK_STREAM SOCK_SEQPACKET. udiag_state TCP_LISTEN TCP_ESTABLISHED. pad 0. udiag_ino . udiag_cookie , . IPv4 IPv6 IPv4 IPv6 : struct inet_diag_req_v2 { __u8 sdiag_family; __u8 sdiag_protocol; __u8 idiag_ext; __u8 pad; __u32 idiag_states; struct inet_diag_sockid id; }; struct inet_diag_sockid : struct inet_diag_sockid { __be16 idiag_sport; __be16 idiag_dport; __be32 idiag_src[4]; __be32 idiag_dst[4]; __u32 idiag_if; __u32 idiag_cookie[2]; }; struct inet_diag_req_v2: sdiag_family AF_INET AF_INET6 IPv4 IPv6, . sdiag_protocol IPPROTO_TCP, IPPROTO_UDP IPPROTO_UDPLITE. idiag_ext , . netlink, : INET_DIAG_TOS , , __u8 TOS . INET_DIAG_TCLASS , , __u8 TClass . IPv6. LISTEN CLOSE INET_DIAG_SKV6ONLY ( __u8), IPv6 . INET_DIAG_MEMINFO , : struct inet_diag_meminfo { __u32 idiag_rmem; __u32 idiag_wmem; __u32 idiag_fmem; __u32 idiag_tmem; }; : idiag_rmem . idiag_wmem , TCP . idiag_fmem , ( TCP). idiag_tmem . INET_DIAG_SKMEMINFO , __u32, << >>. INET_DIAG_INFO , , . TCP struct tcp_info. INET_DIAG_CONG , , , . TCP. pad 0. idiag_states , . . , . id , , . UNIX, IPv4 IPv6 . . struct inet_diag_sockid: idiag_sport . idiag_dport . idiag_src . idiag_dst . idiag_if . idiag_cookie , . , -1. IPv4 IPv6 struct inet_diag_msg { __u8 idiag_family; __u8 idiag_state; __u8 idiag_timer; __u8 idiag_retrans; struct inet_diag_sockid id; __u32 idiag_expires; __u32 idiag_rqueue; __u32 idiag_wqueue; __u32 idiag_uid; __u32 idiag_inode; }; netlink. : idiag_family struct inet_diag_req_v2. idiag_state struct inet_diag_req_v2. idiag_timer TCP . : 0 1 2 3 TIME_WAIT 4 TCP, 0. idiag_retrans idiag_timer 1, 2 4, . idiag_timer 0. idiag_expires TCP, , . 0. idiag_rqueue : . : . idiag_wqueue : (backlog). : , . idiag_uid , . idiag_inode . , netlink UNIX_DIAG_MEMINFO INET_DIAG_SKMEMINFO, __u32: SK_MEMINFO_RMEM_ALLOC . SK_MEMINFO_RCVBUF , SO_RCVBUF. SK_MEMINFO_WMEM_ALLOC . SK_MEMINFO_SNDBUF , SO_SNDBUF. SK_MEMINFO_FWD_ALLOC , ( TCP). SK_MEMINFO_WMEM_QUEUED , TCP, . SK_MEMINFO_OPTMEM , (, ). SK_MEMINFO_BACKLOG ( ). NETLINK_INET_DIAG Linux 2.6.14 AF_INET AF_INET6. Linux 3.3 NETLINK_SOCK_DIAG AF_UNIX. UNIX_DIAG_MEMINFO INET_DIAG_SKMEMINFO Linux 3.6. Linux. , UNIX . #include #include #include #include #include #include #include #include #include #include static int send_query(int fd) { struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct { struct nlmsghdr nlh; struct unix_diag_req udr; } req = { .nlh = { .nlmsg_len = sizeof(req), .nlmsg_type = SOCK_DIAG_BY_FAMILY, .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP }, .udr = { .sdiag_family = AF_UNIX, .udiag_states = -1, .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER } }; struct iovec iov = { .iov_base = &req, .iov_len = sizeof(req) }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1 }; for (;;) { if (sendmsg(fd, &msg, 0) < 0) { if (errno == EINTR) continue; perror("sendmsg"); return -1; } return 0; } } static int print_diag(const struct unix_diag_msg *diag, unsigned int len) { if (len < NLMSG_LENGTH(sizeof(*diag))) { fputs("short response\n", stderr); return -1; } if (diag->udiag_family != AF_UNIX) { fprintf(stderr, "unexpected family %u\n", diag->udiag_family); return -1; } unsigned int rta_len = len - NLMSG_LENGTH(sizeof(*diag)); unsigned int peer = 0; size_t path_len = 0; char path[sizeof(((struct sockaddr_un *) 0)->sun_path) + 1]; for (struct rtattr *attr = (struct rtattr *) (diag + 1); RTA_OK(attr, rta_len); attr = RTA_NEXT(attr, rta_len)) { switch (attr->rta_type) { case UNIX_DIAG_NAME: if (!path_len) { path_len = RTA_PAYLOAD(attr); if (path_len > sizeof(path) - 1) path_len = sizeof(path) - 1; memcpy(path, RTA_DATA(attr), path_len); path[path_len] = '\0'; } break; case UNIX_DIAG_PEER: if (RTA_PAYLOAD(attr) >= sizeof(peer)) peer = *(unsigned int *) RTA_DATA(attr); break; } } printf("inode=%u", diag->udiag_ino); if (peer) printf(", peer=%u", peer); if (path_len) printf(", name=%s%s", *path ? "" : "@", *path ? path : path + 1); putchar('\n'); return 0; } static int receive_responses(int fd) { long buf[8192 / sizeof(long)]; struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) }; int flags = 0; for (;;) { struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1 }; ssize_t ret = recvmsg(fd, &msg, flags); if (ret < 0) { if (errno == EINTR) continue; perror("recvmsg"); return -1; } if (ret == 0) return 0; if (nladdr.nl_family != AF_NETLINK) { fputs("!AF_NETLINK\n", stderr); return -1; } const struct nlmsghdr *h = (struct nlmsghdr *) buf; if (!NLMSG_OK(h, ret)) { fputs("!NLMSG_OK\n", stderr); return -1; } for (; NLMSG_OK(h, ret); h = NLMSG_NEXT(h, ret)) { if (h->nlmsg_type == NLMSG_DONE) return 0; if (h->nlmsg_type == NLMSG_ERROR) { const struct nlmsgerr *err = NLMSG_DATA(h); if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) { fputs("NLMSG_ERROR\n", stderr); } else { errno = -err->error; perror("NLMSG_ERROR"); } return -1; } if (h->nlmsg_type != SOCK_DIAG_BY_FAMILY) { fprintf(stderr, "unexpected nlmsg_type %u\n", (unsigned) h->nlmsg_type); return -1; } if (print_diag(NLMSG_DATA(h), h->nlmsg_len)) return -1; } } } int main(void) { int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG); if (fd < 0) { perror("socket"); return 1; } int ret = send_query(fd) || receive_responses(fd); close(fd); return ret; } . netlink(3), rtnetlink(3), netlink(7), tcp(7) Alexander Golubev , Azamat Hackimov , Hotellook, Nikita , Spiros Georgaras , Vladislav , Yuri Kozlov ; GNU 3 , . . , , . Linux man-pages 6.06 31 2023 . sock_diag(7)