sock_diag(7) | Miscellaneous Information Manual | sock_diag(7) |
sock_diag – Obtention d’informations à propos des sockets
#include <sys/socket.h> #include <linux/sock_diag.h> #include <linux/unix_diag.h> /* pour sockets de domaine UNIX */ #include <linux/inet_diag.h> /* pour sockets IPv4 et IPv6 */
diag_socket = socket(AF_NETLINK, socket_type, NETLINK_SOCK_DIAG);
Le sous-système netlink de sock_diag fournit un mécanisme pour obtenir les informations sur les sockets de diverses familles d’adresses du noyau. Ce sous-système peut être utilisé pour obtenir des informations à propos de sockets particuliers ou pour obtenir la liste des sockets.
Dans la requête, l’appelant peut indiquer les informations supplémentaires qu’il désire obtenir à propos du socket, par exemple, les informations sur la mémoire ou les informations spécifiques à une famille d’adresses.
Lors d’une requête d’une liste de sockets, l’appelant peut indiquer des filtres à appliquer par le noyau pour sélectionner un sous-ensemble de sockets. Pour l’instant, il est seulement possible de filtrer les sockets par état (connecté, à l’écoute, etc).
Remarquez que sock_diag rapporte seulement les sockets ayant un nom. C’est-à-dire soit les sockets liés explicitement avec bind(2) ou les sockets qui ont été automatiquement liés à une adresse (par exemple, par connect(2)). C’est le même ensemble de sockets disponible à l’aide de /proc/net/unix, /proc/net/tcp, /proc/net/udp, etc.
La requête débute par un en-tête struct nlmsghdr décrit dans netlink(7) avec un champ nlmsg_type réglé à SOCK_DIAG_BY_FAMILY. Il est suivi par un en-tête spécifique à une famille d’adresses qui débute par une partie commune partagée par toutes les familles d’adresses :
struct sock_diag_req {
__u8 sdiag_family;
__u8 sdiag_protocol; };
Les membres de cette structure sont les suivants :
Si le champ nlmsg_flags de l’en-tête struct nlmsghdr a l’indicateur NLM_F_DUMP défini, cela signifie qu’une liste de sockets est demandée. Sinon, il s’agit d’une requête concernant un socket particulier.
La réponse débute avec un en-tête struct nlmsghdr et est suivie par un tableau d’objets spécifique à la famille d’adresses. Le tableau est accessible avec les macros NLMSG_* standards de l’API de netlink(3).
Chaque objet est la liste NLA (attributs netlink) accessible avec les macros RTA_* de l’API de rtnetlink(3).
Pour les sockets de domaine UNIX, la requête est décrite dans la structure suivante :
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]; };
Les membres de cette structure sont les suivants :
sdiag_protocol
1 << TCP_LISTEN
struct unix_diag_vfs {
__u32 udiag_vfs_dev;
__u32 udiag_vfs_ino; };
struct unix_diag_rqlen {
__u32 udiag_rqueue;
__u32 udiag_wqueue; };
Les attributs suivants sont rapportés sans requête particulière :
La réponse à une requête de sockets de domaine UNIX est décrite sous forme de tableau de
struct unix_diag_msg {
__u8 udiag_family;
__u8 udiag_type;
__u8 udiag_state;
__u8 pad;
__u32 udiag_ino;
__u32 udiag_cookie[2]; };
suivis par les attributs de netlink.
Les membres de cette structure sont les suivants :
Pour les sockets IPv4 et IPv6, la requête est décrite dans la structure suivante :
struct inet_diag_req_v2 {
__u8 sdiag_family;
__u8 sdiag_protocol;
__u8 idiag_ext;
__u8 pad;
__u32 idiag_states;
struct inet_diag_sockid id; };
où struct inet_diag_sockid est défini comme suit :
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]; };
Les champs de struct inet_diag_req_v2 sont comme suit :
struct inet_diag_meminfo {
__u32 idiag_rmem;
__u32 idiag_wmem;
__u32 idiag_fmem;
__u32 idiag_tmem; };
Les champs de struct inet_diag_sockid sont comme suit :
La réponse à une requête de sockets IPv4 ou IPv6 est décrite sous forme d'un tableau de
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; };
suivis par les attributs de netlink.
Les membres de cette structure sont les suivants :
La charge utile associée avec les attributs UNIX_DIAG_MEMINFO et INET_DIAG_SKMEMINFO de netlink est un tableau des valeurs __u32 suivantes :
NETLINK_INET_DIAG a été introduit dans Linux 2.6.14 et ne gère que les sockets AF_INET et AF_INET6. Dans Linux 3.3, il a été renommé NETLINK_SOCK_DIAG et étendu pour gérer les sockets AF_UNIX.
UNIX_DIAG_MEMINFO et INET_DIAG_SKMEMINFO ont été introduits dans Linux 3.6.
L’API NETLINK_SOCK_DIAG est spécifique à Linux.
L’exemple suivant affiche le numéro d’inœud, le numéro d’inœud du pair et le nom de tous les sockets de domaine UNIX dans l’espace de noms en cours.
#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("short response\n", stderr);
return -1;
}
if (diag->udiag_family != AF_UNIX) {
fprintf(stderr, "unexpected family %u\n", diag->udiag_family);
return -1;
}
unsigned int rta_len = len - NLMSG_LENGTH(sizeof(*diag));
unsigned int peer = 0;
size_t path_len = 0;
char path[sizeof(((struct sockaddr_un *) 0)->sun_path) + 1];
for (struct rtattr *attr = (struct rtattr *) (diag + 1);
RTA_OK(attr, rta_len); attr = RTA_NEXT(attr, rta_len)) {
switch (attr->rta_type) {
case UNIX_DIAG_NAME:
if (!path_len) {
path_len = RTA_PAYLOAD(attr);
if (path_len > sizeof(path) - 1)
path_len = sizeof(path) - 1;
memcpy(path, RTA_DATA(attr), path_len);
path[path_len] = '\0';
}
break;
case UNIX_DIAG_PEER:
if (RTA_PAYLOAD(attr) >= sizeof(peer))
peer = *(unsigned int *) RTA_DATA(attr);
break;
}
}
printf("inode=%u", diag->udiag_ino);
if (peer)
printf(", peer=%u", peer);
if (path_len)
printf(", name=%s%s", *path ? "" : "@",
*path ? path : path + 1);
putchar('\n');
return 0; } static int receive_responses(int fd) {
long buf[8192 / sizeof(long)];
struct sockaddr_nl nladdr;
struct iovec iov = {
.iov_base = buf,
.iov_len = sizeof(buf)
};
int flags = 0;
for (;;) {
struct msghdr msg = {
.msg_name = &nladdr,
.msg_namelen = sizeof(nladdr),
.msg_iov = &iov,
.msg_iovlen = 1
};
ssize_t ret = recvmsg(fd, &msg, flags);
if (ret < 0) {
if (errno == EINTR)
continue;
perror("recvmsg");
return -1;
}
if (ret == 0)
return 0;
if (nladdr.nl_family != AF_NETLINK) {
fputs("!AF_NETLINK\n", stderr);
return -1;
}
const struct nlmsghdr *h = (struct nlmsghdr *) buf;
if (!NLMSG_OK(h, ret)) {
fputs("!NLMSG_OK\n", stderr);
return -1;
}
for (; NLMSG_OK(h, ret); h = NLMSG_NEXT(h, ret)) {
if (h->nlmsg_type == NLMSG_DONE)
return 0;
if (h->nlmsg_type == NLMSG_ERROR) {
const struct nlmsgerr *err = NLMSG_DATA(h);
if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) {
fputs("NLMSG_ERROR\n", stderr);
} else {
errno = -err->error;
perror("NLMSG_ERROR");
}
return -1;
}
if (h->nlmsg_type != SOCK_DIAG_BY_FAMILY) {
fprintf(stderr, "unexpected nlmsg_type %u\n",
(unsigned) h->nlmsg_type);
return -1;
}
if (print_diag(NLMSG_DATA(h), h->nlmsg_len))
return -1;
}
} } int main(void) {
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
if (fd < 0) {
perror("socket");
return 1;
}
int ret = send_query(fd) || receive_responses(fd);
close(fd);
return ret; }
La traduction française de cette page de manuel a été créée par Christophe Blaess <https://www.blaess.fr/christophe/>, Stéphan Rafin <stephan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org>, David Prévot <david@tilapin.org> et Jean-Paul Guillonneau <guillonneau.jeanpaul@free.fr>
Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à debian-l10n-french@lists.debian.org.
5 février 2023 | Pages du manuel de Linux 6.03 |