| 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.
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.
| 15 juin 2024 | Pages du manuel de Linux 6.9.1 |