Comment déterminer le temps de connexion de socket sous Linux

24

Je peux vérifier que la connexion est établie:

$ netstat -tn | grep "192.168.2.110"
tcp  0  0 192.168.2.100:10444  192.168.2.110:52639  ESTABLISHED

existe-t-il un moyen de vérifier combien de temps cette connexion au port TCP a été établie (connectée)?

(Non, je n'ai pas accès aux journaux des applications)

hidralisk
la source

Réponses:

23

Vous pouvez essayer ce qui suit:

  1. obtenir le PID (par exemple $pid) du programme en ajoutant l' -poption à netstat.

  2. identifiez la ligne appropriée dans le /proc/net/tcpfichier en regardant les champs local_addresset / ou rem_address(notez qu'ils sont au format hexadécimal, en particulier l'adresse IP est exprimée dans l'ordre des octets en petits caractères), assurez-vous également que le stest 01(pour ESTABLISHED);

  3. notez le inodechamp associé (par exemple $inode);

  4. recherchez-le inodeparmi les descripteurs de fichiers dans /proc/$pid/fdet enfin interrogez le temps d'accès au fichier du lien symbolique:

    find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %t
    

C'est un gros travail ... voici un script (stub) pour automatiser les points ci-dessus, il nécessite l'adresse distante et il imprime la disponibilité du socket en quelques secondes:

function suptime() {
    local addr=${1:?Specify the remote IPv4 address}
    local port=${2:?Specify the remote port number}
    # convert the provided address to hex format
    local hex_addr=$(python -c "import socket, struct; print(hex(struct.unpack('<L', socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8))")
    local hex_port=$(python -c "print(hex($port)[2:].upper().zfill(4))")
    # get the PID of the owner process
    local pid=$(netstat -ntp 2>/dev/null | awk '$6 == "ESTABLISHED" && $5 == "'$addr:$port'"{sub("/.*", "", $7); print $7}')
    [ -z "$pid" ] && { echo 'Address does not match' 2>&1; return 1; }
    # get the inode of the socket
    local inode=$(awk '$4 == "01" && $3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
    [ -z "$inode" ] && { echo 'Cannot lookup the socket' 2>&1; return 1; }
    # query the inode status change time
    local timestamp=$(find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %T@)
    [ -z "$timestamp" ] && { echo 'Cannot fetch the timestamp' 2>&1; return 1; }
    # compute the time difference
    LANG=C printf '%s (%.2fs ago)\n' "$(date -d @$timestamp)" $(bc <<<"$(date +%s.%N) - $timestamp")
}

(Edit merci à Alex pour les correctifs )

Exemple:

$ suptime 93.184.216.34 80
Thu Dec 24 16:22:58 CET 2015 (46.12s ago)
cYrus
la source
1
Cette recette affiche l'âge du processus qui a créé la connexion TCP, pas la connexion elle-même.
myroslav
@myroslav êtes-vous sûr? Il fonctionne contre ce scénario Node.js .
cYrus
J'avais testé votre nouveau script avec des connexions TCP ouvertes par mon Firefox sur Fedora 22 64 bits, et je n'obtenais certainement pas de numéros de "disponibilité". Quand un nouveau socket s'ouvre, il obtient une disponibilité "aléatoire", généralement le temps du "plus jeune" socket ESTABLISHED.
myroslav
@myroslav J'utilise Debian (3.16.0-4-amd64) ici, la seule chose que je remarque, c'est que le temps signalé est en fait d'environ 3 secondes de retard par rapport à la création de socket. Peut-être qu'il y a des comportements dépendants du système impliqués ...
cYrus
Pour le script, "$ suptime 192: 168: 120: 10 6379 Traceback (dernier appel le plus récent): Fichier" <string> ", ligne 1, dans <module> socket.error: une chaîne d'adresse IP illégale passée à inet_aton ne correspond pas "
Ondra Žižka
4

Ces questions m'ont été utiles, mais j'ai trouvé l'utilisation lsofau lieu de netstatme laisser éviter toutes les choses HEX:

Pour un processus ${APP}exécuté par l'utilisateur ${USER}, ce qui suit renvoie tous les sockets ouverts à l'adresse IP $ {IP}:

PEEID=$(sudo pgrep -u ${USER} ${APP}) && for i in `sudo lsof -anP -i -u logstash | grep ${IP} | awk '{print $6}'` ; do echo "${device} time" ; sudo find /proc/${PEEID}/fd -lname "socket:\[${device}\]" -printf %t 2> /dev/null  ; echo  ;  done

Le lsofcontient PIDégalement, mais je ne sais pas comment l'obtenir ni le numéro de l'appareil.

Cela a été testé sur Amazon Linux.

Raúl Cuza
la source
3

Le script de cYrus a fonctionné pour moi mais j'ai dû le corriger un peu (pour se débarrasser d'un "L" dans l'adresse hexadécimale et faire du port un hexadécimal à 4 chiffres):

--- suptime.orig    2015-08-20 15:46:12.896652464 +0200
+++ suptime 2015-08-20 15:47:48.560074728 +0200
@@ -7,8 +7,8 @@
     hex_addr=$(python -c "
 import socket, struct;
 print hex(struct.unpack('<L',
-socket.inet_aton('$addr'))[0])[2:].upper().zfill(8)")
-    hex_port=$(python -c "print hex($port)[2:].upper()")
+socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8)")
+    hex_port=$(python -c "print hex($port)[2:].upper().zfill(4)")
     inode=$(awk '$3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
     time=$(find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %A@)
     LANG=C printf '%.2fs' $(bc <<<"$(date +%s.%N) - $time")
Alex Vazquez Fente
la source
1

Que diriez-vous:

lsof -t -i @ 192.168.2.110 | xargs ps -fp

Vous pouvez également personnaliser la commande "ps" pour obtenir simplement pid et l'heure de début avec -o comme:

lsof -t -i @ 192.168.2.110 | xargs ps --no-headers -o'pid, start '-p

Bien sûr, cela suppose que le socket a été démarré au moment du processus.

Pete
la source
cela montre combien de temps le processus qui a ouvert le socket est en place. Dans le cas où il y a un processus qui s'exécute tout le temps et qu'il y a des déconnexions réseau, ces valeurs seraient très différentes. +1 pour l'effort
hidralisk
1

Merci pour le script maintenu dans la réponse de cYrus. J'ai eu des problèmes avec l'impression de doublons, probablement parce qu'il peut y avoir de nombreuses connexions de différents PID à l'adresse fournie, alors voici ma version améliorée qui imprime également le PID sur chaque ligne de sortie:

function suptime() {
    local addr=${1:?Specify the remote IPv4 address}
    local port=${2:?Specify the remote port number}

    # convert the provided address to hex format
    local hex_addr=$(python -c "import socket, struct; print(hex(struct.unpack('<L', socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8))")
    local hex_port=$(python -c "print(hex($port)[2:].upper().zfill(4))")

    # get the inode of the socket
    local inodes=$(awk '$4 == "01" && $3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
    [ -z "$inodes" ] && { echo 'Cannot lookup the socket(s)' 2>&1; return 1; }

    # get file descriptors
    for inode in $inodes; do
        # get inode's file descriptor details
        local fdinfo=( $(find /proc/[0-9]*/fd -lname "socket:\[$inode\]" -printf "%p %T@") )
        [ -z "$fdinfo" ] && { echo 'Cannot find file descriptor' 2>&1; return 1; }

        # extract pid
        local fdpath=${fdinfo[0]}
        local pid=${fdpath#/proc/}
        pid=${pid%%/*}

        # extract timestamp
        local timestamp=${fdinfo[1]}

        # compute the time difference
        LANG=C printf 'PID: %s; Age: %s (%.2fs ago)\n' "$pid" "$(date -d @$timestamp)" $(bc <<<"$(date +%s.%N) - $timestamp")
    done
}

Remarques:

  • besoins bc, netstat(fournis par net-toolsle rhel> = 7 et des systèmes similaires)
  • doit être exécuté en tant que root
fholzer
la source