93 votes

Puis-je surveiller un socket de domaine unix local comme tcpdump ?

J'aimerais surveiller les réponses sur un socket unix sans perturber les connexions originales et les acheminer vers un script pour traitement.

Je sais comment faire avec tcpdump pour les connexions tcp mais je ne trouve pas de solution pour les sockets unix locaux.

Est-ce que c'est possible ?

117voto

storoj Points 1221

Vous pouvez utiliser socat.

sudo mv /path/to/sock /path/to/sock.original
sudo socat -t100 -x -v UNIX-LISTEN:/path/to/sock,mode=777,reuseaddr,fork UNIX-CONNECT:/path/to/sock.original

Ce qui se passe au-dessus : Tout d'abord, déplacez le socket original vers sock.original. Socat crée une nouvelle socket ('UNIX-LISTEN') à l'emplacement de l'original et renvoie tout vers l'original ('UNIX-connect'). Le -v indique à socat d'imprimer également la sortie sur STDERR.

19voto

Valor Points 481

Il y a un type qui prétend le faire en créant une application qui agit comme une passerelle entre deux sockets et qui enregistre toutes les données qui circulent. Vous ne pouvez donc pas accéder à un socket, mais si vous pouvez redémarrer le service et le régler pour utiliser cette application, vous serez en mesure de voir tout le trafic.

Voici le lien vers le poste : Renifleur de sockets Unix

Il existe une autre méthode qui nécessite de trouver l'identifiant du processus attaché à la socket, puis de trouver avec lsof le descripteur de fichier de la socket et enfin d'exploiter le descripteur de fichier en utilisant strace.

Si vous pouvez arrêter le client/serveur qui utilise le socket et le reconfigurer, je vous recommande d'utiliser la première méthode. La deuxième méthode est délicate et nécessite de toucher à un processus en cours, ce qui peut provoquer un plantage de certaines applications.

J'espère que quelqu'un nous éclairera d'une autre façon :)

Bonne chance

13voto

omnigrok Points 81

Vous pouvez également essayer d'utiliser strace sur l'un des processus de part et d'autre de la socket, car cela vous permettra d'observer ce qui est écrit/lu. J'ai constaté que dans mes environnements de production, je n'ai pas socat, mais j'ai strace.

Pour tout objectif utile, il est nécessaire de définir -s sur quelque chose de grand.

13voto

任喜军 Points 81
// backup the socket
sudo mv /var/run/docker.sock /var/run/docker.sock.original

// use tcp port 8089 proxy the original socket
sudo socat TCP-LISTEN:8089,reuseaddr,fork UNIX-CONNECT:/var/run/docker.sock.original

// use the new socket to proxy the 8089 port
sudo socat UNIX-LISTEN:/var/run/docker.sock,fork TCP-CONNECT:127.0.0.1:8089

alors :

sudo tcpdump -i lo -netvv port 8089

2voto

robbmanes Points 41

Un peu tard, mais j'ai modifié un script de systemtap qui fera cela pour les personnes qui ne peuvent pas transférer le trafic de socket d'un processus d'écoute. Utilisez-le à vos risques et périls, je ne l'ai testé que pour Red Hat Enterprise Linux 7 mais les structures que nous référençons sont génériques et (espérons-le) ne changent pas beaucoup :

/*
 * watch_unix_socket.stp
 *
 * This is a simply more modern version of the script found here:
 * https://sourceware.org/systemtap/wiki/WSunixSockets
 *
 * The first argument is the location of the file descriptor for a UNIX socket.
 * To find this address, for example, for the Docker socket run:
 *
 * # lsof 2>&1 | awk '/docker.sock/ {print $7}' | grep -v '0t0' | sort -u
 * 0xffff8ed0b4eb1800
 *
 * And use that address to run this systemtap script:
 * 
 * # stap watch_unix_socket.stp 0xffff8ed0b4eb1800
 */

probe begin {
    printf("Watching input into socket 0x%x...\n", $1);
}

probe kernel.function("unix_stream_sendmsg") {
    if ($sock->sk != $1) {
        printf("%d %s is accessing %p\n", pid(), execname(), $sock->sk);
        printf("====================\n");

        len = 0
        for (i = 0; i < $msg->msg_iovlen; i++) {
            len += $msg->msg_iov[i]->iov_len;
        }

        printf("%d [", len);
        for (i = 0; i < $msg->msg_iovlen; i++) {
            printf("%s", user_string_n($msg->msg_iov[i]->iov_base, $msg->msg_iov[i]->iov_len));
        }

        printf("] [");
        for (i = 0; i < $msg->msg_iovlen; i++) {
            printf("%s", user_string_n($msg->msg_iov[i]->iov_base, $msg->msg_iov[i]->iov_len));
        }

        printf("]\n\n");
    }
}

Je le tiens à jour en tant que Github Gist sur ma page .

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X