On 12/07/2016 02:59 PM, Dmitry V. Levin wrote: > From: Pavel Emelyanov <xemul@xxxxxxxxxxxxx> > > Co-authored-by: Dmitry V. Levin <ldv@xxxxxxxxxxxx> > Signed-off-by: Pavel Emelyanov <xemul@xxxxxxxxxxxxx> > Signed-off-by: Dmitry V. Levin <ldv@xxxxxxxxxxxx> Thank you, Pavel and Dmitry, for all the work that went into this page! I've applied and pushed to Git. I made a lot of trivial edits to the page. You may want to review it, but I don't think I broke anything. Perhaps the most notable change was to consistently replace "protocol family" by "address family". Cheers, Michael > --- > man7/sock_diag.7 | 865 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 865 insertions(+) > create mode 100644 man7/sock_diag.7 > > diff --git a/man7/sock_diag.7 b/man7/sock_diag.7 > new file mode 100644 > index 0000000..c4948d7 > --- /dev/null > +++ b/man7/sock_diag.7 > @@ -0,0 +1,865 @@ > +.\" Copyright (c) 2016 Pavel Emelyanov <xemul@xxxxxxxxxxxxx> > +.\" Copyright (c) 2016 Dmitry V. Levin <ldv@xxxxxxxxxxxx> > +.\" > +.\" %%%LICENSE_START(GPLv2+_DOC_FULL) > +.\" This is free documentation; you can redistribute it and/or > +.\" modify it under the terms of the GNU General Public License as > +.\" published by the Free Software Foundation; either version 2 of > +.\" the License, or (at your option) any later version. > +.\" > +.\" The GNU General Public License's references to "object code" > +.\" and "executables" are to be interpreted as the output of any > +.\" document formatting or typesetting system, including > +.\" intermediate and printed output. > +.\" > +.\" This manual is distributed in the hope that it will be useful, > +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of > +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +.\" GNU General Public License for more details. > +.\" > +.\" You should have received a copy of the GNU General Public > +.\" License along with this manual; if not, see > +.\" <http://www.gnu.org/licenses/>. > +.\" %%%LICENSE_END > +.TH SOCK_DIAG 7 2016-12-07 "Linux" "Linux Programmer's Manual" > +.SH NAME > +sock_diag \- obtaining information about sockets > +.SH SYNOPSIS > +.nf > +.B #include <sys/socket.h> > +.B #include <linux/sock_diag.h> > +.BR "#include <linux/unix_diag.h>" " /* for UNIX domain sockets */" > +.BR "#include <linux/inet_diag.h>" " /* for IPv4 and IPv6 sockets */" > + > +.BI "diag_socket = socket(AF_NETLINK, " socket_type ", NETLINK_SOCK_DIAG);" > +.fi > +.SH DESCRIPTION > +The sock_diag netlink subsystem provides a mechanism for obtaining > +information about sockets of various protocol families from the kernel. > +This subsystem can be used to obtain information about individual > +sockets or request a list of sockets. > + > +In the request the caller can specify an additional information it would > +like to obtain about the socket, e.g. memory information or > +family-specific stuff. > + > +When requesting a list of sockets, the caller can specify filters that > +would be applied by the kernel to select a subset of sockets to report. > +For now there is only an ability to filter sockets by state (connected, > +listening, etc.) > + > +Note that sock_diag reports only those sockets that have a name, > +i.e. either bound explicitly with > +.BR bind (2) > +or sockets that were automatically bound to an address (e.g., by > +.BR connect (2)). > +This is the same set of sockets that is available via > +.IR /proc/net/unix , > +.IR /proc/net/tcp , > +.IR /proc/net/udp , > +etc. > + > +.SS Request > +The request starts with > +.I "struct nlmsghdr" > +header described in > +.BR netlink (7) > +with > +.I nlmsg_type > +field set to > +.BR SOCK_DIAG_BY_FAMILY . > +It is followed by a protocol family specific header that starts with > +a common part shared by all protocol families: > + > +.in +4n > +.nf > +struct sock_diag_req { > + __u8 sdiag_family; > + __u8 sdiag_protocol; > +}; > +.fi > +.in > +.PP > +The fields of this structure are as follows: > +.TP > +.I sdiag_family > +A protocol family. It should be set to the appropriate > +.B AF_* > +constant. > +.TP > +.I sdiag_protocol > +Depends on > +.IR sdiag_family . > +It should be set to the appropriate > +.B IPPROTO_* > +constant for > +.B AF_INET > +and > +.BR AF_INET6, > +and to 0 otherwise. > +.PP > +If > +.I nlmsg_flags > +field of the > +.I "struct nlmsghdr" > +header has > +.BR NLM_F_DUMP > +flag set, it means that a list of sockets is being requested, > +otherwise it is a query about an individual socket. > + > +.SS Response > +The response starts with > +.I "struct nlmsghdr" > +header and is followed by an array of family-specific objects. > +The array is to be accessed with the standard > +.B NLMSG_* > +macros from > +.BR netlink (3) > +API. > +.PP > +Each object is the NLA (netlink attributes) list that is to be accessed > +with the > +.B RTA_* > +macros from > +.BR rtnetlink (3) > +API. > + > +.SS UNIX domain sockets > +For UNIX domain sockets the request is represented in the following structure: > + > +.in +4n > +.nf > +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]; > +}; > +.fi > +.in > +.PP > +The fields of this structure are as follows: > +.TP > +.I sdiag_family > +The protocol family, it should be set to > +.BR AF_UNIX . > +.PP > +.I sdiag_protocol > +.PD 0 > +.TP > +.PD > +.I pad > +These fields should be set to 0. > +.TP > +.I udiag_states > +This is a bit mask that defines a filter of sockets states. > +Only those sockets whose states are in this mask will be reported. > +Ignored when querying for an individual socket. > +Supported values are: > +.PD 0 > +.RS > +.IP "" 2 > +1 << > +.B TCP_ESTABLISHED > +.IP > +1 << > +.B TCP_LISTEN > +.RE > +.PD > +.TP > +.I udiag_ino > +This is an inode number when querying for an individual socket. > +Ignored when querying for a list of sockets. > +.TP > +.I udiag_show > +This is a set of flags defining what kind of information to report. > +Each requested kind of information is reported back as a netlink > +attribute as described below: > +.RS > +.IP "" 2 > +.B UDIAG_SHOW_NAME > +.RS 4 > +The attribute reported in answer to this request is > +.BR UNIX_DIAG_NAME . > +The payload associated with this attribute is the pathname to which > +the socket was bound (a sequence of bytes up to > +.B UNIX_PATH_MAX > +length). > +.RE > +.IP "" 2 > +.B UDIAG_SHOW_VFS > +.RS 4 > +The attribute reported in answer to this request is > +.BR UNIX_DIAG_VFS . > +The payload associated with this attribute is represented in the following > +structure: > + > +.in +4n > +.nf > +struct unix_diag_vfs { > + __u32 udiag_vfs_dev; > + __u32 udiag_vfs_ino; > +}; > +.fi > +.in > + > +The fields of this structure are as follows: > +.PD 0 > +.RS 2 > +.IP "" 2 > +.I udiag_vfs_dev > +The device number of the corresponding on-disk socket inode. > +.IP > +.I udiag_vfs_ino > +The inode number of the corresponding on-disk socket inode. > +.RE > +.PD > +.RE > +.IP > +.B UDIAG_SHOW_PEER > +.RS 4 > +The attribute reported in answer to this request is > +.BR UNIX_DIAG_PEER . > +The payload associated with this attribute is a __u32 value > +which is the peer's inode number. > +This attribute is reported for connected sockets only. > +.RE > +.IP > +.B UDIAG_SHOW_ICONS > +.RS 4 > +The attribute reported in answer to this request is > +.BR UNIX_DIAG_ICONS . > +The payload associated with this attribute is an array of __u32 values > +which are inode numbers of sockets that has passed the > +.BR connect (2) > +call, but hasn't been processed with > +.BR accept (2) > +yet. This attribute is reported for listening sockets only. > +.RE > +.IP > +.B UDIAG_SHOW_RQLEN > +.RS 4 > +The attribute reported in answer to this request is > +.BR UNIX_DIAG_RQLEN . > +The payload associated with this attribute is represented in the following > +structure: > + > +.in +4n > +.nf > +struct unix_diag_rqlen { > + __u32 udiag_rqueue; > + __u32 udiag_wqueue; > +}; > +.fi > +.in > + > +The fields of this structure are as follows: > +.PD 0 > +.RS 2 > +.IP "" 2 > +.I udiag_rqueue > +.RS 6 > +.IP "listening sockets:" 2 > +The number of pending connections. The length of the array associated with > +.B UNIX_DIAG_ICONS > +response attribute is equal to this value. > +.IP "established sockets:" > +The amount of data in incoming queue. > +.RE > +.IP > +.I udiag_wqueue > +.RS 6 > +.IP "listening sockets:" 2 > +The backlog length which equals to the value passed as the second argument to > +.BR listen (2). > +.IP "established sockets:" > +The amount of memory available for sending. > +.RE > +.RE > +.PD > +.RE > +.IP > +.B UDIAG_SHOW_MEMINFO > +.RS 4 > +The attribute reported in answer to this request is > +.BR UNIX_DIAG_MEMINFO . > +The payload associated with this attribute is an array of __u32 values > +described below in "Socket memory information" subsection. > +.RE > +.IP > +.RE > +.RS > +The following attributes are reported back without any specific request: > +.IP "" 2 > +.BR UNIX_DIAG_SHUTDOWN . > +The payload associated with this attribute is __u8 value which represents > +bits of > +.BR shutdown (2) > +state. > +.RE > +.TP > +.I udiag_cookie > +This is an array of opaque identifiers that could be used along with > +.I udiag_ino > +to specify an individual socket. It is ignored when querying for a list > +of sockets, as well as when all its elements are set to \-1. > +.PP > +The response to a query for UNIX domain sockets is represented as an array of > + > +.in +4n > +.nf > +struct unix_diag_msg { > + __u8 udiag_family; > + __u8 udiag_type; > + __u8 udiag_state; > + __u8 pad; > + __u32 udiag_ino; > + __u32 udiag_cookie[2]; > +}; > +.fi > +.in > + > +followed by netlink attributes. > +.PP > +The fields of this structure are as follows: > +.TP > +.I udiag_family > +This field has the same meaning as in > +.IR "struct unix_diag_req" . > +.TP > +.I udiag_type > +This is set to one of the following constants: > +.PD 0 > +.RS > +.IP "" 2 > +.B SOCK_PACKET > +.IP > +.B SOCK_STREAM > +.IP > +.B SOCK_SEQPACKET > +.RE > +.PD > +.TP > +.I udiag_state > +This is set to one of the following constants: > +.PD 0 > +.RS > +.IP "" 2 > +.B TCP_LISTEN > +.IP > +.B TCP_ESTABLISHED > +.RE > +.PD > +.TP > +.I pad > +This field is set to 0. > +.TP > +.I udiag_ino > +This is the socket inode number. > +.TP > +.I udiag_cookie > +This is an array of opaque identifiers that could be used in subsequent > +queries. > + > +.SS IPv4 and IPv6 sockets > +For IPv4 and IPv6 sockets the request is represented in the following structure: > + > +.in +4n > +.nf > +struct inet_diag_req_v2 { > + __u8 sdiag_family; > + __u8 sdiag_protocol; > + __u8 idiag_ext; > + __u8 pad; > + __u32 idiag_states; > + struct inet_diag_sockid id; > +}; > +.fi > +.in > + > +where > +.I "struct inet_diag_sockid" > +is defined as follows: > + > +.in +4n > +.nf > +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]; > +}; > +.fi > +.in > +.PP > +The fields of > +.I "struct inet_diag_req_v2" > +are as follows: > +.TP > +.I sdiag_family > +This should be set to either > +.B AF_INET > +or > +.B AF_INET6 > +for > +.B IPv4 > +or > +.B IPv6 > +sockets respectively. > +.TP > +.I sdiag_protocol > +This should be set to one of the following constants: > +.PD 0 > +.RS > +.IP "" 2 > +.B IPPROTO_TCP > +.IP > +.B IPPROTO_UDP > +.IP > +.B IPPROTO_UDPLITE > +.RE > +.PD > +.TP > +.I idiag_ext > +This is a set of flags defining what kind of extended information to report. > +Each requested kind of information is reported back as a netlink attribute > +as described below: > +.RS > +.TP > +.B INET_DIAG_TOS > +The payload associated with this attribute is a __u8 value > +which is the TOS of the socket. > +.TP > +.B INET_DIAG_TCLASS > +The payload associated with this attribute is a __u8 value > +which is the TClass of the socket. IPv6 sockets only. > +For LISTEN and CLOSE sockets this is followed by > +.B INET_DIAG_SKV6ONLY > +attribute with associated __u8 payload value meaning whether the socket > +is IPv6-only or not. > +.TP > +.B INET_DIAG_MEMINFO > +The payload associated with this attribute is represented in the following > +structure: > + > +.in +4n > +.nf > +struct inet_diag_meminfo { > + __u32 idiag_rmem; > + __u32 idiag_wmem; > + __u32 idiag_fmem; > + __u32 idiag_tmem; > +}; > +.fi > +.in > + > +The fields of this structure are as follows: > +.RS > +.TP 12 > +.I idiag_rmem > +The amount of data in the receive queue. > +.TP > +.I idiag_wmem > +The amount of data that is queued by TCP but not yet sent. > +.TP > +.I idiag_fmem > +The amount of memory scheduled for future use (TCP only). > +.TP > +.I idiag_tmem > +The amount of data in send queue. > +.RE > +.TP > +.B INET_DIAG_SKMEMINFO > +The payload associated with this attribute is an array of __u32 values > +described below in "Socket memory information" subsection. > +.TP > +.B INET_DIAG_INFO > +The payload associated with this attribute is protocol specific. > +For TCP sockets it is an object of type > +.IR "struct tcp_info" . > +.TP > +.B INET_DIAG_CONG > +The payload associated with this attribute is a string that describes the > +congestion control algorithm used. For TCP sockets only. > +.RE > +.TP > +.I pad > +This should be set to 0. > +.TP > +.I idiag_states > +This is a bit mask that defines a filter of sockets states. > +Only those sockets whose states are in this mask will be reported. > +Ignored when querying for an individual socket. > +.TP > +.I id > +This is a socket id object that is used in dump requests, in queries > +about individual sockets, and is reported back in each response. > +Unlike UNIX domain sockets, IPv4 and IPv6 sockets are identified > +using addresses and ports. All values are in network byte order. > +.PP > +The fields of > +.I "struct inet_diag_sockid" > +are as follows: > +.TP > +.I idiag_sport > +The source port. > +.TP > +.I idiag_dport > +The destination port. > +.TP > +.I idiag_src > +The source address. > +.TP > +.I idiag_dst > +The destination address. > +.TP > +.I idiag_if > +The interface number the socket is bound to. > +.TP > +.I idiag_cookie > +This is an array of opaque identifiers that could be used along with > +other fields of this structure to specify an individual socket. > +It is ignored when querying for a list of sockets, as well as > +when all its elements are set to \-1. > +.PP > +The response to a query for IPv4 or IPv6 sockets is represented as an array of > + > +.in +4n > +.nf > +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; > +}; > +.fi > +.in > + > +followed by netlink attributes. > +.PP > +The fields of this structure are as follows: > +.TP > +.I idiag_family > +This is the same field as in > +.IR "struct inet_diag_req_v2" . > +.TP > +.I idiag_state > +This denotes socket state as in > +.IR "struct inet_diag_req_v2" . > +.TP > +.I idiag_timer > +For TCP sockets, this field describes the type of timer that is currently > +active for the socket. It is set to one of the following constants: > +.RS > +.TP > +.B 0 > +no timer is active > +.TP > +.B 1 > +a retransmit timer > +.TP > +.B 2 > +a keep-alive timer > +.TP > +.B 3 > +a TIME_WAIT timer > +.TP > +.B 4 > +a zero window probe timer > +.RE > +.IP > +.RS > +For non-TCP sockets this field is set to 0. > +.RE > +.TP > +.I idiag_retrans > +For > +.I idiag_timer > +values 1, 2, and 4 this field contains the number of retransmits. For other > +.I idiag_timer > +values this field is set to 0. > +.TP > +.I idiag_expires > +For TCP sockets that have an active timer this field describes its expiration > +time in milliseconds. For other sockets this field is set to 0. > +.TP > +.I idiag_rqueue > +.RS 7 > +.IP "listening sockets:" 2 > +The number of pending connections. > +.IP "other sockets:" > +The amount of data in incoming queue. > +.RE > +.TP > +.I idiag_wqueue > +.RS 7 > +.IP "listening sockets:" 2 > +The backlog length. > +.IP "other sockets:" > +The amount of memory available for sending. > +.RE > +.TP > +.I idiag_uid > +This is the socket owner UID. > +.TP > +.I idiag_inode > +This is the socket inode number. > + > +.SS Socket memory information > +The payload associated with > +.B UNIX_DIAG_MEMINFO > +and > +.BR INET_DIAG_SKMEMINFO > +netlink attributes is an array of the following __u32 values: > +.TP > +.B SK_MEMINFO_RMEM_ALLOC > +The amount of data in receive queue. > +.TP > +.B SK_MEMINFO_RCVBUF > +The receive socket buffer as set by > +.BR SO_RCVBUF . > +.TP > +.B SK_MEMINFO_WMEM_ALLOC > +The amount of data in send queue. > +.TP > +.B SK_MEMINFO_SNDBUF > +The send socket buffer as set by > +.BR SO_SNDBUF . > +.TP > +.B SK_MEMINFO_FWD_ALLOC > +The amount of memory scheduled for future use (TCP only). > +.TP > +.B SK_MEMINFO_WMEM_QUEUED > +The amount of data queued by TCP, but not yet sent. > +.TP > +.B SK_MEMINFO_OPTMEM > +The amount of memory allocated for socket's service needs (e.g. socket > +filter). > +.TP > +.B SK_MEMINFO_BACKLOG > +The amount of packets in the backlog (not yet processed). > +.SH CONFORMING TO > +The NETLINK_SOCK_DIAG API is Linux-specific. > +.SH VERSIONS > +.B NETLINK_INET_DIAG > +was introduced in Linux 2.6.14 and supported > +.B AF_INET > +and > +.B AF_INET6 > +sockets only. In Linux 3.3 it was renamed to > +.B NETLINK_SOCK_DIAG > +and extended to support > +.B AF_UNIX > +sockets. > +.PP > +.B UNIX_DIAG_MEMINFO > +and > +.BR INET_DIAG_SKMEMINFO > +were introduced in Linux 3.6. > +.SH EXAMPLE > +The following example program prints inode number, peer's inode number, > +and name of all UNIX domain sockets in the current namespace. > + > +.nf > +#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 = (void *) &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; > + } > + > + struct rtattr *attr; > + 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 (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 = { > + .nl_family = AF_NETLINK > + }; > + struct iovec iov = { > + .iov_base = buf, > + .iov_len = sizeof(buf) > + }; > + int flags = 0; > + > + for (;;) { > + struct msghdr msg = { > + .msg_name = (void *) &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; > + > + 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; > +} > +.fi > +.SH SEE ALSO > +.BR netlink (3), > +.BR rtnetlink (3), > +.BR netlink (7), > +.BR tcp (7) > -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ -- To unsubscribe from this list: send the line "unsubscribe linux-man" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html