Provided by: manpages-ru_4.18.1-1_all bug

ИМЯ

       sock_diag - возвращает информацию о сокетах

СИНТАКСИС

       #include <sys/socket.h>
       #include <linux/sock_diag.h>
       #include <linux/unix_diag.h> /* для доменных сокетов UNIX */
       #include <linux/inet_diag.h> /* для сокетов 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.

СТАНДАРТЫ

       Программный интерфейс NETLINK_SOCK_DIAG есть только в Linux.

ПРИМЕРЫ

       Следующий  пример  программы  печатает  номер иноды, номер иноды противоположной стороны и
       имена всех доменных сокетов UNIX в текущем пространстве имён.

       #include <errno.h>
       #include <stdio.h>
       #include <string.h>
       #include <unistd.h>
       #include <sys/socket.h>
       #include <sys/un.h>
       #include <linux/netlink.h>
       #include <linux/rtnetlink.h>
       #include <linux/sock_diag.h>
       #include <linux/unix_diag.h>

       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("короткий ответ\n", stderr);
               return -1;
           }
           if (diag->udiag_family != AF_UNIX) {
               fprintf(stderr, "неожиданное семейство %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("инода=%u", diag->udiag_ino);

           if (peer)
               printf(", другая сторона=%u", peer);

           if (path_len)
               printf(", имя=%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, "неожиданный 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
       <fatzer2@gmail.com>,   Azamat   Hackimov  <azamat.hackimov@gmail.com>,  Hotellook,  Nikita
       <zxcvbnm3230@mail.ru>,       Spiros       Georgaras       <sng@hellug.gr>,       Vladislav
       <ivladislavefimov@gmail.com>,    Yuri    Kozlov   <yuray@komyakino.ru>   и   Иван   Павлов
       <pavia00@gmail.com>

       Этот  перевод  является  бесплатной  документацией;  прочитайте  Стандартную  общественную
       лицензию GNU версии 3 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ или более позднюю, чтобы
       узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

       Если вы обнаружите ошибки в переводе  этой  страницы  руководства,  пожалуйста,  отправьте
       электронное письмо на ⟨man-pages-ru-talks@lists.sourceforge.net⟩.