{
    "mode": "man",
    "parameter": "sock_diag",
    "section": "7",
    "url": "https://www.chedong.com/phpMan.php/man/sock_diag/7/json",
    "generated": "2026-06-15T16:45:13Z",
    "synopsis": "",
    "sections": {
        "NAME": {
            "content": "sockdiag - obtaining information about sockets\n",
            "subsections": []
        },
        "SYNOPSIS": {
            "content": "",
            "subsections": [
                {
                    "name": "#include <sys/socket.h>",
                    "content": "#include <linux/sockdiag.h>\n#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  pro‐\ncessed  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": []
        },
        "CONFORMING TO": {
            "content": "The NETLINKSOCKDIAG API is Linux-specific.\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 = {\n.nlfamily = AFNETLINK\n};\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\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",
            "subsections": []
        },
        "COLOPHON": {
            "content": "This page is part of release 5.10 of the Linux  man-pages  project.   A  description  of  the\nproject,  information about reporting bugs, and the latest version of this page, can be found\nat https://www.kernel.org/doc/man-pages/.\n\n\n\nLinux                                        2020-11-01                                 SOCKDIAG(7)",
            "subsections": []
        }
    },
    "summary": "sockdiag - obtaining information about sockets",
    "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 = {",
        ".nlfamily = AFNETLINK",
        "};",
        "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;",
        "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"
        }
    ]
}