{
    "content": [
        {
            "type": "text",
            "text": "# sock_diag (man)\n\n## NAME\n\nsockdiag - obtaining information about sockets\n\n## DESCRIPTION\n\nThe  sockdiag netlink subsystem provides a mechanism for obtaining information about sockets\nof various address families from the kernel.  This subsystem can be used to  obtain  informa‐\ntion about individual sockets or request a list of sockets.\n\n## Sections\n\n- **NAME**\n- **SYNOPSIS** (2 subsections)\n- **DESCRIPTION** (5 subsections)\n- **VERSIONS**\n- **STANDARDS**\n- **EXAMPLES**\n- **SEE ALSO**\n\nUse structuredContent.sections for detailed options, examples, and full documentation.\n"
        }
    ],
    "structuredContent": {
        "command": "sock_diag",
        "section": "",
        "mode": "man",
        "summary": "sockdiag - obtaining information about sockets",
        "synopsis": "",
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [
            "The  following example program prints inode number, peer's inode number, and name of all UNIX",
            "domain sockets in the current namespace.",
            "#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/sockdiag.h>",
            "#include <linux/unixdiag.h>",
            "static int",
            "sendquery(int fd)",
            "struct sockaddrnl nladdr = {",
            ".nlfamily = AFNETLINK",
            "};",
            "struct",
            "struct nlmsghdr nlh;",
            "struct unixdiagreq udr;",
            "} req = {",
            ".nlh = {",
            ".nlmsglen = sizeof(req),",
            ".nlmsgtype = SOCKDIAGBYFAMILY,",
            ".nlmsgflags = NLMFREQUEST | NLMFDUMP",
            "},",
            ".udr = {",
            ".sdiagfamily = AFUNIX,",
            ".udiagstates = -1,",
            ".udiagshow = UDIAGSHOWNAME | UDIAGSHOWPEER",
            "};",
            "struct iovec iov = {",
            ".iovbase = &req,",
            ".iovlen = sizeof(req)",
            "};",
            "struct msghdr msg = {",
            ".msgname = &nladdr,",
            ".msgnamelen = sizeof(nladdr),",
            ".msgiov = &iov,",
            ".msgiovlen = 1",
            "};",
            "for (;;) {",
            "if (sendmsg(fd, &msg, 0) < 0) {",
            "if (errno == EINTR)",
            "continue;",
            "perror(\"sendmsg\");",
            "return -1;",
            "return 0;",
            "static int",
            "printdiag(const struct unixdiagmsg *diag, unsigned int len)",
            "if (len < NLMSGLENGTH(sizeof(*diag))) {",
            "fputs(\"short response\\n\", stderr);",
            "return -1;",
            "if (diag->udiagfamily != AFUNIX) {",
            "fprintf(stderr, \"unexpected family %u\\n\", diag->udiagfamily);",
            "return -1;",
            "unsigned int rtalen = len - NLMSGLENGTH(sizeof(*diag));",
            "unsigned int peer = 0;",
            "sizet pathlen = 0;",
            "char path[sizeof(((struct sockaddrun *) 0)->sunpath) + 1];",
            "for (struct rtattr *attr = (struct rtattr *) (diag + 1);",
            "RTAOK(attr, rtalen); attr = RTANEXT(attr, rtalen)) {",
            "switch (attr->rtatype) {",
            "case UNIXDIAGNAME:",
            "if (!pathlen) {",
            "pathlen = RTAPAYLOAD(attr);",
            "if (pathlen > sizeof(path) - 1)",
            "pathlen = sizeof(path) - 1;",
            "memcpy(path, RTADATA(attr), pathlen);",
            "path[pathlen] = '\\0';",
            "break;",
            "case UNIXDIAGPEER:",
            "if (RTAPAYLOAD(attr) >= sizeof(peer))",
            "peer = *(unsigned int *) RTADATA(attr);",
            "break;",
            "printf(\"inode=%u\", diag->udiagino);",
            "if (peer)",
            "printf(\", peer=%u\", peer);",
            "if (pathlen)",
            "printf(\", name=%s%s\", *path ? \"\" : \"@\",",
            "*path ? path : path + 1);",
            "putchar('\\n');",
            "return 0;",
            "static int",
            "receiveresponses(int fd)",
            "long buf[8192 / sizeof(long)];",
            "struct sockaddrnl nladdr;",
            "struct iovec iov = {",
            ".iovbase = buf,",
            ".iovlen = sizeof(buf)",
            "};",
            "int flags = 0;",
            "for (;;) {",
            "struct msghdr msg = {",
            ".msgname = &nladdr,",
            ".msgnamelen = sizeof(nladdr),",
            ".msgiov = &iov,",
            ".msgiovlen = 1",
            "};",
            "ssizet ret = recvmsg(fd, &msg, flags);",
            "if (ret < 0) {",
            "if (errno == EINTR)",
            "continue;",
            "perror(\"recvmsg\");",
            "return -1;",
            "if (ret == 0)",
            "return 0;",
            "if (nladdr.nlfamily != AFNETLINK) {",
            "fputs(\"!AFNETLINK\\n\", stderr);",
            "return -1;",
            "const struct nlmsghdr *h = (struct nlmsghdr *) buf;",
            "if (!NLMSGOK(h, ret)) {",
            "fputs(\"!NLMSGOK\\n\", stderr);",
            "return -1;",
            "for (; NLMSGOK(h, ret); h = NLMSGNEXT(h, ret)) {",
            "if (h->nlmsgtype == NLMSGDONE)",
            "return 0;",
            "if (h->nlmsgtype == NLMSGERROR) {",
            "const struct nlmsgerr *err = NLMSGDATA(h);",
            "if (h->nlmsglen < NLMSGLENGTH(sizeof(*err))) {",
            "fputs(\"NLMSGERROR\\n\", stderr);",
            "} else {",
            "errno = -err->error;",
            "perror(\"NLMSGERROR\");",
            "return -1;",
            "if (h->nlmsgtype != SOCKDIAGBYFAMILY) {",
            "fprintf(stderr, \"unexpected nlmsgtype %u\\n\",",
            "(unsigned) h->nlmsgtype);",
            "return -1;",
            "if (printdiag(NLMSGDATA(h), h->nlmsglen))",
            "return -1;",
            "int",
            "main(void)",
            "int fd = socket(AFNETLINK, SOCKRAW, NETLINKSOCKDIAG);",
            "if (fd < 0) {",
            "perror(\"socket\");",
            "return 1;",
            "int ret = sendquery(fd) || receiveresponses(fd);",
            "close(fd);",
            "return ret;"
        ],
        "see_also": [
            {
                "name": "netlink",
                "section": "3",
                "url": "https://www.chedong.com/phpMan.php/man/netlink/3/json"
            },
            {
                "name": "rtnetlink",
                "section": "3",
                "url": "https://www.chedong.com/phpMan.php/man/rtnetlink/3/json"
            },
            {
                "name": "netlink",
                "section": "7",
                "url": "https://www.chedong.com/phpMan.php/man/netlink/7/json"
            },
            {
                "name": "tcp",
                "section": "7",
                "url": "https://www.chedong.com/phpMan.php/man/tcp/7/json"
            }
        ],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "SYNOPSIS",
                "lines": 1,
                "subsections": [
                    {
                        "name": "#include <sys/socket.h>",
                        "lines": 1
                    },
                    {
                        "name": "#include <linux/sock_diag.h>",
                        "lines": 5
                    }
                ]
            },
            {
                "name": "DESCRIPTION",
                "lines": 16,
                "subsections": [
                    {
                        "name": "Request",
                        "lines": 22
                    },
                    {
                        "name": "Response",
                        "lines": 7
                    },
                    {
                        "name": "UNIX domain sockets",
                        "lines": 143
                    },
                    {
                        "name": "IPv4 and IPv6 sockets",
                        "lines": 176
                    },
                    {
                        "name": "Socket memory information",
                        "lines": 27
                    }
                ]
            },
            {
                "name": "VERSIONS",
                "lines": 6,
                "subsections": []
            },
            {
                "name": "STANDARDS",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "EXAMPLES",
                "lines": 198,
                "subsections": []
            },
            {
                "name": "SEE ALSO",
                "lines": 3,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "sockdiag - obtaining information about sockets\n",
                "subsections": []
            },
            "SYNOPSIS": {
                "content": "",
                "subsections": [
                    {
                        "name": "#include <sys/socket.h>",
                        "content": ""
                    },
                    {
                        "name": "#include <linux/sock_diag.h>",
                        "content": "#include <linux/unixdiag.h> /* for UNIX domain sockets */\n#include <linux/inetdiag.h> /* for IPv4 and IPv6 sockets */\n\ndiagsocket = socket(AFNETLINK, sockettype, NETLINKSOCKDIAG);\n"
                    }
                ]
            },
            "DESCRIPTION": {
                "content": "The  sockdiag netlink subsystem provides a mechanism for obtaining information about sockets\nof various address families from the kernel.  This subsystem can be used to  obtain  informa‐\ntion about individual sockets or request a list of sockets.\n\nIn  the  request, the caller can specify additional information it would like to obtain about\nthe socket, for example, memory information or information specific to the address family.\n\nWhen requesting a list of sockets, the caller can specify filters that would  be  applied  by\nthe  kernel  to  select a subset of sockets to report.  For now, there is only the ability to\nfilter sockets by state (connected, listening, and so on.)\n\nNote that sockdiag reports only those sockets that have a  name;  that  is,  either  sockets\nbound  explicitly  with bind(2) or sockets that were automatically bound to an address (e.g.,\nby connect(2)).  This is the same set  of  sockets  that  is  available  via  /proc/net/unix,\n/proc/net/tcp, /proc/net/udp, and so on.\n",
                "subsections": [
                    {
                        "name": "Request",
                        "content": "The  request  starts  with  a  struct nlmsghdr header described in netlink(7) with nlmsgtype\nfield set to SOCKDIAGBYFAMILY.  It is followed by a header specific to the address  family\nthat starts with a common part shared by all address families:\n\nstruct sockdiagreq {\nu8 sdiagfamily;\nu8 sdiagprotocol;\n};\n\nThe fields of this structure are as follows:\n\nsdiagfamily\nAn address family.  It should be set to the appropriate AF* constant.\n\nsdiagprotocol\nDepends  on  sdiagfamily.  It should be set to the appropriate IPPROTO* constant for\nAFINET and AFINET6, and to 0 otherwise.\n\nIf the nlmsgflags field of the struct nlmsghdr header has the NLMFDUMP flag set, it  means\nthat  a  list  of  sockets  is  being  requested; otherwise it is a query about an individual\nsocket.\n"
                    },
                    {
                        "name": "Response",
                        "content": "The response starts with a struct nlmsghdr header and is followed by an array of objects spe‐\ncific to the address family.  The array is to be accessed with the  standard  NLMSG*  macros\nfrom the netlink(3) API.\n\nEach object is the NLA (netlink attributes) list that is to be accessed with the RTA* macros\nfrom rtnetlink(3) API.\n"
                    },
                    {
                        "name": "UNIX domain sockets",
                        "content": "For UNIX domain sockets the request is represented in the following structure:\n\nstruct unixdiagreq {\nu8    sdiagfamily;\nu8    sdiagprotocol;\nu16   pad;\nu32   udiagstates;\nu32   udiagino;\nu32   udiagshow;\nu32   udiagcookie[2];\n};\n\nThe fields of this structure are as follows:\n\nsdiagfamily\nThe address family; it should be set to AFUNIX.\n\nsdiagprotocol\npad    These fields should be set to 0.\n\nudiagstates\nThis  is a bit mask that defines a filter of sockets states.  Only those sockets whose\nstates are in this mask will be reported.  Ignored when  querying  for  an  individual\nsocket.  Supported values are:\n\n1 << TCPESTABLISHED\n\n1 << TCPLISTEN\n\nudiagino\nThis is an inode number when querying for an individual socket.  Ignored when querying\nfor a list of sockets.\n\nudiagshow\nThis  is  a  set of flags defining what kind of information to report.  Each requested\nkind of information is reported back as a netlink attribute as described below:\n\nUDIAGSHOWNAME\nThe attribute reported in answer to this request is UNIXDIAGNAME.   The  pay‐\nload  associated  with  this  attribute is the pathname to which the socket was\nbound (a sequence of bytes up to UNIXPATHMAX length).\n\nUDIAGSHOWVFS\nThe attribute reported in answer to this request is UNIXDIAGVFS.  The payload\nassociated with this attribute is represented in the following structure:\n\nstruct unixdiagvfs {\nu32 udiagvfsdev;\nu32 udiagvfsino;\n};\n\nThe fields of this structure are as follows:\n\nudiagvfsdev\nThe device number of the corresponding on-disk socket inode.\n\nudiagvfsino\nThe inode number of the corresponding on-disk socket inode.\n\nUDIAGSHOWPEER\nThe attribute reported in answer to this request is UNIXDIAGPEER.   The  pay‐\nload  associated with this attribute is a u32 value which is the peer's inode\nnumber.  This attribute is reported for connected sockets only.\n\nUDIAGSHOWICONS\nThe attribute reported in answer to this request is UNIXDIAGICONS.  The  pay‐\nload associated with this attribute is an array of u32 values which are inode\nnumbers  of  sockets  that  has  passed  the  connect(2)  call, but hasn't been\nprocessed with accept(2) yet.  This attribute is reported for listening sockets\nonly.\n\nUDIAGSHOWRQLEN\nThe attribute reported in answer to this request is UNIXDIAGRQLEN.  The  pay‐\nload associated with this attribute is represented in the following structure:\n\nstruct unixdiagrqlen {\nu32 udiagrqueue;\nu32 udiagwqueue;\n};\n\nThe fields of this structure are as follows:\n\nudiagrqueue\nFor listening sockets: the number of pending connections.  The length of\nthe  array  associated  with  the  UNIXDIAGICONS response attribute is\nequal to this value.\n\nFor established sockets: the amount of data in incoming queue.\n\nudiagwqueue\nFor listening sockets: the backlog length  which  equals  to  the  value\npassed as the second argument to listen(2).\n\nFor established sockets: the amount of memory available for sending.\n\nUDIAGSHOWMEMINFO\nThe  attribute  reported  in  answer to this request is UNIXDIAGMEMINFO.  The\npayload associated with this attribute is an array of  u32  values  described\nbelow in the subsection \"Socket memory information\".\n\nThe following attributes are reported back without any specific request:\n\nUNIXDIAGSHUTDOWN\nThe  payload associated with this attribute is u8 value which represents bits\nof shutdown(2) state.\n\nudiagcookie\nThis is an array of opaque identifiers that could be  used  along  with  udiagino  to\nspecify  an  individual socket.  It is ignored when querying for a list of sockets, as\nwell as when all its elements are set to -1.\n\nThe response to a query for UNIX domain sockets is represented as an array of\n\nstruct unixdiagmsg {\nu8    udiagfamily;\nu8    udiagtype;\nu8    udiagstate;\nu8    pad;\nu32   udiagino;\nu32   udiagcookie[2];\n};\n\nfollowed by netlink attributes.\n\nThe fields of this structure are as follows:\n\nudiagfamily\nThis field has the same meaning as in struct unixdiagreq.\n\nudiagtype\nThis is set to one of SOCKPACKET, SOCKSTREAM, or SOCKSEQPACKET.\n\nudiagstate\nThis is set to one of TCPLISTEN or TCPESTABLISHED.\n\npad    This field is set to 0.\n\nudiagino\nThis is the socket inode number.\n\nudiagcookie\nThis is an array of opaque identifiers that could be used in subsequent queries.\n"
                    },
                    {
                        "name": "IPv4 and IPv6 sockets",
                        "content": "For IPv4 and IPv6 sockets, the request is represented in the following structure:\n\nstruct inetdiagreqv2 {\nu8    sdiagfamily;\nu8    sdiagprotocol;\nu8    idiagext;\nu8    pad;\nu32   idiagstates;\nstruct inetdiagsockid id;\n};\n\nwhere struct inetdiagsockid is defined as follows:\n\nstruct inetdiagsockid {\nbe16  idiagsport;\nbe16  idiagdport;\nbe32  idiagsrc[4];\nbe32  idiagdst[4];\nu32   idiagif;\nu32   idiagcookie[2];\n};\n\nThe fields of struct inetdiagreqv2 are as follows:\n\nsdiagfamily\nThis should be set to either AFINET or AFINET6 for  IPv4  or  IPv6  sockets  respec‐\ntively.\n\nsdiagprotocol\nThis should be set to one of IPPROTOTCP, IPPROTOUDP, or IPPROTOUDPLITE.\n\nidiagext\nThis is a set of flags defining what kind of extended information to report.  Each re‐\nquested  kind  of information is reported back as a netlink attribute as described be‐\nlow:\n\nINETDIAGTOS\nThe payload associated with this attribute is a u8 value which is the TOS  of\nthe socket.\n\nINETDIAGTCLASS\nThe  payload associated with this attribute is a u8 value which is the TClass\nof the socket.  IPv6 sockets only.  For LISTEN and CLOSE sockets, this is  fol‐\nlowed  by INETDIAGSKV6ONLY attribute with associated u8 payload value mean‐\ning whether the socket is IPv6-only or not.\n\nINETDIAGMEMINFO\nThe payload associated with this attribute  is  represented  in  the  following\nstructure:\n\nstruct inetdiagmeminfo {\nu32 idiagrmem;\nu32 idiagwmem;\nu32 idiagfmem;\nu32 idiagtmem;\n};\n\nThe fields of this structure are as follows:\n\nidiagrmem  The amount of data in the receive queue.\n\nidiagwmem  The amount of data that is queued by TCP but not yet sent.\n\nidiagfmem  The amount of memory scheduled for future use (TCP only).\n\nidiagtmem  The amount of data in send queue.\n\nINETDIAGSKMEMINFO\nThe  payload  associated  with  this  attribute is an array of u32 values de‐\nscribed below in the subsection \"Socket memory information\".\n\nINETDIAGINFO\nThe payload associated with this attribute is specific to the  address  family.\nFor TCP sockets, it is an object of type struct tcpinfo.\n\nINETDIAGCONG\nThe  payload associated with this attribute is a string that describes the con‐\ngestion control algorithm used.  For TCP sockets only.\n\npad    This should be set to 0.\n\nidiagstates\nThis is a bit mask that defines a filter of socket states.  Only those  sockets  whose\nstates  are  in  this  mask will be reported.  Ignored when querying for an individual\nsocket.\n\nid     This is a socket ID object that is used in dump requests, in queries about  individual\nsockets,  and is reported back in each response.  Unlike UNIX domain sockets, IPv4 and\nIPv6 sockets are identified using addresses and ports.  All values are in network byte\norder.\n\nThe fields of struct inetdiagsockid are as follows:\n\nidiagsport\nThe source port.\n\nidiagdport\nThe destination port.\n\nidiagsrc\nThe source address.\n\nidiagdst\nThe destination address.\n\nidiagif\nThe interface number the socket is bound to.\n\nidiagcookie\nThis is an array of opaque identifiers that could be used along with other  fields  of\nthis  structure  to  specify  an individual socket.  It is ignored when querying for a\nlist of sockets, as well as when all its elements are set to -1.\n\nThe response to a query for IPv4 or IPv6 sockets is represented as an array of\n\nstruct inetdiagmsg {\nu8    idiagfamily;\nu8    idiagstate;\nu8    idiagtimer;\nu8    idiagretrans;\n\nstruct inetdiagsockid id;\n\nu32   idiagexpires;\nu32   idiagrqueue;\nu32   idiagwqueue;\nu32   idiaguid;\nu32   idiaginode;\n};\n\nfollowed by netlink attributes.\n\nThe fields of this structure are as follows:\n\nidiagfamily\nThis is the same field as in struct inetdiagreqv2.\n\nidiagstate\nThis denotes socket state as in struct inetdiagreqv2.\n\nidiagtimer\nFor TCP sockets, this field describes the type of timer that is currently  active  for\nthe socket.  It is set to one of the following constants:\n\n0      no timer is active\n1      a retransmit timer\n2      a keep-alive timer\n3      a TIMEWAIT timer\n4      a zero window probe timer\n\nFor non-TCP sockets, this field is set to 0.\n\nidiagretrans\nFor  idiagtimer  values  1,  2, and 4, this field contains the number of retransmits.\nFor other idiagtimer values, this field is set to 0.\n\nidiagexpires\nFor TCP sockets that have an active timer, this field describes its expiration time in\nmilliseconds.  For other sockets, this field is set to 0.\n\nidiagrqueue\nFor listening sockets: the number of pending connections.\n\nFor other sockets: the amount of data in the incoming queue.\n\nidiagwqueue\nFor listening sockets: the backlog length.\n\nFor other sockets: the amount of memory available for sending.\n\nidiaguid\nThis is the socket owner UID.\n\nidiaginode\nThis is the socket inode number.\n"
                    },
                    {
                        "name": "Socket memory information",
                        "content": "The payload associated with UNIXDIAGMEMINFO and INETDIAGSKMEMINFO netlink  attributes  is\nan array of the following u32 values:\n\nSKMEMINFORMEMALLOC\nThe amount of data in receive queue.\n\nSKMEMINFORCVBUF\nThe receive socket buffer as set by SORCVBUF.\n\nSKMEMINFOWMEMALLOC\nThe amount of data in send queue.\n\nSKMEMINFOSNDBUF\nThe send socket buffer as set by SOSNDBUF.\n\nSKMEMINFOFWDALLOC\nThe amount of memory scheduled for future use (TCP only).\n\nSKMEMINFOWMEMQUEUED\nThe amount of data queued by TCP, but not yet sent.\n\nSKMEMINFOOPTMEM\nThe amount of memory allocated for the socket's service needs (e.g., socket filter).\n\nSKMEMINFOBACKLOG\nThe amount of packets in the backlog (not yet processed).\n"
                    }
                ]
            },
            "VERSIONS": {
                "content": "NETLINKINETDIAG  was  introduced in Linux 2.6.14 and supported AFINET and AFINET6 sockets\nonly.  In Linux 3.3, it was renamed to NETLINKSOCKDIAG  and  extended  to  support  AFUNIX\nsockets.\n\nUNIXDIAGMEMINFO and INETDIAGSKMEMINFO were introduced in Linux 3.6.\n",
                "subsections": []
            },
            "STANDARDS": {
                "content": "Linux.\n",
                "subsections": []
            },
            "EXAMPLES": {
                "content": "The  following example program prints inode number, peer's inode number, and name of all UNIX\ndomain sockets in the current namespace.\n\n#include <errno.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <sys/socket.h>\n#include <sys/un.h>\n#include <linux/netlink.h>\n#include <linux/rtnetlink.h>\n#include <linux/sockdiag.h>\n#include <linux/unixdiag.h>\n\nstatic int\nsendquery(int fd)\n{\nstruct sockaddrnl nladdr = {\n.nlfamily = AFNETLINK\n};\nstruct\n{\nstruct nlmsghdr nlh;\nstruct unixdiagreq udr;\n} req = {\n.nlh = {\n.nlmsglen = sizeof(req),\n.nlmsgtype = SOCKDIAGBYFAMILY,\n.nlmsgflags = NLMFREQUEST | NLMFDUMP\n},\n.udr = {\n.sdiagfamily = AFUNIX,\n.udiagstates = -1,\n.udiagshow = UDIAGSHOWNAME | UDIAGSHOWPEER\n}\n};\nstruct iovec iov = {\n.iovbase = &req,\n.iovlen = sizeof(req)\n};\nstruct msghdr msg = {\n.msgname = &nladdr,\n.msgnamelen = sizeof(nladdr),\n.msgiov = &iov,\n.msgiovlen = 1\n};\n\nfor (;;) {\nif (sendmsg(fd, &msg, 0) < 0) {\nif (errno == EINTR)\ncontinue;\n\nperror(\"sendmsg\");\nreturn -1;\n}\n\nreturn 0;\n}\n}\n\nstatic int\nprintdiag(const struct unixdiagmsg *diag, unsigned int len)\n{\nif (len < NLMSGLENGTH(sizeof(*diag))) {\nfputs(\"short response\\n\", stderr);\nreturn -1;\n}\nif (diag->udiagfamily != AFUNIX) {\nfprintf(stderr, \"unexpected family %u\\n\", diag->udiagfamily);\nreturn -1;\n}\n\nunsigned int rtalen = len - NLMSGLENGTH(sizeof(*diag));\nunsigned int peer = 0;\nsizet pathlen = 0;\nchar path[sizeof(((struct sockaddrun *) 0)->sunpath) + 1];\n\nfor (struct rtattr *attr = (struct rtattr *) (diag + 1);\nRTAOK(attr, rtalen); attr = RTANEXT(attr, rtalen)) {\nswitch (attr->rtatype) {\ncase UNIXDIAGNAME:\nif (!pathlen) {\npathlen = RTAPAYLOAD(attr);\nif (pathlen > sizeof(path) - 1)\npathlen = sizeof(path) - 1;\nmemcpy(path, RTADATA(attr), pathlen);\npath[pathlen] = '\\0';\n}\nbreak;\n\ncase UNIXDIAGPEER:\nif (RTAPAYLOAD(attr) >= sizeof(peer))\npeer = *(unsigned int *) RTADATA(attr);\nbreak;\n}\n}\n\nprintf(\"inode=%u\", diag->udiagino);\n\nif (peer)\nprintf(\", peer=%u\", peer);\n\nif (pathlen)\nprintf(\", name=%s%s\", *path ? \"\" : \"@\",\n*path ? path : path + 1);\n\nputchar('\\n');\nreturn 0;\n}\n\nstatic int\nreceiveresponses(int fd)\n{\nlong buf[8192 / sizeof(long)];\nstruct sockaddrnl nladdr;\nstruct iovec iov = {\n.iovbase = buf,\n.iovlen = sizeof(buf)\n};\nint flags = 0;\n\nfor (;;) {\nstruct msghdr msg = {\n.msgname = &nladdr,\n.msgnamelen = sizeof(nladdr),\n.msgiov = &iov,\n.msgiovlen = 1\n};\n\nssizet ret = recvmsg(fd, &msg, flags);\n\nif (ret < 0) {\nif (errno == EINTR)\ncontinue;\n\nperror(\"recvmsg\");\nreturn -1;\n}\nif (ret == 0)\nreturn 0;\n\nif (nladdr.nlfamily != AFNETLINK) {\nfputs(\"!AFNETLINK\\n\", stderr);\nreturn -1;\n}\n\nconst struct nlmsghdr *h = (struct nlmsghdr *) buf;\n\nif (!NLMSGOK(h, ret)) {\nfputs(\"!NLMSGOK\\n\", stderr);\nreturn -1;\n}\n\nfor (; NLMSGOK(h, ret); h = NLMSGNEXT(h, ret)) {\nif (h->nlmsgtype == NLMSGDONE)\nreturn 0;\n\nif (h->nlmsgtype == NLMSGERROR) {\nconst struct nlmsgerr *err = NLMSGDATA(h);\n\nif (h->nlmsglen < NLMSGLENGTH(sizeof(*err))) {\nfputs(\"NLMSGERROR\\n\", stderr);\n} else {\nerrno = -err->error;\nperror(\"NLMSGERROR\");\n}\n\nreturn -1;\n}\n\nif (h->nlmsgtype != SOCKDIAGBYFAMILY) {\nfprintf(stderr, \"unexpected nlmsgtype %u\\n\",\n(unsigned) h->nlmsgtype);\nreturn -1;\n}\n\nif (printdiag(NLMSGDATA(h), h->nlmsglen))\nreturn -1;\n}\n}\n}\n\nint\nmain(void)\n{\nint fd = socket(AFNETLINK, SOCKRAW, NETLINKSOCKDIAG);\n\nif (fd < 0) {\nperror(\"socket\");\nreturn 1;\n}\n\nint ret = sendquery(fd) || receiveresponses(fd);\n\nclose(fd);\nreturn ret;\n}\n",
                "subsections": []
            },
            "SEE ALSO": {
                "content": "netlink(3), rtnetlink(3), netlink(7), tcp(7)\n\nLinux man-pages 6.7                          2023-10-31                                 sockdiag(7)",
                "subsections": []
            }
        }
    }
}